Files
opus-apps/swshop/apis/k.lua
xAnavrins 2461d060e0 Updates to swshop part 1
Updated URL to new krist node
Form now validates if address own provided domain
Support for third-party sync nodes
Update k.lua and w.lua

Closes #60
2022-07-18 00:07:55 -04:00

391 lines
9.3 KiB
Lua

local w
local r
local jua
local json
local await
local endpoint = "krist.dev"
local wsEndpoint = "wss://"..endpoint
local httpEndpoint = "https://"..endpoint
local function asserttype(var, name, vartype, optional)
if not (type(var) == vartype or optional and type(var) == "nil") then
error(name..": expected "..vartype.." got "..type(var), 3)
end
end
function setNodeUrl(url)
endpoint = url
wsEndpoint = "wss://"..endpoint
httpEndpoint = "https://"..endpoint
end
function init(juai, jsoni, wi, ri)
asserttype(juai, "jua", "table")
asserttype(jsoni, "json", "table")
asserttype(wi, "w", "table", true)
asserttype(ri, "r", "table")
jua = juai
await = juai.await
json = jsoni
w = wi
r = ri
end
local function prints(...)
local objs = {...}
for i, obj in ipairs(objs) do
print(textutils.serialize(obj))
end
end
local function url(call)
return httpEndpoint..call
end
local function api_request(cb, api, data)
local success, url, handle = await(r.request, url(api) .. (api:find("%%?") and "?cc" or "&cc"), {["Content-Type"]="application/json"}, data and json.encode(data))
if success then
cb(success, json.decode(handle.readAll()))
handle.close()
else
cb(success)
end
end
local function authorize_websocket(cb, privatekey)
asserttype(cb, "callback", "function")
asserttype(privatekey, "privatekey", "string", true)
api_request(function(success, data)
cb(success and data and data.ok, data.url and data.url:gsub("ws:", "wss:") or data)
end, "/ws/start", {
privatekey = privatekey
})
end
function address(cb, address)
asserttype(cb, "callback", "function")
asserttype(address, "address", "string")
api_request(function(success, data)
if data.address then
data.address.address = address
end
cb(success and data and data.ok, data.address or data)
end, "/addresses/"..address)
end
function addressTransactions(cb, address, limit, offset)
asserttype(cb, "callback", "function")
asserttype(address, "address", "string")
asserttype(limit, "limit", "number", true)
asserttype(offset, "offset", "number", true)
api_request(function(success, data)
cb(success and data and data.ok, data.transactions or data)
end, "/addresses/"..address.."/transactions?limit="..(limit or 50).."&offset="..(offset or 0))
end
function addressNames(cb, address)
asserttype(cb, "callback", "function")
asserttype(address, "address", "string")
api_request(function(success, data)
cb(success and data and data.ok, data.names or data)
end, "/addresses/"..address.."/names")
end
function addresses(cb, limit, offset)
asserttype(cb, "callback", "function")
asserttype(limit, "limit", "number", true)
asserttype(offset, "offset", "number", true)
api_request(function(success, data)
cb(success and data and data.ok, data.addresses or data)
end, "/addresses?limit="..(limit or 50).."&offset="..(offset or 0))
end
function name(cb, name)
asserttype(cb, "callback", "function")
asserttype(name, "name", "string")
api_request(function(success, data)
cb(success and data and data.ok, data.name or data)
end, "/names/"..name)
end
function rich(cb, limit, offset)
asserttype(cb, "callback", "function")
asserttype(limit, "limit", "number", true)
asserttype(offset, "offset", "number", true)
api_request(function(success, data)
cb(success and data and data.ok, data.addresses or data)
end, "/addresses/rich?limit="..(limit or 50).."&offset="..(offset or 0))
end
function transactions(cb, limit, offset)
asserttype(cb, "callback", "function")
asserttype(limit, "limit", "number", true)
asserttype(offset, "offset", "number", true)
api_request(function(success, data)
cb(success and data and data.ok, data.transactions or data)
end, "/transactions?limit="..(limit or 50).."&offset="..(offset or 0))
end
function latestTransactions(cb, limit, offset)
asserttype(cb, "callback", "function")
asserttype(limit, "limit", "number", true)
asserttype(offset, "offset", "number", true)
api_request(function(success, data)
cb(success and data and data.ok, data.transactions or data)
end, "/transactions/latest?limit="..(limit or 50).."&offset="..(offset or 0))
end
function transaction(cb, txid)
asserttype(cb, "callback", "function")
asserttype(txid, "txid", "number")
api_request(function(success, data)
cb(success and data and data.ok, data.transaction or data)
end, "/transactions/"..txid)
end
function makeTransaction(cb, privatekey, to, amount, metadata)
asserttype(cb, "callback", "function")
asserttype(privatekey, "privatekey", "string")
asserttype(to, "to", "string")
asserttype(amount, "amount", "number")
asserttype(metadata, "metadata", "string", true)
api_request(function(success, data)
cb(success and data and data.ok, data.transaction or data)
end, "/transactions", {
privatekey = privatekey,
to = to,
amount = amount,
metadata = metadata
})
end
local wsEventNameLookup = {
blocks = "block",
ownBlocks = "block",
transactions = "transaction",
ownTransactions = "transaction",
names = "name",
ownNames = "name",
ownWebhooks = "webhook",
motd = "motd",
keepalive = "keepalive"
}
local wsEvents = {}
local wsReqID = 0
local wsReqRegistry = {}
local wsEvtRegistry = {}
local wsHandleRegistry = {}
local function newWsID()
local id = wsReqID
wsReqID = wsReqID + 1
return id
end
local function registerEvent(id, event, callback)
if wsEvtRegistry[id] == nil then
wsEvtRegistry[id] = {}
end
if wsEvtRegistry[id][event] == nil then
wsEvtRegistry[id][event] = {}
end
table.insert(wsEvtRegistry[id][event], callback)
end
local function registerRequest(id, reqid, callback)
if wsReqRegistry[id] == nil then
wsReqRegistry[id] = {}
end
wsReqRegistry[id][reqid] = callback
end
local function discoverEvents(id, event)
local evs = {}
for k,v in pairs(wsEvtRegistry[id]) do
if k == event or string.match(k, event) or event == "*" then
for i,v2 in ipairs(v) do
table.insert(evs, v2)
end
end
end
return evs
end
wsEvents.success = function(id, handle)
-- fire success event
wsHandleRegistry[id] = handle
if wsEvtRegistry[id] then
local evs = discoverEvents(id, "success")
for i, v in ipairs(evs) do
v(id, handle)
end
end
end
wsEvents.failure = function(id)
-- fire failure event
if wsEvtRegistry[id] then
local evs = discoverEvents(id, "failure")
for i, v in ipairs(evs) do
v(id)
end
end
end
wsEvents.message = function(id, data)
local data = json.decode(data)
--print("msg:"..tostring(data.ok)..":"..tostring(data.type)..":"..tostring(data.id))
--prints(data)
-- handle events and responses
if wsReqRegistry[id] and wsReqRegistry[id][tonumber(data.id)] then
wsReqRegistry[id][tonumber(data.id)](data)
elseif wsEvtRegistry[id] then
local evs = discoverEvents(id, data.type)
for i, v in ipairs(evs) do
v(data)
end
if data.event then
local evs = discoverEvents(id, data.event)
for i, v in ipairs(evs) do
v(data)
end
end
local evs2 = discoverEvents(id, "message")
for i, v in ipairs(evs2) do
v(id, data)
end
end
end
wsEvents.closed = function(id)
-- fire closed event
if wsEvtRegistry[id] then
local evs = discoverEvents(id, "closed")
for i, v in ipairs(evs) do
v(id)
end
end
end
local function wsRequest(cb, id, type, data)
local reqID = newWsID()
registerRequest(id, reqID, function(data)
cb(data)
end)
data.id = tostring(reqID)
data.type = type
wsHandleRegistry[id].send(json.encode(data))
end
local function barebonesMixinHandle(id, handle)
handle.on = function(event, cb)
registerEvent(id, event, cb)
end
return handle
end
local function mixinHandle(id, handle)
handle.subscribe = function(cb, event, eventcb)
local data = await(wsRequest, id, "subscribe", {
event = event
})
registerEvent(id, wsEventNameLookup[event], eventcb)
cb(data.ok, data)
end
return barebonesMixinHandle(id, handle)
end
function connect(cb, privatekey, preconnect)
asserttype(cb, "callback", "function")
asserttype(privatekey, "privatekey", "string", true)
asserttype(preconnect, "preconnect", "function", true)
local url
if privatekey then
local success, auth = await(authorize_websocket, privatekey)
url = success and auth or wsEndpoint
end
local id = w.open(wsEvents, url)
if preconnect then
preconnect(id, barebonesMixinHandle(id, {}))
end
registerEvent(id, "success", function(id, handle)
cb(true, mixinHandle(id, handle))
end)
registerEvent(id, "failure", function(id)
cb(false)
end)
end
local domainMatch = "^([%l%d-_]*)@?([%l%d-]+).kst$"
local commonMetaMatch = "^(.+)=(.+)$"
function parseMeta(meta)
asserttype(meta, "meta", "string")
local tbl = {meta={}}
for m in meta:gmatch("[^;]+") do
if m:match(domainMatch) then
-- print("Matched domain")
local p1, p2 = m:match("([%l%d-_]*)@"), m:match("@?([%l%d-]+).kst")
tbl.name = p1
tbl.domain = p2
elseif m:match(commonMetaMatch) then
-- print("Matched common meta")
local p1, p2 = m:match(commonMetaMatch)
tbl.meta[p1] = p2
else
-- print("Unmatched standard meta")
table.insert(tbl.meta, m)
end
-- print(m)
end
-- print(textutils.serialize(tbl))
return tbl
end
return {
setNodeUrl = setNodeUrl,
init = init,
address = address,
addressTransactions = addressTransactions,
addressNames = addressNames,
addresses = addresses,
name = name,
rich = rich,
transactions = transactions,
latestTransactions = latestTransactions,
transaction = transaction,
makeTransaction = makeTransaction,
connect = connect,
parseMeta = parseMeta,
}