· 4 years ago · Sep 03, 2021, 04:10 AM
1-- Load Anav's async APIs
2local asyncWeb = require("asyncWeb") -- DX5Cw7U8
3local asyncKrist = require("asyncKrist") -- 3S026eJ1
4
5local jsonDecode = textutils.unserializeJSON
6local jsonEncode = textutils.serializeJSON
7
8-- Krist Node we want to connect
9local nodeURL = "https://krist.ceriat.net"
10local privatekey = settings.get("krist.privatekey")
11
12-- 3x the normal amount is pretty reasonable for
13-- detection
14-- you also have to account when the server has
15-- some lagspike, it'll allow a 20s lag until it
16-- gives a false positive
17local sessionTimeout = 30
18local token, session, sessionTimer -- global vars
19
20
21
22-- Our Krist callbacks, most of your custom krist code would go there
23local kstCallbacks = {
24 onHello = function(data) -- Give some basic info about the node
25 -- Available data fields are the same as on https://krist.ceriat.net/motd
26 print("MOTD:", data.motd)
27 print("Latest block:", data.last_block.short_hash)
28 print("Current difficulty:", data.work)
29 end,
30
31 onBlock = function(data) -- Called when a new block are mined
32 -- Useful data fields: data.address .difficulty .hash .short_hash .height .new_work .time .value
33 print("New block from", data.address)
34 end,
35 onTransaction = function(data) -- Called when a various transaction types are sent
36 -- Useful data fields: data.from .to .id .time .type .value
37 -- Various .type values: "transfer", "name_purchase", "name_a_record", "name_transfer", "mined"
38 print("New tx from", data.from, "to", data.to, "of", data.value, "kst")
39
40 -- If you need to mess with domains and meta stuff
41 -- use this function to table-ize the metadata field
42 if data.metadata then
43 data.metadata = asyncKrist.parseMeta(data.metadata)
44 end
45 end,
46 onKeepalive = function(data) -- Time updates sent by the server every 10s
47 -- Useful data field: data.server_time
48
49 -- It is very important to detect when the connection is broken
50 os.cancelTimer(sessionTimer or -1)
51 sessionTimer = os.startTimer(sessionTimeout)
52 -- This timer event will never fire unless
53 -- We don't receive a keepalive packet
54 -- within the timeout period
55 -- We handle the timer signal in the event loop at the bottom
56 end,
57
58 onError = function(data) -- When something is sent to the server with invalid parameters, this is be called
59 print("[ERROR]", jsonEncode(data))
60 end,
61
62 onUnknown = nil, -- Gets called when an unknown packet was received from the node (mainly for debugging purposes)
63 onName = nil, -- Subscription exists but name updates are never sent this way, use onTransaction with type == "name_etc"
64 onMotd = nil, -- Subscription exists but motd updates are never sent this way, use onHello with data.motd
65}
66
67-- To initiate a connection to krist, you need to authenticate
68-- with your privkey
69-- Once this below is done, there's no much need
70-- to change it further
71
72-- doHttp(url, body, headers, binaryMode?, callbacks{onSuccess, onFailure})
73asyncWeb.doHttp( nodeURL.."/ws/start", "privatekey="..privatekey, nil, nil, {
74 onSuccess = function(data, url) -- On successful http request
75 token = jsonDecode(data).url
76 -- We got our websocket URL, let's connect to the node
77
78 -- doWebsocket(url, headers, callbacks{onSuccess, onFailure, onClosed, onMessage})
79 asyncWeb.doWebsocket(token, nil, {
80 onSuccess = function(handle, url)
81 -- We're connected to the node
82 -- Send it to the Krist API
83 -- start(websocketHandle, url, callbacks{documented above})
84 session = asyncKrist.start(handle, url, kstCallbacks)
85 print("Successfully connected")
86
87 -- Subscribe to events, such as block and tx
88 session:subEvent("blocks")
89 session:subEvent("transactions")
90
91 -- Get account information, callback prints the address of the wallet
92 session:getAccountInfo(function(data) print("Logged in as", data.address.address)end)
93 end,
94 onMessage = asyncKrist.tick, -- Feed all websocket message to Krist Lib
95 onClosed = function(url) print("Connection to", url, "closed") end,
96 onFailure = function(reason, url) print("Connection failed:", reason) end
97 })
98 end,
99 onFailure = function(reason, url) -- On bad http request
100 print("Failure to connect to node")
101 end
102})
103
104
105
106-- CC is a very event driven environment
107-- so we need an event loop
108-- this is pretty much mandatory for any complex CC app
109
110-- My lib transparently takes its relevant events
111-- from .pullEvent and passes other events to your own loop
112-- This way, it allows it to have a callback system while
113-- allowing to have your own events
114--
115-- The only downsides to this is you cannot use
116-- sleep() or read() since they have their own
117-- loop which interferes with ours
118while true do
119 local eventData = {asyncWeb.tick(os.pullEventRaw())} -- Insert tick function to make our callback system work
120 if eventData[1] == "key" then
121 if eventData[2] == keys.q then
122 if session.handle then session.handle.close() end -- Close connection with session.handle.close()
123 break
124
125 elseif eventData[2] == keys.r then -- Refund test
126 -- This is how you would make a tx to refund ppl
127 -- will use the account of the currently logged in
128 -- privatekey
129 session:makeTransaction(to, amount, metadata, callback)
130 end
131 elseif eventData[1] == "timer" and eventData[2] == sessionTimer then
132 -- We detected that the keepalive took too long
133 -- and we're assuming that the connection to krist is dead
134 -- At this point you'd restart the app
135 print("Connection to Krist is dead!")
136 break
137 end
138end