1+ -- source: https://github.com/TRIGONIM/lua-long-polling/blob/e28fff8141c7d1a22e030c9d6132ef853032da84/lua/long-polling/client.lua
12-- local kupol = require("long-polling.client")
2- -- local client = kupol.new("https://lp.example.com/channel")
3+ -- local Client = kupol.new("https://lp.example.com/channel")
34-- By default, client use copas and lua-cjson, but you can use your own functions
4- -- See how to use it in Garry's Mod (without copas and cjson) in examples/
5+ -- from Garry's Mod for example
56
67local kupol = {}
78
@@ -21,8 +22,8 @@ function MT:publish(tData)
2122 return code == 201 or res == " OK" , code
2223end
2324
24- function MT :get (last_id , timeout )
25- local paramstr = " ?ts=" .. (last_id or " " ) .. " &sleep=" .. (timeout or " " )
25+ function MT :get (offset , timeout )
26+ local paramstr = " ?ts=" .. (offset or " " ) .. " &sleep=" .. (timeout or " " )
2627
2728 local body , code_or_err = kupol .http_get (self .url .. paramstr )
2829 if not body then return false , code_or_err end
@@ -40,23 +41,30 @@ function MT:handle_error(err)
4041 self :log (" 🆘 Error\n\t %s" , err )
4142end
4243
43- function MT :subscribe (fHandler , last_id , timeout )
44- kupol .thread_new (function () while true do
45- local to = last_id and timeout or 0 -- it's better if first request will be fast if last_id not provided
46- local tData , body = self :get (last_id , to )
44+ function MT :subscribe (fHandler , requested_ts , timeout )
45+ self . thread = kupol .thread_new (function () repeat
46+ local tmt = requested_ts and timeout or 0 -- it's better if first request will be fast if requested_ts not provided
47+ local tData , body = self :get (requested_ts , tmt )
4748 if tData then
48- if (last_id or 0 ) > tData .ts then
49- self :log (" 🚧 ts on server is less than requested (%d < %d)" , tData .ts , last_id )
50- end
49+ local ts_diff = tData .ts - (requested_ts or 0 )
50+
51+ local REM = (requested_ts or 0 ) > tData .ts -- REMOTE FUCKUP. e.g. remote ts 0, local ts 1000
52+ local LOC = ts_diff > # tData .updates -- LOCAL FUCKUP. e.g. remote ts 100, local ts 0, but 30 updates instead of 100
53+ if REM or LOC then
54+ if REM then
55+ self :log (" 🚧 ts on server is less than requested (%d < %d)" , tData .ts , requested_ts )
56+ end
57+
58+ if LOC then
59+ self :log (" 🚧 updates lost: %d (got %d, expected %d)" , ts_diff - # tData .updates , # tData .updates , ts_diff ) -- too long time haven't requested them
60+ end
5161
52- local updates_should_be = tData .ts - ( last_id or 0 )
53- if updates_should_be > # tData . updates then
54- local updates_lost = updates_should_be - # tData .updates
55- self : log ( " 🚧 updates lost: %d (got %d, expected %d) " , updates_lost , # tData . updates , updates_should_be ) -- too long haven't requested them
62+ requested_ts = tData .ts -- emerg reset
63+ else
64+ requested_ts = requested_ts and ( requested_ts + # tData .updates ) or tData . ts
65+ -- requested_ts = tData.ts
5666 end
5767
58- -- last_id = last_id and (last_id + #tData.updates) or tData.ts
59- last_id = tData .ts
6068 for _ , update in ipairs (tData .updates ) do
6169 local pcallok , res = pcall (fHandler , update , tData .ts )
6270 if not pcallok then
@@ -67,9 +75,11 @@ function MT:subscribe(fHandler, last_id, timeout)
6775 self :handle_error (body )
6876 kupol .thread_pause (10 )
6977 end
70- end end ) -- while true, thread
78+ until ( not self . thread ) end )
7179end
7280
81+ local IS_GARRYSMOD = (GM or GAMEMODE ) and RunString and hook
82+
7383local copas_ok , copas = pcall (require , " copas" ) -- should be loaded before http_v2
7484if copas_ok then
7585 local http = require (" http_v2" ) -- https://github.com/TRIGONIM/lua-requests-async/blob/main/lua/http_v2.lua
@@ -87,15 +97,54 @@ if copas_ok then
8797
8898 kupol .thread_new = copas .addthread
8999 kupol .thread_pause = copas .sleep
100+
101+ elseif IS_GARRYSMOD then
102+ function kupol .thread_new (f , ...)
103+ local co = coroutine.create (f )
104+ local function cont (...)
105+ local ok , callback = coroutine.resume (co , ... )
106+ if not ok then error ( debug.traceback (co , callback ) ) end
107+ if coroutine.status (co ) ~= " dead" then callback (cont ) end
108+ end
109+ cont (... )
110+ return co
111+ end
112+
113+ function kupol .thread_pause (seconds )
114+ coroutine.yield (function (cont ) timer .Simple (seconds , cont ) end )
115+ end
116+
117+ function kupol .http_get (url )
118+ return coroutine.yield (function (cont )
119+ http .Fetch (url , function (body , _ , _ , code ) cont (body , code ) end ,
120+ function (err ) cont (false , err ) end )
121+ end )
122+ end
123+
124+ function kupol .http_post (url , data )
125+ return coroutine.yield (function (cont )
126+ local ok = HTTP ({ url = url , method = " POST" ,
127+ body = data , type = " application/json" ,
128+ success = function (code , body ) cont (body , code ) end ,
129+ failed = function (err ) cont (false , err ) end
130+ })
131+ if not ok then cont (false , " HTTP() failed" ) end
132+ end )
133+ end
134+
90135else
91- -- e.g. in Garry's Mod
92136 print (" Kupol: looks like copas is not installed. So you should provide own kupol.http_* and kupol.thread_* functions" )
93137end
94138
95139local cjson_ok , cjson = pcall (require , " cjson.safe" )
96140if cjson_ok then
97141 kupol .json_encode = cjson .encode
98142 kupol .json_decode = cjson .decode
143+
144+ elseif IS_GARRYSMOD then
145+ kupol .json_encode = util .TableToJSON
146+ kupol .json_decode = util .JSONToTable
147+
99148else
100149 print (" Kupol: looks like lua-cjson is not installed. So you should provide own kupol.json_encode and kupol.json_decode functions" )
101150end
0 commit comments