1
+ -- source: https://github.com/TRIGONIM/lua-long-polling/blob/e28fff8141c7d1a22e030c9d6132ef853032da84/lua/long-polling/client.lua
1
2
-- 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")
3
4
-- 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
5
6
6
7
local kupol = {}
7
8
@@ -21,8 +22,8 @@ function MT:publish(tData)
21
22
return code == 201 or res == " OK" , code
22
23
end
23
24
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 " " )
26
27
27
28
local body , code_or_err = kupol .http_get (self .url .. paramstr )
28
29
if not body then return false , code_or_err end
@@ -40,23 +41,30 @@ function MT:handle_error(err)
40
41
self :log (" 🆘 Error\n\t %s" , err )
41
42
end
42
43
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 )
47
48
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
51
61
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
56
66
end
57
67
58
- -- last_id = last_id and (last_id + #tData.updates) or tData.ts
59
- last_id = tData .ts
60
68
for _ , update in ipairs (tData .updates ) do
61
69
local pcallok , res = pcall (fHandler , update , tData .ts )
62
70
if not pcallok then
@@ -67,9 +75,11 @@ function MT:subscribe(fHandler, last_id, timeout)
67
75
self :handle_error (body )
68
76
kupol .thread_pause (10 )
69
77
end
70
- end end ) -- while true, thread
78
+ until ( not self . thread ) end )
71
79
end
72
80
81
+ local IS_GARRYSMOD = (GM or GAMEMODE ) and RunString and hook
82
+
73
83
local copas_ok , copas = pcall (require , " copas" ) -- should be loaded before http_v2
74
84
if copas_ok then
75
85
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
87
97
88
98
kupol .thread_new = copas .addthread
89
99
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
+
90
135
else
91
- -- e.g. in Garry's Mod
92
136
print (" Kupol: looks like copas is not installed. So you should provide own kupol.http_* and kupol.thread_* functions" )
93
137
end
94
138
95
139
local cjson_ok , cjson = pcall (require , " cjson.safe" )
96
140
if cjson_ok then
97
141
kupol .json_encode = cjson .encode
98
142
kupol .json_decode = cjson .decode
143
+
144
+ elseif IS_GARRYSMOD then
145
+ kupol .json_encode = util .TableToJSON
146
+ kupol .json_decode = util .JSONToTable
147
+
99
148
else
100
149
print (" Kupol: looks like lua-cjson is not installed. So you should provide own kupol.json_encode and kupol.json_decode functions" )
101
150
end
0 commit comments