Initial WIP commit, functionnal
This commit is contained in:
parent
eac69d3fd4
commit
d0a8e78d33
|
@ -0,0 +1 @@
|
||||||
|
default
|
|
@ -0,0 +1,54 @@
|
||||||
|
local json = require("json")
|
||||||
|
ssb = dofile(minetest.get_modpath("scuttlebutt") .. "/ssb.lua")
|
||||||
|
|
||||||
|
function ssb_receive(key, json)
|
||||||
|
relation = "FROM JSON"
|
||||||
|
message = key .. "said: " .. "FROM JSON"
|
||||||
|
name = "FROM RELATION"
|
||||||
|
minetest.chat_send_player(name, message)
|
||||||
|
end
|
||||||
|
|
||||||
|
function ssb_send(player, key, message)
|
||||||
|
if key == "" or message == "" then
|
||||||
|
return "error: empty key or message!"
|
||||||
|
end
|
||||||
|
|
||||||
|
local pname = player:get_player_name()
|
||||||
|
message = string.format("Minetest bot here. %s says: %s", pname, message)
|
||||||
|
|
||||||
|
local content = {
|
||||||
|
type = "post",
|
||||||
|
text = message,
|
||||||
|
recps = {key},
|
||||||
|
}
|
||||||
|
|
||||||
|
local ret, err = ssb:publish(content)
|
||||||
|
if (not err) then
|
||||||
|
return "ok: message sent."
|
||||||
|
-- return (string.format("ret: %s", json.encode(ret)))
|
||||||
|
else
|
||||||
|
return (string.format("error happened: %s", err))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_chatcommand("ssb", {
|
||||||
|
params = "<@key> [message]",
|
||||||
|
description = "Scuttlebutt Chat",
|
||||||
|
privs = {
|
||||||
|
ssb = true,
|
||||||
|
},
|
||||||
|
func = function(name, param)
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
local key, message = string.match(param, "^(@[^ ]+) *(.*)$")
|
||||||
|
if not key or key == "" then
|
||||||
|
return true, "error: could not parse key"
|
||||||
|
elseif not message or message == "" then
|
||||||
|
local settings = minetest.settings:to_table()
|
||||||
|
local ip = settings.server_address or "127.0.0.1"
|
||||||
|
local port = settings.port or 30000
|
||||||
|
message = "Please join me on minetest: " .. ip .. ":" .. port
|
||||||
|
-- return true, "error: could not parse message"
|
||||||
|
end
|
||||||
|
return true, ssb_send(player, key, message)
|
||||||
|
end
|
||||||
|
})
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = scuttlebutt
|
||||||
|
description = Add Scuttlebutt chat.
|
||||||
|
depends = default
|
|
@ -0,0 +1,192 @@
|
||||||
|
local json = require("json")
|
||||||
|
local socket = require("socket")
|
||||||
|
local unix = require("socket.unix")
|
||||||
|
local bit32 = require("bit32")
|
||||||
|
local ssb = { VERSION = '0.1' }
|
||||||
|
|
||||||
|
local function get_ssb_dir()
|
||||||
|
local home = os.getenv("HOME")
|
||||||
|
return string.format("%s/.ssb", home)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function read_manifest()
|
||||||
|
local manifest = get_ssb_dir() .. "/manifest.json"
|
||||||
|
local f = io.open(manifest, "rb")
|
||||||
|
if not f then
|
||||||
|
return nil, "cannot find manifest: " .. manifest
|
||||||
|
end
|
||||||
|
local buf = f:read("*all")
|
||||||
|
f:close()
|
||||||
|
local js = json.decode(buf)
|
||||||
|
return js, nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function do_read(conn, id, final)
|
||||||
|
local buf, err = conn:receive(9)
|
||||||
|
if string.len(buf) < 9 then
|
||||||
|
minetest.log("do_read: header len should be 9 but is: " .. string.len(buf))
|
||||||
|
return nil, string.len(buf)
|
||||||
|
end
|
||||||
|
|
||||||
|
local first = string.byte(buf, 1)
|
||||||
|
local len = bit32.bor(bit32.lshift(string.byte(buf, 2), 24),
|
||||||
|
bit32.lshift(string.byte(buf, 3), 16),
|
||||||
|
bit32.lshift(string.byte(buf, 4), 8),
|
||||||
|
string.byte(buf, 5))
|
||||||
|
-- remove minus sign
|
||||||
|
local id = bit32.bxor(bit32.bor(bit32.lshift(string.byte(buf, 6), 24),
|
||||||
|
bit32.lshift(string.byte(buf, 7), 16),
|
||||||
|
bit32.lshift(string.byte(buf, 8), 8),
|
||||||
|
string.byte(buf, 9)), 0xFFFFFFFF) + 1
|
||||||
|
-- minetest.log("do_read: len: " .. len)
|
||||||
|
-- minetest.log("do_read: id : " .. id)
|
||||||
|
if id ~= 1 then
|
||||||
|
minetest.log("do_read: id should be 1 but is: " .. id)
|
||||||
|
-- minetest.log("do_read: " .. string.byte(buf, 6) .. string.byte(buf, 7) .. string.byte(buf, 8) .. string.byte(buf, 9))
|
||||||
|
end
|
||||||
|
return conn:receive(len)
|
||||||
|
end
|
||||||
|
|
||||||
|
function do_write(conn, req, mtype, ptype, id, final)
|
||||||
|
-- first byte construction
|
||||||
|
local pkt = {
|
||||||
|
buffer = 0,
|
||||||
|
string = 1,
|
||||||
|
json = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
local pktype = pkt[ptype]
|
||||||
|
local stream
|
||||||
|
if mtype == "async" then stream = 0 else stream = 1 end
|
||||||
|
local fin
|
||||||
|
if final then fin = 1 else fin = 0 end
|
||||||
|
local first = string.char(bit32.bor(bit32.lshift(stream, 3), bit32.lshift(fin, 2), bit32.band(pktype, 3)))
|
||||||
|
|
||||||
|
-- big-endian header construction
|
||||||
|
local b0 = bit32.rshift(bit32.band(string.len(req), 0xFF000000), 24)
|
||||||
|
local b1 = bit32.rshift(bit32.band(string.len(req), 0x00FF0000), 16)
|
||||||
|
local b2 = bit32.rshift(bit32.band(string.len(req), 0x0000FF00), 8)
|
||||||
|
local b3 = bit32.band(string.len(req), 0x000000FF)
|
||||||
|
-- limitation to 255 ids
|
||||||
|
local head = string.char(b0, b1, b2, b3, 0, 0, 0, id)
|
||||||
|
|
||||||
|
-- concat
|
||||||
|
local buf = first .. head .. req
|
||||||
|
return conn:send(buf)
|
||||||
|
end
|
||||||
|
|
||||||
|
function do_goodbye(conn)
|
||||||
|
return do_write(conn, "", "async", "buffer", 0, true)
|
||||||
|
end
|
||||||
|
|
||||||
|
function rpc_async(conn, meth, mtype, param)
|
||||||
|
-- wrap
|
||||||
|
local req = json.encode({
|
||||||
|
name = meth,
|
||||||
|
args = {param},
|
||||||
|
})
|
||||||
|
|
||||||
|
local ret, err = do_write(conn, req, mtype, "json", 1, false)
|
||||||
|
-- minetest.log("do_write: len: " .. ret)
|
||||||
|
if err then
|
||||||
|
minetest.log("do_write: " .. err)
|
||||||
|
return ret, err
|
||||||
|
end
|
||||||
|
|
||||||
|
ret, err = do_read(conn, 1, false)
|
||||||
|
-- minetest.log("do_read: len: " .. string.len(ret))
|
||||||
|
if err then
|
||||||
|
minetest.log("do_read: " .. err)
|
||||||
|
return ret, err
|
||||||
|
end
|
||||||
|
|
||||||
|
do_goodbye(conn)
|
||||||
|
|
||||||
|
-- local ret = json.encode({
|
||||||
|
-- name = meth,
|
||||||
|
-- type = mtype,
|
||||||
|
-- arg = param,
|
||||||
|
-- })
|
||||||
|
-- local err = nil
|
||||||
|
return ret, err
|
||||||
|
end
|
||||||
|
|
||||||
|
function muxrpc(conn, meth, mtype, param)
|
||||||
|
local switch = {
|
||||||
|
async = rpc_async,
|
||||||
|
-- TODO implement all types
|
||||||
|
}
|
||||||
|
|
||||||
|
local rpc = switch[mtype]
|
||||||
|
if not rpc then
|
||||||
|
return nil, "method type unimplemented yet."
|
||||||
|
end
|
||||||
|
|
||||||
|
return rpc(conn, meth, mtype, param)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function parse_msgs(arr)
|
||||||
|
local r = {}
|
||||||
|
for i, msg in ipairs(arr) do
|
||||||
|
r[i] = json.decode(msg)
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
local mt = {
|
||||||
|
__index = function(self, k)
|
||||||
|
local manifest, err = read_manifest()
|
||||||
|
if err then
|
||||||
|
return function(s, ...)
|
||||||
|
return nil, "cannot initialize: " .. err
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return function(s, ...)
|
||||||
|
local res, err = nil
|
||||||
|
|
||||||
|
if not manifest[k] then
|
||||||
|
return err, "method not found: " .. k
|
||||||
|
end
|
||||||
|
|
||||||
|
local mtype = manifest[k]
|
||||||
|
|
||||||
|
local params = {...}
|
||||||
|
local js
|
||||||
|
-- for key, val in ipairs(params) do
|
||||||
|
-- minetest.log(key .. "=" .. json.encode(val))
|
||||||
|
-- end
|
||||||
|
-- take only first param
|
||||||
|
js = params[1]
|
||||||
|
|
||||||
|
local c = unix()
|
||||||
|
local ret, err = c:connect(get_ssb_dir() .. "/socket")
|
||||||
|
if err then
|
||||||
|
return c, err
|
||||||
|
end
|
||||||
|
|
||||||
|
local ret, err = muxrpc(c, k, mtype, js)
|
||||||
|
if err then
|
||||||
|
c:close()
|
||||||
|
return ret, err
|
||||||
|
end
|
||||||
|
|
||||||
|
-- minetest.log(ret)
|
||||||
|
if not err then
|
||||||
|
if (type(ret) ~= "table") then
|
||||||
|
res = json.decode(ret)
|
||||||
|
else
|
||||||
|
res = parse_msgs(ret)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
res = nil
|
||||||
|
err = ret
|
||||||
|
end
|
||||||
|
|
||||||
|
return res, err
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
setmetatable(ssb, mt)
|
||||||
|
return ssb
|
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
Loading…
Reference in New Issue