-
-
Save airstruck/5e0d0336231cfdefd3f6424afe6e75dc to your computer and use it in GitHub Desktop.
RPC in Lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- RPC for Lua | |
-- From: https://gist.github.com/airstruck/5e0d0336231cfdefd3f6424afe6e75dc | |
-- License: MIT https://opensource.org/licenses/MIT | |
local socket = require 'socket' -- https://github.com/diegonehab/luasocket | |
local binser = require 'binser' -- https://github.com/bakpakin/binser | |
local DEFAULT_HOST = '127.0.0.1' | |
local DEFAULT_PORT = 4135 | |
local unpack = unpack or table.unpack | |
-- Escape and unescape data for network transfer. | |
-- Escapes line breaks, they signal end of data. | |
local ESC = string.char(27) | |
local ESC_ESC = ESC .. '1' | |
local ESC_LF = ESC .. '2' | |
local function escape (data) | |
return (data:gsub(ESC, ESC_ESC):gsub('\n', ESC_LF)) | |
end | |
local function unescape (data) | |
return (data:gsub(ESC_LF, '\n'):gsub(ESC_ESC, ESC)) | |
end | |
-- Serialize and deserialize data. | |
local function serialize (...) | |
return escape(binser.serialize(...)) .. '\n' | |
end | |
local function deserialize (data) | |
local results, len = binser.deserialize(unescape(data)) | |
return unpack(results, 1, len) | |
end | |
-- Client stuff. | |
-- Call an RPC method and return the results. | |
local function call (client, ...) | |
local tcp = socket.tcp() | |
tcp:settimeout(1) | |
tcp:connect(client.host, client.port) | |
assert(tcp:send(serialize(...))) | |
local result = assert(tcp:receive()) | |
tcp:close() | |
return select(2, assert(deserialize(result))) | |
end | |
-- Indexing an undefined field creates an RPC method. | |
local clientMeta = { | |
__index = function (t, k) | |
t[k] = function (t, ...) return call(t, k, ...) end | |
return t[k] | |
end, | |
} | |
-- Client constructor. | |
local function createClient (host, port) | |
local client = {} | |
client.host = host or DEFAULT_HOST | |
client.port = port or DEFAULT_PORT | |
return setmetatable(client, clientMeta) | |
end | |
-- Server stuff | |
-- Execute an RPC method. | |
local function execute (server, ok, proc, ...) | |
if not ok then return ok, proc, ... end | |
return pcall(server.exports[proc], server, ...) | |
end | |
-- Handles clients. Call server:update() in a loop. | |
local function update (server) | |
local tcp = server.socket:accept() | |
if not tcp then return end | |
local data = tcp:receive() | |
if data then | |
rawset(server, 'client', tcp) -- expose client socket to remote procs | |
tcp:send(serialize(execute(server, pcall(deserialize, data)))) | |
else | |
tcp:send(serialize(false, 'no data')) | |
end | |
tcp:close() | |
end | |
-- User-defined methods are exposed to RPC clients. | |
local serverMeta = { | |
__newindex = function (t, k, v) t.exports[k] = v end, | |
__index = function (t, k) return t.exports[k] end, | |
} | |
-- Server constructor | |
local function createServer (host, port) | |
local server = {} | |
server.update = update | |
server.host = host or DEFAULT_HOST | |
server.port = port or DEFAULT_PORT | |
server.exports = {} | |
server.socket = assert(socket.bind(server.host, server.port)) | |
server.socket:settimeout(1) | |
print('RPC on', server.socket:getsockname()) | |
return setmetatable(server, serverMeta) | |
end | |
return { client = createClient, server = createServer } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local rpc = require 'rpc' .client() | |
print(rpc:multiply(3, 4)) | |
print(rpc:concat('hello', 'world')) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
local rpc = require 'rpc' .server() | |
function rpc:multiply (a, b) | |
return a * b | |
end | |
function rpc:concat (a, b) | |
return a .. b | |
end | |
while 1 do rpc:update() end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment