milo cleanup + shop

This commit is contained in:
kepler155c@gmail.com
2019-01-11 10:01:37 -05:00
parent 42e72cf3c8
commit bfa528756e
23 changed files with 1141 additions and 101 deletions

6
swshop/.package Normal file
View File

@@ -0,0 +1,6 @@
{
title = 'Switchcraft basic shop',
repository = 'kepler155c/opus-apps/{{OPUS_BRANCH}}/swshop',
description = 'Modification of the k store by Lemmmy',
licence = 'MIT',
}

209
swshop/json Normal file
View File

@@ -0,0 +1,209 @@
------------------------------------------------------------------ utils
local controls = {["\n"]="\\n", ["\r"]="\\r", ["\t"]="\\t", ["\b"]="\\b", ["\f"]="\\f", ["\""]="\\\"", ["\\"]="\\\\"}
local function isArray(t)
local max = 0
for k,v in pairs(t) do
if type(k) ~= "number" then
return false
elseif k > max then
max = k
end
end
return max == #t
end
local whites = {['\n']=true; ['\r']=true; ['\t']=true; [' ']=true; [',']=true; [':']=true}
function removeWhite(str)
while whites[str:sub(1, 1)] do
str = str:sub(2)
end
return str
end
------------------------------------------------------------------ encoding
local function encodeCommon(val, pretty, tabLevel, tTracking)
local str = ""
-- Tabbing util
local function tab(s)
str = str .. ("\t"):rep(tabLevel) .. s
end
local function arrEncoding(val, bracket, closeBracket, iterator, loopFunc)
str = str .. bracket
if pretty then
str = str .. "\n"
tabLevel = tabLevel + 1
end
for k,v in iterator(val) do
tab("")
loopFunc(k,v)
str = str .. ","
if pretty then str = str .. "\n" end
end
if pretty then
tabLevel = tabLevel - 1
end
if str:sub(-2) == ",\n" then
str = str:sub(1, -3) .. "\n"
elseif str:sub(-1) == "," then
str = str:sub(1, -2)
end
tab(closeBracket)
end
-- Table encoding
if type(val) == "table" then
assert(not tTracking[val], "Cannot encode a table holding itself recursively")
tTracking[val] = true
if isArray(val) then
arrEncoding(val, "[", "]", ipairs, function(k,v)
str = str .. encodeCommon(v, pretty, tabLevel, tTracking)
end)
else
arrEncoding(val, "{", "}", pairs, function(k,v)
assert(type(k) == "string", "JSON object keys must be strings", 2)
str = str .. encodeCommon(k, pretty, tabLevel, tTracking)
str = str .. (pretty and ": " or ":") .. encodeCommon(v, pretty, tabLevel, tTracking)
end)
end
-- String encoding
elseif type(val) == "string" then
str = '"' .. val:gsub("[%c\"\\]", controls) .. '"'
-- Number encoding
elseif type(val) == "number" or type(val) == "boolean" then
str = tostring(val)
else
error("JSON only supports arrays, objects, numbers, booleans, and strings", 2)
end
return str
end
function encode(val)
return encodeCommon(val, false, 0, {})
end
function encodePretty(val)
return encodeCommon(val, true, 0, {})
end
------------------------------------------------------------------ decoding
local decodeControls = {}
for k,v in pairs(controls) do
decodeControls[v] = k
end
function parseBoolean(str)
if str:sub(1, 4) == "true" then
return true, removeWhite(str:sub(5))
else
return false, removeWhite(str:sub(6))
end
end
function parseNull(str)
return nil, removeWhite(str:sub(5))
end
local numChars = {['e']=true; ['E']=true; ['+']=true; ['-']=true; ['.']=true}
function parseNumber(str)
local i = 1
while numChars[str:sub(i, i)] or tonumber(str:sub(i, i)) do
i = i + 1
end
local val = tonumber(str:sub(1, i - 1))
str = removeWhite(str:sub(i))
return val, str
end
function parseString(str)
str = str:sub(2)
local s = ""
while str:sub(1,1) ~= "\"" do
local next = str:sub(1,1)
str = str:sub(2)
assert(next ~= "\n", "Unclosed string")
if next == "\\" then
local escape = str:sub(1,1)
str = str:sub(2)
next = assert(decodeControls[next..escape], "Invalid escape character")
end
s = s .. next
end
return s, removeWhite(str:sub(2))
end
function parseArray(str)
str = removeWhite(str:sub(2))
local val = {}
local i = 1
while str:sub(1, 1) ~= "]" do
local v = nil
v, str = parseValue(str)
val[i] = v
i = i + 1
str = removeWhite(str)
end
str = removeWhite(str:sub(2))
return val, str
end
function parseObject(str)
str = removeWhite(str:sub(2))
local val = {}
while str:sub(1, 1) ~= "}" do
local k, v = nil, nil
k, v, str = parseMember(str)
val[k] = v
str = removeWhite(str)
end
str = removeWhite(str:sub(2))
return val, str
end
function parseMember(str)
local k = nil
k, str = parseValue(str)
local val = nil
val, str = parseValue(str)
return k, val, str
end
function parseValue(str)
local fchar = str:sub(1, 1)
if fchar == "{" then
return parseObject(str)
elseif fchar == "[" then
return parseArray(str)
elseif tonumber(fchar) ~= nil or numChars[fchar] then
return parseNumber(str)
elseif str:sub(1, 4) == "true" or str:sub(1, 5) == "false" then
return parseBoolean(str)
elseif fchar == "\"" then
return parseString(str)
elseif str:sub(1, 4) == "null" then
return parseNull(str)
end
return nil
end
function decode(str)
str = removeWhite(str)
t = parseValue(str)
return t
end
function decodeFromFile(path)
local file = assert(fs.open(path, "r"))
local decoded = decode(file.readAll())
file.close()
return decoded
end

122
swshop/jua.lua Normal file
View File

@@ -0,0 +1,122 @@
local juaVersion = "0.0"
juaRunning = false
eventRegistry = {}
timedRegistry = {}
local function registerEvent(event, callback)
if eventRegistry[event] == nil then
eventRegistry[event] = {}
end
table.insert(eventRegistry[event], callback)
end
local function registerTimed(time, repeating, callback)
if repeating then
callback(true)
end
table.insert(timedRegistry, {
time = time,
repeating = repeating,
callback = callback,
timer = os.startTimer(time)
})
end
local function discoverEvents(event)
local evs = {}
for k,v in pairs(eventRegistry) 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
function on(event, callback)
registerEvent(event, callback)
end
function setInterval(callback, time)
registerTimed(time, true, callback)
end
function setTimeout(callback, time)
registerTimed(time, false, callback)
end
function tick()
local eargs = {os.pullEventRaw()}
local event = eargs[1]
if eventRegistry[event] == nil then
eventRegistry[event] = {}
else
local evs = discoverEvents(event)
for i, v in ipairs(evs) do
v(unpack(eargs))
end
end
if event == "timer" then
local timer = eargs[2]
for i = #timedRegistry, 1, -1 do
local v = timedRegistry[i]
if v.timer == timer then
v.callback(not v.repeating or nil)
if v.repeating then
v.timer = os.startTimer(v.time)
else
table.remove(timedRegistry, i)
end
end
end
end
end
function run()
os.queueEvent("init")
juaRunning = true
while juaRunning do
tick()
end
end
function go(func)
on("init", func)
run()
end
function stop()
juaRunning = false
end
function await(func, ...)
local args = {...}
local out
local finished
func(function(...)
out = {...}
finished = true
end, unpack(args))
while not finished do tick() end
return unpack(out)
end
return {
on = on,
setInterval = setInterval,
setTimeout = setTimeout,
tick = tick,
run = run,
go = go,
stop = stop,
await = await
}

413
swshop/k.lua Normal file
View File

@@ -0,0 +1,413 @@
local w
local r
local jua
local json
local await
local endpoint = "krist.ceriat.net"
local wsEndpoint = "ws://"..endpoint
local httpEndpoint = "http://"..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 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("wss:", "ws:") 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 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"
}
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
local g = string.gsub
sha256 = loadstring(g(g(g(g(g(g(g(g('Sa=XbandSb=XbxWSc=XlshiftSd=unpackSe=2^32SYf(g,h)Si=g/2^hSj=i%1Ui-j+j*eVSYk(l,m)Sn=l/2^mUn-n%1VSo={0x6a09e667Tbb67ae85T3c6ef372Ta54ff53aT510e527fT9b05688cT1f83d9abT5be0cd19}Sp={0x428a2f98T71374491Tb5c0fbcfTe9b5dba5T3956c25bT59f111f1T923f82a4Tab1c5ed5Td807aa98T12835b01T243185beT550c7dc3T72be5d74T80deb1feT9bdc06a7Tc19bf174Te49b69c1Tefbe4786T0fc19dc6T240ca1ccT2de92c6fT4a7484aaT5cb0a9dcT76f988daT983e5152Ta831c66dTb00327c8Tbf597fc7Tc6e00bf3Td5a79147T06ca6351T14292967T27b70a85T2e1b2138T4d2c6dfcT53380d13T650a7354T766a0abbT81c2c92eT92722c85Ta2bfe8a1Ta81a664bTc24b8b70Tc76c51a3Td192e819Td6990624Tf40e3585T106aa070T19a4c116T1e376c08T2748774cT34b0bcb5T391c0cb3T4ed8aa4aT5b9cca4fT682e6ff3T748f82eeT78a5636fT84c87814T8cc70208T90befffaTa4506cebTbef9a3f7Tc67178f2}SYq(r,q)if e-1-r[1]<q then r[2]=r[2]+1;r[1]=q-(e-1-r[1])-1 else r[1]=r[1]+qVUrVSYs(t)Su=#t;t[#t+1]=0x80;while#t%64~=56Zt[#t+1]=0VSv=q({0,0},u*8)fWw=2,1,-1Zt[#t+1]=a(k(a(v[w]TFF000000),24)TFF)t[#t+1]=a(k(a(v[w]TFF0000),16)TFF)t[#t+1]=a(k(a(v[w]TFF00),8)TFF)t[#t+1]=a(v[w]TFF)VUtVSYx(y,w)Uc(y[w]W0,24)+c(y[w+1]W0,16)+c(y[w+2]W0,8)+(y[w+3]W0)VSYz(t,w,A)SB={}fWC=1,16ZB[C]=x(t,w+(C-1)*4)VfWC=17,64ZSD=B[C-15]SE=b(b(f(B[C-15],7),f(B[C-15],18)),k(B[C-15],3))SF=b(b(f(B[C-2],17),f(B[C-2],19)),k(B[C-2],10))B[C]=(B[C-16]+E+B[C-7]+F)%eVSG,h,H,I,J,j,K,L=d(A)fWC=1,64ZSM=b(b(f(J,6),f(J,11)),f(J,25))SN=b(a(J,j),a(Xbnot(J),K))SO=(L+M+N+p[C]+B[C])%eSP=b(b(f(G,2),f(G,13)),f(G,22))SQ=b(b(a(G,h),a(G,H)),a(h,H))SR=(P+Q)%e;L,K,j,J,I,H,h,G=K,j,J,(I+O)%e,H,h,G,(O+R)%eVA[1]=(A[1]+G)%e;A[2]=(A[2]+h)%e;A[3]=(A[3]+H)%e;A[4]=(A[4]+I)%e;A[5]=(A[5]+J)%e;A[6]=(A[6]+j)%e;A[7]=(A[7]+K)%e;A[8]=(A[8]+L)%eUAVUY(t)t=t W""t=type(t)=="string"and{t:byte(1,-1)}Wt;t=s(t)SA={d(o)}fWw=1,#t,64ZA=z(t,w,A)VU("%08x"):rep(8):format(d(A))V',"S"," local "),"T",",0x"),"U"," return "),"V"," end "),"W","or "),"X","bit32."),"Y","function "),"Z"," do "))()
function makeaddressbyte(byte)
local byte = 48 + math.floor(byte / 7)
return string.char(byte + 39 > 122 and 101 or byte > 57 and byte + 39 or byte)
end
function makev2address(key)
local protein = {}
local stick = sha256(sha256(key))
local n = 0
local link = 0
local v2 = "k"
repeat
if n < 9 then protein[n] = string.sub(stick,0,2)
stick = sha256(sha256(stick)) end
n = n + 1
until n == 9
n = 0
repeat
link = tonumber(string.sub(stick,1+(2*n),2+(2*n)),16) % 9
if string.len(protein[link]) ~= 0 then
v2 = v2 .. makeaddressbyte(tonumber(protein[link],16))
protein[link] = ''
n = n + 1
else
stick = sha256(stick)
end
until n == 9
return v2
end
function toKristWalletFormat(passphrase)
return sha256("KRISTWALLET"..passphrase).."-000"
end
return {
init = init,
address = address,
addressTransactions = addressTransactions,
addressNames = addressNames,
addresses = addresses,
rich = rich,
transactions = transactions,
latestTransactions = latestTransactions,
transaction = transaction,
makeTransaction = makeTransaction,
connect = connect,
parseMeta = parseMeta,
sha256 = sha256,
makeaddressbyte = makeaddressbyte,
makev2address = makev2address,
toKristWalletFormat = toKristWalletFormat
}

63
swshop/r.lua Normal file
View File

@@ -0,0 +1,63 @@
local jua = nil
local idPatt = "#R%d+"
callbackRegistry = {}
local function gfind(str, patt)
local t = {}
for found in str:gmatch(patt) do
table.insert(t, found)
end
if #t > 0 then
return t
else
return nil
end
end
local function findID(url)
local found = gfind(url, idPatt)
return tonumber(found[#found]:sub(found[#found]:find("%d+")))
end
local function newID()
return #callbackRegistry + 1
end
local function trimID(url)
local found = gfind(url, idPatt)
local s, e = url:find(found[#found])
return url:sub(1, s-1)
end
function request(callback, url, headers, postData)
local id = newID()
local newUrl = url .. "#R" .. id
http.request(newUrl, postData, headers)
callbackRegistry[id] = callback
end
function init(jua)
jua = jua
jua.on("http_success", function(event, url, handle)
local id = findID(url)
if callbackRegistry[id] then
callbackRegistry[id](true, trimID(url), handle)
table.remove(callbackRegistry, id)
end
end)
jua.on("http_failure", function(event, url, handle)
local id = findID(url)
if callbackRegistry[id] then
callbackRegistry[id](false, trimID(url), handle)
table.remove(callbackRegistry, id)
end
end)
end
return {
request = request,
init = init
}

119
swshop/shop.lua Normal file
View File

@@ -0,0 +1,119 @@
local programDir = fs.getDir(shell.getRunningProgram())
os.loadAPI(programDir .. '/'.. 'json')
local w = require("w")
local r = require("r")
local k = require("k")
local jua = require("jua")
local await = jua.await
local fs = _G.fs
local json = _G.json
local os = _G.os
local textutils = _G.textutils
r.init(jua)
w.init(jua)
k.init(jua, json, w, r)
local domain
local password
local privatekey
local address
jua.on("terminate", function()
jua.stop()
_G.printError("Terminated")
end)
local function getItemDetails(item)
local f = fs.open('usr/config/shop', "r")
if f then
local t = f.readAll()
f.close()
t = textutils.unserialize(t)
for k, v in pairs(t) do
if v.name == item then
return k, v.price
end
end
end
end
local function handleTransaction(transaction)
local from = transaction.from
local to = transaction.to
local value = transaction.value
if to ~= address or not transaction.metadata then return end
local metadata = k.parseMeta(transaction.metadata)
if not metadata.domain or metadata.domain ~= domain then return end
local recipient = metadata.meta and (metadata.meta["return"] or from) or from
print("Handling transaction from ", recipient)
print('purchase: ' .. tostring(metadata.name))
print('value: ' .. value)
local function refundTransaction(amount, reason)
print("Refunding to ", recipient)
await(k.makeTransaction, privatekey, recipient, amount, reason)
end
local itemId, price = getItemDetails(metadata.name)
if not itemId or not price then
print('invalid item')
--return refundTransaction(value, "error=Item specified is not valid")
return -- there could be multiple stores...
end
if value < price then
print('value too low')
return refundTransaction(value, "error=Please pay the price listed on-screen.")
end
local count = math.floor(value / price)
local uid = math.random()
os.queueEvent('store_provide', itemId, count, uid)
local timerId = os.startTimer(5)
while true do
local e, p1, p2 = os.pullEvent()
if e == 'timer' and p1 == timerId then
print('timed out waiting for provide')
refundTransaction(value, "error=Timed out attempting to provide items")
break
elseif e == 'store_provided' and p1 == uid then
local extra = value - (price * p2)
if extra > 0 then
print('extra: ' .. extra)
refundTransaction(extra, "message=Here's your change!")
end
break
end
end
end
jua.on('open_store', function(_, _domain, _password)
domain = _domain
password = _password
print('opening store for: ' .. domain)
privatekey = k.toKristWalletFormat(password)
address = k.makev2address(privatekey)
local success, ws = await(k.connect, privatekey)
assert(success, "Failed to get websocket URL")
print("Connected to websocket.")
success = await(ws.subscribe, "ownTransactions", function(data)
local transaction = data.transaction
handleTransaction(transaction)
end)
assert(success, "Failed to subscribe to event")
end)
jua.go(function()
print("Ready")
end)

134
swshop/w.lua Normal file
View File

@@ -0,0 +1,134 @@
local jua = nil
local idPatt = "#R%d+"
if not ((socket and socket.websocket) or http.websocketAsync) then
error("You do not have CC:Tweaked/CCTweaks installed or you are not on the latest version.")
end
local newws = socket and socket.websocket or http.websocketAsync
local async
if socket and socket.websocket then
async = false
else
async = true
end
callbackRegistry = {}
wsRegistry = {}
local function gfind(str, patt)
local t = {}
for found in str:gmatch(patt) do
table.insert(t, found)
end
if #t > 0 then
return t
else
return nil
end
end
local function findID(url)
local found = gfind(url, idPatt)
return tonumber(found[#found]:sub(found[#found]:find("%d+")))
end
local function newID()
return #callbackRegistry + 1
end
local function trimID(url)
local found = gfind(url, idPatt)
local s, e = url:find(found[#found])
return url:sub(1, s-1)
end
function open(callback, url, headers)
local id
if async then
id = newID()
end
local newUrl
if async then
newUrl = url .. "#R" .. id
newws(newUrl, headers)
else
if headers then
error("Websocket headers not supported under CCTweaks")
end
local ws = newws(url)
ws.send = ws.write
id = ws.id()
wsRegistry[id] = ws
end
callbackRegistry[id] = callback
return id
end
function init(jua)
jua = jua
if async then
jua.on("websocket_success", function(event, url, handle)
local id = findID(url)
if id and callbackRegistry[id] and callbackRegistry[id].success then
callbackRegistry[id].success(id, handle)
end
end)
jua.on("websocket_failure", function(event, url)
local id = findID(url)
if id and callbackRegistry[id] and callbackRegistry[id].failure then
callbackRegistry[id].failure(id)
end
table.remove(callbackRegistry, id)
end)
jua.on("websocket_message", function(event, url, data)
local id = findID(url)
if id and callbackRegistry[id] and callbackRegistry[id].message then
callbackRegistry[id].message(id, data)
end
end)
jua.on("websocket_closed", function(event, url)
local id = findID(url)
if id and callbackRegistry[id] and callbackRegistry[id].closed then
callbackRegistry[id].closed(id)
end
table.remove(callbackRegistry, id)
end)
else
jua.on("socket_connect", function(event, id)
if id and callbackRegistry[id] and callbackRegistry[id].success then
callbackRegistry[id].success(id, wsRegistry[id])
end
end)
jua.on("socket_error", function(event, id, msg)
if id and callbackRegistry[id] and callbackRegistry[id].failure then
callbackRegistry[id].failure(id, msg)
end
table.remove(callbackRegistry, id)
end)
jua.on("socket_message", function(event, id)
if id and callbackRegistry[id] and callbackRegistry[id].message then
local data = wsRegistry[id].read()
callbackRegistry[id].message(id, data)
end
end)
jua.on("socket_closed", function(event, id)
if id and callbackRegistry[id] and callbackRegistry[id].closed then
callbackRegistry[id].closed(id)
end
table.remove(callbackRegistry, id)
end)
end
end
return {
open = open,
init = init
}