@trioforge/crucible 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/client/index.d.ts +7 -0
- package/out/client/init.luau +36 -1
- package/out/configs.d.ts +37 -0
- package/out/configs.luau +46 -0
- package/out/data.d.ts +224 -0
- package/out/data.luau +97 -0
- package/out/emit/configs.d.ts +4 -0
- package/out/emit/configs.luau +22 -0
- package/out/emit/data.d.ts +6 -0
- package/out/emit/data.luau +19 -0
- package/out/emit/index.d.ts +5 -1
- package/out/emit/init.luau +23 -7
- package/out/emit/network.d.ts +6 -0
- package/out/emit/network.luau +36 -0
- package/out/emit/replicated.d.ts +4 -0
- package/out/emit/replicated.luau +13 -0
- package/out/index.d.ts +8 -0
- package/out/init.luau +23 -0
- package/out/internal/binding.luau +5 -0
- package/out/internal/boot.luau +107 -8
- package/out/internal/configs/limits.d.ts +10 -0
- package/out/internal/configs/limits.luau +25 -0
- package/out/internal/configs/port.d.ts +29 -0
- package/out/internal/configs/port.luau +99 -0
- package/out/internal/configs/runtime.d.ts +21 -0
- package/out/internal/configs/runtime.luau +981 -0
- package/out/internal/data/admission.d.ts +1 -0
- package/out/internal/data/admission.luau +673 -0
- package/out/internal/data/declarations.d.ts +1 -0
- package/out/internal/data/declarations.luau +384 -0
- package/out/internal/data/envelope.d.ts +1 -0
- package/out/internal/data/envelope.luau +318 -0
- package/out/internal/data/handles.d.ts +1 -0
- package/out/internal/data/handles.luau +255 -0
- package/out/internal/data/inbox-transforms.d.ts +1 -0
- package/out/internal/data/inbox-transforms.luau +458 -0
- package/out/internal/data/inbox.d.ts +1 -0
- package/out/internal/data/inbox.luau +437 -0
- package/out/internal/data/lease.d.ts +1 -0
- package/out/internal/data/lease.luau +304 -0
- package/out/internal/data/limits.d.ts +1 -0
- package/out/internal/data/limits.luau +234 -0
- package/out/internal/data/messages.d.ts +1 -0
- package/out/internal/data/messages.luau +69 -0
- package/out/internal/data/operation-id.d.ts +1 -0
- package/out/internal/data/operation-id.luau +61 -0
- package/out/internal/data/paths.d.ts +2 -0
- package/out/internal/data/paths.luau +323 -0
- package/out/internal/data/port.d.ts +1 -0
- package/out/internal/data/port.luau +290 -0
- package/out/internal/data/profiles.d.ts +1 -0
- package/out/internal/data/profiles.luau +862 -0
- package/out/internal/data/receipts.d.ts +1 -0
- package/out/internal/data/receipts.luau +190 -0
- package/out/internal/data/record-bindings.d.ts +1 -0
- package/out/internal/data/record-bindings.luau +92 -0
- package/out/internal/data/record-declarations.d.ts +1 -0
- package/out/internal/data/record-declarations.luau +140 -0
- package/out/internal/data/records.d.ts +1 -0
- package/out/internal/data/records.luau +400 -0
- package/out/internal/data/runtime.d.ts +1 -0
- package/out/internal/data/runtime.luau +918 -0
- package/out/internal/data/scheduler.d.ts +1 -0
- package/out/internal/data/scheduler.luau +507 -0
- package/out/internal/data/session.d.ts +1 -0
- package/out/internal/data/session.luau +234 -0
- package/out/internal/data/shutdown.d.ts +1 -0
- package/out/internal/data/shutdown.luau +91 -0
- package/out/internal/data/waiters.d.ts +1 -0
- package/out/internal/data/waiters.luau +65 -0
- package/out/internal/lifecycle.luau +45 -0
- package/out/internal/network/catalog.d.ts +26 -0
- package/out/internal/network/catalog.luau +182 -0
- package/out/internal/network/claims.d.ts +1 -0
- package/out/internal/network/claims.luau +154 -0
- package/out/internal/network/client-session.d.ts +1 -0
- package/out/internal/network/client-session.luau +403 -0
- package/out/internal/network/codec.d.ts +63 -0
- package/out/internal/network/codec.luau +1183 -0
- package/out/internal/network/envelope.d.ts +1 -0
- package/out/internal/network/envelope.luau +247 -0
- package/out/internal/network/limits.d.ts +26 -0
- package/out/internal/network/limits.luau +55 -0
- package/out/internal/network/port.d.ts +1 -0
- package/out/internal/network/port.luau +19 -0
- package/out/internal/network/roblox-network-port.d.ts +1 -0
- package/out/internal/network/roblox-network-port.luau +105 -0
- package/out/internal/network/schema.d.ts +72 -0
- package/out/internal/network/schema.luau +386 -0
- package/out/internal/network/server-session.d.ts +1 -0
- package/out/internal/network/server-session.luau +393 -0
- package/out/internal/network/session.d.ts +1 -0
- package/out/internal/network/session.luau +266 -0
- package/out/internal/reactive/context.d.ts +1 -0
- package/out/internal/reactive/context.luau +149 -0
- package/out/internal/reactive/flush.d.ts +1 -0
- package/out/internal/reactive/flush.luau +355 -0
- package/out/internal/reactive/graph.d.ts +1 -0
- package/out/internal/reactive/graph.luau +626 -0
- package/out/internal/reactive/limits.d.ts +1 -0
- package/out/internal/reactive/limits.luau +54 -0
- package/out/internal/reactive/ownership.d.ts +1 -0
- package/out/internal/reactive/ownership.luau +626 -0
- package/out/internal/registry.luau +10 -1
- package/out/internal/sync/client-sync.d.ts +1 -0
- package/out/internal/sync/client-sync.luau +157 -0
- package/out/internal/sync/declarations.d.ts +1 -0
- package/out/internal/sync/declarations.luau +276 -0
- package/out/internal/sync/frame.d.ts +1 -0
- package/out/internal/sync/frame.luau +91 -0
- package/out/internal/sync/server-sync.d.ts +1 -0
- package/out/internal/sync/server-sync.luau +502 -0
- package/out/internal/sync/values.d.ts +1 -0
- package/out/internal/sync/values.luau +930 -0
- package/out/network.d.ts +66 -0
- package/out/network.luau +24 -0
- package/out/reactive.d.ts +76 -0
- package/out/reactive.luau +136 -0
- package/out/replicated.d.ts +38 -0
- package/out/replicated.luau +45 -0
- package/out/server/data.d.ts +54 -0
- package/out/server/data.luau +44 -0
- package/out/server/index.d.ts +16 -0
- package/out/server/init.luau +49 -3
- package/out/server/publish.d.ts +20 -0
- package/out/server/publish.luau +24 -0
- package/out/vide/index.d.ts +7 -0
- package/out/vide/init.luau +50 -0
- package/package.json +13 -2
- package/transformer/data.cjs +72 -0
- package/transformer/declarations.cjs +153 -0
- package/transformer/index.js +37 -11
- package/transformer/network.cjs +961 -0
- package/vide/package.json +4 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local bootClock = TS.import(script, script.Parent.Parent, "boot").bootClock
|
|
4
|
+
local _inbox_transforms = TS.import(script, script.Parent, "inbox-transforms")
|
|
5
|
+
local append = _inbox_transforms.append
|
|
6
|
+
local clearQuarantine = _inbox_transforms.clearQuarantine
|
|
7
|
+
local _envelope = TS.import(script, script.Parent, "envelope")
|
|
8
|
+
local jsonBytes = _envelope.jsonBytes
|
|
9
|
+
local parseEnvelope = _envelope.parseEnvelope
|
|
10
|
+
local _limits = TS.import(script, script.Parent, "limits")
|
|
11
|
+
local CALL_DEADLINE_SECONDS = _limits.CALL_DEADLINE_SECONDS
|
|
12
|
+
local INBOX_MAX_ATTEMPTS = _limits.INBOX_MAX_ATTEMPTS
|
|
13
|
+
local INBOX_RETRY_SECONDS = _limits.INBOX_RETRY_SECONDS
|
|
14
|
+
local MESSAGE_ID_MAX_AGE_SECONDS = _limits.MESSAGE_ID_MAX_AGE_SECONDS
|
|
15
|
+
local MESSAGE_PAYLOAD_MAX_BYTES = _limits.MESSAGE_PAYLOAD_MAX_BYTES
|
|
16
|
+
local OPERATION_ID_MAX_BYTES = _limits.OPERATION_ID_MAX_BYTES
|
|
17
|
+
local _operation_id = TS.import(script, script.Parent, "operation-id")
|
|
18
|
+
local ageOf = _operation_id.ageOf
|
|
19
|
+
local createdAt = _operation_id.createdAt
|
|
20
|
+
local newOperationId = _operation_id.newOperationId
|
|
21
|
+
--* @internal A message payload admitted against a descriptor (rule 76), or refused.
|
|
22
|
+
--* @internal A declared message: its name and the admission of its payload (rule 65).
|
|
23
|
+
--* @internal A quarantined item as `quarantined` lists it (rule 73).
|
|
24
|
+
local function retryAfter(attempts)
|
|
25
|
+
return INBOX_RETRY_SECONDS[math.min(attempts, #INBOX_RETRY_SECONDS)]
|
|
26
|
+
end
|
|
27
|
+
--* @internal One profile store's offline inbox: its receivers, its sends and the session-side delivery (rules 65 to 73).
|
|
28
|
+
local Inbox
|
|
29
|
+
do
|
|
30
|
+
Inbox = setmetatable({}, {
|
|
31
|
+
__tostring = function()
|
|
32
|
+
return "Inbox"
|
|
33
|
+
end,
|
|
34
|
+
})
|
|
35
|
+
Inbox.__index = Inbox
|
|
36
|
+
function Inbox.new(...)
|
|
37
|
+
local self = setmetatable({}, Inbox)
|
|
38
|
+
return self:constructor(...) or self
|
|
39
|
+
end
|
|
40
|
+
function Inbox:constructor(runtime)
|
|
41
|
+
self.runtime = runtime
|
|
42
|
+
self.receivers = {}
|
|
43
|
+
self.engine = runtime.engine
|
|
44
|
+
self.store = runtime.schema.name
|
|
45
|
+
end
|
|
46
|
+
function Inbox:receive(message, receive)
|
|
47
|
+
local _receivers = self.receivers
|
|
48
|
+
local _name = message.name
|
|
49
|
+
local _arg1 = {
|
|
50
|
+
message = message,
|
|
51
|
+
receive = receive,
|
|
52
|
+
}
|
|
53
|
+
_receivers[_name] = _arg1
|
|
54
|
+
end
|
|
55
|
+
function Inbox:unreceive(name)
|
|
56
|
+
local _receivers = self.receivers
|
|
57
|
+
local _name = name
|
|
58
|
+
_receivers[_name] = nil
|
|
59
|
+
end
|
|
60
|
+
function Inbox:send(userId, message, payload, id)
|
|
61
|
+
local admitted = message.admit(payload)
|
|
62
|
+
if not admitted.ok then
|
|
63
|
+
error(`{self.store}: the payload of message {message.name} is invalid`, 2)
|
|
64
|
+
end
|
|
65
|
+
local bytes = jsonBytes(admitted.value)
|
|
66
|
+
if bytes > MESSAGE_PAYLOAD_MAX_BYTES then
|
|
67
|
+
error(`{self.store}: the payload of message {message.name} is {bytes} bytes, over {MESSAGE_PAYLOAD_MAX_BYTES}`, 2)
|
|
68
|
+
end
|
|
69
|
+
local port = self.engine.port
|
|
70
|
+
local _condition = id
|
|
71
|
+
if _condition == nil then
|
|
72
|
+
_condition = newOperationId(port)
|
|
73
|
+
end
|
|
74
|
+
local sent = _condition
|
|
75
|
+
if not (type(sent) == "string") or #sent > OPERATION_ID_MAX_BYTES or createdAt(sent) == nil then
|
|
76
|
+
error(`{self.store}: a message id comes from operationId() and is at most {OPERATION_ID_MAX_BYTES} bytes`, 2)
|
|
77
|
+
end
|
|
78
|
+
if ageOf(sent, port.wall(), MESSAGE_ID_MAX_AGE_SECONDS) ~= "fresh" then
|
|
79
|
+
return {
|
|
80
|
+
kind = "expired",
|
|
81
|
+
}
|
|
82
|
+
end
|
|
83
|
+
local item = {
|
|
84
|
+
id = sent,
|
|
85
|
+
name = message.name,
|
|
86
|
+
version = self.runtime.schema.version,
|
|
87
|
+
payload = admitted.value,
|
|
88
|
+
generation = 0,
|
|
89
|
+
attempts = 0,
|
|
90
|
+
}
|
|
91
|
+
local decision
|
|
92
|
+
local deadline = bootClock() + CALL_DEADLINE_SECONDS
|
|
93
|
+
local ticket = self.engine.scheduler:submit({
|
|
94
|
+
store = self.store,
|
|
95
|
+
key = tostring(userId),
|
|
96
|
+
priority = 5,
|
|
97
|
+
kind = "update",
|
|
98
|
+
dispatchDeadline = deadline,
|
|
99
|
+
bytes = bytes + 1024,
|
|
100
|
+
transform = function()
|
|
101
|
+
return function(current)
|
|
102
|
+
return append(current, userId, item, port.wall, function(d)
|
|
103
|
+
decision = d
|
|
104
|
+
return decision
|
|
105
|
+
end)
|
|
106
|
+
end
|
|
107
|
+
end,
|
|
108
|
+
})
|
|
109
|
+
local settled = ticket:wait(deadline) or {
|
|
110
|
+
kind = if ticket.dispatched then "uncertain" else "timeout",
|
|
111
|
+
}
|
|
112
|
+
if settled.kind ~= "done" then
|
|
113
|
+
return {
|
|
114
|
+
kind = settled.kind,
|
|
115
|
+
}
|
|
116
|
+
end
|
|
117
|
+
if settled.outcome.kind == "error" or decision == nil then
|
|
118
|
+
return {
|
|
119
|
+
kind = "unavailable",
|
|
120
|
+
}
|
|
121
|
+
end
|
|
122
|
+
if decision.kind == "unreadable" then
|
|
123
|
+
return {
|
|
124
|
+
kind = "unavailable",
|
|
125
|
+
}
|
|
126
|
+
end
|
|
127
|
+
if decision.kind ~= "appended" and decision.kind ~= "duplicate" then
|
|
128
|
+
return {
|
|
129
|
+
kind = decision.kind,
|
|
130
|
+
}
|
|
131
|
+
end
|
|
132
|
+
self:prompt(userId)
|
|
133
|
+
return {
|
|
134
|
+
kind = "ok",
|
|
135
|
+
value = nil,
|
|
136
|
+
}
|
|
137
|
+
end
|
|
138
|
+
function Inbox:prompt(userId)
|
|
139
|
+
for _, session in self.runtime.sessions do
|
|
140
|
+
if session.userId == userId and session.phase == 1 then
|
|
141
|
+
self.runtime:requestWrite(session, 3)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
function Inbox:quarantined(userId)
|
|
146
|
+
local deadline = bootClock() + CALL_DEADLINE_SECONDS
|
|
147
|
+
local ticket = self.engine.scheduler:submit({
|
|
148
|
+
store = self.store,
|
|
149
|
+
key = tostring(userId),
|
|
150
|
+
priority = 5,
|
|
151
|
+
kind = "read",
|
|
152
|
+
dispatchDeadline = deadline,
|
|
153
|
+
bytes = 1024,
|
|
154
|
+
})
|
|
155
|
+
local settled = ticket:wait(deadline) or {
|
|
156
|
+
kind = if ticket.dispatched then "uncertain" else "timeout",
|
|
157
|
+
}
|
|
158
|
+
if settled.kind ~= "done" then
|
|
159
|
+
return {
|
|
160
|
+
kind = settled.kind,
|
|
161
|
+
}
|
|
162
|
+
end
|
|
163
|
+
if settled.outcome.kind == "error" then
|
|
164
|
+
return {
|
|
165
|
+
kind = "unavailable",
|
|
166
|
+
}
|
|
167
|
+
end
|
|
168
|
+
local _result = settled.outcome.value
|
|
169
|
+
if _result ~= nil then
|
|
170
|
+
_result = _result.value
|
|
171
|
+
end
|
|
172
|
+
local parsed = parseEnvelope(_result, "profiles")
|
|
173
|
+
if parsed.kind == "absent" then
|
|
174
|
+
return {
|
|
175
|
+
kind = "ok",
|
|
176
|
+
value = {},
|
|
177
|
+
}
|
|
178
|
+
end
|
|
179
|
+
if parsed.kind == "unreadable" then
|
|
180
|
+
return {
|
|
181
|
+
kind = "unavailable",
|
|
182
|
+
}
|
|
183
|
+
end
|
|
184
|
+
local _object = {
|
|
185
|
+
kind = "ok",
|
|
186
|
+
}
|
|
187
|
+
local _left = "value"
|
|
188
|
+
local _exp = parsed.envelope.quarantine
|
|
189
|
+
-- ▼ ReadonlyArray.map ▼
|
|
190
|
+
local _newValue = table.create(#_exp)
|
|
191
|
+
local _callback = function(item)
|
|
192
|
+
local _object_1 = {
|
|
193
|
+
id = item.id,
|
|
194
|
+
name = item.name,
|
|
195
|
+
reason = item.reason,
|
|
196
|
+
attempts = item.attempts,
|
|
197
|
+
}
|
|
198
|
+
local _left_1 = "sentAt"
|
|
199
|
+
local _condition = createdAt(item.id)
|
|
200
|
+
if _condition == nil then
|
|
201
|
+
_condition = 0
|
|
202
|
+
end
|
|
203
|
+
_object_1[_left_1] = _condition
|
|
204
|
+
_object_1.payload = item.payload
|
|
205
|
+
return _object_1
|
|
206
|
+
end
|
|
207
|
+
for _k, _v in _exp do
|
|
208
|
+
_newValue[_k] = _callback(_v, _k - 1, _exp)
|
|
209
|
+
end
|
|
210
|
+
-- ▲ ReadonlyArray.map ▲
|
|
211
|
+
_object[_left] = _newValue
|
|
212
|
+
return _object
|
|
213
|
+
end
|
|
214
|
+
function Inbox:clearQuarantined(userId, ids, action)
|
|
215
|
+
for _, id in ids do
|
|
216
|
+
if not (type(id) == "string") or #id > OPERATION_ID_MAX_BYTES then
|
|
217
|
+
error(`{self.store}: a message id is at most {OPERATION_ID_MAX_BYTES} bytes`, 2)
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
local decision
|
|
221
|
+
local _set = {}
|
|
222
|
+
for _, _v in ids do
|
|
223
|
+
_set[_v] = true
|
|
224
|
+
end
|
|
225
|
+
local listed = _set
|
|
226
|
+
local deadline = bootClock() + CALL_DEADLINE_SECONDS
|
|
227
|
+
local ticket = self.engine.scheduler:submit({
|
|
228
|
+
store = self.store,
|
|
229
|
+
key = tostring(userId),
|
|
230
|
+
priority = 5,
|
|
231
|
+
kind = "update",
|
|
232
|
+
dispatchDeadline = deadline,
|
|
233
|
+
bytes = 1024,
|
|
234
|
+
transform = function()
|
|
235
|
+
return function(current)
|
|
236
|
+
return clearQuarantine(current, userId, listed, action, function(d)
|
|
237
|
+
decision = d
|
|
238
|
+
return decision
|
|
239
|
+
end)
|
|
240
|
+
end
|
|
241
|
+
end,
|
|
242
|
+
})
|
|
243
|
+
local settled = ticket:wait(deadline) or {
|
|
244
|
+
kind = if ticket.dispatched then "uncertain" else "timeout",
|
|
245
|
+
}
|
|
246
|
+
if settled.kind ~= "done" then
|
|
247
|
+
return {
|
|
248
|
+
kind = settled.kind,
|
|
249
|
+
}
|
|
250
|
+
end
|
|
251
|
+
if settled.outcome.kind == "error" or decision == nil or decision.kind == "unreadable" then
|
|
252
|
+
return {
|
|
253
|
+
kind = "unavailable",
|
|
254
|
+
}
|
|
255
|
+
end
|
|
256
|
+
if decision.kind == "full" then
|
|
257
|
+
return {
|
|
258
|
+
kind = "full",
|
|
259
|
+
}
|
|
260
|
+
end
|
|
261
|
+
if decision.changed > 0 then
|
|
262
|
+
self:prompt(userId)
|
|
263
|
+
end
|
|
264
|
+
return {
|
|
265
|
+
kind = "ok",
|
|
266
|
+
value = decision.changed,
|
|
267
|
+
}
|
|
268
|
+
end
|
|
269
|
+
function Inbox:deliver(session, envelope)
|
|
270
|
+
for id, revision in session.acks do
|
|
271
|
+
if revision <= session.confirmed then
|
|
272
|
+
session.acks[id] = nil
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
for id, mark in session.marks do
|
|
276
|
+
local _exp = envelope.inbox
|
|
277
|
+
-- ▼ ReadonlyArray.find ▼
|
|
278
|
+
local _callback = function(other)
|
|
279
|
+
return other.id == id
|
|
280
|
+
end
|
|
281
|
+
local _result
|
|
282
|
+
for _i, _v in _exp do
|
|
283
|
+
if _callback(_v, _i - 1, _exp) == true then
|
|
284
|
+
_result = _v
|
|
285
|
+
break
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
-- ▲ ReadonlyArray.find ▲
|
|
289
|
+
local item = _result
|
|
290
|
+
local _result_1 = item
|
|
291
|
+
if _result_1 ~= nil then
|
|
292
|
+
_result_1 = _result_1.generation
|
|
293
|
+
end
|
|
294
|
+
if _result_1 == mark.generation then
|
|
295
|
+
continue
|
|
296
|
+
end
|
|
297
|
+
local _condition = mark.quarantine ~= nil
|
|
298
|
+
if _condition then
|
|
299
|
+
local _result_2 = item
|
|
300
|
+
if _result_2 ~= nil then
|
|
301
|
+
_result_2 = _result_2.generation
|
|
302
|
+
end
|
|
303
|
+
_condition = _result_2 == mark.generation + 1
|
|
304
|
+
if _condition then
|
|
305
|
+
_condition = item.attempts == mark.attempts
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
if _condition then
|
|
309
|
+
self.engine:diagnose(`quarantine-full:{self.store}:{session.userId}`, `quarantine full for {self.store} {session.userId}; clear it with clearQuarantined`)
|
|
310
|
+
end
|
|
311
|
+
session.marks[id] = nil
|
|
312
|
+
end
|
|
313
|
+
session.inbox = envelope.inbox
|
|
314
|
+
self:apply(session)
|
|
315
|
+
end
|
|
316
|
+
function Inbox:apply(session)
|
|
317
|
+
if not self.runtime:accept(session) then
|
|
318
|
+
return nil
|
|
319
|
+
end
|
|
320
|
+
local present = {}
|
|
321
|
+
for _, item in session.inbox do
|
|
322
|
+
local _id = item.id
|
|
323
|
+
present[_id] = true
|
|
324
|
+
end
|
|
325
|
+
for id in session.retryAt do
|
|
326
|
+
if not (present[id] ~= nil) then
|
|
327
|
+
session.retryAt[id] = nil
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
local soonest
|
|
331
|
+
local staged = false
|
|
332
|
+
for _, item in session.inbox do
|
|
333
|
+
local now = bootClock()
|
|
334
|
+
local _receivers = self.receivers
|
|
335
|
+
local _name = item.name
|
|
336
|
+
local receiver = _receivers[_name]
|
|
337
|
+
local _condition = receiver == nil
|
|
338
|
+
if not _condition then
|
|
339
|
+
local _acks = session.acks
|
|
340
|
+
local _id = item.id
|
|
341
|
+
_condition = _acks[_id] ~= nil
|
|
342
|
+
if not _condition then
|
|
343
|
+
local _marks = session.marks
|
|
344
|
+
local _id_1 = item.id
|
|
345
|
+
_condition = _marks[_id_1] ~= nil
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
if _condition then
|
|
349
|
+
continue
|
|
350
|
+
end
|
|
351
|
+
if item.version > self.runtime.schema.version then
|
|
352
|
+
self.engine:diagnose(`inbox-version:{session.token}:{item.id}`, `{self.store}: {session.userId}'s inbox item {item.id} was sent by a newer build (version {item.version}) and stays queued`)
|
|
353
|
+
continue
|
|
354
|
+
end
|
|
355
|
+
local _retryAt = session.retryAt
|
|
356
|
+
local _id = item.id
|
|
357
|
+
local at = _retryAt[_id]
|
|
358
|
+
if at == nil and item.attempts > 0 then
|
|
359
|
+
at = now + retryAfter(item.attempts)
|
|
360
|
+
local _retryAt_1 = session.retryAt
|
|
361
|
+
local _id_1 = item.id
|
|
362
|
+
local _at = at
|
|
363
|
+
_retryAt_1[_id_1] = _at
|
|
364
|
+
end
|
|
365
|
+
if at ~= nil and now < at then
|
|
366
|
+
local _condition_1 = soonest
|
|
367
|
+
if _condition_1 == nil then
|
|
368
|
+
_condition_1 = at
|
|
369
|
+
end
|
|
370
|
+
soonest = math.min(_condition_1, at)
|
|
371
|
+
continue
|
|
372
|
+
end
|
|
373
|
+
local admitted = receiver.message.admit(item.payload)
|
|
374
|
+
if not admitted.ok then
|
|
375
|
+
local _marks = session.marks
|
|
376
|
+
local _id_1 = item.id
|
|
377
|
+
local _arg1 = {
|
|
378
|
+
id = item.id,
|
|
379
|
+
generation = item.generation,
|
|
380
|
+
attempts = item.attempts,
|
|
381
|
+
quarantine = "payload",
|
|
382
|
+
}
|
|
383
|
+
_marks[_id_1] = _arg1
|
|
384
|
+
local _retryAt_1 = session.retryAt
|
|
385
|
+
local _id_2 = item.id
|
|
386
|
+
local _arg1_1 = now + retryAfter(#INBOX_RETRY_SECONDS)
|
|
387
|
+
_retryAt_1[_id_2] = _arg1_1
|
|
388
|
+
self.engine:diagnose(`inbox-payload:{session.token}:{item.id}`, `{self.store}: {session.userId}'s inbox item {item.id} ({item.name}) has a payload this build refuses; quarantined`)
|
|
389
|
+
staged = true
|
|
390
|
+
continue
|
|
391
|
+
end
|
|
392
|
+
local ok = pcall(function()
|
|
393
|
+
return session:write(function(data)
|
|
394
|
+
return receiver.receive(session.player, data, admitted.value)
|
|
395
|
+
end, function()
|
|
396
|
+
local _acks = session.acks
|
|
397
|
+
local _id_1 = item.id
|
|
398
|
+
local _arg1 = session.revision + 1
|
|
399
|
+
_acks[_id_1] = _arg1
|
|
400
|
+
return _acks
|
|
401
|
+
end)
|
|
402
|
+
end)
|
|
403
|
+
if not ok then
|
|
404
|
+
local attempts = item.attempts + 1
|
|
405
|
+
local _marks = session.marks
|
|
406
|
+
local _id_1 = item.id
|
|
407
|
+
local _arg1 = {
|
|
408
|
+
id = item.id,
|
|
409
|
+
generation = item.generation,
|
|
410
|
+
attempts = attempts,
|
|
411
|
+
quarantine = if attempts >= INBOX_MAX_ATTEMPTS then "attempts" else nil,
|
|
412
|
+
}
|
|
413
|
+
_marks[_id_1] = _arg1
|
|
414
|
+
local _retryAt_1 = session.retryAt
|
|
415
|
+
local _id_2 = item.id
|
|
416
|
+
local _arg1_1 = now + retryAfter(attempts)
|
|
417
|
+
_retryAt_1[_id_2] = _arg1_1
|
|
418
|
+
self.engine:diagnose(`inbox-attempt:{session.token}:{item.id}`, `{self.store}: {session.userId}'s inbox item {item.id} ({item.name}) failed attempt {attempts}`)
|
|
419
|
+
staged = true
|
|
420
|
+
else
|
|
421
|
+
staged = true
|
|
422
|
+
end
|
|
423
|
+
end
|
|
424
|
+
if staged then
|
|
425
|
+
self.runtime:requestWrite(session, 3)
|
|
426
|
+
end
|
|
427
|
+
if soonest ~= nil then
|
|
428
|
+
local at = soonest
|
|
429
|
+
self.engine.port.delay(math.max(at - bootClock(), 0), function()
|
|
430
|
+
return self:apply(session)
|
|
431
|
+
end)
|
|
432
|
+
end
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
return {
|
|
436
|
+
Inbox = Inbox,
|
|
437
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|