Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local storage
- local save
- local PROTOCOL = "TURTI_NETWORK_PROTOCOL"
- local CONFIRMATION_TIMEOUT = 5
- local EVENT_START_SERVER = PROTOCOL .. "_EVENT_START_SERVER"
- local EVENT_DISCOVERY_CONFIRMATION = PROTOCOL .. "_EVENT_DISCOVERY_CONFIRMATION"
- local EVENT_CONFIRMATION = PROTOCOL .. "_EVENT_CONFIRMATION"
- local EVENT_RESPONSE = PROTOCOL .. "_EVENT_RESPONSE"
- local function openRednet()
- ThreadManager.blockExecutionOfOtherThreads()
- local side
- peripheral.find("modem", function(name, modem)
- if modem.isWireless() then
- side = name
- end
- end)
- if not rednet.isOpen(side) then
- rednet.open(side)
- end
- ThreadManager.unblockExecutionOfOtherThreads()
- end
- local function listenerThread()
- while true do
- openRednet()
- local id, rawMessage = rednet.receive(PROTOCOL, 1)
- if id then
- local message = getTableFromSaveText(rawMessage)
- local protocol = message.protocol
- local handle = message.handle
- local arguments = message.arguments
- if handle and protocol and message.type and message.type == "call" and message.callId then
- yield()
- if not arguments then
- arguments = {}
- end
- local networkAPI = storage.activeNetworks[protocol]
- if networkAPI then
- ThreadManager.startThread(function()
- local result = networkAPI._class_prototype.privateMethods.executeHandle(networkAPI, networkAPI._class_context, id, message.callId, handle, arguments)
- local throw = result.throw
- result.throw = nil
- result.protocol = protocol
- openRednet()
- rednet.send(id, getTableSaveText(result), PROTOCOL)
- if result.responseType == "error" and throw then
- error(tostring(throw))
- end
- end, true, "execute handle for network api " .. getClassContext(networkAPI).protocol)
- end
- elseif protocol and message.type and message.type == "discover" and message.callId then
- local networkAPI = storage.activeNetworks[protocol]
- if networkAPI then
- rednet.send(id, getTableSaveText({
- protocol = protocol,
- type = "discoveryConfirmation",
- callId = message.callId,
- serverId = os.getComputerID()
- }), PROTOCOL)
- end
- elseif protocol and message.type and message.type == "discoveryConfirmation" and message.callId and message.serverId then
- print(message.callId, message.serverId)
- os.queueEvent(EVENT_DISCOVERY_CONFIRMATION, message.callId, message.serverId)
- elseif protocol and message.type and message.type == "response" and message.callId then
- os.queueEvent(EVENT_RESPONSE, message.callId, rawMessage)
- elseif protocol and message.type == "startServer" then
- os.queueEvent(EVENT_START_SERVER, protocol)
- end
- end
- end
- end
- local TYPE_HANDLE_SLIM = "TYPE_HANDLE_SLIM"
- local TYPE_HANDLE_WITH_CONTEXT = "TYPE_HANDLE_WITH_CONTEXT"
- local NETWORK_SERVER_CLASS_PROTOTYPE = {
- key = "NetworkServer",
- methods = {
- register = function(api, context, method, hookName)
- if not hookName then
- hookName = method.name
- end
- context.handles[hookName] = {
- method = method,
- type = TYPE_HANDLE_SLIM
- }
- end,
- registerWithContext = function(api, context, method, hookName)
- if not hookName then
- hookName = method.name
- end
- context.handles[hookName] = {
- method = method,
- type = TYPE_HANDLE_WITH_CONTEXT
- }
- end
- },
- privateMethods = {
- executeHandle = function(api, context, callerId, callId, handleName, arguments)
- local handle = context.handles[handleName]
- if not handle then
- return {
- type = "response",
- callId = callId,
- responseType = "error",
- msg = "unknown handle: " .. handleName
- }
- end
- local status, ret
- if handle.type == TYPE_HANDLE_SLIM then
- status, ret = xpcall(api._class_prototype.privateMethods.executeHandleInternal, debug.traceback, handle.method, arguments)
- else
- table.insert(arguments, 1, toTurtiTable({
- id = callerId
- }))
- status, ret = xpcall(api._class_prototype.privateMethods.executeHandleInternal, debug.traceback, handle.method, arguments)
- end
- if status then
- return {
- type = "response",
- callId = callId,
- responseType = "return",
- returnValue = ret,
- callerId = callerId
- }
- else
- return {
- type = "response",
- callId = callId,
- responseType = "error",
- msg = "handle error (" .. handleName .. ")",
- throw = ret,
- callerId = callerId
- }
- end
- end,
- executeHandleInternal = function(handle, arguments)
- return invokeHook(handle.name, table.unpack(arguments))
- end
- },
- init = function()
- return { handles = {} }
- end,
- construct = function(api, context, protocol)
- context.protocol = protocol
- if storage.activeNetworks[protocol] then
- error("api with protocol " .. protocol .. " is already active")
- end
- storage.activeNetworks[protocol] = api
- save()
- openRednet()
- rednet.broadcast(getTableSaveText({
- protocol = context.protocol,
- type = "startServer"
- }), PROTOCOL)
- end
- }
- local NETWORK_CLIENT_CLASS_PROTOTYPE = {
- key = "NetworkClient",
- methods = {
- call = function(api, context, handleName, ...)
- local _, ret = api._class_prototype.privateMethods.call(api, context, nil, handleName, ...)
- return ret
- end,
- callWithId = function(api, context, id, handleName, ...)
- local _, ret = api._class_prototype.privateMethods.call(api, context, id, handleName, ...)
- return ret
- end,
- callGetId = function(api, context, handleName, ...)
- local responseId, ret = api._class_prototype.privateMethods.call(api, context, nil, handleName, ...)
- return responseId, ret
- end,
- callNoWait = function(api, context, handleName, ...)
- local callId = api._class_prototype.privateMethods.newCallId()
- local serverId = api._class_prototype.privateMethods.discoverServer(api, context, nil, callId)
- api._class_prototype.privateMethods.placeCall(api, context, serverId, callId, handleName, ...)
- end,
- broadcast = function(api, context, handleName, ...)
- local callId = api._class_prototype.privateMethods.newCallId()
- api._class_prototype.privateMethods.placeCall(api, context, nil, callId, handleName, ...)
- end,
- callWithIdNoWait = function(api, context, id, handleName, ...)
- local callId = api._class_prototype.privateMethods.newCallId()
- local serverId = api._class_prototype.privateMethods.discoverServer(api, context, id, callId)
- api._class_prototype.privateMethods.placeCall(api, context, serverId, callId, handleName, ...)
- end
- },
- privateMethods = {
- call = function(api, context, id, handleName, ...)
- local callId = api._class_prototype.privateMethods.newCallId()
- local serverId = api._class_prototype.privateMethods.discoverServer(api, context, id, callId)
- while true do
- api._class_prototype.privateMethods.placeCall(api, context, serverId, callId, handleName, ...)
- local success, idRet, ret = api._class_prototype.privateMethods.waitForResponse(context, callId)
- if success then
- return idRet, ret
- end
- print("recalling")
- end
- end,
- discoverServer = function(api, context, id, callId)
- local message = getTableSaveText({
- protocol = context.protocol,
- type = "discover",
- callId = callId
- })
- while true do
- if id == nil then
- rednet.broadcast(message, PROTOCOL)
- else
- rednet.send(id, message, PROTOCOL)
- end
- local serverId = api._class_prototype.privateMethods.waitForDiscoveryConfirmation(api, context, callId)
- if serverId then
- return serverId
- end
- end
- end,
- waitForDiscoveryConfirmation = function(api, context, callId)
- local timer = os.startTimer(storage.confirmationTimeout)
- while true do
- local event, arg1, arg2 = os.pullEvent()
- if event == "timer" then
- if arg1 == timer then
- return nil
- end
- elseif event == EVENT_DISCOVERY_CONFIRMATION then
- if arg1 == callId then
- return arg2
- end
- elseif event == EVENT_START_SERVER then
- if arg1 == context.protocol then
- return nil
- end
- end
- end
- end,
- newCallId = function()
- local callId = storage.currentCallId
- storage.currentCallId = storage.currentCallId + 1
- save()
- return callId
- end,
- placeCall = function(api, context, serverId, callId, handleName, ...)
- local message = getTableSaveText({
- protocol = context.protocol,
- handle = handleName,
- type = "call",
- callId = callId,
- arguments = { ... }
- })
- openRednet()
- if serverId==nil then
- rednet.broadcast(message, PROTOCOL)
- else
- rednet.send(serverId, message, PROTOCOL)
- end
- return callId
- end,
- waitForConfirmation = function(context, callId)
- local timer = os.startTimer(storage.confirmationTimeout)
- while true do
- local event, arg1 = os.pullEvent()
- if event == "timer" then
- if arg1 == timer then
- return false
- end
- elseif event == EVENT_CONFIRMATION then
- if arg1 == callId then
- return true
- end
- elseif event == EVENT_START_SERVER then
- if arg1 == context.protocol then
- return false
- end
- end
- end
- end,
- waitForResponse = function(context, callId)
- while true do
- local event, arg1, arg2 = os.pullEvent()
- if event == EVENT_START_SERVER then
- if arg1 == context.protocol then
- return false, nil
- end
- elseif event == EVENT_RESPONSE then
- if arg1 == callId then
- local response = getTableFromSaveText(arg2)
- if response.responseType == "error" then
- error(response.msg)
- elseif response.responseType == "return" then
- return true, response.callerId, response.returnValue
- else
- error("unknown response type: " .. response.responseType)
- end
- end
- end
- end
- end
- },
- construct = function(api, context, protocol)
- context.protocol = protocol
- end
- }
- local api = {
- setConfirmationTimeout = function(timeout)
- storage.confirmationTimeout = timeout
- save()
- end
- }
- return {
- name = "network",
- onSetup = function()
- ThreadManager.startThread(
- listenerThread, true, "network listener"
- )
- end,
- onInitStorage = function(_storage, _save)
- storage = _storage
- save = _save
- if not storage.activeNetworks then
- storage.activeNetworks = {}
- storage.currentCallId = 0
- storage.confirmationTimeout = CONFIRMATION_TIMEOUT
- end
- end,
- api = api,
- classes = {
- NETWORK_SERVER_CLASS_PROTOTYPE,
- NETWORK_CLIENT_CLASS_PROTOTYPE
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement