Compare commits

..

No commits in common. "8528b39f3a15e07d579a7979fc8495bfdf6e1a74" and "b3ba105f0cf0d8d5d098f2e332fa0be719710d5c" have entirely different histories.

7 changed files with 321 additions and 612 deletions

View File

@ -1,6 +1,6 @@
MIT License MIT License
Copyright (c) 2020 Alessandro Copyright (c) 2019 Alessandro
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -30,7 +30,6 @@ interface Client {
interface PollingClient extends Client { interface PollingClient extends Client {
lastPing: number, lastPing: number,
queue: Array<any>, queue: Array<any>,
token: string,
} }
interface Channels { interface Channels {
@ -429,7 +428,6 @@ pollingRouter.get("/connect", (req, res, next) => {
client.client = req; client.client = req;
client.queue = []; client.queue = [];
client.token = sessionToken;
client.send = function (data: string | object) { client.send = function (data: string | object) {
if (typeof data === "string") data = JSON.parse(data); if (typeof data === "string") data = JSON.parse(data);
@ -459,6 +457,11 @@ pollingRouter.use("*", function (req, res, next) {
}) })
} }
let client = clients[pollingTokens[sessionToken]] as PollingClient;
client.lastPing = Date.now();
clients[pollingTokens[sessionToken]] = client; // you're never 100% sure
next(); next();
}) })
@ -544,7 +547,6 @@ pollingRouter.post("/update", (req, res, next) => {
queue: client.queue, queue: client.queue,
}); });
client.lastPing = Date.now();
client.queue = []; client.queue = [];
}) })
@ -575,10 +577,7 @@ app.listen(config.port, () => {
let v = clients[id] as PollingClient; let v = clients[id] as PollingClient;
if ((Date.now() - v.lastPing) > 60000) { if ((Date.now() - v.lastPing) > 60000) {
console.log("[POL]", `Client connected: ${id}`);
let clientToken = (clients[id] as PollingClient).token;
delete clients[id]; delete clients[id];
delete pollingTokens[clientToken]
} }
}) })
}, 60000) }, 60000)

95
oc/oc_soqet.lua Normal file
View File

@ -0,0 +1,95 @@
local component = require("component")
local modem = component.modem
if not modem then
error("Missing network card", 2)
end
local serial = require("serialization")
local event = require("event")
local soqet = {
uuid = nil,
running = false,
}
local lastid
local function open()
modem.open(1010)
end
local function receive()
if not modem.isOpen(1010) then
open()
end
while true do
local ev = {event.pull(nil, "modem_message")}
local ch = ev[4]
local message = serial.unserialize(ev[6])
--print(serial.serialize(message))
soqet.uuid = message.uuid
if lastid ~= message.mid then
if message.message and message.channel and message.meta then
lastid = message.mid
return message.channel, message.message, message.meta
end
end
end
end
local function send(data)
if not modem.isOpen(1010) then
open()
end
modem.broadcast(1010, serial.serialize(data))
end
function soqet.open(channel)
send({
type = "open",
channel = channel,
})
end
function soqet.close(channel)
send({
type = "close",
channel = channel,
})
end
function soqet.auth(token)
send({
type = "auth",
token = token,
})
end
function soqet.send(channel, message, meta)
send({
type = "send",
channel = channel,
message = message,
meta = meta,
})
end
function soqet.listen()
open()
soqet.running = true
while soqet.running do
event.push("soqet_message", receive())
end
end
function soqet.receive()
open()
return receive()
end
function soqet.unlisten()
soqet.running = false
end
return soqet

46
oc/proxy.lua Normal file
View File

@ -0,0 +1,46 @@
local modem = peripheral.find("modem")
modem.open(1010)
local soqet = require("soqet")
local function action(data)
if data.type == "open" and data.channel then
print("Opening " .. data.channel)
soqet.open(data.channel)
elseif data.type == "close" and data.channel then
print("Closing " .. data.channel)
soqet.close(data.channel)
elseif data.type == "send" then
print("Sending message...")
soqet.send(data.channel, data.message, data.meta)
elseif data.type == "auth" then
print("Authenticating...")
soqet.auth(data.token)
end
end
local function main()
while true do
local ev = {os.pullEvent()}
--for k,v in pairs(ev) do
--print(k, v)
--end
if ev[1] == "soqet_message" then
modem.transmit(1010, 0, textutils.serialise({
channel = ev[2],
message = ev[3],
meta = ev[4],
uuid = soqet.uuid,
mid = math.random(0,99999)
}))
elseif ev[1] == "modem_message" and ev[3] == 1010 then
local data = textutils.unserialize(ev[5])
action(data)
end
end
end
parallel.waitForAny(soqet.listen, main)

View File

@ -1,290 +0,0 @@
--[[
-- OC_Soqet.lua --
https://github.com/Ale32bit/Soqet/
MIT License
Copyright (c) 2020 Alessandro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]] --
--[[
-- json.lua --
https://github.com/rxi/json.lua
Copyright (c) 2019 rxi
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
]] --
local http = require("internet")
local fs = require("filesystem")
if not http then
error("Missing internet card", 2)
end
local function _request(...)
local handle = http.request(...)
handle.finishConnect()
local content = ""
for chunk in handle do
content = content .. chunk
end
return content
end
local function get(url)
return _request(url)
end
local function post(url, data, headers)
return _request(url, data, headers, "POST")
end
if not fs.exists("/lib/json.lua") then
local con = get("https://raw.githubusercontent.com/rxi/json.lua/master/json.lua")
local f = io.open("/lib/json.lua", "w")
f:write(con)
f:close()
end
local function expect(index, value, ...)
local types = {...}
local valueType = type(value)
local valid = false
for _, v in ipairs(types) do
if valueType == v then
valid = true
break
end
end
if not valid then
error(("bad argument #%d (expected %s, got %s)"):format(index, table.concat(types, ", "), valueType), 3)
end
return value
end
local soqet = {
ENDPOINT = "soqet.alexdevs.pw",
ssl = false,
json = require("json"),
credits = "OC_Soqet.lua by AlexDevs"
}
local function postJson(url, data)
return _request(
url,
soqet.json.encode(data),
{
["Content-Type"] = "application/json"
}
)
end
function soqet.new()
error("WebSocket client is not supported. Use long polling instead.", 2)
end
function soqet.poll()
local client = {
channels = {},
uuid = nil,
sessionId = math.random(0xffffff),
sessionToken = nil,
ssl = soqet.ssl,
connected = false,
listening = true,
updateInterval = 1
}
if ssl then
client.ENDPOINT = "https://" .. soqet.ENDPOINT
else
client.ENDPOINT = "http://" .. soqet.ENDPOINT
end
local function send(path, body)
return postJson(client.ENDPOINT .. "/api/" .. path, body)
end
local function rawreceive()
if not client.connected then
client.connect()
end
while true do
local h =
send(
"update",
{
token = client.sessionToken
}
)
local data = soqet.json.decode(h)
local queue = {}
for i, v in ipairs(data.queue) do
if v.type == "message" then
table.insert(
queue,
{
channel = v.channel,
message = v.message,
meta = v.meta
}
)
end
end
if #queue > 0 then
return queue
else
os.sleep(client.updateInterval)
end
end
end
function client.connect(token)
if nil and type(token) ~= "string" then
error("bad argument #1", 2)
end
local h = get(client.ENDPOINT .. "/api/connect?token=" .. (token or ""))
local data = soqet.json.decode(h)
client.uuid = data.uuid
client.sessionToken = data.token
client.motd = data.motd
client.connected = true
for i, v in pairs(client.channels) do
client.open(v)
end
return true
end
function client.open(channel)
expect(1, channel, "string", "number")
client.channels[#client.channels + 1] = channel
send(
"open",
{
token = client.sessionToken,
channel = channel
}
)
return true
end
function client.close(channel)
expect(1, channel, "string", "number")
for i, v in pairs(client.channels) do
if v == channel then
client.channels[i] = nil
end
end
send(
"close",
{
token = client.sessionToken,
channel = channel
}
)
return true
end
function client.send(channel, message, meta)
expect(1, channel, "string", "number")
expect(3, meta, "nil", "table")
meta = meta or {}
meta.library = meta.library or soqet.credits
send(
"send",
{
token = client.sessionToken,
channel = channel,
message = message,
meta = meta
}
)
end
function client.receive()
return rawreceive()
end
function client.listen()
client.listening = true
while client.listening do
local queue = rawreceive()
for i, v in ipairs(queue) do
computer.pushSignal("soqet_message", v.channel, v.message, v.meta, client.sessionId)
end
sleep(client.updateInterval)
end
end
function client.unlisten()
client.listening = false
return true
end
return client
end
return soqet

View File

@ -297,7 +297,7 @@
<code>token</code> field.</p> <code>token</code> field.</p>
<p>Field <code>motd</code> is also supplied upon connection.</p> <p>Field <code>motd</code> is also supplied upon connection.</p>
<p><b>Once connected you need to request <code>/api/update</code> at least once every 60 seconds to keep the session token alive!</b> <p><b>Once connected you need to request at least once every 60 seconds to keep the session token alive!</b>
</p> </p>
</div> </div>
@ -487,7 +487,7 @@
<tr> <tr>
<td>motd</td> <td>motd</td>
<td>string</td> <td>string</td>
<td><i>Inspiring quotes to help the developer and the user get over problems and easily achieve life goals.</i></td> <td><i>Any message the </i></td>
</tr> </tr>
</table> </table>

439
soqet.lua
View File

@ -4,7 +4,7 @@ https://github.com/Ale32bit/Soqet/
MIT License MIT License
Copyright (c) 2020 Alessandro Copyright (c) 2019 Alessandro
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
@ -23,7 +23,7 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] -- ]]--
--[[ --[[
-- json.lua -- -- json.lua --
@ -50,361 +50,220 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
]] -- ]]--
local expect = dofile("rom/modules/main/cc/expect.lua").expect local h = http.get("https://raw.githubusercontent.com/rxi/json.lua/master/json.lua")
local f = fs.open("json.lua", "w")
f.write(h.readAll())
f.close()
h.close()
local json = require("json")
local soqet = { local soqet = {
ENDPOINT = "soqet.alexdevs.pw", ENDPOINT = "wss://soqet.alexdevs.pw",
ssl = true, channels = {},
json = json, socket = nil,
credits = "Soqet.lua v2 by AlexDevs" running = false,
uuid = nil,
sessionId = nil,
} }
if not soqet.json then local function send(data)
if not fs.exists("json.lua") then if not soqet.socket then
local h = http.get("https://raw.githubusercontent.com/rxi/json.lua/master/json.lua") soqet.connect()
local f = fs.open("json.lua", "w")
f.write(h.readAll())
f.close()
h.close()
end end
soqet.json = require("json") return soqet.socket.send(json.encode(data))
end end
function soqet.new() local function receive()
if not http then if not soqet.socket then
return false, "HTTP is not enabled!" soqet.connect()
end
if not http.websocket then
return false, "HTTP WebSocket feature is not enabled!"
end
local client = {
channels = {},
uuid = nil,
socket = nil,
sessionId = math.random(0xffffff),
ssl = soqet.ssl
}
local function rawsend(data)
if not client.socket then
return false
end
client.socket.send(soqet.json.encode(data))
return true
end
local function rawreceive()
if not client.socket then
client.connect()
end end
while true do while true do
local data = client.socket.receive() local data = soqet.socket.receive()
data = soqet.json.decode(data) data = json.decode(data)
soqet.uuid = data.uuid
if data.type == "message" then
local message = data.message
local channel = data.channel
local meta = data.meta
client.uuid = data.uuid return channel, message, meta
elseif data.type == "ping" then
if data.type == "ping" then send({
rawsend(
{
type = "ping", type = "ping",
id = 99 id = 5,
} })
)
elseif data.type == "motd" then
client.motd = data.motd
elseif data.type == "message" then
return data.channel, data.message, data.meta
end
end end
end end
end
if ssl then function soqet.connect()
client.ENDPOINT = "wss://" .. soqet.ENDPOINT .. "/" .. client.sessionId assert(http.websocket, "WebSocket not enabled or not compatible with this ComputerCraft version.")
else soqet.sessionId = tostring(math.random(0xffffff))
client.ENDPOINT = "ws://" .. soqet.ENDPOINT .. "/" .. client.sessionId local socket, err = http.websocket(soqet.ENDPOINT .. "/" .. soqet.sessionId)
end
function client.connect()
if client.socket then
pcall(client.socket.close)
end
local socket, err = http.websocket(client.ENDPOINT)
if not socket then if not socket then
return false, err error(err, 1);
end end
soqet.socket = socket;
end
client.socket = socket function soqet.open(channel)
send({
for i, v in pairs(client.channels) do
client.open(v)
end
return true
end
function client.open(channel)
expect(1, channel, "string", "number")
client.channels[#client.channels + 1] = channel
return rawsend(
{
type = "open", type = "open",
channel = channel channel = channel,
} id = 2,
) })
end end
function client.close(channel) function soqet.close(channel)
expect(1, channel, "string", "number") send({
for i, v in pairs(client.channels) do
if v == channel then
client.channels[i] = nil
end
end
return rawsend(
{
type = "close", type = "close",
channel = channel channel = channel,
} id = 3,
) })
end end
function client.send(channel, message, meta) function soqet.auth(token)
expect(1, channel, "string", "number") send({
expect(3, meta, "nil", "table") type = "auth",
token = token,
id = 4,
})
end
meta = meta or {} function soqet.send(channel, message, meta)
meta.library = meta.library or soqet.credits send({
return rawsend(
{
type = "send", type = "send",
channel = channel, channel = channel,
message = message, message = message,
meta = meta meta = meta or {},
} id = 1,
) })
end
function client.auth(token)
expect(1, token, "string")
return rawsend(
{
type = "auth",
token = token
}
)
end
function client.receive()
return rawreceive()
end
function client.listen()
client.listening = true
while client.listening do
local channel, message, meta = rawreceive()
os.queueEvent("soqet_message", channel, message, meta, client.sessionId)
end
return true
end
function client.unlisten()
client.listening = false
return true
end
return client, client.sessionId
end end
function soqet.poll(token) function soqet.receive()
local client = { return receive()
channels = {}, end
function soqet.listen()
soqet.running = true
while soqet.running do
local channel, message, meta = receive()
os.queueEvent("soqet_message", channel, message, meta)
end
end
function soqet.unlisten()
soqet.running = false
end
soqet.polling = {
host = "https://soqet.alexdevs.pw",
token = nil,
uuid = nil, uuid = nil,
sessionId = math.random(0xffffff), motd = "soqet",
sessionToken = nil,
ssl = soqet.ssl,
connected = false, connected = false,
listening = true, };
updateInterval = 1
}
if ssl then function soqet.polling.connect(token)
client.ENDPOINT = "https://" .. soqet.ENDPOINT local h, err = http.get(soqet.polling.host .. "/api/connect?token=" .. textutils.urlEncode(token));
else if not h then
client.ENDPOINT = "http://" .. soqet.ENDPOINT return false, err
end end
local function postJson(path, body) local result = json.decode(h.readAll())
return http.post(
client.ENDPOINT .. "/api/" .. path, if not result.ok then
soqet.json.encode(body), return false, result.error
{
["Content-Type"] = "application/json"
}
)
end end
local function rawreceive() soqet.polling.token = result.token
if not client.connected then soqet.polling.motd = result.motd
client.connect() soqet.polling.connected = true
end
while true do return true
local h, err = end
postJson(
"update", function soqet.polling.update()
{ local h, err = http.post(soqet.polling.host .. "/api/update", textutils.serialiseJSON({
token = client.sessionToken token = soqet.polling.token,
} }))
)
if not h then if not h then
error(err) return false, err
end end
local data = soqet.json.decode(h.readAll()) local result = json.decode(h.readAll());
h.close()
local queue = {} if not result.ok then
return false, result.err
for i, v in ipairs(data.queue) do
if v.type == "message" then
table.insert(
queue,
{
channel = v.channel,
message = v.message,
meta = v.meta
}
)
end
end end
if #queue > 0 then return result.queue
return queue end
else
sleep(client.updateInterval)
end
end
end
function client.connect(token) function soqet.polling.open(channel)
expect(1, token, "nil", "string") local h, err = http.post(soqet.polling.host .. "/api/open", textutils.serialiseJSON({
token = soqet.polling.token,
local h, err, eh = http.get(client.ENDPOINT .. "/api/connect?token=" .. textutils.urlEncode(token or "")) channel = channel,
}))
if not h then if not h then
return false, err, eh return false, err
end end
local data = soqet.json.decode(h.readAll()) local result = json.decode(h.readAll());
h.close() if not result.ok then
return false, result.err
client.uuid = data.uuid
client.sessionToken = data.token
client.motd = data.motd
client.connected = true
for i, v in pairs(client.channels) do
client.open(v)
end end
return true return true
end
function soqet.polling.close(channel)
local h, err = http.post(soqet.polling.host .. "/api/close", textutils.serialiseJSON({
token = soqet.polling.token,
channel = channel,
}))
if not h then
return false, err
end end
function client.open(channel) local result = json.decode(h.readAll());
expect(1, channel, "string", "number")
client.channels[#client.channels + 1] = channel if not result.ok then
return false, result.err
postJson( end
"open",
{
token = client.sessionToken,
channel = channel
}
)
return true return true
end end
function client.close(channel) function soqet.polling.send(channel, message, meta)
expect(1, channel, "string", "number") local h, err = http.post(soqet.polling.host .. "/api/send", textutils.serialiseJSON({
token = soqet.polling.token,
for i, v in pairs(client.channels) do
if v == channel then
client.channels[i] = nil
end
end
postJson(
"close",
{
token = client.sessionToken,
channel = channel
}
)
return true
end
function client.send(channel, message, meta)
expect(1, channel, "string", "number")
expect(3, meta, "nil", "table")
meta = meta or {}
meta.library = meta.library or soqet.credits
postJson(
"send",
{
token = client.sessionToken,
channel = channel, channel = channel,
message = message, message = message,
meta = meta meta = meta,
} }))
)
if not h then
return false, err
end end
function client.receive() local result = json.decode(h.readAll());
return rawreceive()
if not result.ok then
return false, result.err
end end
function client.listen()
client.listening = true
while client.listening do
local queue = rawreceive()
for i, v in ipairs(queue) do
os.queueEvent("soqet_message", v.channel, v.message, v.meta, client.sessionId)
end
sleep(client.updateInterval)
end
end
function client.unlisten()
client.listening = false
return true return true
end
return client
end end
return soqet return soqet