parent
cfa2f41f1b
commit
dab7d2f5b8
226
init.lua
226
init.lua
|
@ -11,17 +11,25 @@ if http == nil then
|
|||
error("Please add matrix_bridge to secure.http_mods")
|
||||
end
|
||||
|
||||
local token = nil
|
||||
local txid = 0
|
||||
-- used for msync()
|
||||
local since = nil
|
||||
local eventid = nil
|
||||
-- defines functions for matrix protocol
|
||||
local MatrixChat = {
|
||||
server = MATRIX_SERVER,
|
||||
username = MATRIX_USERNAME,
|
||||
password = MATRIX_PASSWORD,
|
||||
room = MATRIX_ROOM,
|
||||
-- acquired on login
|
||||
userid = nil,
|
||||
token = nil,
|
||||
since = nil,
|
||||
lastok_since = nil,
|
||||
eventid = nil
|
||||
}
|
||||
|
||||
local function mchat(data)
|
||||
function MatrixChat:minechat(data)
|
||||
if data == nil then
|
||||
return
|
||||
end
|
||||
if since == data.next_batch then
|
||||
if self.since == data.next_batch then
|
||||
return
|
||||
end
|
||||
-- lets just get this working
|
||||
|
@ -31,13 +39,13 @@ local function mchat(data)
|
|||
if data["rooms"]["join"] == nil then
|
||||
return
|
||||
end
|
||||
if data["rooms"]["join"][MATRIX_ROOM] == nil then
|
||||
if data["rooms"]["join"][self.room] == nil then
|
||||
return
|
||||
end
|
||||
if data["rooms"]["join"][MATRIX_ROOM]["timeline"] == nil then
|
||||
if data["rooms"]["join"][self.room]["timeline"] == nil then
|
||||
return
|
||||
else
|
||||
local events = data["rooms"]["join"][MATRIX_ROOM]["timeline"]["events"]
|
||||
local events = data["rooms"]["join"][self.room]["timeline"]["events"]
|
||||
if events == nil then
|
||||
minetest.log("action", "matrix_bridge - found timeline but no events")
|
||||
return
|
||||
|
@ -45,7 +53,7 @@ local function mchat(data)
|
|||
minetest.log("action", "matrix_bridge - sync'd and found new messages")
|
||||
for i, event in ipairs(events) do
|
||||
if event.type == "m.room.message"
|
||||
and event.sender ~= MATRIX_USERNAME_LONG then
|
||||
and event.sender ~= self.userid then
|
||||
local message = event.sender .. ": " .. event.content.body
|
||||
minetest.log("action", message)
|
||||
minetest.chat_send_all(message)
|
||||
|
@ -54,48 +62,60 @@ local function mchat(data)
|
|||
end
|
||||
end
|
||||
|
||||
local function msync(s)
|
||||
-- optimization note: request more recent instead of unfiltered req
|
||||
-- local param1 = '&filter={\"room\":{\"timeline\":{\"limit\":1}}}'
|
||||
-- local param1 = "?access_token=" .. token
|
||||
local param2 = "?full_state=false"
|
||||
local param3 = "&timeout=5000"
|
||||
local u = MATRIX_SERVER.."/_matrix/client/r0/sync" .. param2 .. param3
|
||||
if s == nil then -- first time sync
|
||||
-- do nothing for now
|
||||
else -- second time sync -> append since parameter
|
||||
u = u .. "&since="..s
|
||||
-- https://matrix.org/docs/api/client-server/#get-/sync
|
||||
-- GET /sync
|
||||
function MatrixChat:get_sync_table(timeout)
|
||||
local params = {}
|
||||
-- no filter param
|
||||
if self.since ~= nil then
|
||||
params[1] = "since=" .. self.since
|
||||
end
|
||||
local h = {"Authorization: Bearer " .. token}
|
||||
http.fetch({url=u, method="GET", extra_headers=h},
|
||||
function (res)
|
||||
if res == nil then -- received nothing from server
|
||||
minetest.log("error", "matrix_bridge - sync response is nil")
|
||||
elseif res.code == 0 then
|
||||
minetest.log("info", "matrix_bridge - not found / timeout")
|
||||
elseif res.code == 404 then
|
||||
else
|
||||
local response = minetest.parse_json(res.data)
|
||||
if response ~= nil then
|
||||
mchat(response)
|
||||
since = response.next_batch
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
if timeout ~= nil then
|
||||
-- if timeout is defined and since took the starting '?'
|
||||
params[2] = "timeout=" .. timeout
|
||||
end
|
||||
local u = self.server .."/_matrix/client/r0/sync"
|
||||
if params[1] ~= nil then
|
||||
u = u .. "?" .. table.concat(params, "&")
|
||||
end
|
||||
local h = {"Authorization: Bearer " .. self.token}
|
||||
return {url=u, method="GET", extra_headers=h}
|
||||
end
|
||||
|
||||
local function mlogin()
|
||||
local u = MATRIX_SERVER.."/_matrix/client/r0/login"
|
||||
local d = '{"type":"m.login.password","password":"'..MATRIX_PASSWORD..'","identifier":{"type":"m.id.user","user":"'..MATRIX_USERNAME..'"}}'
|
||||
function MatrixChat:sync(timeout)
|
||||
http.fetch(MatrixChat:get_sync_table(timeout),
|
||||
function (res)
|
||||
if res == nil then -- received nothing from server
|
||||
minetest.log("error", "matrix_bridge - sync response is nil")
|
||||
elseif res.code == 0 then
|
||||
minetest.log("info", "matrix_bridge - not found / timeout")
|
||||
elseif res.code == 404 then
|
||||
else
|
||||
local response = minetest.parse_json(res.data)
|
||||
if response ~= nil then
|
||||
MatrixChat:minechat(response)
|
||||
self.lastok_since = self.since
|
||||
self.since = response.next_batch
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
-- https://matrix.org/docs/api/client-server/#post-/login
|
||||
-- POST /login
|
||||
function MatrixChat:login()
|
||||
local u = self.server .."/_matrix/client/r0/login"
|
||||
local d = '{"type":"m.login.password","password":"'.. self.password ..'","identifier":{"type":"m.id.user","user":"'.. self.username ..'"}}'
|
||||
local h = {"Content-Type: application/json"}
|
||||
http.fetch({url=u, method="POST", extra_headers=h, data=d},
|
||||
function(res)
|
||||
if res.code == 200 then
|
||||
minetest.log("action", res.data)
|
||||
local data = minetest.parse_json(res.data)
|
||||
token = data.access_token
|
||||
msync()
|
||||
self.token = data.access_token
|
||||
self.userid = data.user_id
|
||||
MatrixChat:sync()
|
||||
minetest.log("action", "Matrix authenticated")
|
||||
else
|
||||
minetest.log("error", to_string(res))
|
||||
|
@ -103,19 +123,24 @@ local function mlogin()
|
|||
end
|
||||
)
|
||||
end
|
||||
mlogin()
|
||||
MatrixChat:login()
|
||||
|
||||
local function send_message(msg)
|
||||
txid = txid + 1
|
||||
local u = MATRIX_SERVER.."/_matrix/client/r0/rooms/"..MATRIX_ROOM.."/send/m.room.message/" .. txid -- ?access_token=..token
|
||||
local h = {"Content-Type: application/json", "Authorization: Bearer " .. token}
|
||||
-- https://matrix.org/docs/api/client-server/#put-/rooms/-roomId-/send/-eventType-/-txnId-
|
||||
-- PUT /rooms/{roomId}/send/{eventType}/{txnId}
|
||||
function MatrixChat:send(msg)
|
||||
if self.token == nil then
|
||||
return
|
||||
end
|
||||
local txid = os.time()
|
||||
local u = self.server .."/_matrix/client/r0/rooms/".. self.room .."/send/m.room.message/" .. txid -- ?access_token=..token
|
||||
local h = {"Content-Type: application/json", "Authorization: Bearer " .. self.token}
|
||||
local d = minetest.write_json({msgtype="m.text", body=msg})
|
||||
http.fetch({url=u, method="PUT", extra_headers=h, data=d},
|
||||
function (res)
|
||||
if res.code == 200 then
|
||||
local data = minetest.parse_json(res.data)
|
||||
minetest.log("action", "got " .. data["event_id"])
|
||||
eventid = data["event_id"]
|
||||
self.eventid = data["event_id"]
|
||||
elseif res.code == 401 then
|
||||
minetest.log("error", "matrix_bridge - not authorized to send messages")
|
||||
elseif res.code == 404 then
|
||||
|
@ -124,34 +149,52 @@ local function send_message(msg)
|
|||
end)
|
||||
end
|
||||
|
||||
-- http.fetch({
|
||||
-- url = MATRIX_SERVER.."/_matrix/client/r0/login",
|
||||
-- method = "POST",
|
||||
-- extra_headers = {"Content-Type: application/json"},
|
||||
-- data = '{"type":"m.login.password","password":"'..MATRIX_PASSWORD..'","identifier":{"type":"m.id.user","user":"'..MATRIX_USERNAME..'"}}'
|
||||
-- }, function(res)
|
||||
-- if res.code == 200 then
|
||||
-- minetest.log("action", res.data)
|
||||
-- local data = minetest.parse_json(res.data)
|
||||
-- token = data.access_token
|
||||
-- minetest.log("action", "Matrix authenticated")
|
||||
-- else
|
||||
-- minetest.log("error", to_string(res))
|
||||
-- end
|
||||
-- end)
|
||||
|
||||
function mlogout ()
|
||||
local u = MATRIX_SERVER.."/logout/all"
|
||||
http.fetch({url=u, method="POST", function (res) end})
|
||||
-- https://matrix.org/docs/api/client-server/#post-/logout/all
|
||||
-- POST /logout/all
|
||||
function MatrixChat:logout ()
|
||||
local u = self.server .."/logout/all"
|
||||
local h = {"Authorization: Bearer " .. self.token}
|
||||
http.fetch({url=u, method="POST", extra_headers=h, function (res) end})
|
||||
minetest.log("action", "matrix_bridge - signing out.")
|
||||
end
|
||||
|
||||
local SECONDS = 0
|
||||
-- print a sync url to console to test matrix connection in other applications
|
||||
function MatrixChat:get_access_url()
|
||||
local params = {}
|
||||
-- no filter param
|
||||
if self.since ~= nil then
|
||||
params[1] = "since=" .. self.since
|
||||
end
|
||||
params[2] = "access_token=" .. self.token
|
||||
local u = self.server .. "/_matrix/client/r0/sync?" .. table.concat(params, "&")
|
||||
print(u)
|
||||
end
|
||||
|
||||
-- local SECONDS = 0
|
||||
local INTERVAL = 60
|
||||
local HANDLE = nil
|
||||
minetest.register_globalstep(function(dtime)
|
||||
SECONDS = SECONDS + dtime
|
||||
if SECONDS > 5 then
|
||||
msync(since)
|
||||
SECONDS = 0 -- reset
|
||||
-- SECONDS = SECONDS + dtime
|
||||
if HANDLE == nil then
|
||||
local request = MatrixChat:get_sync_table(INTERVAL * 1000)
|
||||
request.timeout = INTERVAL
|
||||
HANDLE = http.fetch_async(request)
|
||||
-- SECONDS = 0 -- reset
|
||||
elseif HANDLE ~= nil then
|
||||
local result = http.fetch_async_get(HANDLE)
|
||||
if result.completed then
|
||||
if result.code == 200 then
|
||||
local activity = minetest.parse_json(result.data)
|
||||
if activity ~= nil then
|
||||
MatrixChat:minechat(activity)
|
||||
end
|
||||
MatrixChat.since = activity.next_batch
|
||||
elseif result.code == 0 then
|
||||
elseif result.code == 404 then
|
||||
end
|
||||
HANDLE = nil
|
||||
-- SECONDS = 0 -- reset
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
@ -160,47 +203,38 @@ minetest.register_chatcommand("matrix", {
|
|||
interact = true
|
||||
},
|
||||
func = function(name, param)
|
||||
if param == "nil" then -- test sync as called from login
|
||||
msync()
|
||||
return true, "[matrix_bridge] command: sync(nil)"
|
||||
if param == "sync" then -- test sync as called from login
|
||||
MatrixChat:sync()
|
||||
return true, "[matrix_bridge] command: sync"
|
||||
elseif param == "logout" then
|
||||
mlogout()
|
||||
MatrixChat:logout()
|
||||
return true, "[matrix_bridge] command: log out"
|
||||
elseif param == "login" then
|
||||
mlogin()
|
||||
MatrixChat:login()
|
||||
return true, "[matrix_bridge] command: log in"
|
||||
elseif #param > 1 then -- test sync with specific 'since' parameter
|
||||
msync(param)
|
||||
return true, "[matrix_bridge] command: sync("..since..")"
|
||||
else -- test sync with current since parameter
|
||||
msync(since)
|
||||
return true, "[matrix_bridge] command: sync(<current>)"
|
||||
elseif param == "print" then
|
||||
MatrixChat:get_access_url()
|
||||
return true, "[matrix_bridge] printed url to server console"
|
||||
end
|
||||
|
||||
end})
|
||||
|
||||
minetest.register_on_shutdown(function()
|
||||
mlogout()
|
||||
MatrixChat:logout()
|
||||
end)
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local name = player:get_player_name()
|
||||
if token then
|
||||
send_message("*** "..name.." joined the game")
|
||||
end
|
||||
MatrixChat:send("*** "..name.." joined the game")
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player, timed_out)
|
||||
local name = player:get_player_name()
|
||||
if token then
|
||||
send_message("*** "..name.." left the game"..
|
||||
MatrixChat:send("*** "..name.." left the game"..
|
||||
(timed_out and " (Timed out)" or ""))
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_chat_message(function(name, message)
|
||||
if token == nil
|
||||
or message:sub(1, 1) == "/"
|
||||
if message:sub(1, 1) == "/"
|
||||
or message:sub(1, 5) == "[off]"
|
||||
or (not minetest.check_player_privs(name, {shout=true})) then
|
||||
return
|
||||
|
@ -209,7 +243,7 @@ minetest.register_on_chat_message(function(name, message)
|
|||
if nl then
|
||||
message = message:sub(1, nl - 1)
|
||||
end
|
||||
send_message("<"..name.."> "..message)
|
||||
MatrixChat:send("<"..name.."> "..message)
|
||||
end)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue