skynet/client.lua

133 lines
3.3 KiB
Lua

-- download JSON library
local a=http.get"https://raw.githubusercontent.com/rxi/json.lua/bee7ee3431133009a97257bde73da8a34e53c15c/json.lua"local b=fs.open("json","w")b.write(a.readAll())a.close()b.close()
local json = dofile "./json"
local skynet = {
server = "wss://osmarks.tk/skynet/connect/",
socket = nil,
open_channels = {},
json = json
}
function skynet.connect(force)
if not skynet.socket or force then
-- If we already have a socket and are throwing it away, close old one.
if skynet.socket then skynet.socket.close() end
sock = http.websocket(skynet.server)
if not sock then error "Skynet server unavailable, broken or running newer protocol version." end
skynet.socket = sock
for _, c in pairs(skynet.open_channels) do
skynet.open(channel)
end
end
end
function skynet.disconnect()
if skynet.socket then skynet.socket.close() end
end
local function value_in_table(t, v)
for k, tv in pairs(t) do if tv == v then return true, k end end
return false
end
local function send_raw(data, tries)
local tries = tries or 0
skynet.connect()
local ok, err = pcall(skynet.socket.send, json.encode(data))
if not ok then
if tries > 0 then sleep(tries) end
if tries > 5 then error("Max reconnection attempts exceeded. " .. err) end
pcall(skynet.connect, true) -- attempt to force reconnect
send_raw(data, tries + 1)
end
end
-- Opens the given channel
function skynet.open(channel)
-- Don't send unnecessary channel-open messages
if not value_in_table(skynet.open_channels, channel) then
send_raw {
type = "open",
channel = channel
}
table.insert(skynet.open_channels, channel)
end
end
local function recv_one(filter)
skynet.connect()
while true do
local contents = skynet.socket.receive()
local result = json.decode(contents)
if type(result) == "table" and filter(result) then
return result
end
end
end
local function recv_message(channel)
local m = recv_one(function(msg)
return msg.type == "message" and (channel == nil or msg.channel == channel)
end)
return m.channel, m.message, m
end
local function recv_result(for_cmd)
return recv_one(function(m)
if m.type == "error" then
error(m.error)
elseif m.type == "result" and m["for"] == for_cmd then
return true
end
end)
end
function skynet.logs(start, end_)
send_raw {
type = "log",
start = start,
["end"] = end_
}
return recv_result "log".log
end
local listener_running = false
-- Converts "websocket_message"s into "skynet_message"s.
function skynet.listen(force_run)
local function run()
while true do
os.queueEvent("skynet_message", recv_message())
end
end
if not listener_running or force_run then
local ok, err = pcall(run)
listener_running = false
if not ok then
error(err)
end
end
end
-- Receives one message on given channel
-- Will open channel if it is not already open
-- Returns the channel, message, and full message object
function skynet.receive(channel)
if channel then skynet.open(channel) end
return recv_message(channel)
end
-- Send given data on given channel
-- Can accept a third argument - an object of extra metadata to send
function skynet.send(channel, data, full)
local obj = full or {}
obj.type = "message"
obj.message = data
obj.channel = channel
send_raw(obj)
end
return skynet