ComputerCraft Archive

neovariable2

computer networking LDDestroier github

Description

A collection of all my ComputerCraft programs and the APIs they use. This is mostly just to get them the fuck off of pastebin, and also to ensure that API owners don't change things to break my precious programs...!

Installation

Copy one of these commands into your ComputerCraft terminal:

wget:wget https://raw.githubusercontent.com/LDDestroier/CC/master/neovariable2.lua neovariable2
Archive:wget https://cc.shobie.xyz/cc/get/gh-LDDestroier-CC-neovariable2 neovariable2
Quick Install: wget https://cc.shobie.xyz/cc/get/gh-LDDestroier-CC-neovariable2 neovariable2

Usage

Run: neovariable2

Tags

networking

Source

View Original Source

Code Preview

--[[
	NewVariable 2 (WIP) by LDDestroier
	Get with:
	 wget https://raw.githubusercontent.com/LDDestroier/CC/master/neovariable2.lua

	To Do:
	 + asymmetrical encryption (actually forget that, functions wouldn't work out)
	 + work on stability
	 + steal underpants
--]]

local tArg = {...}
local mode = tArg[1] -- "server" or "demo", otherwise works as API

if not peripheral.find("modem") then
	ccemux.attach("top", "wireless_modem")
end

local makeMT = function(indexFunc, newindexFunc)
	local output = {}
	local _output = output
	output = {}
	local mt = {
		__index = function(t, k)
			if indexFunc then
				return indexFunc(_output, k)
			else
				return _output[k]
			end
		end,
		__newindex = function(t, k, v)
			if newindexFunc then
				_output[k] = newindexFunc(_output, k, v)
			else
				_output[k] = v
			end
		end
	}
	setmetatable(output, mt)
	return output
end

-- information about the API
local nv = {
	dir = {						-- all DIRECTORIES will end with "/"
		main = "neovariable",	-- main directory where all neovariable stuff are
		privateID = "private",	-- private computer ID, protect with your life
		publicID = "public",	-- public computer ID, is shared all the time
		config = "config",		-- config options
		api = "api/"			-- where APIs are stored
	},
	envKey = 1,			-- determines which environment to use
	environment = {},	-- stores multiple environments
	privateID = nil,	-- every computer should have a secret, individual "ID"
	publicID = nil,		-- every computer should also have a public key
	channel = 1002,		-- modem channel
}

-- functions that are put in the api for use
local API = {}

for k,v in pairs(nv.dir) do
	if k ~= "main" then
		nv.dir[k] = fs.combine(nv.dir.main, v)
	end
	if (not fs.exists(v)) and v:sub(-1, -1) == "/" then
		fs.makeDir(nv.dir[k])
	end
end

local getID = function(path)
	if fs.exists(path) then
		local file = fs.open(path, "r")
		local contents = file.readAll()
		file.close()
		return contents
	else
		return false
	end
end

local makeNewID = function(path, _id)
	local file = fs.open(path, "w")
	if _id then
		file.write(_id)
	else
		local id = ""
		for i = 1, 256 do
			id = id .. string.char(math.random(11, 127))
		end
		file.write(id)
	end
	file.close()
	return id
end

nv.privateID, nv.publicID = getID(nv.dir.privateID), getID(nv.dir.publicID)
if not nv.privateID then
	nv.privateID = makeNewID(nv.dir.privateID)
end
if not nv.publicID then
	nv.publicID = makeNewID(nv.dir.publicID)
end

local getModem = function()
	local m = peripheral.find("modem")
	if m then
		if not m.isOpen(nv.channel) then
			m.open(nv.channel)
		end
	end
	return m
end

local modem = getModem()

local send = function(envKey, cID, command, recipient, tbl, key, value)
	modem.transmit(nv.channel, nv.channel, {
		envKey = envKey,
		command = command,
		t = tbl,
		k = key,
		v = value,
		publicID = nv.publicID,
		cID = cID or math.random(1, 2^30),
		recipient = recipient
	})
end

-- easy way to view values
local debugErrorScreen = function(value)
	term.setBackgroundColor(colors.black)
	term.setTextColor(colors.white)
	term.clear()
	term.setCursorPos(1,1)
	print(textutils.serialize(value))
	term.setCursorPos(1, 18)
	error()
end

local rawReceive = function(valueType, timeout)
	local evt, tID
	if timeout then
		tID = os.startTimer(timeout)
	end
	repeat
		evt = {os.pullEvent()}
	until (
		evt[1] == "modem_message" and type(evt[5]) == valueType
	) or (
		evt[1] == "timer" and evt[2] == tID
	)
	return evt[5]
end

local receive = function(envKey, cID, timeout)
	local output
	repeat
		output = rawReceive("table", timeout)
	until (output or {}).cID == cID or output == nil
	return output
end

-- runs a neovariable server, and sets envList to the list of environments used
API.runServer = function( envList, verbose )
	local evt, msg
	while true do

		repeat
			repeat
				evt = {os.pullEvent("modem_message")}
			until type(evt[5]) == "table"
		until evt[5].cID ~= nil
		msg = evt[5]

		if msg.command == "find" then
			if verbose then print("got 'find' request") end
			send(nil, msg.cID, "find_response", msg.publicID, nv.publicID)
		elseif msg.command == "set" or msg.command == "get" then
			if ( -- check the types of all the input
				msg.envKey ~= nil and
				type(msg.publicID) == "string" and
				msg.k ~= nil and
				msg.recipient == nv.publicID
			) then
				nv.environment[msg.publicID] = nv.environment[msg.publicID] or {}
				nv.environment[msg.publicID][msg.envKey] = nv.environment[msg.publicID][msg.envKey] or {}

				if msg.command == "set" then
					if msg.v ~= nil then
						if verbose then print("[" .. tostring(msg.envKey) .. "] " .. tostring(msg.k) .. " = " .. tostring(msg.v)) end
						nv.environment[msg.publicID][msg.envKey][msg.k] = msg.v
					end
				elseif msg.command == "get" then
					if verbose then print("[" .. tostring(msg.envKey) .. "] " .. tostring(msg.k)) end
					send(msg.envKey, msg.cID, "get_response", msg.publicID, nv.environment[msg.publicID][msg.envKey][msg.k])
				end
			end
		end
		envList = nv.environment
		
	end
end

API.findServer = function(getList, timeout)
	timeout = tonumber(timeout) or 1
	local cID = math.random(1, 2^30)
	send(nil, cID, "find")
	if getList then
		local servers = {}
		parallel.waitForAny(
			function()
				while true do
					servers[#servers+1] = receive(nil, cID).publicID
				end
			end,
			function()
				sleep(timeout)
			end
		)
		return servers
	else
		return (receive(nil, cID, timeout) or {}).publicID
	end
end

API.newEnvironment = function(server, envKey)
	assert(type(server) == "string", "server ID must be a string")
	assert(envKey ~= nil, "envKey must not be nil")
	return makeMT(
		function(t, k)
			local cID = math.random(1, 2^30)
			send(envKey, cID, "get", server, t, k)
			local response = receive(envKey, cID, 3)
			if response then
				return response.t
			else
				return nil, "no response"
			end
		end,
		function(t, k, v)
			local cID = math.random(1, 2^30)
			send(envKey, cID, "set", server, t, k, v)
		end
	)
end

if mode == "server" then
	API.runServer(nil, true)
elseif mode == "demo" then
	local server = API.findServer(false, 1)
	if server then
		print("found server")
		local noo = API.newEnvironment(server, 1)
		local yoo = API.newEnvironment(server, 2)
		print("made envs")
		noo.hi = "what"
		yoo.he = "bumbo"
		print("set")
		local var = noo.hi
		local ver = yoo.he
		print("get")
		print("noo.hi = " .. tostring(noo.hi))
		print("yoo.he = " .. tostring(yoo.he))
	else
		print("no neovariable server")
	end
else
	return API
end