rivetkit 2.0.24-rc.1 → 2.0.24
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/dist/schemas/actor-persist/v2.ts +3 -3
- package/dist/schemas/actor-persist/v3.ts +274 -0
- package/dist/schemas/client-protocol/v2.ts +432 -0
- package/dist/schemas/file-system-driver/v2.ts +136 -0
- package/dist/tsup/actor/errors.cjs +2 -4
- package/dist/tsup/actor/errors.cjs.map +1 -1
- package/dist/tsup/actor/errors.d.cts +7 -10
- package/dist/tsup/actor/errors.d.ts +7 -10
- package/dist/tsup/actor/errors.js +9 -11
- package/dist/tsup/{actor-router-consts-B3Lu87yJ.d.cts → actor-router-consts-DzI2szci.d.cts} +5 -9
- package/dist/tsup/{actor-router-consts-B3Lu87yJ.d.ts → actor-router-consts-DzI2szci.d.ts} +5 -9
- package/dist/tsup/{chunk-HHFKKVLR.cjs → chunk-3543NCSN.cjs} +45 -57
- package/dist/tsup/chunk-3543NCSN.cjs.map +1 -0
- package/dist/tsup/chunk-4SHILYS5.cjs +5694 -0
- package/dist/tsup/chunk-4SHILYS5.cjs.map +1 -0
- package/dist/tsup/{chunk-ZTH3KYFH.cjs → chunk-5BZO5XPS.cjs} +3 -3
- package/dist/tsup/{chunk-ZTH3KYFH.cjs.map → chunk-5BZO5XPS.cjs.map} +1 -1
- package/dist/tsup/{chunk-PLUN2NQT.js → chunk-BAIGSF64.js} +189 -187
- package/dist/tsup/chunk-BAIGSF64.js.map +1 -0
- package/dist/tsup/{chunk-SHVX2QUR.cjs → chunk-CHLZBSI2.cjs} +17 -17
- package/dist/tsup/chunk-CHLZBSI2.cjs.map +1 -0
- package/dist/tsup/chunk-D3SLADUD.cjs +512 -0
- package/dist/tsup/chunk-D3SLADUD.cjs.map +1 -0
- package/dist/tsup/{chunk-KSRXX3Z4.cjs → chunk-D6762AOA.cjs} +20 -25
- package/dist/tsup/chunk-D6762AOA.cjs.map +1 -0
- package/dist/tsup/{chunk-7L65NNWP.cjs → chunk-DLK5YCTN.cjs} +187 -185
- package/dist/tsup/chunk-DLK5YCTN.cjs.map +1 -0
- package/dist/tsup/{chunk-YBG6R7LX.js → chunk-DUJQWGYD.js} +3 -7
- package/dist/tsup/chunk-DUJQWGYD.js.map +1 -0
- package/dist/tsup/{chunk-CD33GT6Z.js → chunk-EIPANQMF.js} +2 -2
- package/dist/tsup/{chunk-2JYPS5YM.cjs → chunk-ESMTDP7G.cjs} +6 -6
- package/dist/tsup/chunk-ESMTDP7G.cjs.map +1 -0
- package/dist/tsup/{chunk-VHGY7PU5.cjs → chunk-FVAKREFB.cjs} +1900 -1737
- package/dist/tsup/chunk-FVAKREFB.cjs.map +1 -0
- package/dist/tsup/{chunk-BLK27ES3.js → chunk-I3XT7WOF.js} +44 -56
- package/dist/tsup/chunk-I3XT7WOF.js.map +1 -0
- package/dist/tsup/{chunk-YBHYXIP6.js → chunk-IMDS5T42.js} +3 -3
- package/dist/tsup/chunk-IMDS5T42.js.map +1 -0
- package/dist/tsup/{chunk-INNFK746.cjs → chunk-J3HZJF2P.cjs} +10 -14
- package/dist/tsup/chunk-J3HZJF2P.cjs.map +1 -0
- package/dist/tsup/{chunk-BYMKMOBS.js → chunk-MBBJUHSP.js} +1844 -1681
- package/dist/tsup/chunk-MBBJUHSP.js.map +1 -0
- package/dist/tsup/{chunk-BOMZS2TJ.js → chunk-MO5CB6MD.js} +9 -9
- package/dist/tsup/chunk-MO5CB6MD.js.map +1 -0
- package/dist/tsup/chunk-OFOTPKAH.js +512 -0
- package/dist/tsup/chunk-OFOTPKAH.js.map +1 -0
- package/dist/tsup/{chunk-G64QUEDJ.js → chunk-W6RDS6NW.js} +23 -28
- package/dist/tsup/chunk-W6RDS6NW.js.map +1 -0
- package/dist/tsup/{chunk-36JJ4IQB.cjs → chunk-YC5DUHPM.cjs} +4 -8
- package/dist/tsup/chunk-YC5DUHPM.cjs.map +1 -0
- package/dist/tsup/{chunk-FX7TWFQR.js → chunk-YC7YPM2T.js} +2 -6
- package/dist/tsup/chunk-YC7YPM2T.js.map +1 -0
- package/dist/tsup/{chunk-227FEWMB.js → chunk-ZSPU5R4C.js} +3322 -2251
- package/dist/tsup/chunk-ZSPU5R4C.js.map +1 -0
- package/dist/tsup/client/mod.cjs +9 -9
- package/dist/tsup/client/mod.d.cts +5 -7
- package/dist/tsup/client/mod.d.ts +5 -7
- package/dist/tsup/client/mod.js +8 -8
- package/dist/tsup/common/log.cjs +3 -3
- package/dist/tsup/common/log.js +2 -2
- package/dist/tsup/common/websocket.cjs +4 -4
- package/dist/tsup/common/websocket.js +3 -3
- package/dist/tsup/{conn-B3Vhbgnd.d.ts → config-BRDYDraU.d.cts} +1119 -1047
- package/dist/tsup/{conn-DJWL3nGx.d.cts → config-Bo-blHpJ.d.ts} +1119 -1047
- package/dist/tsup/driver-helpers/mod.cjs +5 -13
- package/dist/tsup/driver-helpers/mod.cjs.map +1 -1
- package/dist/tsup/driver-helpers/mod.d.cts +11 -9
- package/dist/tsup/driver-helpers/mod.d.ts +11 -9
- package/dist/tsup/driver-helpers/mod.js +14 -22
- package/dist/tsup/driver-test-suite/mod.cjs +474 -303
- package/dist/tsup/driver-test-suite/mod.cjs.map +1 -1
- package/dist/tsup/driver-test-suite/mod.d.cts +6 -9
- package/dist/tsup/driver-test-suite/mod.d.ts +6 -9
- package/dist/tsup/driver-test-suite/mod.js +1085 -914
- package/dist/tsup/driver-test-suite/mod.js.map +1 -1
- package/dist/tsup/inspector/mod.cjs +6 -6
- package/dist/tsup/inspector/mod.d.cts +5 -7
- package/dist/tsup/inspector/mod.d.ts +5 -7
- package/dist/tsup/inspector/mod.js +5 -5
- package/dist/tsup/mod.cjs +10 -16
- package/dist/tsup/mod.cjs.map +1 -1
- package/dist/tsup/mod.d.cts +23 -25
- package/dist/tsup/mod.d.ts +23 -25
- package/dist/tsup/mod.js +17 -23
- package/dist/tsup/test/mod.cjs +11 -11
- package/dist/tsup/test/mod.d.cts +4 -6
- package/dist/tsup/test/mod.d.ts +4 -6
- package/dist/tsup/test/mod.js +10 -10
- package/dist/tsup/utils.cjs +3 -5
- package/dist/tsup/utils.cjs.map +1 -1
- package/dist/tsup/utils.d.cts +1 -2
- package/dist/tsup/utils.d.ts +1 -2
- package/dist/tsup/utils.js +2 -4
- package/package.json +13 -6
- package/src/actor/config.ts +56 -44
- package/src/actor/conn/driver.ts +61 -0
- package/src/actor/conn/drivers/http.ts +17 -0
- package/src/actor/conn/drivers/raw-request.ts +24 -0
- package/src/actor/conn/drivers/raw-websocket.ts +65 -0
- package/src/actor/conn/drivers/websocket.ts +129 -0
- package/src/actor/conn/mod.ts +232 -0
- package/src/actor/conn/persisted.ts +81 -0
- package/src/actor/conn/state-manager.ts +196 -0
- package/src/actor/contexts/action.ts +23 -0
- package/src/actor/{context.ts → contexts/actor.ts} +19 -8
- package/src/actor/contexts/conn-init.ts +31 -0
- package/src/actor/contexts/conn.ts +48 -0
- package/src/actor/contexts/create-conn-state.ts +13 -0
- package/src/actor/contexts/on-before-connect.ts +13 -0
- package/src/actor/contexts/on-connect.ts +22 -0
- package/src/actor/contexts/request.ts +48 -0
- package/src/actor/contexts/websocket.ts +48 -0
- package/src/actor/definition.ts +3 -3
- package/src/actor/driver.ts +36 -5
- package/src/actor/errors.ts +19 -24
- package/src/actor/instance/connection-manager.ts +465 -0
- package/src/actor/instance/event-manager.ts +292 -0
- package/src/actor/instance/kv.ts +15 -0
- package/src/actor/instance/mod.ts +1107 -0
- package/src/actor/instance/persisted.ts +67 -0
- package/src/actor/instance/schedule-manager.ts +349 -0
- package/src/actor/instance/state-manager.ts +502 -0
- package/src/actor/mod.ts +13 -16
- package/src/actor/protocol/old.ts +131 -43
- package/src/actor/protocol/serde.ts +19 -4
- package/src/actor/router-endpoints.ts +61 -586
- package/src/actor/router-websocket-endpoints.ts +408 -0
- package/src/actor/router.ts +63 -197
- package/src/actor/schedule.ts +1 -1
- package/src/client/actor-conn.ts +183 -249
- package/src/client/actor-handle.ts +29 -6
- package/src/client/client.ts +0 -4
- package/src/client/config.ts +1 -4
- package/src/client/mod.ts +0 -1
- package/src/client/raw-utils.ts +3 -3
- package/src/client/utils.ts +85 -39
- package/src/common/actor-router-consts.ts +5 -12
- package/src/common/{inline-websocket-adapter2.ts → inline-websocket-adapter.ts} +26 -48
- package/src/common/log.ts +1 -1
- package/src/common/router.ts +28 -17
- package/src/common/utils.ts +2 -0
- package/src/driver-helpers/mod.ts +7 -10
- package/src/driver-helpers/utils.ts +18 -9
- package/src/driver-test-suite/mod.ts +26 -50
- package/src/driver-test-suite/test-inline-client-driver.ts +27 -51
- package/src/driver-test-suite/tests/actor-conn-hibernation.ts +150 -0
- package/src/driver-test-suite/tests/actor-conn-state.ts +1 -4
- package/src/driver-test-suite/tests/actor-conn.ts +5 -9
- package/src/driver-test-suite/tests/actor-destroy.ts +294 -0
- package/src/driver-test-suite/tests/actor-driver.ts +0 -7
- package/src/driver-test-suite/tests/actor-handle.ts +12 -12
- package/src/driver-test-suite/tests/actor-metadata.ts +1 -1
- package/src/driver-test-suite/tests/manager-driver.ts +1 -1
- package/src/driver-test-suite/tests/raw-http-direct-registry.ts +8 -8
- package/src/driver-test-suite/tests/raw-http-request-properties.ts +6 -5
- package/src/driver-test-suite/tests/raw-http.ts +5 -5
- package/src/driver-test-suite/tests/raw-websocket-direct-registry.ts +7 -7
- package/src/driver-test-suite/tests/request-access.ts +4 -4
- package/src/driver-test-suite/utils.ts +6 -10
- package/src/drivers/engine/actor-driver.ts +614 -424
- package/src/drivers/engine/mod.ts +0 -1
- package/src/drivers/file-system/actor.ts +24 -12
- package/src/drivers/file-system/global-state.ts +427 -37
- package/src/drivers/file-system/manager.ts +71 -83
- package/src/drivers/file-system/mod.ts +3 -0
- package/src/drivers/file-system/utils.ts +18 -8
- package/src/engine-process/mod.ts +38 -38
- package/src/inspector/utils.ts +7 -5
- package/src/manager/driver.ts +11 -4
- package/src/manager/gateway.ts +4 -29
- package/src/manager/protocol/mod.ts +0 -2
- package/src/manager/protocol/query.ts +0 -4
- package/src/manager/router.ts +67 -64
- package/src/manager-api/actors.ts +13 -0
- package/src/mod.ts +1 -3
- package/src/registry/mod.ts +20 -20
- package/src/registry/serve.ts +9 -14
- package/src/remote-manager-driver/actor-websocket-client.ts +1 -16
- package/src/remote-manager-driver/api-endpoints.ts +13 -1
- package/src/remote-manager-driver/api-utils.ts +8 -0
- package/src/remote-manager-driver/metadata.ts +58 -0
- package/src/remote-manager-driver/mod.ts +47 -62
- package/src/remote-manager-driver/ws-proxy.ts +1 -1
- package/src/schemas/actor-persist/mod.ts +1 -1
- package/src/schemas/actor-persist/versioned.ts +56 -31
- package/src/schemas/client-protocol/mod.ts +1 -1
- package/src/schemas/client-protocol/versioned.ts +41 -21
- package/src/schemas/client-protocol-zod/mod.ts +103 -0
- package/src/schemas/file-system-driver/mod.ts +1 -1
- package/src/schemas/file-system-driver/versioned.ts +42 -19
- package/src/serde.ts +33 -11
- package/src/test/mod.ts +7 -3
- package/src/utils/node.ts +173 -0
- package/src/utils.ts +0 -4
- package/dist/tsup/chunk-227FEWMB.js.map +0 -1
- package/dist/tsup/chunk-2JYPS5YM.cjs.map +0 -1
- package/dist/tsup/chunk-36JJ4IQB.cjs.map +0 -1
- package/dist/tsup/chunk-7L65NNWP.cjs.map +0 -1
- package/dist/tsup/chunk-BLK27ES3.js.map +0 -1
- package/dist/tsup/chunk-BOMZS2TJ.js.map +0 -1
- package/dist/tsup/chunk-BYMKMOBS.js.map +0 -1
- package/dist/tsup/chunk-FX7TWFQR.js.map +0 -1
- package/dist/tsup/chunk-G64QUEDJ.js.map +0 -1
- package/dist/tsup/chunk-HHFKKVLR.cjs.map +0 -1
- package/dist/tsup/chunk-INNFK746.cjs.map +0 -1
- package/dist/tsup/chunk-KSRXX3Z4.cjs.map +0 -1
- package/dist/tsup/chunk-O44LFKSB.cjs +0 -4623
- package/dist/tsup/chunk-O44LFKSB.cjs.map +0 -1
- package/dist/tsup/chunk-PLUN2NQT.js.map +0 -1
- package/dist/tsup/chunk-S4UJG7ZE.js +0 -1119
- package/dist/tsup/chunk-S4UJG7ZE.js.map +0 -1
- package/dist/tsup/chunk-SHVX2QUR.cjs.map +0 -1
- package/dist/tsup/chunk-VFB23BYZ.cjs +0 -1119
- package/dist/tsup/chunk-VFB23BYZ.cjs.map +0 -1
- package/dist/tsup/chunk-VHGY7PU5.cjs.map +0 -1
- package/dist/tsup/chunk-YBG6R7LX.js.map +0 -1
- package/dist/tsup/chunk-YBHYXIP6.js.map +0 -1
- package/src/actor/action.ts +0 -178
- package/src/actor/conn-drivers.ts +0 -216
- package/src/actor/conn-socket.ts +0 -8
- package/src/actor/conn.ts +0 -272
- package/src/actor/instance.ts +0 -2336
- package/src/actor/persisted.ts +0 -49
- package/src/actor/unstable-react.ts +0 -110
- package/src/driver-test-suite/tests/actor-reconnect.ts +0 -170
- package/src/drivers/engine/kv.ts +0 -3
- package/src/manager/hono-websocket-adapter.ts +0 -393
- /package/dist/tsup/{chunk-CD33GT6Z.js.map → chunk-EIPANQMF.js.map} +0 -0
|
@@ -4,64 +4,64 @@ import {
|
|
|
4
4
|
inspectorLogger,
|
|
5
5
|
isInspectorEnabled,
|
|
6
6
|
secureInspector
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-YC7YPM2T.js";
|
|
8
8
|
import {
|
|
9
|
+
ActionContext,
|
|
9
10
|
ActorDefinition,
|
|
10
|
-
|
|
11
|
+
CONN_DRIVER_SYMBOL,
|
|
12
|
+
CONN_STATE_MANAGER_SYMBOL,
|
|
13
|
+
HTTP_ACTION_REQUEST_VERSIONED,
|
|
14
|
+
HTTP_ACTION_RESPONSE_VERSIONED,
|
|
15
|
+
HTTP_RESPONSE_ERROR_VERSIONED,
|
|
16
|
+
HttpActionRequestSchema,
|
|
17
|
+
HttpActionResponseSchema,
|
|
18
|
+
HttpResponseErrorSchema,
|
|
11
19
|
RemoteManagerDriver,
|
|
12
20
|
createActorInspectorRouter,
|
|
13
21
|
createClientWithDriver,
|
|
22
|
+
createHttpDriver,
|
|
14
23
|
deserializeActorKey,
|
|
15
|
-
generateConnRequestId,
|
|
16
24
|
getDatacenters,
|
|
17
25
|
getEndpoint,
|
|
26
|
+
getValueLength,
|
|
18
27
|
lookupInRegistry,
|
|
28
|
+
parseMessage,
|
|
19
29
|
serializeActorKey,
|
|
20
30
|
updateRunnerConfig
|
|
21
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-ZSPU5R4C.js";
|
|
22
32
|
import {
|
|
23
33
|
CreateActorSchema
|
|
24
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-DUJQWGYD.js";
|
|
25
35
|
import {
|
|
26
|
-
ActionContext,
|
|
27
36
|
ClientConfigSchema,
|
|
28
|
-
|
|
29
|
-
HTTP_ACTION_RESPONSE_VERSIONED,
|
|
30
|
-
HTTP_RESPONSE_ERROR_VERSIONED,
|
|
37
|
+
KEYS,
|
|
31
38
|
RunnerConfigSchema,
|
|
32
|
-
TO_SERVER_VERSIONED,
|
|
33
39
|
createVersionedDataHandler,
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
} from "./chunk-S4UJG7ZE.js";
|
|
40
|
+
getInitialActorKvState
|
|
41
|
+
} from "./chunk-OFOTPKAH.js";
|
|
37
42
|
import {
|
|
38
43
|
EncodingSchema,
|
|
39
44
|
HEADER_ACTOR_ID,
|
|
40
|
-
HEADER_CONN_ID,
|
|
41
45
|
HEADER_CONN_PARAMS,
|
|
42
|
-
HEADER_CONN_TOKEN,
|
|
43
46
|
HEADER_ENCODING,
|
|
44
47
|
HEADER_RIVET_ACTOR,
|
|
45
48
|
HEADER_RIVET_TARGET,
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
PATH_CONNECT,
|
|
50
|
+
PATH_INSPECTOR_CONNECT,
|
|
51
|
+
PATH_WEBSOCKET_BASE,
|
|
52
|
+
PATH_WEBSOCKET_PREFIX,
|
|
48
53
|
WS_PROTOCOL_ACTOR,
|
|
49
|
-
WS_PROTOCOL_CONN_ID,
|
|
50
54
|
WS_PROTOCOL_CONN_PARAMS,
|
|
51
|
-
WS_PROTOCOL_CONN_TOKEN,
|
|
52
55
|
WS_PROTOCOL_ENCODING,
|
|
53
|
-
WS_PROTOCOL_PATH,
|
|
54
56
|
WS_PROTOCOL_TARGET,
|
|
55
|
-
|
|
57
|
+
WS_TEST_PROTOCOL_PATH,
|
|
56
58
|
contentTypeForEncoding,
|
|
57
59
|
deserializeWithEncoding,
|
|
58
|
-
encodingIsBinary,
|
|
59
60
|
generateRandomString,
|
|
60
61
|
loggerWithoutContext,
|
|
61
62
|
serializeWithEncoding
|
|
62
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-I3XT7WOF.js";
|
|
63
64
|
import {
|
|
64
|
-
EXTRA_ERROR_LOG,
|
|
65
65
|
VERSION,
|
|
66
66
|
arrayBuffersEqual,
|
|
67
67
|
assertUnreachable,
|
|
@@ -71,18 +71,15 @@ import {
|
|
|
71
71
|
deconstructError,
|
|
72
72
|
getEnvUniversal,
|
|
73
73
|
getLogger,
|
|
74
|
-
idToStr,
|
|
75
74
|
noopNext,
|
|
76
75
|
package_default,
|
|
77
76
|
promiseWithResolvers,
|
|
78
77
|
setLongTimeout,
|
|
79
78
|
stringifyError
|
|
80
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-BAIGSF64.js";
|
|
81
80
|
import {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
IncorrectConnToken,
|
|
85
|
-
InternalError,
|
|
81
|
+
ActorDuplicateKey,
|
|
82
|
+
ActorStopping,
|
|
86
83
|
InvalidEncoding,
|
|
87
84
|
InvalidParams,
|
|
88
85
|
InvalidRequest,
|
|
@@ -90,20 +87,21 @@ import {
|
|
|
90
87
|
Unsupported,
|
|
91
88
|
UserError,
|
|
92
89
|
WebSocketsNotEnabled
|
|
93
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-W6RDS6NW.js";
|
|
94
91
|
|
|
95
92
|
// src/actor/config.ts
|
|
96
93
|
import { z } from "zod";
|
|
97
94
|
var ActorConfigSchema = z.object({
|
|
98
95
|
onCreate: z.function().optional(),
|
|
99
|
-
|
|
100
|
-
|
|
96
|
+
onDestroy: z.function().optional(),
|
|
97
|
+
onWake: z.function().optional(),
|
|
98
|
+
onSleep: z.function().optional(),
|
|
101
99
|
onStateChange: z.function().optional(),
|
|
102
100
|
onBeforeConnect: z.function().optional(),
|
|
103
101
|
onConnect: z.function().optional(),
|
|
104
102
|
onDisconnect: z.function().optional(),
|
|
105
103
|
onBeforeActionResponse: z.function().optional(),
|
|
106
|
-
|
|
104
|
+
onRequest: z.function().optional(),
|
|
107
105
|
onWebSocket: z.function().optional(),
|
|
108
106
|
actions: z.record(z.function()).default({}),
|
|
109
107
|
state: z.any().optional(),
|
|
@@ -118,7 +116,8 @@ var ActorConfigSchema = z.object({
|
|
|
118
116
|
createConnStateTimeout: z.number().positive().default(5e3),
|
|
119
117
|
onConnectTimeout: z.number().positive().default(5e3),
|
|
120
118
|
// This must be less than ACTOR_STOP_THRESHOLD_MS
|
|
121
|
-
|
|
119
|
+
onSleepTimeout: z.number().positive().default(5e3),
|
|
120
|
+
onDestroyTimeout: z.number().positive().default(5e3),
|
|
122
121
|
stateSaveInterval: z.number().positive().default(1e4),
|
|
123
122
|
actionTimeout: z.number().positive().default(6e4),
|
|
124
123
|
// Max time to wait for waitUntil background promises during shutdown
|
|
@@ -127,8 +126,14 @@ var ActorConfigSchema = z.object({
|
|
|
127
126
|
connectionLivenessInterval: z.number().positive().default(5e3),
|
|
128
127
|
noSleep: z.boolean().default(false),
|
|
129
128
|
sleepTimeout: z.number().positive().default(3e4),
|
|
130
|
-
/**
|
|
131
|
-
|
|
129
|
+
/**
|
|
130
|
+
* Can hibernate WebSockets for onWebSocket.
|
|
131
|
+
*
|
|
132
|
+
* WebSockets using actions/events are hibernatable by default.
|
|
133
|
+
*
|
|
134
|
+
* @experimental
|
|
135
|
+
**/
|
|
136
|
+
canHibernateWebSocket: z.union([
|
|
132
137
|
z.boolean(),
|
|
133
138
|
z.function().args(z.custom()).returns(z.boolean())
|
|
134
139
|
]).default(false)
|
|
@@ -159,359 +164,434 @@ import invariant2 from "invariant";
|
|
|
159
164
|
|
|
160
165
|
// src/actor/router-endpoints.ts
|
|
161
166
|
import * as cbor from "cbor-x";
|
|
162
|
-
import { streamSSE } from "hono/streaming";
|
|
163
|
-
import invariant from "invariant";
|
|
164
167
|
|
|
165
|
-
// src/
|
|
166
|
-
function
|
|
167
|
-
return
|
|
168
|
+
// src/actor/conn/drivers/raw-request.ts
|
|
169
|
+
function createRawRequestDriver() {
|
|
170
|
+
return {
|
|
171
|
+
type: "raw-request",
|
|
172
|
+
disconnect: async () => {
|
|
173
|
+
},
|
|
174
|
+
getConnectionReadyState: () => {
|
|
175
|
+
return 1 /* OPEN */;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
168
178
|
}
|
|
169
179
|
|
|
170
|
-
// src/
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
180
|
+
// src/actor/router-endpoints.ts
|
|
181
|
+
async function handleAction(c, _runConfig, actorDriver, actionName, actorId) {
|
|
182
|
+
const encoding = getRequestEncoding(c.req);
|
|
183
|
+
const parameters = getRequestConnParams(c.req);
|
|
184
|
+
const arrayBuffer = await c.req.arrayBuffer();
|
|
185
|
+
const request = deserializeWithEncoding(
|
|
186
|
+
encoding,
|
|
187
|
+
new Uint8Array(arrayBuffer),
|
|
188
|
+
HTTP_ACTION_REQUEST_VERSIONED,
|
|
189
|
+
HttpActionRequestSchema,
|
|
190
|
+
// JSON: args is already the decoded value (raw object/array)
|
|
191
|
+
(json) => json.args,
|
|
192
|
+
// BARE/CBOR: args is ArrayBuffer that needs CBOR-decoding
|
|
193
|
+
(bare2) => cbor.decode(new Uint8Array(bare2.args))
|
|
194
|
+
);
|
|
195
|
+
const actionArgs = request;
|
|
196
|
+
let actor2;
|
|
197
|
+
let conn;
|
|
198
|
+
let output;
|
|
199
|
+
try {
|
|
200
|
+
actor2 = await actorDriver.loadActor(actorId);
|
|
201
|
+
actor2.rLog.debug({ msg: "handling action", actionName, encoding });
|
|
202
|
+
conn = await actor2.connectionManager.prepareAndConnectConn(
|
|
203
|
+
createHttpDriver(),
|
|
204
|
+
parameters,
|
|
205
|
+
c.req.raw,
|
|
206
|
+
c.req.path,
|
|
207
|
+
c.req.header()
|
|
208
|
+
);
|
|
209
|
+
const ctx = new ActionContext(actor2, conn);
|
|
210
|
+
output = await actor2.executeAction(ctx, actionName, actionArgs);
|
|
211
|
+
} finally {
|
|
212
|
+
if (conn) {
|
|
213
|
+
conn.disconnect();
|
|
214
|
+
}
|
|
200
215
|
}
|
|
201
|
-
|
|
202
|
-
|
|
216
|
+
const serialized = serializeWithEncoding(
|
|
217
|
+
encoding,
|
|
218
|
+
output,
|
|
219
|
+
HTTP_ACTION_RESPONSE_VERSIONED,
|
|
220
|
+
HttpActionResponseSchema,
|
|
221
|
+
// JSON: output is the raw value (will be serialized by jsonStringifyCompat)
|
|
222
|
+
(value) => ({ output: value }),
|
|
223
|
+
// BARE/CBOR: output needs to be CBOR-encoded to ArrayBuffer
|
|
224
|
+
(value) => ({
|
|
225
|
+
output: bufferToArrayBuffer(cbor.encode(value))
|
|
226
|
+
})
|
|
227
|
+
);
|
|
228
|
+
return c.body(serialized, 200, {
|
|
229
|
+
"Content-Type": contentTypeForEncoding(encoding)
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
async function handleRawRequest(c, req, actorDriver, actorId) {
|
|
233
|
+
const actor2 = await actorDriver.loadActor(actorId);
|
|
234
|
+
const parameters = getRequestConnParams(c.req);
|
|
235
|
+
let createdConn;
|
|
236
|
+
try {
|
|
237
|
+
const conn = await actor2.connectionManager.prepareAndConnectConn(
|
|
238
|
+
createRawRequestDriver(),
|
|
239
|
+
parameters,
|
|
240
|
+
req,
|
|
241
|
+
c.req.path,
|
|
242
|
+
c.req.header()
|
|
243
|
+
);
|
|
244
|
+
createdConn = conn;
|
|
245
|
+
return await actor2.handleRawRequest(conn, req);
|
|
246
|
+
} finally {
|
|
247
|
+
if (createdConn) {
|
|
248
|
+
createdConn.disconnect();
|
|
249
|
+
}
|
|
203
250
|
}
|
|
204
|
-
|
|
251
|
+
}
|
|
252
|
+
function getRequestEncoding(req) {
|
|
253
|
+
const encodingParam = req.header(HEADER_ENCODING);
|
|
254
|
+
if (!encodingParam) {
|
|
255
|
+
return "json";
|
|
205
256
|
}
|
|
206
|
-
|
|
207
|
-
|
|
257
|
+
const result = EncodingSchema.safeParse(encodingParam);
|
|
258
|
+
if (!result.success) {
|
|
259
|
+
throw new InvalidEncoding(encodingParam);
|
|
208
260
|
}
|
|
209
|
-
|
|
210
|
-
|
|
261
|
+
return result.data;
|
|
262
|
+
}
|
|
263
|
+
function getRequestExposeInternalError(_req) {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
function getRequestConnParams(req) {
|
|
267
|
+
const paramsParam = req.header(HEADER_CONN_PARAMS);
|
|
268
|
+
if (!paramsParam) {
|
|
269
|
+
return null;
|
|
211
270
|
}
|
|
212
|
-
|
|
213
|
-
return
|
|
271
|
+
try {
|
|
272
|
+
return JSON.parse(paramsParam);
|
|
273
|
+
} catch (err) {
|
|
274
|
+
throw new InvalidParams(
|
|
275
|
+
`Invalid params JSON: ${stringifyError(err)}`
|
|
276
|
+
);
|
|
214
277
|
}
|
|
215
|
-
|
|
216
|
-
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// src/common/router.ts
|
|
281
|
+
import * as cbor2 from "cbor-x";
|
|
282
|
+
|
|
283
|
+
// src/registry/config.ts
|
|
284
|
+
import { z as z2 } from "zod";
|
|
285
|
+
var ActorsSchema = z2.record(
|
|
286
|
+
z2.string(),
|
|
287
|
+
z2.custom()
|
|
288
|
+
);
|
|
289
|
+
var TestConfigSchema = z2.object({ enabled: z2.boolean() });
|
|
290
|
+
var RegistryConfigSchema = z2.object({
|
|
291
|
+
use: z2.record(z2.string(), z2.custom()),
|
|
292
|
+
// TODO: Find a better way of passing around the test config
|
|
293
|
+
/**
|
|
294
|
+
* Test configuration.
|
|
295
|
+
*
|
|
296
|
+
* DO NOT MANUALLY ENABLE. THIS IS USED INTERNALLY.
|
|
297
|
+
* @internal
|
|
298
|
+
**/
|
|
299
|
+
test: TestConfigSchema.optional().default({ enabled: false })
|
|
300
|
+
});
|
|
301
|
+
function buildActorNames(registryConfig) {
|
|
302
|
+
return Object.fromEntries(
|
|
303
|
+
Object.keys(registryConfig.use).map((name) => [name, { metadata: {} }])
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// src/common/router.ts
|
|
308
|
+
function logger() {
|
|
309
|
+
return getLogger("router");
|
|
310
|
+
}
|
|
311
|
+
function loggerMiddleware(logger8) {
|
|
312
|
+
return async (c, next) => {
|
|
313
|
+
const method = c.req.method;
|
|
314
|
+
const path = c.req.path;
|
|
315
|
+
const startTime = Date.now();
|
|
316
|
+
await next();
|
|
317
|
+
const duration = Date.now() - startTime;
|
|
318
|
+
logger8.debug({
|
|
319
|
+
msg: "http request",
|
|
320
|
+
method,
|
|
321
|
+
path,
|
|
322
|
+
status: c.res.status,
|
|
323
|
+
dt: `${duration}ms`,
|
|
324
|
+
reqSize: c.req.header("content-length"),
|
|
325
|
+
resSize: c.res.headers.get("content-length"),
|
|
326
|
+
userAgent: c.req.header("user-agent"),
|
|
327
|
+
...getEnvUniversal("_RIVET_LOG_HEADERS") ? { allHeaders: JSON.stringify(c.req.header()) } : {}
|
|
328
|
+
});
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
function handleRouteNotFound(c) {
|
|
332
|
+
return c.text("Not Found (RivetKit)", 404);
|
|
333
|
+
}
|
|
334
|
+
function handleRouteError(error, c) {
|
|
335
|
+
const exposeInternalError = getRequestExposeInternalError(c.req.raw);
|
|
336
|
+
const { statusCode, group, code, message, metadata } = deconstructError(
|
|
337
|
+
error,
|
|
338
|
+
logger(),
|
|
339
|
+
{
|
|
340
|
+
method: c.req.method,
|
|
341
|
+
path: c.req.path
|
|
342
|
+
},
|
|
343
|
+
exposeInternalError
|
|
344
|
+
);
|
|
345
|
+
let encoding;
|
|
346
|
+
try {
|
|
347
|
+
encoding = getRequestEncoding(c.req);
|
|
348
|
+
} catch (_) {
|
|
349
|
+
encoding = "json";
|
|
217
350
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
351
|
+
const errorData = { group, code, message, metadata };
|
|
352
|
+
const output = serializeWithEncoding(
|
|
353
|
+
encoding,
|
|
354
|
+
errorData,
|
|
355
|
+
HTTP_RESPONSE_ERROR_VERSIONED,
|
|
356
|
+
HttpResponseErrorSchema,
|
|
357
|
+
// JSON: metadata is the raw value (will be serialized by jsonStringifyCompat)
|
|
358
|
+
(value) => ({
|
|
359
|
+
group: value.group,
|
|
360
|
+
code: value.code,
|
|
361
|
+
message: value.message,
|
|
362
|
+
metadata: value.metadata
|
|
363
|
+
}),
|
|
364
|
+
// BARE/CBOR: metadata needs to be CBOR-encoded to ArrayBuffer
|
|
365
|
+
(value) => ({
|
|
366
|
+
group: value.group,
|
|
367
|
+
code: value.code,
|
|
368
|
+
message: value.message,
|
|
369
|
+
metadata: value.metadata ? bufferToArrayBuffer(cbor2.encode(value.metadata)) : null
|
|
370
|
+
})
|
|
371
|
+
);
|
|
372
|
+
return c.body(output, { status: statusCode });
|
|
373
|
+
}
|
|
374
|
+
function handleMetadataRequest(c, registryConfig, runConfig) {
|
|
375
|
+
const response = {
|
|
376
|
+
runtime: "rivetkit",
|
|
377
|
+
version: VERSION,
|
|
378
|
+
runner: {
|
|
379
|
+
kind: runConfig.runnerKind === "serverless" ? { serverless: {} } : { normal: {} }
|
|
380
|
+
},
|
|
381
|
+
actorNames: buildActorNames(registryConfig),
|
|
382
|
+
// If server address is changed, return a different client endpoint.
|
|
383
|
+
// Otherwise, return null indicating the client should use the current
|
|
384
|
+
// endpoint it's already configured with.
|
|
385
|
+
clientEndpoint: runConfig.overrideServerAddress
|
|
386
|
+
};
|
|
387
|
+
return c.json(response);
|
|
388
|
+
}
|
|
389
|
+
function handleHealthRequest(c) {
|
|
390
|
+
return c.json({
|
|
391
|
+
status: "ok",
|
|
392
|
+
runtime: "rivetkit",
|
|
393
|
+
version: VERSION
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// src/actor/router-websocket-endpoints.ts
|
|
398
|
+
import invariant from "invariant";
|
|
399
|
+
|
|
400
|
+
// src/actor/conn/drivers/raw-websocket.ts
|
|
401
|
+
function createRawWebSocketDriver(hibernatable, closePromise) {
|
|
402
|
+
let websocket;
|
|
403
|
+
const driver = {
|
|
404
|
+
type: "raw-websocket",
|
|
405
|
+
hibernatable,
|
|
406
|
+
// No sendMessage implementation since this is a raw WebSocket that doesn't
|
|
407
|
+
// handle messages from the RivetKit protocol
|
|
408
|
+
disconnect: async (_actor, _conn, reason) => {
|
|
409
|
+
if (!websocket) {
|
|
410
|
+
loggerWithoutContext().warn(
|
|
411
|
+
"disconnecting raw ws without websocket"
|
|
238
412
|
);
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
websocket.close(1e3, reason);
|
|
416
|
+
await closePromise;
|
|
417
|
+
},
|
|
418
|
+
terminate: () => {
|
|
419
|
+
var _a;
|
|
420
|
+
(_a = websocket == null ? void 0 : websocket.terminate) == null ? void 0 : _a.call(websocket);
|
|
421
|
+
},
|
|
422
|
+
getConnectionReadyState: (_actor, _conn) => {
|
|
423
|
+
return (websocket == null ? void 0 : websocket.readyState) ?? 0 /* CONNECTING */;
|
|
424
|
+
}
|
|
425
|
+
};
|
|
426
|
+
return {
|
|
427
|
+
driver,
|
|
428
|
+
setWebSocket(ws) {
|
|
429
|
+
websocket = ws;
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// src/actor/conn/drivers/websocket.ts
|
|
435
|
+
function createWebSocketDriver(hibernatable, encoding, closePromise) {
|
|
436
|
+
loggerWithoutContext().debug({
|
|
437
|
+
msg: "createWebSocketDriver creating driver",
|
|
438
|
+
hibernatable
|
|
439
|
+
});
|
|
440
|
+
let websocket;
|
|
441
|
+
const driver = {
|
|
442
|
+
type: "websocket",
|
|
443
|
+
hibernatable,
|
|
444
|
+
rivetKitProtocol: {
|
|
445
|
+
sendMessage: (actor2, conn, message) => {
|
|
446
|
+
if (!websocket) {
|
|
447
|
+
actor2.rLog.warn({
|
|
448
|
+
msg: "websocket not open",
|
|
449
|
+
connId: conn.id
|
|
253
450
|
});
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
if (websocket.readyState !== 1 /* OPEN */) {
|
|
454
|
+
actor2.rLog.warn({
|
|
455
|
+
msg: "attempting to send message to closed websocket, this is likely a bug in RivetKit",
|
|
456
|
+
connId: conn.id,
|
|
457
|
+
wsReadyState: websocket.readyState
|
|
258
458
|
});
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
const serialized = message.serialize(encoding);
|
|
462
|
+
actor2.rLog.debug({
|
|
463
|
+
msg: "sending websocket message",
|
|
464
|
+
encoding,
|
|
465
|
+
dataType: typeof serialized,
|
|
466
|
+
isUint8Array: serialized instanceof Uint8Array,
|
|
467
|
+
isArrayBuffer: serialized instanceof ArrayBuffer,
|
|
468
|
+
dataLength: serialized.byteLength || serialized.length
|
|
259
469
|
});
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
470
|
+
if (serialized instanceof Uint8Array) {
|
|
471
|
+
const buffer = serialized.buffer.slice(
|
|
472
|
+
serialized.byteOffset,
|
|
473
|
+
serialized.byteOffset + serialized.byteLength
|
|
474
|
+
);
|
|
475
|
+
if (buffer instanceof SharedArrayBuffer) {
|
|
476
|
+
const arrayBuffer = new ArrayBuffer(buffer.byteLength);
|
|
477
|
+
new Uint8Array(arrayBuffer).set(new Uint8Array(buffer));
|
|
478
|
+
actor2.rLog.debug({
|
|
479
|
+
msg: "converted SharedArrayBuffer to ArrayBuffer",
|
|
480
|
+
byteLength: arrayBuffer.byteLength
|
|
481
|
+
});
|
|
482
|
+
websocket.send(arrayBuffer);
|
|
483
|
+
} else {
|
|
484
|
+
actor2.rLog.debug({
|
|
485
|
+
msg: "sending ArrayBuffer",
|
|
486
|
+
byteLength: buffer.byteLength
|
|
487
|
+
});
|
|
488
|
+
websocket.send(buffer);
|
|
489
|
+
}
|
|
490
|
+
} else {
|
|
491
|
+
actor2.rLog.debug({
|
|
492
|
+
msg: "sending string data",
|
|
493
|
+
length: serialized.length
|
|
494
|
+
});
|
|
495
|
+
websocket.send(serialized);
|
|
496
|
+
}
|
|
267
497
|
}
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
498
|
+
},
|
|
499
|
+
disconnect: async (_actor, _conn, reason) => {
|
|
500
|
+
if (!websocket) {
|
|
501
|
+
loggerWithoutContext().warn(
|
|
502
|
+
"disconnecting ws without websocket"
|
|
503
|
+
);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
websocket.close(1e3, reason);
|
|
507
|
+
await closePromise;
|
|
508
|
+
},
|
|
509
|
+
terminate: () => {
|
|
510
|
+
websocket.terminate();
|
|
511
|
+
},
|
|
512
|
+
getConnectionReadyState: (_actor, _conn) => {
|
|
513
|
+
return (websocket == null ? void 0 : websocket.readyState) ?? 0 /* CONNECTING */;
|
|
272
514
|
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
515
|
+
};
|
|
516
|
+
return {
|
|
517
|
+
driver,
|
|
518
|
+
setWebSocket(ws) {
|
|
519
|
+
websocket = ws;
|
|
277
520
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
this.#closeReason = reason;
|
|
281
|
-
try {
|
|
282
|
-
this.#ws.close(code, reason);
|
|
283
|
-
this.#readyState = this.CLOSED;
|
|
284
|
-
this.#fireEvent("close", {
|
|
285
|
-
type: "close",
|
|
286
|
-
target: this,
|
|
287
|
-
code,
|
|
288
|
-
reason,
|
|
289
|
-
wasClean: code === 1e3,
|
|
290
|
-
rivetRequestId: this.rivetRequestId
|
|
291
|
-
});
|
|
292
|
-
} catch (error) {
|
|
293
|
-
logger().error({ msg: "error closing websocket", error });
|
|
294
|
-
this.#readyState = this.CLOSED;
|
|
295
|
-
this.#fireEvent("close", {
|
|
296
|
-
type: "close",
|
|
297
|
-
target: this,
|
|
298
|
-
code: 1006,
|
|
299
|
-
reason: "Abnormal closure",
|
|
300
|
-
wasClean: false,
|
|
301
|
-
rivetRequestId: this.rivetRequestId
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
addEventListener(type, listener) {
|
|
306
|
-
if (!this.#eventListeners.has(type)) {
|
|
307
|
-
this.#eventListeners.set(type, /* @__PURE__ */ new Set());
|
|
308
|
-
}
|
|
309
|
-
this.#eventListeners.get(type).add(listener);
|
|
310
|
-
}
|
|
311
|
-
removeEventListener(type, listener) {
|
|
312
|
-
const listeners = this.#eventListeners.get(type);
|
|
313
|
-
if (listeners) {
|
|
314
|
-
listeners.delete(listener);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
dispatchEvent(event) {
|
|
318
|
-
const listeners = this.#eventListeners.get(event.type);
|
|
319
|
-
if (listeners) {
|
|
320
|
-
for (const listener of listeners) {
|
|
321
|
-
try {
|
|
322
|
-
listener(event);
|
|
323
|
-
} catch (error) {
|
|
324
|
-
logger().error({
|
|
325
|
-
msg: `error in ${event.type} event listener`,
|
|
326
|
-
error
|
|
327
|
-
});
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
return true;
|
|
332
|
-
}
|
|
333
|
-
// Internal method to handle incoming messages from WSContext
|
|
334
|
-
_handleMessage(data) {
|
|
335
|
-
let messageData;
|
|
336
|
-
let rivetRequestId;
|
|
337
|
-
let rivetMessageIndex;
|
|
338
|
-
if (typeof data === "string") {
|
|
339
|
-
messageData = data;
|
|
340
|
-
} else if (data instanceof ArrayBuffer || ArrayBuffer.isView(data)) {
|
|
341
|
-
messageData = data;
|
|
342
|
-
} else if (data && typeof data === "object" && "data" in data) {
|
|
343
|
-
messageData = data.data;
|
|
344
|
-
if ("rivetRequestId" in data) {
|
|
345
|
-
rivetRequestId = data.rivetRequestId;
|
|
346
|
-
}
|
|
347
|
-
if ("rivetMessageIndex" in data) {
|
|
348
|
-
rivetMessageIndex = data.rivetMessageIndex;
|
|
349
|
-
}
|
|
350
|
-
} else {
|
|
351
|
-
messageData = String(data);
|
|
352
|
-
}
|
|
353
|
-
logger().debug({
|
|
354
|
-
msg: "bridge handling message",
|
|
355
|
-
dataType: typeof messageData,
|
|
356
|
-
isArrayBuffer: messageData instanceof ArrayBuffer,
|
|
357
|
-
dataStr: typeof messageData === "string" ? messageData : "<binary>",
|
|
358
|
-
rivetMessageIndex
|
|
359
|
-
});
|
|
360
|
-
this.#fireEvent("message", {
|
|
361
|
-
type: "message",
|
|
362
|
-
target: this,
|
|
363
|
-
data: messageData,
|
|
364
|
-
rivetRequestId,
|
|
365
|
-
rivetMessageIndex
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
// Internal method to handle close from WSContext
|
|
369
|
-
_handleClose(code, reason) {
|
|
370
|
-
this.#ws.close(1e3, "hack_force_close");
|
|
371
|
-
if (this.readyState === this.CLOSED) return;
|
|
372
|
-
this.#readyState = this.CLOSED;
|
|
373
|
-
this.#closeCode = code;
|
|
374
|
-
this.#closeReason = reason;
|
|
375
|
-
this.#fireEvent("close", {
|
|
376
|
-
type: "close",
|
|
377
|
-
target: this,
|
|
378
|
-
code,
|
|
379
|
-
reason,
|
|
380
|
-
wasClean: code === 1e3,
|
|
381
|
-
rivetRequestId: this.rivetRequestId
|
|
382
|
-
});
|
|
383
|
-
}
|
|
384
|
-
// Internal method to handle errors from WSContext
|
|
385
|
-
_handleError(error) {
|
|
386
|
-
this.#fireEvent("error", {
|
|
387
|
-
type: "error",
|
|
388
|
-
target: this,
|
|
389
|
-
error
|
|
390
|
-
});
|
|
391
|
-
}
|
|
392
|
-
#fireEvent(type, event) {
|
|
393
|
-
const listeners = this.#eventListeners.get(type);
|
|
394
|
-
if (listeners) {
|
|
395
|
-
for (const listener of listeners) {
|
|
396
|
-
try {
|
|
397
|
-
listener(event);
|
|
398
|
-
} catch (error) {
|
|
399
|
-
logger().error({
|
|
400
|
-
msg: `error in ${type} event listener`,
|
|
401
|
-
error
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
switch (type) {
|
|
407
|
-
case "open":
|
|
408
|
-
if (this.#onopen) {
|
|
409
|
-
try {
|
|
410
|
-
this.#onopen(event);
|
|
411
|
-
} catch (error) {
|
|
412
|
-
logger().error({
|
|
413
|
-
msg: "error in onopen handler",
|
|
414
|
-
error
|
|
415
|
-
});
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
break;
|
|
419
|
-
case "close":
|
|
420
|
-
if (this.#onclose) {
|
|
421
|
-
try {
|
|
422
|
-
this.#onclose(event);
|
|
423
|
-
} catch (error) {
|
|
424
|
-
logger().error({
|
|
425
|
-
msg: "error in onclose handler",
|
|
426
|
-
error
|
|
427
|
-
});
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
break;
|
|
431
|
-
case "error":
|
|
432
|
-
if (this.#onerror) {
|
|
433
|
-
try {
|
|
434
|
-
this.#onerror(event);
|
|
435
|
-
} catch (error) {
|
|
436
|
-
logger().error({
|
|
437
|
-
msg: "error in onerror handler",
|
|
438
|
-
error
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
}
|
|
442
|
-
break;
|
|
443
|
-
case "message":
|
|
444
|
-
if (this.#onmessage) {
|
|
445
|
-
try {
|
|
446
|
-
this.#onmessage(event);
|
|
447
|
-
} catch (error) {
|
|
448
|
-
logger().error({
|
|
449
|
-
msg: "error in onmessage handler",
|
|
450
|
-
error
|
|
451
|
-
});
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
break;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
// Event handler properties with getters/setters
|
|
458
|
-
#onopen = null;
|
|
459
|
-
#onclose = null;
|
|
460
|
-
#onerror = null;
|
|
461
|
-
#onmessage = null;
|
|
462
|
-
get onopen() {
|
|
463
|
-
return this.#onopen;
|
|
464
|
-
}
|
|
465
|
-
set onopen(handler) {
|
|
466
|
-
this.#onopen = handler;
|
|
467
|
-
}
|
|
468
|
-
get onclose() {
|
|
469
|
-
return this.#onclose;
|
|
470
|
-
}
|
|
471
|
-
set onclose(handler) {
|
|
472
|
-
this.#onclose = handler;
|
|
473
|
-
}
|
|
474
|
-
get onerror() {
|
|
475
|
-
return this.#onerror;
|
|
476
|
-
}
|
|
477
|
-
set onerror(handler) {
|
|
478
|
-
this.#onerror = handler;
|
|
479
|
-
}
|
|
480
|
-
get onmessage() {
|
|
481
|
-
return this.#onmessage;
|
|
482
|
-
}
|
|
483
|
-
set onmessage(handler) {
|
|
484
|
-
this.#onmessage = handler;
|
|
485
|
-
}
|
|
486
|
-
};
|
|
521
|
+
};
|
|
522
|
+
}
|
|
487
523
|
|
|
488
|
-
// src/actor/router-endpoints.ts
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
const {
|
|
493
|
-
promise: handlersPromise,
|
|
494
|
-
resolve: handlersResolve,
|
|
495
|
-
reject: handlersReject
|
|
496
|
-
} = promiseWithResolvers();
|
|
497
|
-
let actor2;
|
|
524
|
+
// src/actor/router-websocket-endpoints.ts
|
|
525
|
+
async function routeWebSocket(request, requestPath, requestHeaders, runConfig, actorDriver, actorId, encoding, parameters, gatewayId, requestId, isHibernatable, isRestoringHibernatable) {
|
|
526
|
+
const exposeInternalError = request ? getRequestExposeInternalError(request) : false;
|
|
527
|
+
let createdConn;
|
|
498
528
|
try {
|
|
499
|
-
actor2 = await actorDriver.loadActor(actorId);
|
|
529
|
+
const actor2 = await actorDriver.loadActor(actorId);
|
|
530
|
+
actor2.rLog.debug({
|
|
531
|
+
msg: "new websocket connection",
|
|
532
|
+
actorId,
|
|
533
|
+
requestPath,
|
|
534
|
+
isHibernatable
|
|
535
|
+
});
|
|
536
|
+
const closePromiseResolvers = promiseWithResolvers();
|
|
537
|
+
let handler;
|
|
538
|
+
let connDriver;
|
|
539
|
+
if (requestPath === PATH_CONNECT) {
|
|
540
|
+
const { driver, setWebSocket } = createWebSocketDriver(
|
|
541
|
+
isHibernatable ? { gatewayId, requestId } : void 0,
|
|
542
|
+
encoding,
|
|
543
|
+
closePromiseResolvers.promise
|
|
544
|
+
);
|
|
545
|
+
handler = handleWebSocketConnect.bind(void 0, setWebSocket);
|
|
546
|
+
connDriver = driver;
|
|
547
|
+
} else if (requestPath === PATH_WEBSOCKET_BASE || requestPath.startsWith(PATH_WEBSOCKET_PREFIX)) {
|
|
548
|
+
const { driver, setWebSocket } = createRawWebSocketDriver(
|
|
549
|
+
isHibernatable ? { gatewayId, requestId } : void 0,
|
|
550
|
+
closePromiseResolvers.promise
|
|
551
|
+
);
|
|
552
|
+
handler = handleRawWebSocket.bind(void 0, setWebSocket);
|
|
553
|
+
connDriver = driver;
|
|
554
|
+
} else if (requestPath === PATH_INSPECTOR_CONNECT) {
|
|
555
|
+
return await handleWebSocketInspectorConnect();
|
|
556
|
+
} else {
|
|
557
|
+
throw `WebSocket Path Not Found: ${requestPath}`;
|
|
558
|
+
}
|
|
559
|
+
const conn = await actor2.connectionManager.prepareConn(
|
|
560
|
+
connDriver,
|
|
561
|
+
parameters,
|
|
562
|
+
request,
|
|
563
|
+
requestPath,
|
|
564
|
+
requestHeaders,
|
|
565
|
+
isHibernatable,
|
|
566
|
+
isRestoringHibernatable
|
|
567
|
+
);
|
|
568
|
+
createdConn = conn;
|
|
569
|
+
return await handler({
|
|
570
|
+
runConfig,
|
|
571
|
+
request,
|
|
572
|
+
encoding,
|
|
573
|
+
actor: actor2,
|
|
574
|
+
closePromiseResolvers,
|
|
575
|
+
conn,
|
|
576
|
+
exposeInternalError
|
|
577
|
+
});
|
|
500
578
|
} catch (error) {
|
|
579
|
+
const { group, code } = deconstructError(
|
|
580
|
+
error,
|
|
581
|
+
loggerWithoutContext(),
|
|
582
|
+
{},
|
|
583
|
+
exposeInternalError
|
|
584
|
+
);
|
|
585
|
+
if (createdConn) {
|
|
586
|
+
createdConn.disconnect(`${group}.${code}`);
|
|
587
|
+
}
|
|
501
588
|
return {
|
|
589
|
+
conn: createdConn,
|
|
502
590
|
onOpen: (_evt, ws) => {
|
|
503
|
-
const { code } = deconstructError(
|
|
504
|
-
error,
|
|
505
|
-
actor2.rLog,
|
|
506
|
-
{
|
|
507
|
-
wsEvent: "open"
|
|
508
|
-
},
|
|
509
|
-
exposeInternalError
|
|
510
|
-
);
|
|
511
591
|
ws.close(1011, code);
|
|
512
592
|
},
|
|
513
593
|
onMessage: (_evt, ws) => {
|
|
514
|
-
ws.close(1011, "
|
|
594
|
+
ws.close(1011, "actor.not_loaded");
|
|
515
595
|
},
|
|
516
596
|
onClose: (_event, _ws) => {
|
|
517
597
|
},
|
|
@@ -519,79 +599,38 @@ async function handleWebSocketConnect(req, runConfig, actorDriver, actorId, enco
|
|
|
519
599
|
}
|
|
520
600
|
};
|
|
521
601
|
}
|
|
522
|
-
|
|
523
|
-
|
|
602
|
+
}
|
|
603
|
+
async function handleWebSocketConnect(setWebSocket, {
|
|
604
|
+
runConfig,
|
|
605
|
+
encoding,
|
|
606
|
+
actor: actor2,
|
|
607
|
+
closePromiseResolvers,
|
|
608
|
+
conn,
|
|
609
|
+
exposeInternalError
|
|
610
|
+
}) {
|
|
524
611
|
return {
|
|
612
|
+
conn,
|
|
613
|
+
actor: actor2,
|
|
614
|
+
onRestore: (ws) => {
|
|
615
|
+
setWebSocket(ws);
|
|
616
|
+
},
|
|
617
|
+
// NOTE: onOpen cannot be async since this messes up the open event listener order
|
|
525
618
|
onOpen: (_evt, ws) => {
|
|
526
619
|
actor2.rLog.debug("actor websocket open");
|
|
527
|
-
(
|
|
528
|
-
|
|
529
|
-
let conn;
|
|
530
|
-
actor2.rLog.debug({
|
|
531
|
-
msg: connId ? "websocket reconnection attempt" : "new websocket connection",
|
|
532
|
-
connId,
|
|
533
|
-
actorId
|
|
534
|
-
});
|
|
535
|
-
const isHibernatable = !!requestIdBuf && actor2[PERSIST_SYMBOL].hibernatableWebSocket.findIndex(
|
|
536
|
-
(ws2) => arrayBuffersEqual(ws2.requestId, requestIdBuf)
|
|
537
|
-
) !== -1;
|
|
538
|
-
conn = await actor2.createConn(
|
|
539
|
-
{
|
|
540
|
-
requestId,
|
|
541
|
-
requestIdBuf,
|
|
542
|
-
hibernatable: isHibernatable,
|
|
543
|
-
driverState: {
|
|
544
|
-
[0 /* WEBSOCKET */]: {
|
|
545
|
-
encoding,
|
|
546
|
-
websocket: ws,
|
|
547
|
-
closePromise
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
},
|
|
551
|
-
parameters,
|
|
552
|
-
req,
|
|
553
|
-
connId,
|
|
554
|
-
connToken
|
|
555
|
-
);
|
|
556
|
-
createdConn = conn;
|
|
557
|
-
handlersResolve({ conn, actor: actor2, connId: conn.id });
|
|
558
|
-
} catch (error) {
|
|
559
|
-
handlersReject(error);
|
|
560
|
-
const { code } = deconstructError(
|
|
561
|
-
error,
|
|
562
|
-
actor2.rLog,
|
|
563
|
-
{
|
|
564
|
-
wsEvent: "open"
|
|
565
|
-
},
|
|
566
|
-
exposeInternalError
|
|
567
|
-
);
|
|
568
|
-
ws.close(1011, code);
|
|
569
|
-
}
|
|
570
|
-
})();
|
|
620
|
+
setWebSocket(ws);
|
|
621
|
+
actor2.connectionManager.connectConn(conn);
|
|
571
622
|
},
|
|
572
623
|
onMessage: (evt, ws) => {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
actor3.processMessage(message, conn).catch((error) => {
|
|
581
|
-
const { code } = deconstructError(
|
|
582
|
-
error,
|
|
583
|
-
actor3.rLog,
|
|
584
|
-
{
|
|
585
|
-
wsEvent: "message"
|
|
586
|
-
},
|
|
587
|
-
exposeInternalError
|
|
588
|
-
);
|
|
589
|
-
ws.close(1011, code);
|
|
590
|
-
});
|
|
591
|
-
}).catch((error) => {
|
|
624
|
+
actor2.rLog.debug({ msg: "received message" });
|
|
625
|
+
const value = evt.data.valueOf();
|
|
626
|
+
parseMessage(value, {
|
|
627
|
+
encoding,
|
|
628
|
+
maxIncomingMessageSize: runConfig.maxIncomingMessageSize
|
|
629
|
+
}).then((message) => {
|
|
630
|
+
actor2.processMessage(message, conn).catch((error) => {
|
|
592
631
|
const { code } = deconstructError(
|
|
593
632
|
error,
|
|
594
|
-
|
|
633
|
+
actor2.rLog,
|
|
595
634
|
{
|
|
596
635
|
wsEvent: "message"
|
|
597
636
|
},
|
|
@@ -612,8 +651,7 @@ async function handleWebSocketConnect(req, runConfig, actorDriver, actorId, enco
|
|
|
612
651
|
});
|
|
613
652
|
},
|
|
614
653
|
onClose: (event, ws) => {
|
|
615
|
-
|
|
616
|
-
closePromise.resolve();
|
|
654
|
+
closePromiseResolvers.resolve();
|
|
617
655
|
if (event.wasClean) {
|
|
618
656
|
actor2.rLog.info({
|
|
619
657
|
msg: "websocket closed",
|
|
@@ -630,12 +668,7 @@ async function handleWebSocketConnect(req, runConfig, actorDriver, actorId, enco
|
|
|
630
668
|
});
|
|
631
669
|
}
|
|
632
670
|
ws.close(1e3, "hack_force_close");
|
|
633
|
-
|
|
634
|
-
if (createdConn) {
|
|
635
|
-
const wasClean = event.wasClean || event.code === 1e3;
|
|
636
|
-
actor2.__connDisconnected(createdConn, wasClean, requestId);
|
|
637
|
-
}
|
|
638
|
-
});
|
|
671
|
+
conn.disconnect(event == null ? void 0 : event.reason);
|
|
639
672
|
},
|
|
640
673
|
onError: (_error) => {
|
|
641
674
|
try {
|
|
@@ -651,192 +684,24 @@ async function handleWebSocketConnect(req, runConfig, actorDriver, actorId, enco
|
|
|
651
684
|
}
|
|
652
685
|
};
|
|
653
686
|
}
|
|
654
|
-
async function
|
|
655
|
-
c.header("Content-Encoding", "Identity");
|
|
656
|
-
const encoding = getRequestEncoding(c.req);
|
|
657
|
-
const parameters = getRequestConnParams(c.req);
|
|
658
|
-
const requestId = generateConnRequestId();
|
|
659
|
-
const connId = c.req.header(HEADER_CONN_ID);
|
|
660
|
-
const connToken = c.req.header(HEADER_CONN_TOKEN);
|
|
661
|
-
return streamSSE(c, async (stream) => {
|
|
662
|
-
let actor2;
|
|
663
|
-
let conn;
|
|
664
|
-
try {
|
|
665
|
-
actor2 = await actorDriver.loadActor(actorId);
|
|
666
|
-
actor2.rLog.debug({
|
|
667
|
-
msg: connId ? "sse reconnection attempt" : "sse open",
|
|
668
|
-
connId
|
|
669
|
-
});
|
|
670
|
-
conn = await actor2.createConn(
|
|
671
|
-
{
|
|
672
|
-
requestId,
|
|
673
|
-
hibernatable: false,
|
|
674
|
-
driverState: {
|
|
675
|
-
[1 /* SSE */]: {
|
|
676
|
-
encoding,
|
|
677
|
-
stream
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
},
|
|
681
|
-
parameters,
|
|
682
|
-
c.req.raw,
|
|
683
|
-
connId,
|
|
684
|
-
connToken
|
|
685
|
-
);
|
|
686
|
-
const abortResolver = promiseWithResolvers();
|
|
687
|
-
stream.onAbort(() => {
|
|
688
|
-
});
|
|
689
|
-
c.req.raw.signal.addEventListener("abort", async () => {
|
|
690
|
-
invariant(actor2, "actor should exist");
|
|
691
|
-
const rLog = actor2.rLog ?? loggerWithoutContext();
|
|
692
|
-
try {
|
|
693
|
-
rLog.debug("sse stream aborted");
|
|
694
|
-
if (conn) {
|
|
695
|
-
actor2.__connDisconnected(conn, false, requestId);
|
|
696
|
-
}
|
|
697
|
-
abortResolver.resolve(void 0);
|
|
698
|
-
} catch (error) {
|
|
699
|
-
rLog.error({ msg: "error closing sse connection", error });
|
|
700
|
-
abortResolver.resolve(void 0);
|
|
701
|
-
}
|
|
702
|
-
});
|
|
703
|
-
while (true) {
|
|
704
|
-
if (stream.closed || stream.aborted) {
|
|
705
|
-
actor2 == null ? void 0 : actor2.rLog.debug({
|
|
706
|
-
msg: "sse stream closed",
|
|
707
|
-
closed: stream.closed,
|
|
708
|
-
aborted: stream.aborted
|
|
709
|
-
});
|
|
710
|
-
break;
|
|
711
|
-
}
|
|
712
|
-
await stream.writeSSE({ event: "ping", data: "" });
|
|
713
|
-
await stream.sleep(SSE_PING_INTERVAL);
|
|
714
|
-
}
|
|
715
|
-
} catch (error) {
|
|
716
|
-
loggerWithoutContext().error({
|
|
717
|
-
msg: "error in sse connection",
|
|
718
|
-
error
|
|
719
|
-
});
|
|
720
|
-
if (conn && actor2 !== void 0) {
|
|
721
|
-
actor2.__connDisconnected(conn, false, requestId);
|
|
722
|
-
}
|
|
723
|
-
stream.close();
|
|
724
|
-
}
|
|
725
|
-
});
|
|
726
|
-
}
|
|
727
|
-
async function handleAction(c, _runConfig, actorDriver, actionName, actorId) {
|
|
728
|
-
const encoding = getRequestEncoding(c.req);
|
|
729
|
-
const parameters = getRequestConnParams(c.req);
|
|
730
|
-
const arrayBuffer = await c.req.arrayBuffer();
|
|
731
|
-
const request = deserializeWithEncoding(
|
|
732
|
-
encoding,
|
|
733
|
-
new Uint8Array(arrayBuffer),
|
|
734
|
-
HTTP_ACTION_REQUEST_VERSIONED
|
|
735
|
-
);
|
|
736
|
-
const actionArgs = cbor.decode(new Uint8Array(request.args));
|
|
737
|
-
const requestId = generateConnRequestId();
|
|
738
|
-
let actor2;
|
|
739
|
-
let conn;
|
|
740
|
-
let output;
|
|
741
|
-
try {
|
|
742
|
-
actor2 = await actorDriver.loadActor(actorId);
|
|
743
|
-
actor2.rLog.debug({ msg: "handling action", actionName, encoding });
|
|
744
|
-
conn = await actor2.createConn(
|
|
745
|
-
{
|
|
746
|
-
requestId,
|
|
747
|
-
hibernatable: false,
|
|
748
|
-
driverState: { [2 /* HTTP */]: {} }
|
|
749
|
-
},
|
|
750
|
-
parameters,
|
|
751
|
-
c.req.raw
|
|
752
|
-
);
|
|
753
|
-
const ctx = new ActionContext(actor2.actorContext, conn);
|
|
754
|
-
output = await actor2.executeAction(ctx, actionName, actionArgs);
|
|
755
|
-
} finally {
|
|
756
|
-
if (conn) {
|
|
757
|
-
actor2 == null ? void 0 : actor2.__connDisconnected(conn, true, requestId);
|
|
758
|
-
}
|
|
759
|
-
}
|
|
760
|
-
const responseData = {
|
|
761
|
-
output: bufferToArrayBuffer(cbor.encode(output))
|
|
762
|
-
};
|
|
763
|
-
const serialized = serializeWithEncoding(
|
|
764
|
-
encoding,
|
|
765
|
-
responseData,
|
|
766
|
-
HTTP_ACTION_RESPONSE_VERSIONED
|
|
767
|
-
);
|
|
768
|
-
return c.body(serialized, 200, {
|
|
769
|
-
"Content-Type": contentTypeForEncoding(encoding)
|
|
770
|
-
});
|
|
771
|
-
}
|
|
772
|
-
async function handleConnectionMessage(c, _runConfig, actorDriver, connId, connToken, actorId) {
|
|
773
|
-
const encoding = getRequestEncoding(c.req);
|
|
774
|
-
const arrayBuffer = await c.req.arrayBuffer();
|
|
775
|
-
const message = deserializeWithEncoding(
|
|
776
|
-
encoding,
|
|
777
|
-
new Uint8Array(arrayBuffer),
|
|
778
|
-
TO_SERVER_VERSIONED
|
|
779
|
-
);
|
|
780
|
-
const actor2 = await actorDriver.loadActor(actorId);
|
|
781
|
-
const conn = actor2.conns.get(connId);
|
|
782
|
-
if (!conn) {
|
|
783
|
-
throw new ConnNotFound(connId);
|
|
784
|
-
}
|
|
785
|
-
if (conn._token !== connToken) {
|
|
786
|
-
throw new IncorrectConnToken();
|
|
787
|
-
}
|
|
788
|
-
await actor2.processMessage(message, conn);
|
|
789
|
-
return c.json({});
|
|
790
|
-
}
|
|
791
|
-
async function handleConnectionClose(c, _runConfig, actorDriver, connId, connToken, actorId) {
|
|
792
|
-
var _a;
|
|
793
|
-
const actor2 = await actorDriver.loadActor(actorId);
|
|
794
|
-
const conn = actor2.conns.get(connId);
|
|
795
|
-
if (!conn) {
|
|
796
|
-
throw new ConnNotFound(connId);
|
|
797
|
-
}
|
|
798
|
-
if (conn._token !== connToken) {
|
|
799
|
-
throw new IncorrectConnToken();
|
|
800
|
-
}
|
|
801
|
-
if (!((_a = conn.__socket) == null ? void 0 : _a.driverState) || !(1 /* SSE */ in conn.__socket.driverState)) {
|
|
802
|
-
throw new UserError(
|
|
803
|
-
"Connection close is only supported for SSE connections"
|
|
804
|
-
);
|
|
805
|
-
}
|
|
806
|
-
await conn.disconnect("Connection closed by client request");
|
|
807
|
-
return c.json({});
|
|
808
|
-
}
|
|
809
|
-
async function handleRawWebSocketHandler(req, path4, actorDriver, actorId, requestIdBuf) {
|
|
810
|
-
const actor2 = await actorDriver.loadActor(actorId);
|
|
687
|
+
async function handleRawWebSocket(setWebSocket, { request, actor: actor2, closePromiseResolvers, conn }) {
|
|
811
688
|
return {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
const
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
newRequest = new Request(`http://actor${newPath}`, {
|
|
829
|
-
method: "GET"
|
|
830
|
-
});
|
|
831
|
-
}
|
|
832
|
-
actor2.rLog.debug({
|
|
833
|
-
msg: "rewriting websocket url",
|
|
834
|
-
fromPath: path4,
|
|
835
|
-
toUrl: newRequest.url
|
|
836
|
-
});
|
|
837
|
-
actor2.handleWebSocket(adapter, {
|
|
838
|
-
request: newRequest
|
|
839
|
-
});
|
|
689
|
+
conn,
|
|
690
|
+
actor: actor2,
|
|
691
|
+
onRestore: (wsContext) => {
|
|
692
|
+
const ws = wsContext.raw;
|
|
693
|
+
invariant(ws, "missing wsContext.raw");
|
|
694
|
+
setWebSocket(ws);
|
|
695
|
+
},
|
|
696
|
+
// NOTE: onOpen cannot be async since this will cause the client's open
|
|
697
|
+
// event to be called before this completes. Do all async work in
|
|
698
|
+
// handleRawWebSocket root.
|
|
699
|
+
onOpen: (_evt, wsContext) => {
|
|
700
|
+
const ws = wsContext.raw;
|
|
701
|
+
invariant(ws, "missing wsContext.raw");
|
|
702
|
+
setWebSocket(ws);
|
|
703
|
+
actor2.connectionManager.connectConn(conn);
|
|
704
|
+
actor2.handleRawWebSocket(conn, ws, request);
|
|
840
705
|
},
|
|
841
706
|
onMessage: (event, ws) => {
|
|
842
707
|
const adapter = ws.__adapter;
|
|
@@ -844,157 +709,53 @@ async function handleRawWebSocketHandler(req, path4, actorDriver, actorId, reque
|
|
|
844
709
|
adapter._handleMessage(event);
|
|
845
710
|
}
|
|
846
711
|
},
|
|
847
|
-
onClose: (evt, ws) => {
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
}
|
|
853
|
-
onError: (error, ws) => {
|
|
854
|
-
const adapter = ws.__adapter;
|
|
855
|
-
if (adapter) {
|
|
856
|
-
adapter._handleError(error);
|
|
857
|
-
}
|
|
858
|
-
}
|
|
859
|
-
};
|
|
860
|
-
}
|
|
861
|
-
function getRequestEncoding(req) {
|
|
862
|
-
const encodingParam = req.header(HEADER_ENCODING);
|
|
863
|
-
if (!encodingParam) {
|
|
864
|
-
throw new InvalidEncoding("undefined");
|
|
865
|
-
}
|
|
866
|
-
const result = EncodingSchema.safeParse(encodingParam);
|
|
867
|
-
if (!result.success) {
|
|
868
|
-
throw new InvalidEncoding(encodingParam);
|
|
869
|
-
}
|
|
870
|
-
return result.data;
|
|
871
|
-
}
|
|
872
|
-
function getRequestExposeInternalError(_req) {
|
|
873
|
-
return false;
|
|
874
|
-
}
|
|
875
|
-
function getRequestConnParams(req) {
|
|
876
|
-
const paramsParam = req.header(HEADER_CONN_PARAMS);
|
|
877
|
-
if (!paramsParam) {
|
|
878
|
-
return null;
|
|
879
|
-
}
|
|
880
|
-
try {
|
|
881
|
-
return JSON.parse(paramsParam);
|
|
882
|
-
} catch (err) {
|
|
883
|
-
throw new InvalidParams(
|
|
884
|
-
`Invalid params JSON: ${stringifyError(err)}`
|
|
885
|
-
);
|
|
886
|
-
}
|
|
887
|
-
}
|
|
888
|
-
function truncateRawWebSocketPathPrefix(path4) {
|
|
889
|
-
const url = new URL(path4, "http://actor");
|
|
890
|
-
const pathname = url.pathname.replace(/^\/raw\/websocket\/?/, "") || "/";
|
|
891
|
-
const normalizedPath = (pathname.startsWith("/") ? pathname : "/" + pathname) + url.search;
|
|
892
|
-
return normalizedPath;
|
|
893
|
-
}
|
|
894
|
-
|
|
895
|
-
// src/common/router.ts
|
|
896
|
-
import * as cbor2 from "cbor-x";
|
|
897
|
-
|
|
898
|
-
// src/registry/config.ts
|
|
899
|
-
import { z as z2 } from "zod";
|
|
900
|
-
var ActorsSchema = z2.record(
|
|
901
|
-
z2.string(),
|
|
902
|
-
z2.custom()
|
|
903
|
-
);
|
|
904
|
-
var TestConfigSchema = z2.object({ enabled: z2.boolean() });
|
|
905
|
-
var RegistryConfigSchema = z2.object({
|
|
906
|
-
use: z2.record(z2.string(), z2.custom()),
|
|
907
|
-
// TODO: Find a better way of passing around the test config
|
|
908
|
-
/**
|
|
909
|
-
* Test configuration.
|
|
910
|
-
*
|
|
911
|
-
* DO NOT MANUALLY ENABLE. THIS IS USED INTERNALLY.
|
|
912
|
-
* @internal
|
|
913
|
-
**/
|
|
914
|
-
test: TestConfigSchema.optional().default({ enabled: false })
|
|
915
|
-
});
|
|
916
|
-
function buildActorNames(registryConfig) {
|
|
917
|
-
return Object.fromEntries(
|
|
918
|
-
Object.keys(registryConfig.use).map((name) => [name, { metadata: {} }])
|
|
919
|
-
);
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
// src/common/router.ts
|
|
923
|
-
function logger2() {
|
|
924
|
-
return getLogger("router");
|
|
925
|
-
}
|
|
926
|
-
function loggerMiddleware(logger8) {
|
|
927
|
-
return async (c, next) => {
|
|
928
|
-
const method = c.req.method;
|
|
929
|
-
const path4 = c.req.path;
|
|
930
|
-
const startTime = Date.now();
|
|
931
|
-
await next();
|
|
932
|
-
const duration = Date.now() - startTime;
|
|
933
|
-
logger8.debug({
|
|
934
|
-
msg: "http request",
|
|
935
|
-
method,
|
|
936
|
-
path: path4,
|
|
937
|
-
status: c.res.status,
|
|
938
|
-
dt: `${duration}ms`,
|
|
939
|
-
reqSize: c.req.header("content-length"),
|
|
940
|
-
resSize: c.res.headers.get("content-length"),
|
|
941
|
-
userAgent: c.req.header("user-agent"),
|
|
942
|
-
...getEnvUniversal("_RIVET_LOG_HEADERS") ? { allHeaders: JSON.stringify(c.req.header()) } : {}
|
|
943
|
-
});
|
|
712
|
+
onClose: (evt, ws) => {
|
|
713
|
+
closePromiseResolvers.resolve();
|
|
714
|
+
conn.disconnect(evt == null ? void 0 : evt.reason);
|
|
715
|
+
},
|
|
716
|
+
onError: (error, ws) => {
|
|
717
|
+
}
|
|
944
718
|
};
|
|
945
719
|
}
|
|
946
|
-
function
|
|
947
|
-
return
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
const { statusCode, group, code, message, metadata } = deconstructError(
|
|
952
|
-
error,
|
|
953
|
-
logger2(),
|
|
954
|
-
{
|
|
955
|
-
method: c.req.method,
|
|
956
|
-
path: c.req.path
|
|
720
|
+
async function handleWebSocketInspectorConnect() {
|
|
721
|
+
return {
|
|
722
|
+
// NOTE: onOpen cannot be async since this messes up the open event listener order
|
|
723
|
+
onOpen: (_evt, ws) => {
|
|
724
|
+
ws.send("Hello world");
|
|
957
725
|
},
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
let encoding;
|
|
961
|
-
try {
|
|
962
|
-
encoding = getRequestEncoding(c.req);
|
|
963
|
-
} catch (_) {
|
|
964
|
-
encoding = "json";
|
|
965
|
-
}
|
|
966
|
-
const output = serializeWithEncoding(
|
|
967
|
-
encoding,
|
|
968
|
-
{
|
|
969
|
-
group,
|
|
970
|
-
code,
|
|
971
|
-
message,
|
|
972
|
-
// TODO: Cannot serialize non-binary meta since it requires ArrayBuffer atm
|
|
973
|
-
metadata: encodingIsBinary(encoding) ? bufferToArrayBuffer(cbor2.encode(metadata)) : null
|
|
726
|
+
onMessage: (evt, ws) => {
|
|
727
|
+
ws.send("Pong");
|
|
974
728
|
},
|
|
975
|
-
|
|
976
|
-
);
|
|
977
|
-
return c.body(output, { status: statusCode });
|
|
978
|
-
}
|
|
979
|
-
function handleMetadataRequest(c, registryConfig, runConfig) {
|
|
980
|
-
const response = {
|
|
981
|
-
runtime: "rivetkit",
|
|
982
|
-
version: VERSION,
|
|
983
|
-
runner: {
|
|
984
|
-
kind: runConfig.runnerKind === "serverless" ? { serverless: {} } : { normal: {} }
|
|
729
|
+
onClose: (event, ws) => {
|
|
985
730
|
},
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
clientEndpoint: runConfig.overrideServerAddress ?? (runConfig.disableDefaultServer ? void 0 : getEndpoint(runConfig))
|
|
731
|
+
onError: (_error) => {
|
|
732
|
+
}
|
|
989
733
|
};
|
|
990
|
-
return c.json(response);
|
|
991
734
|
}
|
|
992
|
-
function
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
735
|
+
function parseWebSocketProtocols(protocols) {
|
|
736
|
+
let encodingRaw;
|
|
737
|
+
let connParamsRaw;
|
|
738
|
+
if (protocols) {
|
|
739
|
+
const protocolList = protocols.split(",").map((p) => p.trim());
|
|
740
|
+
for (const protocol of protocolList) {
|
|
741
|
+
if (protocol.startsWith(WS_PROTOCOL_ENCODING)) {
|
|
742
|
+
encodingRaw = protocol.substring(WS_PROTOCOL_ENCODING.length);
|
|
743
|
+
} else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {
|
|
744
|
+
connParamsRaw = decodeURIComponent(
|
|
745
|
+
protocol.substring(WS_PROTOCOL_CONN_PARAMS.length)
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
const encoding = EncodingSchema.parse(encodingRaw);
|
|
751
|
+
const connParams = connParamsRaw ? JSON.parse(connParamsRaw) : void 0;
|
|
752
|
+
return { encoding, connParams };
|
|
753
|
+
}
|
|
754
|
+
function truncateRawWebSocketPathPrefix(path) {
|
|
755
|
+
const url = new URL(path, "http://actor");
|
|
756
|
+
const pathname = url.pathname.replace(/^\/websocket\/?/, "") || "/";
|
|
757
|
+
const normalizedPath = (pathname.startsWith("/") ? pathname : `/${pathname}`) + url.search;
|
|
758
|
+
return normalizedPath;
|
|
998
759
|
}
|
|
999
760
|
|
|
1000
761
|
// src/actor/router.ts
|
|
@@ -1005,11 +766,11 @@ function createActorRouter(runConfig, actorDriver, isTest) {
|
|
|
1005
766
|
router.use("*", loggerMiddleware(loggerWithoutContext()));
|
|
1006
767
|
router.use("*", async (c, next) => {
|
|
1007
768
|
const actor2 = await actorDriver.loadActor(c.env.actorId);
|
|
1008
|
-
actor2.
|
|
769
|
+
actor2.beginHonoHttpRequest();
|
|
1009
770
|
try {
|
|
1010
771
|
await next();
|
|
1011
772
|
} finally {
|
|
1012
|
-
actor2.
|
|
773
|
+
actor2.endHonoHttpRequest();
|
|
1013
774
|
}
|
|
1014
775
|
});
|
|
1015
776
|
router.get("/", (c) => {
|
|
@@ -1022,85 +783,55 @@ function createActorRouter(runConfig, actorDriver, isTest) {
|
|
|
1022
783
|
});
|
|
1023
784
|
if (isTest) {
|
|
1024
785
|
router.post("/.test/force-disconnect", async (c) => {
|
|
786
|
+
var _a;
|
|
1025
787
|
const connId = c.req.query("conn");
|
|
1026
788
|
if (!connId) {
|
|
1027
789
|
return c.text("Missing conn query parameter", 400);
|
|
1028
790
|
}
|
|
1029
791
|
const actor2 = await actorDriver.loadActor(c.env.actorId);
|
|
1030
|
-
const conn = actor2.
|
|
792
|
+
const conn = actor2.connectionManager.getConnForId(connId);
|
|
1031
793
|
if (!conn) {
|
|
1032
794
|
return c.text(`Connection not found: ${connId}`, 404);
|
|
1033
795
|
}
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
const ws = driverState[0 /* WEBSOCKET */].websocket;
|
|
1037
|
-
ws.raw.terminate();
|
|
1038
|
-
} else if (driverState && 1 /* SSE */ in driverState) {
|
|
1039
|
-
const stream = driverState[1 /* SSE */].stream;
|
|
1040
|
-
stream.abort();
|
|
796
|
+
if ((_a = conn[CONN_DRIVER_SYMBOL]) == null ? void 0 : _a.terminate) {
|
|
797
|
+
conn[CONN_DRIVER_SYMBOL].terminate(actor2, conn);
|
|
1041
798
|
}
|
|
1042
799
|
return c.json({ success: true });
|
|
1043
800
|
});
|
|
1044
801
|
}
|
|
1045
|
-
router.
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
WS_PROTOCOL_CONN_TOKEN.length
|
|
1075
|
-
);
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
const encoding = EncodingSchema.parse(encodingRaw);
|
|
1080
|
-
const connParams = connParamsRaw ? JSON.parse(connParamsRaw) : void 0;
|
|
1081
|
-
return await handleWebSocketConnect(
|
|
1082
|
-
c2.req.raw,
|
|
1083
|
-
runConfig,
|
|
1084
|
-
actorDriver,
|
|
1085
|
-
c2.env.actorId,
|
|
1086
|
-
encoding,
|
|
1087
|
-
connParams,
|
|
1088
|
-
generateConnRequestId(),
|
|
1089
|
-
void 0,
|
|
1090
|
-
connIdRaw,
|
|
1091
|
-
connTokenRaw
|
|
802
|
+
router.on(
|
|
803
|
+
"GET",
|
|
804
|
+
[PATH_CONNECT, `${PATH_WEBSOCKET_PREFIX}*`, PATH_INSPECTOR_CONNECT],
|
|
805
|
+
async (c) => {
|
|
806
|
+
var _a;
|
|
807
|
+
const upgradeWebSocket = (_a = runConfig.getUpgradeWebSocket) == null ? void 0 : _a.call(runConfig);
|
|
808
|
+
if (upgradeWebSocket) {
|
|
809
|
+
return upgradeWebSocket(async (c2) => {
|
|
810
|
+
const protocols = c2.req.header("sec-websocket-protocol");
|
|
811
|
+
const { encoding, connParams } = parseWebSocketProtocols(protocols);
|
|
812
|
+
return await routeWebSocket(
|
|
813
|
+
c2.req.raw,
|
|
814
|
+
c2.req.path,
|
|
815
|
+
c2.req.header(),
|
|
816
|
+
runConfig,
|
|
817
|
+
actorDriver,
|
|
818
|
+
c2.env.actorId,
|
|
819
|
+
encoding,
|
|
820
|
+
connParams,
|
|
821
|
+
void 0,
|
|
822
|
+
void 0,
|
|
823
|
+
false,
|
|
824
|
+
false
|
|
825
|
+
);
|
|
826
|
+
})(c, noopNext());
|
|
827
|
+
} else {
|
|
828
|
+
return c.text(
|
|
829
|
+
"WebSockets are not enabled for this driver.",
|
|
830
|
+
400
|
|
1092
831
|
);
|
|
1093
|
-
}
|
|
1094
|
-
} else {
|
|
1095
|
-
return c.text(
|
|
1096
|
-
"WebSockets are not enabled for this driver. Use SSE instead.",
|
|
1097
|
-
400
|
|
1098
|
-
);
|
|
832
|
+
}
|
|
1099
833
|
}
|
|
1100
|
-
|
|
1101
|
-
router.get("/connect/sse", async (c) => {
|
|
1102
|
-
return handleSseConnect(c, runConfig, actorDriver, c.env.actorId);
|
|
1103
|
-
});
|
|
834
|
+
);
|
|
1104
835
|
router.post("/action/:action", async (c) => {
|
|
1105
836
|
const actionName = c.req.param("action");
|
|
1106
837
|
return handleAction(
|
|
@@ -1111,40 +842,9 @@ function createActorRouter(runConfig, actorDriver, isTest) {
|
|
|
1111
842
|
c.env.actorId
|
|
1112
843
|
);
|
|
1113
844
|
});
|
|
1114
|
-
router.
|
|
1115
|
-
const connId = c.req.header(HEADER_CONN_ID);
|
|
1116
|
-
const connToken = c.req.header(HEADER_CONN_TOKEN);
|
|
1117
|
-
if (!connId || !connToken) {
|
|
1118
|
-
throw new Error("Missing required parameters");
|
|
1119
|
-
}
|
|
1120
|
-
return handleConnectionMessage(
|
|
1121
|
-
c,
|
|
1122
|
-
runConfig,
|
|
1123
|
-
actorDriver,
|
|
1124
|
-
connId,
|
|
1125
|
-
connToken,
|
|
1126
|
-
c.env.actorId
|
|
1127
|
-
);
|
|
1128
|
-
});
|
|
1129
|
-
router.post("/connections/close", async (c) => {
|
|
1130
|
-
const connId = c.req.header(HEADER_CONN_ID);
|
|
1131
|
-
const connToken = c.req.header(HEADER_CONN_TOKEN);
|
|
1132
|
-
if (!connId || !connToken) {
|
|
1133
|
-
throw new Error("Missing required parameters");
|
|
1134
|
-
}
|
|
1135
|
-
return handleConnectionClose(
|
|
1136
|
-
c,
|
|
1137
|
-
runConfig,
|
|
1138
|
-
actorDriver,
|
|
1139
|
-
connId,
|
|
1140
|
-
connToken,
|
|
1141
|
-
c.env.actorId
|
|
1142
|
-
);
|
|
1143
|
-
});
|
|
1144
|
-
router.all("/raw/http/*", async (c) => {
|
|
1145
|
-
const actor2 = await actorDriver.loadActor(c.env.actorId);
|
|
845
|
+
router.all("/request/*", async (c) => {
|
|
1146
846
|
const url = new URL(c.req.url);
|
|
1147
|
-
const originalPath = url.pathname.replace(/^\/
|
|
847
|
+
const originalPath = url.pathname.replace(/^\/request/, "") || "/";
|
|
1148
848
|
const correctedUrl = new URL(originalPath + url.search, url.origin);
|
|
1149
849
|
const correctedRequest = new Request(correctedUrl, {
|
|
1150
850
|
method: c.req.method,
|
|
@@ -1157,40 +857,12 @@ function createActorRouter(runConfig, actorDriver, isTest) {
|
|
|
1157
857
|
from: c.req.url,
|
|
1158
858
|
to: correctedRequest.url
|
|
1159
859
|
});
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
router.get(`${PATH_RAW_WEBSOCKET_PREFIX}*`, async (c) => {
|
|
1167
|
-
var _a;
|
|
1168
|
-
const upgradeWebSocket = (_a = runConfig.getUpgradeWebSocket) == null ? void 0 : _a.call(runConfig);
|
|
1169
|
-
if (upgradeWebSocket) {
|
|
1170
|
-
return upgradeWebSocket(async (c2) => {
|
|
1171
|
-
const url = new URL(c2.req.url);
|
|
1172
|
-
const pathWithQuery = c2.req.path + url.search;
|
|
1173
|
-
loggerWithoutContext().debug({
|
|
1174
|
-
msg: "actor router raw websocket",
|
|
1175
|
-
path: c2.req.path,
|
|
1176
|
-
url: c2.req.url,
|
|
1177
|
-
search: url.search,
|
|
1178
|
-
pathWithQuery
|
|
1179
|
-
});
|
|
1180
|
-
return await handleRawWebSocketHandler(
|
|
1181
|
-
c2.req.raw,
|
|
1182
|
-
pathWithQuery,
|
|
1183
|
-
actorDriver,
|
|
1184
|
-
c2.env.actorId,
|
|
1185
|
-
void 0
|
|
1186
|
-
);
|
|
1187
|
-
})(c, noopNext());
|
|
1188
|
-
} else {
|
|
1189
|
-
return c.text(
|
|
1190
|
-
"WebSockets are not enabled for this driver. Use SSE instead.",
|
|
1191
|
-
400
|
|
1192
|
-
);
|
|
1193
|
-
}
|
|
860
|
+
return await handleRawRequest(
|
|
861
|
+
c,
|
|
862
|
+
correctedRequest,
|
|
863
|
+
actorDriver,
|
|
864
|
+
c.env.actorId
|
|
865
|
+
);
|
|
1194
866
|
});
|
|
1195
867
|
if (isInspectorEnabled(runConfig, "actor")) {
|
|
1196
868
|
router.route(
|
|
@@ -1217,12 +889,12 @@ function actor(input) {
|
|
|
1217
889
|
return new ActorDefinition(config2);
|
|
1218
890
|
}
|
|
1219
891
|
|
|
1220
|
-
// src/common/inline-websocket-
|
|
892
|
+
// src/common/inline-websocket-adapter.ts
|
|
1221
893
|
import { WSContext } from "hono/ws";
|
|
1222
|
-
function
|
|
894
|
+
function logger2() {
|
|
1223
895
|
return getLogger("fake-event-source2");
|
|
1224
896
|
}
|
|
1225
|
-
var
|
|
897
|
+
var InlineWebSocketAdapter = class {
|
|
1226
898
|
// WebSocket readyState values
|
|
1227
899
|
CONNECTING = 0;
|
|
1228
900
|
OPEN = 1;
|
|
@@ -1234,27 +906,26 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1234
906
|
#readyState = 0;
|
|
1235
907
|
// Start in CONNECTING state
|
|
1236
908
|
#queuedMessages = [];
|
|
1237
|
-
// Event
|
|
1238
|
-
// before JavaScript has a chance to add event listeners (e.g. within the same tick)
|
|
1239
|
-
#bufferedEvents = [];
|
|
1240
|
-
// Event listeners with buffering
|
|
909
|
+
// Event listeners
|
|
1241
910
|
#eventListeners = /* @__PURE__ */ new Map();
|
|
1242
911
|
constructor(handler) {
|
|
1243
912
|
this.#handler = handler;
|
|
1244
913
|
this.#wsContext = new WSContext({
|
|
1245
914
|
raw: this,
|
|
1246
915
|
send: (data) => {
|
|
1247
|
-
|
|
916
|
+
logger2().debug({ msg: "WSContext.send called" });
|
|
1248
917
|
this.#handleMessage(data);
|
|
1249
918
|
},
|
|
1250
919
|
close: (code, reason) => {
|
|
1251
|
-
|
|
920
|
+
logger2().debug({ msg: "WSContext.close called", code, reason });
|
|
1252
921
|
this.#handleClose(code || 1e3, reason || "");
|
|
1253
922
|
},
|
|
1254
923
|
// Set readyState to 1 (OPEN) since handlers expect an open connection
|
|
1255
924
|
readyState: 1
|
|
1256
925
|
});
|
|
1257
|
-
|
|
926
|
+
setTimeout(() => {
|
|
927
|
+
this.#initialize();
|
|
928
|
+
}, 0);
|
|
1258
929
|
}
|
|
1259
930
|
get readyState() {
|
|
1260
931
|
return this.#readyState;
|
|
@@ -1277,17 +948,18 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1277
948
|
return "";
|
|
1278
949
|
}
|
|
1279
950
|
send(data) {
|
|
1280
|
-
|
|
1281
|
-
if (this.readyState
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
951
|
+
logger2().debug({ msg: "send called", readyState: this.readyState });
|
|
952
|
+
if (this.readyState === this.CONNECTING) {
|
|
953
|
+
throw new DOMException(
|
|
954
|
+
"WebSocket is still in CONNECTING state",
|
|
955
|
+
"InvalidStateError"
|
|
956
|
+
);
|
|
957
|
+
}
|
|
958
|
+
if (this.readyState === this.CLOSING || this.readyState === this.CLOSED) {
|
|
959
|
+
logger2().debug({
|
|
960
|
+
msg: "ignoring send, websocket is closing or closed",
|
|
961
|
+
readyState: this.readyState
|
|
1289
962
|
});
|
|
1290
|
-
this.#fireError(error);
|
|
1291
963
|
return;
|
|
1292
964
|
}
|
|
1293
965
|
this.#handler.onMessage({ data }, this.#wsContext);
|
|
@@ -1299,7 +971,7 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1299
971
|
if (this.readyState === this.CLOSED || this.readyState === this.CLOSING) {
|
|
1300
972
|
return;
|
|
1301
973
|
}
|
|
1302
|
-
|
|
974
|
+
logger2().debug({ msg: "closing fake websocket", code, reason });
|
|
1303
975
|
this.#readyState = this.CLOSING;
|
|
1304
976
|
try {
|
|
1305
977
|
this.#handler.onClose(
|
|
@@ -1307,7 +979,7 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1307
979
|
this.#wsContext
|
|
1308
980
|
);
|
|
1309
981
|
} catch (err) {
|
|
1310
|
-
|
|
982
|
+
logger2().error({ msg: "error closing websocket", error: err });
|
|
1311
983
|
} finally {
|
|
1312
984
|
this.#readyState = this.CLOSED;
|
|
1313
985
|
const closeEvent = {
|
|
@@ -1326,31 +998,31 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1326
998
|
*/
|
|
1327
999
|
async #initialize() {
|
|
1328
1000
|
try {
|
|
1329
|
-
|
|
1330
|
-
|
|
1001
|
+
logger2().debug({ msg: "fake websocket initializing" });
|
|
1002
|
+
logger2().debug({ msg: "calling handler.onOpen with WSContext" });
|
|
1331
1003
|
this.#handler.onOpen(void 0, this.#wsContext);
|
|
1332
1004
|
this.#readyState = this.OPEN;
|
|
1333
|
-
|
|
1005
|
+
logger2().debug({ msg: "fake websocket initialized and now OPEN" });
|
|
1334
1006
|
this.#fireOpen();
|
|
1335
1007
|
if (this.#queuedMessages.length > 0) {
|
|
1336
1008
|
if (this.readyState !== this.OPEN) {
|
|
1337
|
-
|
|
1009
|
+
logger2().warn({
|
|
1338
1010
|
msg: "socket no longer open, dropping queued messages"
|
|
1339
1011
|
});
|
|
1340
1012
|
return;
|
|
1341
1013
|
}
|
|
1342
|
-
|
|
1014
|
+
logger2().debug({
|
|
1343
1015
|
msg: `now processing ${this.#queuedMessages.length} queued messages`
|
|
1344
1016
|
});
|
|
1345
1017
|
const messagesToProcess = [...this.#queuedMessages];
|
|
1346
1018
|
this.#queuedMessages = [];
|
|
1347
1019
|
for (const message of messagesToProcess) {
|
|
1348
|
-
|
|
1020
|
+
logger2().debug({ msg: "processing queued message" });
|
|
1349
1021
|
this.#handleMessage(message);
|
|
1350
1022
|
}
|
|
1351
1023
|
}
|
|
1352
1024
|
} catch (err) {
|
|
1353
|
-
|
|
1025
|
+
logger2().error({
|
|
1354
1026
|
msg: "error opening fake websocket",
|
|
1355
1027
|
error: err,
|
|
1356
1028
|
errorMessage: err instanceof Error ? err.message : String(err),
|
|
@@ -1365,7 +1037,7 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1365
1037
|
*/
|
|
1366
1038
|
#handleMessage(data) {
|
|
1367
1039
|
if (this.readyState !== this.OPEN) {
|
|
1368
|
-
|
|
1040
|
+
logger2().debug({
|
|
1369
1041
|
msg: "message received before socket is OPEN, queuing",
|
|
1370
1042
|
readyState: this.readyState,
|
|
1371
1043
|
dataType: typeof data,
|
|
@@ -1374,7 +1046,7 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1374
1046
|
this.#queuedMessages.push(data);
|
|
1375
1047
|
return;
|
|
1376
1048
|
}
|
|
1377
|
-
|
|
1049
|
+
logger2().debug({
|
|
1378
1050
|
msg: "fake websocket received message from server",
|
|
1379
1051
|
dataType: typeof data,
|
|
1380
1052
|
dataLength: typeof data === "string" ? data.length : data instanceof ArrayBuffer ? data.byteLength : data instanceof Uint8Array ? data.byteLength : "unknown"
|
|
@@ -1405,7 +1077,6 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1405
1077
|
this.#eventListeners.set(type, []);
|
|
1406
1078
|
}
|
|
1407
1079
|
this.#eventListeners.get(type).push(listener);
|
|
1408
|
-
this.#flushBufferedEvents(type);
|
|
1409
1080
|
}
|
|
1410
1081
|
removeEventListener(type, listener) {
|
|
1411
1082
|
const listeners = this.#eventListeners.get(type);
|
|
@@ -1419,24 +1090,19 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1419
1090
|
#dispatchEvent(type, event) {
|
|
1420
1091
|
const listeners = this.#eventListeners.get(type);
|
|
1421
1092
|
if (listeners && listeners.length > 0) {
|
|
1422
|
-
|
|
1093
|
+
logger2().debug(
|
|
1423
1094
|
`dispatching ${type} event to ${listeners.length} listeners`
|
|
1424
1095
|
);
|
|
1425
1096
|
for (const listener of listeners) {
|
|
1426
1097
|
try {
|
|
1427
1098
|
listener(event);
|
|
1428
1099
|
} catch (err) {
|
|
1429
|
-
|
|
1100
|
+
logger2().error({
|
|
1430
1101
|
msg: `error in ${type} event listener`,
|
|
1431
1102
|
error: err
|
|
1432
1103
|
});
|
|
1433
1104
|
}
|
|
1434
1105
|
}
|
|
1435
|
-
} else {
|
|
1436
|
-
logger3().debug({
|
|
1437
|
-
msg: `no ${type} listeners registered, buffering event`
|
|
1438
|
-
});
|
|
1439
|
-
this.#bufferedEvents.push({ type, event });
|
|
1440
1106
|
}
|
|
1441
1107
|
switch (type) {
|
|
1442
1108
|
case "open":
|
|
@@ -1444,7 +1110,7 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1444
1110
|
try {
|
|
1445
1111
|
this.#onopen(event);
|
|
1446
1112
|
} catch (error) {
|
|
1447
|
-
|
|
1113
|
+
logger2().error({
|
|
1448
1114
|
msg: "error in onopen handler",
|
|
1449
1115
|
error
|
|
1450
1116
|
});
|
|
@@ -1456,7 +1122,7 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1456
1122
|
try {
|
|
1457
1123
|
this.#onclose(event);
|
|
1458
1124
|
} catch (error) {
|
|
1459
|
-
|
|
1125
|
+
logger2().error({
|
|
1460
1126
|
msg: "error in onclose handler",
|
|
1461
1127
|
error
|
|
1462
1128
|
});
|
|
@@ -1468,7 +1134,7 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1468
1134
|
try {
|
|
1469
1135
|
this.#onerror(event);
|
|
1470
1136
|
} catch (error) {
|
|
1471
|
-
|
|
1137
|
+
logger2().error({
|
|
1472
1138
|
msg: "error in onerror handler",
|
|
1473
1139
|
error
|
|
1474
1140
|
});
|
|
@@ -1480,7 +1146,7 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1480
1146
|
try {
|
|
1481
1147
|
this.#onmessage(event);
|
|
1482
1148
|
} catch (error) {
|
|
1483
|
-
|
|
1149
|
+
logger2().error({
|
|
1484
1150
|
msg: "error in onmessage handler",
|
|
1485
1151
|
error
|
|
1486
1152
|
});
|
|
@@ -1493,17 +1159,6 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1493
1159
|
this.#dispatchEvent(event.type, event);
|
|
1494
1160
|
return true;
|
|
1495
1161
|
}
|
|
1496
|
-
#flushBufferedEvents(type) {
|
|
1497
|
-
const eventsToFlush = this.#bufferedEvents.filter(
|
|
1498
|
-
(buffered) => buffered.type === type
|
|
1499
|
-
);
|
|
1500
|
-
this.#bufferedEvents = this.#bufferedEvents.filter(
|
|
1501
|
-
(buffered) => buffered.type !== type
|
|
1502
|
-
);
|
|
1503
|
-
for (const { event } of eventsToFlush) {
|
|
1504
|
-
this.#dispatchEvent(type, event);
|
|
1505
|
-
}
|
|
1506
|
-
}
|
|
1507
1162
|
#fireOpen() {
|
|
1508
1163
|
try {
|
|
1509
1164
|
const event = {
|
|
@@ -1513,14 +1168,14 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1513
1168
|
};
|
|
1514
1169
|
this.#dispatchEvent("open", event);
|
|
1515
1170
|
} catch (err) {
|
|
1516
|
-
|
|
1171
|
+
logger2().error({ msg: "error in open event", error: err });
|
|
1517
1172
|
}
|
|
1518
1173
|
}
|
|
1519
1174
|
#fireClose(event) {
|
|
1520
1175
|
try {
|
|
1521
1176
|
this.#dispatchEvent("close", event);
|
|
1522
1177
|
} catch (err) {
|
|
1523
|
-
|
|
1178
|
+
logger2().error({ msg: "error in close event", error: err });
|
|
1524
1179
|
}
|
|
1525
1180
|
}
|
|
1526
1181
|
#fireError(error) {
|
|
@@ -1534,9 +1189,9 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1534
1189
|
};
|
|
1535
1190
|
this.#dispatchEvent("error", event);
|
|
1536
1191
|
} catch (err) {
|
|
1537
|
-
|
|
1192
|
+
logger2().error({ msg: "error in error event", error: err });
|
|
1538
1193
|
}
|
|
1539
|
-
|
|
1194
|
+
logger2().error({ msg: "websocket error", error });
|
|
1540
1195
|
}
|
|
1541
1196
|
// Event handler properties with getters/setters
|
|
1542
1197
|
#onopen = null;
|
|
@@ -1570,24 +1225,21 @@ var InlineWebSocketAdapter2 = class {
|
|
|
1570
1225
|
};
|
|
1571
1226
|
|
|
1572
1227
|
// src/drivers/engine/actor-driver.ts
|
|
1573
|
-
import { Runner } from "@rivetkit/engine-runner";
|
|
1228
|
+
import { idToStr, Runner } from "@rivetkit/engine-runner";
|
|
1574
1229
|
import * as cbor3 from "cbor-x";
|
|
1575
|
-
import { streamSSE
|
|
1230
|
+
import { streamSSE } from "hono/streaming";
|
|
1576
1231
|
import { WSContext as WSContext2 } from "hono/ws";
|
|
1577
1232
|
import invariant3 from "invariant";
|
|
1578
1233
|
|
|
1579
|
-
// src/drivers/engine/kv.ts
|
|
1580
|
-
var KEYS = {
|
|
1581
|
-
PERSIST_DATA: Uint8Array.from([1])
|
|
1582
|
-
};
|
|
1583
|
-
|
|
1584
1234
|
// src/drivers/engine/log.ts
|
|
1585
|
-
function
|
|
1235
|
+
function logger3() {
|
|
1586
1236
|
return getLogger("driver-engine");
|
|
1587
1237
|
}
|
|
1588
1238
|
|
|
1589
1239
|
// src/drivers/engine/actor-driver.ts
|
|
1590
1240
|
var RUNNER_SSE_PING_INTERVAL = 1e3;
|
|
1241
|
+
var CONN_MESSAGE_ACK_DEADLINE = 5e3;
|
|
1242
|
+
var CONN_BUFFERED_MESSAGE_SIZE_THRESHOLD = 5e5;
|
|
1591
1243
|
var EngineActorDriver = class {
|
|
1592
1244
|
#registryConfig;
|
|
1593
1245
|
#runConfig;
|
|
@@ -1602,9 +1254,23 @@ var EngineActorDriver = class {
|
|
|
1602
1254
|
#runnerStarted = promiseWithResolvers();
|
|
1603
1255
|
#runnerStopped = promiseWithResolvers();
|
|
1604
1256
|
#isRunnerStopped = false;
|
|
1605
|
-
//
|
|
1606
|
-
|
|
1607
|
-
|
|
1257
|
+
// HACK: Track actor stop intent locally since the runner protocol doesn't
|
|
1258
|
+
// pass the stop reason to onActorStop. This will be fixed when the runner
|
|
1259
|
+
// protocol is updated to send the intent directly (see RVT-5284)
|
|
1260
|
+
#actorStopIntent = /* @__PURE__ */ new Map();
|
|
1261
|
+
// Map of conn IDs to message index waiting to be persisted before sending
|
|
1262
|
+
// an ack
|
|
1263
|
+
//
|
|
1264
|
+
// serverMessageIndex is updated and pendingAck is flagged in needed in
|
|
1265
|
+
// onBeforePersistConnect, then the HWS ack message is sent in
|
|
1266
|
+
// onAfterPersistConn. This allows us to track what's about to be written
|
|
1267
|
+
// to storage to prevent race conditions with the serverMessageIndex being
|
|
1268
|
+
// updated while writing the existing state.
|
|
1269
|
+
//
|
|
1270
|
+
// bufferedMessageSize tracks the total bytes received since last persist
|
|
1271
|
+
// to force a saveState when threshold is reached. This is the amount of
|
|
1272
|
+
// data currently buffered on the gateway.
|
|
1273
|
+
#hwsMessageIndex = /* @__PURE__ */ new Map();
|
|
1608
1274
|
constructor(registryConfig, runConfig, managerDriver, inlineClient) {
|
|
1609
1275
|
this.#registryConfig = registryConfig;
|
|
1610
1276
|
this.#runConfig = runConfig;
|
|
@@ -1642,147 +1308,24 @@ var EngineActorDriver = class {
|
|
|
1642
1308
|
},
|
|
1643
1309
|
fetch: this.#runnerFetch.bind(this),
|
|
1644
1310
|
websocket: this.#runnerWebSocket.bind(this),
|
|
1311
|
+
hibernatableWebSocket: {
|
|
1312
|
+
canHibernate: this.#hwsCanHibernate.bind(this)
|
|
1313
|
+
},
|
|
1645
1314
|
onActorStart: this.#runnerOnActorStart.bind(this),
|
|
1646
1315
|
onActorStop: this.#runnerOnActorStop.bind(this),
|
|
1647
|
-
logger: getLogger("engine-runner")
|
|
1648
|
-
getActorHibernationConfig: (actorId, requestId, request) => {
|
|
1649
|
-
var _a;
|
|
1650
|
-
const url = new URL(request.url);
|
|
1651
|
-
const path4 = url.pathname;
|
|
1652
|
-
const actorInstance = this.#runner.getActor(actorId);
|
|
1653
|
-
if (!actorInstance) {
|
|
1654
|
-
logger4().warn({
|
|
1655
|
-
msg: "actor not found in getActorHibernationConfig",
|
|
1656
|
-
actorId
|
|
1657
|
-
});
|
|
1658
|
-
return { enabled: false, lastMsgIndex: void 0 };
|
|
1659
|
-
}
|
|
1660
|
-
const handler = this.#actors.get(actorId);
|
|
1661
|
-
if (!handler) {
|
|
1662
|
-
logger4().warn({
|
|
1663
|
-
msg: "actor handler not found in getActorHibernationConfig",
|
|
1664
|
-
actorId
|
|
1665
|
-
});
|
|
1666
|
-
return { enabled: false, lastMsgIndex: void 0 };
|
|
1667
|
-
}
|
|
1668
|
-
if (!handler.actor) {
|
|
1669
|
-
logger4().warn({
|
|
1670
|
-
msg: "actor not found in getActorHibernationConfig",
|
|
1671
|
-
actorId
|
|
1672
|
-
});
|
|
1673
|
-
return { enabled: false, lastMsgIndex: void 0 };
|
|
1674
|
-
}
|
|
1675
|
-
const hibernatableArray = handler.actor[PERSIST_SYMBOL].hibernatableWebSocket;
|
|
1676
|
-
logger4().debug({
|
|
1677
|
-
msg: "checking hibernatable websockets",
|
|
1678
|
-
requestId: idToStr(requestId),
|
|
1679
|
-
existingHibernatableWebSockets: hibernatableArray.length
|
|
1680
|
-
});
|
|
1681
|
-
const existingWs = hibernatableArray.find(
|
|
1682
|
-
(ws) => arrayBuffersEqual(ws.requestId, requestId)
|
|
1683
|
-
);
|
|
1684
|
-
let hibernationConfig;
|
|
1685
|
-
if (existingWs) {
|
|
1686
|
-
logger4().debug({
|
|
1687
|
-
msg: "found existing hibernatable websocket",
|
|
1688
|
-
requestId: idToStr(requestId),
|
|
1689
|
-
lastMsgIndex: existingWs.msgIndex
|
|
1690
|
-
});
|
|
1691
|
-
hibernationConfig = {
|
|
1692
|
-
enabled: true,
|
|
1693
|
-
lastMsgIndex: Number(existingWs.msgIndex)
|
|
1694
|
-
};
|
|
1695
|
-
} else {
|
|
1696
|
-
logger4().debug({
|
|
1697
|
-
msg: "no existing hibernatable websocket found",
|
|
1698
|
-
requestId: idToStr(requestId)
|
|
1699
|
-
});
|
|
1700
|
-
if (path4 === PATH_CONNECT_WEBSOCKET) {
|
|
1701
|
-
hibernationConfig = {
|
|
1702
|
-
enabled: true,
|
|
1703
|
-
lastMsgIndex: void 0
|
|
1704
|
-
};
|
|
1705
|
-
} else if (path4.startsWith(PATH_RAW_WEBSOCKET_PREFIX)) {
|
|
1706
|
-
const definition = lookupInRegistry(
|
|
1707
|
-
this.#registryConfig,
|
|
1708
|
-
actorInstance.config.name
|
|
1709
|
-
);
|
|
1710
|
-
const canHibernatWebSocket = (_a = definition.config.options) == null ? void 0 : _a.canHibernatWebSocket;
|
|
1711
|
-
if (canHibernatWebSocket === true) {
|
|
1712
|
-
hibernationConfig = {
|
|
1713
|
-
enabled: true,
|
|
1714
|
-
lastMsgIndex: void 0
|
|
1715
|
-
};
|
|
1716
|
-
} else if (typeof canHibernatWebSocket === "function") {
|
|
1717
|
-
try {
|
|
1718
|
-
const newPath = truncateRawWebSocketPathPrefix(
|
|
1719
|
-
url.pathname
|
|
1720
|
-
);
|
|
1721
|
-
const truncatedRequest = new Request(
|
|
1722
|
-
`http://actor${newPath}`,
|
|
1723
|
-
request
|
|
1724
|
-
);
|
|
1725
|
-
const canHibernate = canHibernatWebSocket(truncatedRequest);
|
|
1726
|
-
hibernationConfig = {
|
|
1727
|
-
enabled: canHibernate,
|
|
1728
|
-
lastMsgIndex: void 0
|
|
1729
|
-
};
|
|
1730
|
-
} catch (error) {
|
|
1731
|
-
logger4().error({
|
|
1732
|
-
msg: "error calling canHibernatWebSocket",
|
|
1733
|
-
error
|
|
1734
|
-
});
|
|
1735
|
-
hibernationConfig = {
|
|
1736
|
-
enabled: false,
|
|
1737
|
-
lastMsgIndex: void 0
|
|
1738
|
-
};
|
|
1739
|
-
}
|
|
1740
|
-
} else {
|
|
1741
|
-
hibernationConfig = {
|
|
1742
|
-
enabled: false,
|
|
1743
|
-
lastMsgIndex: void 0
|
|
1744
|
-
};
|
|
1745
|
-
}
|
|
1746
|
-
} else {
|
|
1747
|
-
logger4().warn({
|
|
1748
|
-
msg: "unexpected path for getActorHibernationConfig",
|
|
1749
|
-
path: path4
|
|
1750
|
-
});
|
|
1751
|
-
hibernationConfig = {
|
|
1752
|
-
enabled: false,
|
|
1753
|
-
lastMsgIndex: void 0
|
|
1754
|
-
};
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1757
|
-
if (existingWs) {
|
|
1758
|
-
logger4().debug({
|
|
1759
|
-
msg: "updated existing hibernatable websocket timestamp",
|
|
1760
|
-
requestId: idToStr(requestId)
|
|
1761
|
-
});
|
|
1762
|
-
existingWs.lastSeenTimestamp = BigInt(Date.now());
|
|
1763
|
-
} else {
|
|
1764
|
-
logger4().debug({
|
|
1765
|
-
msg: "created new hibernatable websocket entry",
|
|
1766
|
-
requestId: idToStr(requestId)
|
|
1767
|
-
});
|
|
1768
|
-
handler.actor[PERSIST_SYMBOL].hibernatableWebSocket.push({
|
|
1769
|
-
requestId,
|
|
1770
|
-
lastSeenTimestamp: BigInt(Date.now()),
|
|
1771
|
-
msgIndex: -1n
|
|
1772
|
-
});
|
|
1773
|
-
}
|
|
1774
|
-
return hibernationConfig;
|
|
1775
|
-
}
|
|
1316
|
+
logger: getLogger("engine-runner")
|
|
1776
1317
|
};
|
|
1777
1318
|
this.#runner = new Runner(engineRunnerConfig);
|
|
1778
1319
|
this.#runner.start();
|
|
1779
|
-
|
|
1320
|
+
logger3().debug({
|
|
1780
1321
|
msg: "engine runner started",
|
|
1781
1322
|
endpoint: runConfig.endpoint,
|
|
1782
1323
|
namespace: runConfig.namespace,
|
|
1783
1324
|
runnerName: runConfig.runnerName
|
|
1784
1325
|
});
|
|
1785
|
-
|
|
1326
|
+
}
|
|
1327
|
+
getExtraActorLogParams() {
|
|
1328
|
+
return { runnerId: this.#runner.runnerId ?? "-" };
|
|
1786
1329
|
}
|
|
1787
1330
|
async #loadActorHandler(actorId) {
|
|
1788
1331
|
const handler = this.#actors.get(actorId);
|
|
@@ -1792,40 +1335,9 @@ var EngineActorDriver = class {
|
|
|
1792
1335
|
if (!handler.actor) throw new Error("Actor should be loaded");
|
|
1793
1336
|
return handler;
|
|
1794
1337
|
}
|
|
1795
|
-
async loadActor(actorId) {
|
|
1796
|
-
const handler = await this.#loadActorHandler(actorId);
|
|
1797
|
-
if (!handler.actor) throw new Error(`Actor ${actorId} failed to load`);
|
|
1798
|
-
return handler.actor;
|
|
1799
|
-
}
|
|
1800
|
-
#flushWsAcks() {
|
|
1801
|
-
if (this.#wsAckQueue.size === 0) return;
|
|
1802
|
-
for (const {
|
|
1803
|
-
requestIdBuf: requestId,
|
|
1804
|
-
messageIndex: index
|
|
1805
|
-
} of this.#wsAckQueue.values()) {
|
|
1806
|
-
this.#runner.sendWebsocketMessageAck(requestId, index);
|
|
1807
|
-
}
|
|
1808
|
-
this.#wsAckQueue.clear();
|
|
1809
|
-
}
|
|
1810
1338
|
getContext(actorId) {
|
|
1811
1339
|
return {};
|
|
1812
1340
|
}
|
|
1813
|
-
async readPersistedData(actorId) {
|
|
1814
|
-
const handler = this.#actors.get(actorId);
|
|
1815
|
-
if (!handler) throw new Error(`Actor ${actorId} not loaded`);
|
|
1816
|
-
return handler.persistedData;
|
|
1817
|
-
}
|
|
1818
|
-
async writePersistedData(actorId, data) {
|
|
1819
|
-
const handler = this.#actors.get(actorId);
|
|
1820
|
-
if (!handler) throw new Error(`Actor ${actorId} not loaded`);
|
|
1821
|
-
handler.persistedData = data;
|
|
1822
|
-
logger4().debug({
|
|
1823
|
-
msg: "writing persisted data for actor",
|
|
1824
|
-
actorId,
|
|
1825
|
-
dataSize: data.byteLength
|
|
1826
|
-
});
|
|
1827
|
-
await this.#runner.kvPut(actorId, [[KEYS.PERSIST_DATA, data]]);
|
|
1828
|
-
}
|
|
1829
1341
|
async setAlarm(actor2, timestamp) {
|
|
1830
1342
|
if (this.#alarmTimeout) {
|
|
1831
1343
|
this.#alarmTimeout.abort();
|
|
@@ -1833,7 +1345,7 @@ var EngineActorDriver = class {
|
|
|
1833
1345
|
}
|
|
1834
1346
|
const delay = Math.max(0, timestamp - Date.now());
|
|
1835
1347
|
this.#alarmTimeout = setLongTimeout(() => {
|
|
1836
|
-
actor2.
|
|
1348
|
+
actor2.onAlarm();
|
|
1837
1349
|
this.#alarmTimeout = void 0;
|
|
1838
1350
|
}, delay);
|
|
1839
1351
|
this.#runner.setAlarm(actor2.id, timestamp);
|
|
@@ -1841,10 +1353,114 @@ var EngineActorDriver = class {
|
|
|
1841
1353
|
async getDatabase(_actorId) {
|
|
1842
1354
|
return void 0;
|
|
1843
1355
|
}
|
|
1844
|
-
//
|
|
1356
|
+
// MARK: - Batch KV operations
|
|
1357
|
+
async kvBatchPut(actorId, entries) {
|
|
1358
|
+
await this.#runner.kvPut(actorId, entries);
|
|
1359
|
+
}
|
|
1360
|
+
async kvBatchGet(actorId, keys) {
|
|
1361
|
+
return await this.#runner.kvGet(actorId, keys);
|
|
1362
|
+
}
|
|
1363
|
+
async kvBatchDelete(actorId, keys) {
|
|
1364
|
+
await this.#runner.kvDelete(actorId, keys);
|
|
1365
|
+
}
|
|
1366
|
+
async kvList(actorId) {
|
|
1367
|
+
const entries = await this.#runner.kvListPrefix(
|
|
1368
|
+
actorId,
|
|
1369
|
+
new Uint8Array()
|
|
1370
|
+
);
|
|
1371
|
+
const keys = entries.map(([key]) => key);
|
|
1372
|
+
logger3().info({
|
|
1373
|
+
msg: "kvList called",
|
|
1374
|
+
actorId,
|
|
1375
|
+
keysCount: keys.length,
|
|
1376
|
+
keys: keys.map((k) => new TextDecoder().decode(k))
|
|
1377
|
+
});
|
|
1378
|
+
return keys;
|
|
1379
|
+
}
|
|
1380
|
+
async kvListPrefix(actorId, prefix) {
|
|
1381
|
+
const result = await this.#runner.kvListPrefix(actorId, prefix);
|
|
1382
|
+
logger3().info({
|
|
1383
|
+
msg: "kvListPrefix called",
|
|
1384
|
+
actorId,
|
|
1385
|
+
prefixStr: new TextDecoder().decode(prefix),
|
|
1386
|
+
entriesCount: result.length,
|
|
1387
|
+
keys: result.map(([key]) => new TextDecoder().decode(key))
|
|
1388
|
+
});
|
|
1389
|
+
return result;
|
|
1390
|
+
}
|
|
1391
|
+
// MARK: - Actor Lifecycle
|
|
1392
|
+
async loadActor(actorId) {
|
|
1393
|
+
const handler = await this.#loadActorHandler(actorId);
|
|
1394
|
+
if (!handler.actor) throw new Error(`Actor ${actorId} failed to load`);
|
|
1395
|
+
return handler.actor;
|
|
1396
|
+
}
|
|
1397
|
+
startSleep(actorId) {
|
|
1398
|
+
this.#actorStopIntent.set(actorId, "sleep");
|
|
1399
|
+
this.#runner.sleepActor(actorId);
|
|
1400
|
+
}
|
|
1401
|
+
startDestroy(actorId) {
|
|
1402
|
+
this.#actorStopIntent.set(actorId, "destroy");
|
|
1403
|
+
this.#runner.stopActor(actorId);
|
|
1404
|
+
}
|
|
1405
|
+
async shutdownRunner(immediate) {
|
|
1406
|
+
logger3().info({ msg: "stopping engine actor driver", immediate });
|
|
1407
|
+
logger3().debug({
|
|
1408
|
+
msg: "stopping all actors before shutdown",
|
|
1409
|
+
actorCount: this.#actors.size
|
|
1410
|
+
});
|
|
1411
|
+
const stopPromises = [];
|
|
1412
|
+
for (const [_actorId, handler] of this.#actors.entries()) {
|
|
1413
|
+
if (handler.actor) {
|
|
1414
|
+
stopPromises.push(
|
|
1415
|
+
handler.actor.onStop("sleep").catch((err) => {
|
|
1416
|
+
var _a;
|
|
1417
|
+
(_a = handler.actor) == null ? void 0 : _a.rLog.error({
|
|
1418
|
+
msg: "onStop errored",
|
|
1419
|
+
error: stringifyError(err)
|
|
1420
|
+
});
|
|
1421
|
+
})
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
await Promise.all(stopPromises);
|
|
1426
|
+
logger3().debug({ msg: "all actors stopped" });
|
|
1427
|
+
await this.#runner.shutdown(immediate);
|
|
1428
|
+
}
|
|
1429
|
+
async serverlessHandleStart(c) {
|
|
1430
|
+
return streamSSE(c, async (stream) => {
|
|
1431
|
+
stream.onAbort(() => {
|
|
1432
|
+
});
|
|
1433
|
+
c.req.raw.signal.addEventListener("abort", () => {
|
|
1434
|
+
logger3().debug("SSE aborted, shutting down runner");
|
|
1435
|
+
this.shutdownRunner(false);
|
|
1436
|
+
});
|
|
1437
|
+
await this.#runnerStarted.promise;
|
|
1438
|
+
const payload = this.#runner.getServerlessInitPacket();
|
|
1439
|
+
invariant3(payload, "runnerId not set");
|
|
1440
|
+
await stream.writeSSE({ data: payload });
|
|
1441
|
+
while (true) {
|
|
1442
|
+
if (this.#isRunnerStopped) {
|
|
1443
|
+
logger3().debug({
|
|
1444
|
+
msg: "runner is stopped"
|
|
1445
|
+
});
|
|
1446
|
+
break;
|
|
1447
|
+
}
|
|
1448
|
+
if (stream.closed || stream.aborted) {
|
|
1449
|
+
logger3().debug({
|
|
1450
|
+
msg: "runner sse stream closed",
|
|
1451
|
+
closed: stream.closed,
|
|
1452
|
+
aborted: stream.aborted
|
|
1453
|
+
});
|
|
1454
|
+
break;
|
|
1455
|
+
}
|
|
1456
|
+
await stream.writeSSE({ event: "ping", data: "" });
|
|
1457
|
+
await stream.sleep(RUNNER_SSE_PING_INTERVAL);
|
|
1458
|
+
}
|
|
1459
|
+
await this.#runnerStopped.promise;
|
|
1460
|
+
});
|
|
1461
|
+
}
|
|
1845
1462
|
async #runnerOnActorStart(actorId, generation, actorConfig) {
|
|
1846
|
-
|
|
1847
|
-
logger4().debug({
|
|
1463
|
+
logger3().debug({
|
|
1848
1464
|
msg: "runner actor starting",
|
|
1849
1465
|
actorId,
|
|
1850
1466
|
name: actorConfig.name,
|
|
@@ -1858,24 +1474,30 @@ var EngineActorDriver = class {
|
|
|
1858
1474
|
let handler = this.#actors.get(actorId);
|
|
1859
1475
|
if (!handler) {
|
|
1860
1476
|
handler = {
|
|
1861
|
-
actorStartPromise: promiseWithResolvers()
|
|
1862
|
-
persistedData: void 0
|
|
1477
|
+
actorStartPromise: promiseWithResolvers()
|
|
1863
1478
|
};
|
|
1864
1479
|
this.#actors.set(actorId, handler);
|
|
1865
|
-
const [persistedValue] = await this.#runner.kvGet(actorId, [
|
|
1866
|
-
KEYS.PERSIST_DATA
|
|
1867
|
-
]);
|
|
1868
|
-
handler.persistedData = persistedValue !== null ? persistedValue : serializeEmptyPersistData(input);
|
|
1869
|
-
logger4().debug({
|
|
1870
|
-
msg: "loaded persisted data for actor",
|
|
1871
|
-
actorId,
|
|
1872
|
-
dataSize: (_a = handler.persistedData) == null ? void 0 : _a.byteLength,
|
|
1873
|
-
wasInStorage: persistedValue !== null
|
|
1874
|
-
});
|
|
1875
1480
|
}
|
|
1876
1481
|
const name = actorConfig.name;
|
|
1877
1482
|
invariant3(actorConfig.key, "actor should have a key");
|
|
1878
1483
|
const key = deserializeActorKey(actorConfig.key);
|
|
1484
|
+
const [persistDataBuffer] = await this.#runner.kvGet(actorId, [
|
|
1485
|
+
KEYS.PERSIST_DATA
|
|
1486
|
+
]);
|
|
1487
|
+
if (persistDataBuffer === null) {
|
|
1488
|
+
const initialKvState = getInitialActorKvState(input);
|
|
1489
|
+
await this.#runner.kvPut(actorId, initialKvState);
|
|
1490
|
+
logger3().debug({
|
|
1491
|
+
msg: "initialized persist data for new actor",
|
|
1492
|
+
actorId
|
|
1493
|
+
});
|
|
1494
|
+
} else {
|
|
1495
|
+
logger3().debug({
|
|
1496
|
+
msg: "found existing persist data for actor",
|
|
1497
|
+
actorId,
|
|
1498
|
+
dataSize: persistDataBuffer.byteLength
|
|
1499
|
+
});
|
|
1500
|
+
}
|
|
1879
1501
|
const definition = lookupInRegistry(
|
|
1880
1502
|
this.#registryConfig,
|
|
1881
1503
|
actorConfig.name
|
|
@@ -1890,28 +1512,29 @@ var EngineActorDriver = class {
|
|
|
1890
1512
|
"unknown"
|
|
1891
1513
|
// TODO: Add regions
|
|
1892
1514
|
);
|
|
1893
|
-
(
|
|
1894
|
-
handler.actorStartPromise = void 0;
|
|
1895
|
-
logger4().debug({ msg: "runner actor started", actorId, name, key });
|
|
1515
|
+
logger3().debug({ msg: "runner actor started", actorId, name, key });
|
|
1896
1516
|
}
|
|
1897
1517
|
async #runnerOnActorStop(actorId, generation) {
|
|
1898
|
-
|
|
1518
|
+
logger3().debug({ msg: "runner actor stopping", actorId, generation });
|
|
1519
|
+
const reason = this.#actorStopIntent.get(actorId) ?? "sleep";
|
|
1520
|
+
this.#actorStopIntent.delete(actorId);
|
|
1899
1521
|
const handler = this.#actors.get(actorId);
|
|
1900
1522
|
if (handler == null ? void 0 : handler.actor) {
|
|
1901
1523
|
try {
|
|
1902
|
-
await handler.actor.
|
|
1524
|
+
await handler.actor.onStop(reason);
|
|
1903
1525
|
} catch (err) {
|
|
1904
|
-
|
|
1905
|
-
msg: "error in
|
|
1526
|
+
logger3().error({
|
|
1527
|
+
msg: "error in onStop, proceeding with removing actor",
|
|
1906
1528
|
err: stringifyError(err)
|
|
1907
1529
|
});
|
|
1908
1530
|
}
|
|
1909
1531
|
this.#actors.delete(actorId);
|
|
1910
1532
|
}
|
|
1911
|
-
|
|
1533
|
+
logger3().debug({ msg: "runner actor stopped", actorId, reason });
|
|
1912
1534
|
}
|
|
1913
|
-
|
|
1914
|
-
|
|
1535
|
+
// MARK: - Runner Networking
|
|
1536
|
+
async #runnerFetch(_runner, actorId, _gatewayIdBuf, _requestIdBuf, request) {
|
|
1537
|
+
logger3().debug({
|
|
1915
1538
|
msg: "runner fetch",
|
|
1916
1539
|
actorId,
|
|
1917
1540
|
url: request.url,
|
|
@@ -1919,183 +1542,302 @@ var EngineActorDriver = class {
|
|
|
1919
1542
|
});
|
|
1920
1543
|
return await this.#actorRouter.fetch(request, { actorId });
|
|
1921
1544
|
}
|
|
1922
|
-
async #runnerWebSocket(_runner, actorId, websocketRaw, requestIdBuf, request) {
|
|
1545
|
+
async #runnerWebSocket(_runner, actorId, websocketRaw, gatewayIdBuf, requestIdBuf, request, requestPath, requestHeaders, isHibernatable, isRestoringHibernatable) {
|
|
1546
|
+
var _a, _b, _c, _d;
|
|
1923
1547
|
const websocket = websocketRaw;
|
|
1924
|
-
const
|
|
1925
|
-
|
|
1926
|
-
|
|
1548
|
+
const wsUniqueId = `ws_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
1549
|
+
websocket.__rivet_ws_id = wsUniqueId;
|
|
1550
|
+
logger3().debug({
|
|
1551
|
+
msg: "runner websocket",
|
|
1552
|
+
actorId,
|
|
1553
|
+
url: request.url,
|
|
1554
|
+
isRestoringHibernatable,
|
|
1555
|
+
websocketObjectId: websocketRaw ? Object.prototype.toString.call(websocketRaw) : "null",
|
|
1556
|
+
websocketType: (_a = websocketRaw == null ? void 0 : websocketRaw.constructor) == null ? void 0 : _a.name,
|
|
1557
|
+
wsUniqueId,
|
|
1558
|
+
websocketProps: websocketRaw ? Object.keys(websocketRaw).join(", ") : "null"
|
|
1559
|
+
});
|
|
1927
1560
|
const protocols = request.headers.get("sec-websocket-protocol");
|
|
1928
|
-
|
|
1929
|
-
let
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
for (const protocol of protocolList) {
|
|
1933
|
-
if (protocol.startsWith(WS_PROTOCOL_ENCODING)) {
|
|
1934
|
-
encodingRaw = protocol.substring(
|
|
1935
|
-
WS_PROTOCOL_ENCODING.length
|
|
1936
|
-
);
|
|
1937
|
-
} else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {
|
|
1938
|
-
connParamsRaw = decodeURIComponent(
|
|
1939
|
-
protocol.substring(WS_PROTOCOL_CONN_PARAMS.length)
|
|
1940
|
-
);
|
|
1941
|
-
}
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
|
-
const encoding = EncodingSchema.parse(encodingRaw);
|
|
1945
|
-
const connParams = connParamsRaw ? JSON.parse(connParamsRaw) : void 0;
|
|
1946
|
-
let wsHandlerPromise;
|
|
1947
|
-
if (url.pathname === PATH_CONNECT_WEBSOCKET) {
|
|
1948
|
-
wsHandlerPromise = handleWebSocketConnect(
|
|
1561
|
+
const { encoding, connParams } = parseWebSocketProtocols(protocols);
|
|
1562
|
+
let wsHandler;
|
|
1563
|
+
try {
|
|
1564
|
+
wsHandler = await routeWebSocket(
|
|
1949
1565
|
request,
|
|
1566
|
+
requestPath,
|
|
1567
|
+
requestHeaders,
|
|
1950
1568
|
this.#runConfig,
|
|
1951
1569
|
this,
|
|
1952
1570
|
actorId,
|
|
1953
1571
|
encoding,
|
|
1954
1572
|
connParams,
|
|
1955
|
-
|
|
1573
|
+
gatewayIdBuf,
|
|
1956
1574
|
requestIdBuf,
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
void 0
|
|
1575
|
+
isHibernatable,
|
|
1576
|
+
isRestoringHibernatable
|
|
1960
1577
|
);
|
|
1961
|
-
}
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
this,
|
|
1966
|
-
actorId,
|
|
1967
|
-
requestIdBuf
|
|
1968
|
-
);
|
|
1969
|
-
} else {
|
|
1970
|
-
throw new Error(`Unreachable path: ${url.pathname}`);
|
|
1578
|
+
} catch (err) {
|
|
1579
|
+
logger3().error({ msg: "building websocket handlers errored", err });
|
|
1580
|
+
websocketRaw.close(1011, "ws.route_error");
|
|
1581
|
+
return;
|
|
1971
1582
|
}
|
|
1583
|
+
websocket.raw = websocket;
|
|
1972
1584
|
const wsContext = new WSContext2(websocket);
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1585
|
+
const conn = wsHandler.conn;
|
|
1586
|
+
const actor2 = wsHandler.actor;
|
|
1587
|
+
const connStateManager = conn == null ? void 0 : conn[CONN_STATE_MANAGER_SYMBOL];
|
|
1588
|
+
logger3().debug({
|
|
1589
|
+
msg: "attaching websocket event listeners",
|
|
1590
|
+
actorId,
|
|
1591
|
+
connId: conn == null ? void 0 : conn.id,
|
|
1592
|
+
wsUniqueId: websocket.__rivet_ws_id,
|
|
1593
|
+
isRestoringHibernatable,
|
|
1594
|
+
websocketType: (_b = websocket == null ? void 0 : websocket.constructor) == null ? void 0 : _b.name
|
|
1976
1595
|
});
|
|
1977
|
-
if (
|
|
1978
|
-
|
|
1979
|
-
(x) => {
|
|
1980
|
-
var _a;
|
|
1981
|
-
return (_a = x.onOpen) == null ? void 0 : _a.call(x, new Event("open"), wsContext);
|
|
1982
|
-
}
|
|
1983
|
-
);
|
|
1984
|
-
} else {
|
|
1985
|
-
websocket.addEventListener("open", (event) => {
|
|
1986
|
-
wsHandlerPromise.then((x) => {
|
|
1987
|
-
var _a;
|
|
1988
|
-
return (_a = x.onOpen) == null ? void 0 : _a.call(x, event, wsContext);
|
|
1989
|
-
});
|
|
1990
|
-
});
|
|
1596
|
+
if (isRestoringHibernatable) {
|
|
1597
|
+
(_c = wsHandler.onRestore) == null ? void 0 : _c.call(wsHandler, wsContext);
|
|
1991
1598
|
}
|
|
1599
|
+
websocket.addEventListener("open", (event) => {
|
|
1600
|
+
wsHandler.onOpen(event, wsContext);
|
|
1601
|
+
});
|
|
1992
1602
|
websocket.addEventListener("message", (event) => {
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1603
|
+
var _a2, _b2;
|
|
1604
|
+
logger3().debug({
|
|
1605
|
+
msg: "websocket message event listener triggered",
|
|
1606
|
+
connId: conn == null ? void 0 : conn.id,
|
|
1607
|
+
actorId: actor2 == null ? void 0 : actor2.id,
|
|
1608
|
+
messageIndex: event.rivetMessageIndex,
|
|
1609
|
+
hasWsHandler: !!wsHandler,
|
|
1610
|
+
hasOnMessage: !!(wsHandler == null ? void 0 : wsHandler.onMessage),
|
|
1611
|
+
actorIsStopping: actor2 == null ? void 0 : actor2.isStopping,
|
|
1612
|
+
websocketType: (_a2 = websocket == null ? void 0 : websocket.constructor) == null ? void 0 : _a2.name,
|
|
1613
|
+
wsUniqueId: websocket.__rivet_ws_id,
|
|
1614
|
+
eventTargetWsId: (_b2 = event.target) == null ? void 0 : _b2.__rivet_ws_id
|
|
1996
1615
|
});
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
1616
|
+
if (actor2 == null ? void 0 : actor2.isStopping) {
|
|
1617
|
+
logger3().debug({
|
|
1618
|
+
msg: "ignoring ws message, actor is stopping",
|
|
1619
|
+
connId: conn == null ? void 0 : conn.id,
|
|
1620
|
+
actorId: actor2 == null ? void 0 : actor2.id,
|
|
1621
|
+
messageIndex: event.rivetMessageIndex
|
|
1622
|
+
});
|
|
1623
|
+
return;
|
|
1624
|
+
}
|
|
1625
|
+
logger3().debug({
|
|
1626
|
+
msg: "calling wsHandler.onMessage",
|
|
1627
|
+
connId: conn == null ? void 0 : conn.id,
|
|
1628
|
+
messageIndex: event.rivetMessageIndex
|
|
1629
|
+
});
|
|
1630
|
+
wsHandler.onMessage(event, wsContext);
|
|
1631
|
+
const hibernate = connStateManager == null ? void 0 : connStateManager.hibernatableData;
|
|
1632
|
+
if (hibernate && conn && actor2) {
|
|
1633
|
+
invariant3(
|
|
1634
|
+
typeof event.rivetMessageIndex === "number",
|
|
1635
|
+
"missing event.rivetMessageIndex"
|
|
1636
|
+
);
|
|
1637
|
+
const previousMsgIndex = hibernate.serverMessageIndex;
|
|
1638
|
+
hibernate.serverMessageIndex = event.rivetMessageIndex;
|
|
1639
|
+
logger3().info({
|
|
1640
|
+
msg: "persisting message index",
|
|
1641
|
+
connId: conn.id,
|
|
1642
|
+
previousMsgIndex,
|
|
1643
|
+
newMsgIndex: event.rivetMessageIndex
|
|
1644
|
+
});
|
|
1645
|
+
const entry = this.#hwsMessageIndex.get(conn.id);
|
|
1646
|
+
if (entry) {
|
|
1647
|
+
const messageLength = getValueLength(event.data);
|
|
1648
|
+
entry.bufferedMessageSize += messageLength;
|
|
1649
|
+
if (entry.bufferedMessageSize >= CONN_BUFFERED_MESSAGE_SIZE_THRESHOLD) {
|
|
1650
|
+
entry.bufferedMessageSize = 0;
|
|
1651
|
+
entry.pendingAckFromBufferSize = true;
|
|
1652
|
+
actor2.stateManager.saveState({
|
|
1653
|
+
immediate: true
|
|
1654
|
+
});
|
|
1655
|
+
} else {
|
|
1656
|
+
actor2.stateManager.saveState({
|
|
1657
|
+
maxWait: CONN_MESSAGE_ACK_DEADLINE
|
|
1658
|
+
});
|
|
1659
|
+
}
|
|
2003
1660
|
} else {
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
requestId,
|
|
2007
|
-
queuedMessageIndex: currentEntry,
|
|
2008
|
-
eventMessageIndex: event.rivetMessageIndex
|
|
1661
|
+
actor2.stateManager.saveState({
|
|
1662
|
+
maxWait: CONN_MESSAGE_ACK_DEADLINE
|
|
2009
1663
|
});
|
|
2010
1664
|
}
|
|
2011
|
-
} else {
|
|
2012
|
-
this.#wsAckQueue.set(requestId, {
|
|
2013
|
-
requestIdBuf,
|
|
2014
|
-
messageIndex: event.rivetMessageIndex
|
|
2015
|
-
});
|
|
2016
1665
|
}
|
|
2017
1666
|
});
|
|
2018
1667
|
websocket.addEventListener("close", (event) => {
|
|
2019
|
-
|
|
2020
|
-
wsHandlerPromise.then((x) => {
|
|
2021
|
-
var _a;
|
|
2022
|
-
return (_a = x.onClose) == null ? void 0 : _a.call(x, event, wsContext);
|
|
2023
|
-
});
|
|
1668
|
+
wsHandler.onClose(event, wsContext);
|
|
2024
1669
|
});
|
|
2025
1670
|
websocket.addEventListener("error", (event) => {
|
|
2026
|
-
|
|
2027
|
-
var _a;
|
|
2028
|
-
return (_a = x.onError) == null ? void 0 : _a.call(x, event, wsContext);
|
|
2029
|
-
});
|
|
2030
|
-
});
|
|
2031
|
-
}
|
|
2032
|
-
startSleep(actorId) {
|
|
2033
|
-
this.#runner.sleepActor(actorId);
|
|
2034
|
-
}
|
|
2035
|
-
async shutdownRunner(immediate) {
|
|
2036
|
-
logger4().info({ msg: "stopping engine actor driver", immediate });
|
|
2037
|
-
logger4().debug({
|
|
2038
|
-
msg: "stopping all actors before shutdown",
|
|
2039
|
-
actorCount: this.#actors.size
|
|
1671
|
+
wsHandler.onError(event, wsContext);
|
|
2040
1672
|
});
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
})
|
|
2052
|
-
);
|
|
2053
|
-
}
|
|
2054
|
-
}
|
|
2055
|
-
await Promise.all(stopPromises);
|
|
2056
|
-
logger4().debug({ msg: "all actors stopped" });
|
|
2057
|
-
if (this.#wsAckFlushInterval) {
|
|
2058
|
-
clearInterval(this.#wsAckFlushInterval);
|
|
2059
|
-
this.#wsAckFlushInterval = void 0;
|
|
1673
|
+
if (isRestoringHibernatable) {
|
|
1674
|
+
logger3().info({
|
|
1675
|
+
msg: "event listeners attached to restored websocket",
|
|
1676
|
+
actorId,
|
|
1677
|
+
connId: conn == null ? void 0 : conn.id,
|
|
1678
|
+
gatewayId: idToStr(gatewayIdBuf),
|
|
1679
|
+
requestId: idToStr(requestIdBuf),
|
|
1680
|
+
websocketType: (_d = websocket == null ? void 0 : websocket.constructor) == null ? void 0 : _d.name,
|
|
1681
|
+
hasMessageListener: !!websocket.addEventListener
|
|
1682
|
+
});
|
|
2060
1683
|
}
|
|
2061
|
-
this.#flushWsAcks();
|
|
2062
|
-
await this.#runner.shutdown(immediate);
|
|
2063
1684
|
}
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
1685
|
+
// MARK: - Hibernating WebSockets
|
|
1686
|
+
#hwsCanHibernate(actorId, gatewayId, requestId, request) {
|
|
1687
|
+
var _a;
|
|
1688
|
+
const url = new URL(request.url);
|
|
1689
|
+
const path = url.pathname;
|
|
1690
|
+
const actorInstance = this.#runner.getActor(actorId);
|
|
1691
|
+
if (!actorInstance) {
|
|
1692
|
+
logger3().warn({
|
|
1693
|
+
msg: "actor not found in #hwsCanHibernate",
|
|
1694
|
+
actorId
|
|
2067
1695
|
});
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
1696
|
+
return false;
|
|
1697
|
+
}
|
|
1698
|
+
const handler = this.#actors.get(actorId);
|
|
1699
|
+
if (!handler) {
|
|
1700
|
+
logger3().warn({
|
|
1701
|
+
msg: "actor handler not found in #hwsCanHibernate",
|
|
1702
|
+
actorId
|
|
2071
1703
|
});
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
1704
|
+
return false;
|
|
1705
|
+
}
|
|
1706
|
+
if (!handler.actor) {
|
|
1707
|
+
logger3().warn({
|
|
1708
|
+
msg: "actor not found in #hwsCanHibernate",
|
|
1709
|
+
actorId
|
|
1710
|
+
});
|
|
1711
|
+
return false;
|
|
1712
|
+
}
|
|
1713
|
+
logger3().debug({
|
|
1714
|
+
msg: "no existing hibernatable websocket found",
|
|
1715
|
+
gatewayId: idToStr(gatewayId),
|
|
1716
|
+
requestId: idToStr(requestId)
|
|
1717
|
+
});
|
|
1718
|
+
if (path === PATH_CONNECT) {
|
|
1719
|
+
return true;
|
|
1720
|
+
} else if (path === PATH_WEBSOCKET_BASE || path.startsWith(PATH_WEBSOCKET_PREFIX)) {
|
|
1721
|
+
const definition = lookupInRegistry(
|
|
1722
|
+
this.#registryConfig,
|
|
1723
|
+
actorInstance.config.name
|
|
1724
|
+
);
|
|
1725
|
+
const canHibernateWebSocket = (_a = definition.config.options) == null ? void 0 : _a.canHibernateWebSocket;
|
|
1726
|
+
if (canHibernateWebSocket === true) {
|
|
1727
|
+
return true;
|
|
1728
|
+
} else if (typeof canHibernateWebSocket === "function") {
|
|
1729
|
+
try {
|
|
1730
|
+
const newPath = truncateRawWebSocketPathPrefix(
|
|
1731
|
+
url.pathname
|
|
1732
|
+
);
|
|
1733
|
+
const truncatedRequest = new Request(
|
|
1734
|
+
`http://actor${newPath}`,
|
|
1735
|
+
request
|
|
1736
|
+
);
|
|
1737
|
+
const canHibernate = canHibernateWebSocket(truncatedRequest);
|
|
1738
|
+
return canHibernate;
|
|
1739
|
+
} catch (error) {
|
|
1740
|
+
logger3().error({
|
|
1741
|
+
msg: "error calling canHibernateWebSocket",
|
|
1742
|
+
error
|
|
2088
1743
|
});
|
|
2089
|
-
|
|
1744
|
+
return false;
|
|
2090
1745
|
}
|
|
2091
|
-
|
|
2092
|
-
|
|
1746
|
+
} else {
|
|
1747
|
+
return false;
|
|
2093
1748
|
}
|
|
2094
|
-
|
|
1749
|
+
} else if (path === PATH_INSPECTOR_CONNECT) {
|
|
1750
|
+
return false;
|
|
1751
|
+
} else {
|
|
1752
|
+
logger3().warn({
|
|
1753
|
+
msg: "unexpected path for getActorHibernationConfig",
|
|
1754
|
+
path
|
|
1755
|
+
});
|
|
1756
|
+
return false;
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
async #hwsLoadAll(actorId) {
|
|
1760
|
+
const actor2 = await this.loadActor(actorId);
|
|
1761
|
+
return actor2.conns.values().map((conn) => {
|
|
1762
|
+
const connStateManager = conn[CONN_STATE_MANAGER_SYMBOL];
|
|
1763
|
+
const hibernatable = connStateManager.hibernatableData;
|
|
1764
|
+
if (!hibernatable) return void 0;
|
|
1765
|
+
return {
|
|
1766
|
+
gatewayId: hibernatable.gatewayId,
|
|
1767
|
+
requestId: hibernatable.requestId,
|
|
1768
|
+
serverMessageIndex: hibernatable.serverMessageIndex,
|
|
1769
|
+
clientMessageIndex: hibernatable.clientMessageIndex,
|
|
1770
|
+
path: hibernatable.requestPath,
|
|
1771
|
+
headers: hibernatable.requestHeaders
|
|
1772
|
+
};
|
|
1773
|
+
}).filter((x) => x !== void 0).toArray();
|
|
1774
|
+
}
|
|
1775
|
+
async onBeforeActorStart(actor2) {
|
|
1776
|
+
var _a;
|
|
1777
|
+
const handler = this.#actors.get(actor2.id);
|
|
1778
|
+
invariant3(handler, "missing actor handler in onBeforeActorReady");
|
|
1779
|
+
(_a = handler.actorStartPromise) == null ? void 0 : _a.resolve();
|
|
1780
|
+
handler.actorStartPromise = void 0;
|
|
1781
|
+
const metaEntries = await this.#hwsLoadAll(actor2.id);
|
|
1782
|
+
await this.#runner.restoreHibernatingRequests(actor2.id, metaEntries);
|
|
1783
|
+
}
|
|
1784
|
+
onCreateConn(conn) {
|
|
1785
|
+
const hibernatable = conn[CONN_STATE_MANAGER_SYMBOL].hibernatableData;
|
|
1786
|
+
if (!hibernatable) return;
|
|
1787
|
+
this.#hwsMessageIndex.set(conn.id, {
|
|
1788
|
+
serverMessageIndex: hibernatable.serverMessageIndex,
|
|
1789
|
+
bufferedMessageSize: 0,
|
|
1790
|
+
pendingAckFromMessageIndex: false,
|
|
1791
|
+
pendingAckFromBufferSize: false
|
|
1792
|
+
});
|
|
1793
|
+
logger3().debug({
|
|
1794
|
+
msg: "created #hwsMessageIndex entry",
|
|
1795
|
+
connId: conn.id,
|
|
1796
|
+
serverMessageIndex: hibernatable.serverMessageIndex
|
|
2095
1797
|
});
|
|
2096
1798
|
}
|
|
2097
|
-
|
|
2098
|
-
|
|
1799
|
+
onDestroyConn(conn) {
|
|
1800
|
+
this.#hwsMessageIndex.delete(conn.id);
|
|
1801
|
+
logger3().debug({
|
|
1802
|
+
msg: "removed #hwsMessageIndex entry",
|
|
1803
|
+
connId: conn.id
|
|
1804
|
+
});
|
|
1805
|
+
}
|
|
1806
|
+
onBeforePersistConn(conn) {
|
|
1807
|
+
const stateManager = conn[CONN_STATE_MANAGER_SYMBOL];
|
|
1808
|
+
const hibernatable = stateManager.hibernatableDataOrError();
|
|
1809
|
+
const entry = this.#hwsMessageIndex.get(conn.id);
|
|
1810
|
+
if (!entry) {
|
|
1811
|
+
logger3().warn({
|
|
1812
|
+
msg: "missing EngineActorDriver.#hwsMessageIndex entry for conn",
|
|
1813
|
+
connId: conn.id
|
|
1814
|
+
});
|
|
1815
|
+
return;
|
|
1816
|
+
}
|
|
1817
|
+
entry.pendingAckFromMessageIndex = hibernatable.serverMessageIndex > entry.serverMessageIndex;
|
|
1818
|
+
entry.serverMessageIndex = hibernatable.serverMessageIndex;
|
|
1819
|
+
}
|
|
1820
|
+
onAfterPersistConn(conn) {
|
|
1821
|
+
const stateManager = conn[CONN_STATE_MANAGER_SYMBOL];
|
|
1822
|
+
const hibernatable = stateManager.hibernatableDataOrError();
|
|
1823
|
+
const entry = this.#hwsMessageIndex.get(conn.id);
|
|
1824
|
+
if (!entry) {
|
|
1825
|
+
logger3().warn({
|
|
1826
|
+
msg: "missing EngineActorDriver.#hwsMessageIndex entry for conn",
|
|
1827
|
+
connId: conn.id
|
|
1828
|
+
});
|
|
1829
|
+
return;
|
|
1830
|
+
}
|
|
1831
|
+
if (entry.pendingAckFromMessageIndex || entry.pendingAckFromBufferSize) {
|
|
1832
|
+
this.#runner.sendHibernatableWebSocketMessageAck(
|
|
1833
|
+
hibernatable.gatewayId,
|
|
1834
|
+
hibernatable.requestId,
|
|
1835
|
+
entry.serverMessageIndex
|
|
1836
|
+
);
|
|
1837
|
+
entry.pendingAckFromMessageIndex = false;
|
|
1838
|
+
entry.pendingAckFromBufferSize = false;
|
|
1839
|
+
entry.bufferedMessageSize = 0;
|
|
1840
|
+
}
|
|
2099
1841
|
}
|
|
2100
1842
|
};
|
|
2101
1843
|
|
|
@@ -2117,6 +1859,117 @@ function createEngineDriver() {
|
|
|
2117
1859
|
};
|
|
2118
1860
|
}
|
|
2119
1861
|
|
|
1862
|
+
// src/utils/node.ts
|
|
1863
|
+
import { createRequire } from "module";
|
|
1864
|
+
var nodeCrypto;
|
|
1865
|
+
var nodeFsSync;
|
|
1866
|
+
var nodeFs;
|
|
1867
|
+
var nodePath;
|
|
1868
|
+
var nodeOs;
|
|
1869
|
+
var nodeChildProcess;
|
|
1870
|
+
var nodeStream;
|
|
1871
|
+
var hasImportedDependencies = false;
|
|
1872
|
+
function getRequireFn() {
|
|
1873
|
+
return createRequire(import.meta.url);
|
|
1874
|
+
}
|
|
1875
|
+
function importNodeDependencies() {
|
|
1876
|
+
if (hasImportedDependencies) return;
|
|
1877
|
+
try {
|
|
1878
|
+
const requireFn = getRequireFn();
|
|
1879
|
+
nodeCrypto = requireFn(
|
|
1880
|
+
/* webpackIgnore: true */
|
|
1881
|
+
"node:crypto"
|
|
1882
|
+
);
|
|
1883
|
+
nodeFsSync = requireFn(
|
|
1884
|
+
/* webpackIgnore: true */
|
|
1885
|
+
"node:fs"
|
|
1886
|
+
);
|
|
1887
|
+
nodeFs = requireFn(
|
|
1888
|
+
/* webpackIgnore: true */
|
|
1889
|
+
"node:fs/promises"
|
|
1890
|
+
);
|
|
1891
|
+
nodePath = requireFn(
|
|
1892
|
+
/* webpackIgnore: true */
|
|
1893
|
+
"node:path"
|
|
1894
|
+
);
|
|
1895
|
+
nodeOs = requireFn(
|
|
1896
|
+
/* webpackIgnore: true */
|
|
1897
|
+
"node:os"
|
|
1898
|
+
);
|
|
1899
|
+
nodeChildProcess = requireFn(
|
|
1900
|
+
/* webpackIgnore: true */
|
|
1901
|
+
"node:child_process"
|
|
1902
|
+
);
|
|
1903
|
+
nodeStream = requireFn(
|
|
1904
|
+
/* webpackIgnore: true */
|
|
1905
|
+
"node:stream/promises"
|
|
1906
|
+
);
|
|
1907
|
+
hasImportedDependencies = true;
|
|
1908
|
+
} catch (err) {
|
|
1909
|
+
console.warn(
|
|
1910
|
+
"Node.js modules not available, file system driver will not work",
|
|
1911
|
+
err
|
|
1912
|
+
);
|
|
1913
|
+
throw err;
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
function getNodeCrypto() {
|
|
1917
|
+
if (!nodeCrypto) {
|
|
1918
|
+
throw new Error(
|
|
1919
|
+
"Node crypto module not loaded. Ensure importNodeDependencies() has been called."
|
|
1920
|
+
);
|
|
1921
|
+
}
|
|
1922
|
+
return nodeCrypto;
|
|
1923
|
+
}
|
|
1924
|
+
function getNodeFsSync() {
|
|
1925
|
+
if (!nodeFsSync) {
|
|
1926
|
+
throw new Error(
|
|
1927
|
+
"Node fs module not loaded. Ensure importNodeDependencies() has been called."
|
|
1928
|
+
);
|
|
1929
|
+
}
|
|
1930
|
+
return nodeFsSync;
|
|
1931
|
+
}
|
|
1932
|
+
function getNodeFs() {
|
|
1933
|
+
if (!nodeFs) {
|
|
1934
|
+
throw new Error(
|
|
1935
|
+
"Node fs/promises module not loaded. Ensure importNodeDependencies() has been called."
|
|
1936
|
+
);
|
|
1937
|
+
}
|
|
1938
|
+
return nodeFs;
|
|
1939
|
+
}
|
|
1940
|
+
function getNodePath() {
|
|
1941
|
+
if (!nodePath) {
|
|
1942
|
+
throw new Error(
|
|
1943
|
+
"Node path module not loaded. Ensure importNodeDependencies() has been called."
|
|
1944
|
+
);
|
|
1945
|
+
}
|
|
1946
|
+
return nodePath;
|
|
1947
|
+
}
|
|
1948
|
+
function getNodeOs() {
|
|
1949
|
+
if (!nodeOs) {
|
|
1950
|
+
throw new Error(
|
|
1951
|
+
"Node os module not loaded. Ensure importNodeDependencies() has been called."
|
|
1952
|
+
);
|
|
1953
|
+
}
|
|
1954
|
+
return nodeOs;
|
|
1955
|
+
}
|
|
1956
|
+
function getNodeChildProcess() {
|
|
1957
|
+
if (!nodeChildProcess) {
|
|
1958
|
+
throw new Error(
|
|
1959
|
+
"Node child_process module not loaded. Ensure importNodeDependencies() has been called."
|
|
1960
|
+
);
|
|
1961
|
+
}
|
|
1962
|
+
return nodeChildProcess;
|
|
1963
|
+
}
|
|
1964
|
+
function getNodeStream() {
|
|
1965
|
+
if (!nodeStream) {
|
|
1966
|
+
throw new Error(
|
|
1967
|
+
"Node stream/promises module not loaded. Ensure importNodeDependencies() has been called."
|
|
1968
|
+
);
|
|
1969
|
+
}
|
|
1970
|
+
return nodeStream;
|
|
1971
|
+
}
|
|
1972
|
+
|
|
2120
1973
|
// src/drivers/file-system/actor.ts
|
|
2121
1974
|
var FileSystemActorDriver = class {
|
|
2122
1975
|
#registryConfig;
|
|
@@ -2149,17 +2002,17 @@ var FileSystemActorDriver = class {
|
|
|
2149
2002
|
getContext(_actorId) {
|
|
2150
2003
|
return {};
|
|
2151
2004
|
}
|
|
2152
|
-
async
|
|
2153
|
-
|
|
2154
|
-
(await this.#state.loadActorStateOrError(actorId)).persistedData
|
|
2155
|
-
);
|
|
2005
|
+
async kvBatchPut(actorId, entries) {
|
|
2006
|
+
await this.#state.kvBatchPut(actorId, entries);
|
|
2156
2007
|
}
|
|
2157
|
-
async
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2008
|
+
async kvBatchGet(actorId, keys) {
|
|
2009
|
+
return await this.#state.kvBatchGet(actorId, keys);
|
|
2010
|
+
}
|
|
2011
|
+
async kvBatchDelete(actorId, keys) {
|
|
2012
|
+
await this.#state.kvBatchDelete(actorId, keys);
|
|
2013
|
+
}
|
|
2014
|
+
async kvListPrefix(actorId, prefix) {
|
|
2015
|
+
return await this.#state.kvListPrefix(actorId, prefix);
|
|
2163
2016
|
}
|
|
2164
2017
|
async setAlarm(actor2, timestamp) {
|
|
2165
2018
|
await this.#state.setActorAlarm(actor2.id, timestamp);
|
|
@@ -2170,18 +2023,27 @@ var FileSystemActorDriver = class {
|
|
|
2170
2023
|
startSleep(actorId) {
|
|
2171
2024
|
this.#state.sleepActor(actorId);
|
|
2172
2025
|
}
|
|
2026
|
+
async startDestroy(actorId) {
|
|
2027
|
+
await this.#state.destroyActor(actorId);
|
|
2028
|
+
}
|
|
2173
2029
|
};
|
|
2174
2030
|
|
|
2175
2031
|
// src/drivers/file-system/global-state.ts
|
|
2176
|
-
import * as crypto3 from "crypto";
|
|
2177
|
-
import * as fsSync2 from "fs";
|
|
2178
|
-
import * as fs2 from "fs/promises";
|
|
2179
|
-
import * as path2 from "path";
|
|
2180
2032
|
import invariant4 from "invariant";
|
|
2181
2033
|
|
|
2182
|
-
// dist/schemas/file-system-driver/
|
|
2034
|
+
// dist/schemas/file-system-driver/v2.ts
|
|
2183
2035
|
import * as bare from "@bare-ts/lib";
|
|
2184
2036
|
var config = /* @__PURE__ */ bare.Config({});
|
|
2037
|
+
function readActorKvEntry(bc) {
|
|
2038
|
+
return {
|
|
2039
|
+
key: bare.readData(bc),
|
|
2040
|
+
value: bare.readData(bc)
|
|
2041
|
+
};
|
|
2042
|
+
}
|
|
2043
|
+
function writeActorKvEntry(bc, x) {
|
|
2044
|
+
bare.writeData(bc, x.key);
|
|
2045
|
+
bare.writeData(bc, x.value);
|
|
2046
|
+
}
|
|
2185
2047
|
function read0(bc) {
|
|
2186
2048
|
const len = bare.readUintSafe(bc);
|
|
2187
2049
|
if (len === 0) {
|
|
@@ -2199,12 +2061,29 @@ function write0(bc, x) {
|
|
|
2199
2061
|
bare.writeString(bc, x[i]);
|
|
2200
2062
|
}
|
|
2201
2063
|
}
|
|
2064
|
+
function read1(bc) {
|
|
2065
|
+
const len = bare.readUintSafe(bc);
|
|
2066
|
+
if (len === 0) {
|
|
2067
|
+
return [];
|
|
2068
|
+
}
|
|
2069
|
+
const result = [readActorKvEntry(bc)];
|
|
2070
|
+
for (let i = 1; i < len; i++) {
|
|
2071
|
+
result[i] = readActorKvEntry(bc);
|
|
2072
|
+
}
|
|
2073
|
+
return result;
|
|
2074
|
+
}
|
|
2075
|
+
function write1(bc, x) {
|
|
2076
|
+
bare.writeUintSafe(bc, x.length);
|
|
2077
|
+
for (let i = 0; i < x.length; i++) {
|
|
2078
|
+
writeActorKvEntry(bc, x[i]);
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2202
2081
|
function readActorState(bc) {
|
|
2203
2082
|
return {
|
|
2204
2083
|
actorId: bare.readString(bc),
|
|
2205
2084
|
name: bare.readString(bc),
|
|
2206
2085
|
key: read0(bc),
|
|
2207
|
-
|
|
2086
|
+
kvStorage: read1(bc),
|
|
2208
2087
|
createdAt: bare.readU64(bc)
|
|
2209
2088
|
};
|
|
2210
2089
|
}
|
|
@@ -2212,7 +2091,7 @@ function writeActorState(bc, x) {
|
|
|
2212
2091
|
bare.writeString(bc, x.actorId);
|
|
2213
2092
|
bare.writeString(bc, x.name);
|
|
2214
2093
|
write0(bc, x.key);
|
|
2215
|
-
|
|
2094
|
+
write1(bc, x.kvStorage);
|
|
2216
2095
|
bare.writeU64(bc, x.createdAt);
|
|
2217
2096
|
}
|
|
2218
2097
|
function encodeActorState(x) {
|
|
@@ -2259,8 +2138,29 @@ function decodeActorAlarm(bytes) {
|
|
|
2259
2138
|
}
|
|
2260
2139
|
|
|
2261
2140
|
// src/schemas/file-system-driver/versioned.ts
|
|
2262
|
-
var CURRENT_VERSION =
|
|
2263
|
-
var migrations = /* @__PURE__ */ new Map(
|
|
2141
|
+
var CURRENT_VERSION = 2;
|
|
2142
|
+
var migrations = /* @__PURE__ */ new Map([
|
|
2143
|
+
[
|
|
2144
|
+
2,
|
|
2145
|
+
(v1State) => {
|
|
2146
|
+
const kvStorage = [];
|
|
2147
|
+
if (v1State.persistedData) {
|
|
2148
|
+
const key = new Uint8Array([1]);
|
|
2149
|
+
kvStorage.push({
|
|
2150
|
+
key: bufferToArrayBuffer(key),
|
|
2151
|
+
value: v1State.persistedData
|
|
2152
|
+
});
|
|
2153
|
+
}
|
|
2154
|
+
return {
|
|
2155
|
+
actorId: v1State.actorId,
|
|
2156
|
+
name: v1State.name,
|
|
2157
|
+
key: v1State.key,
|
|
2158
|
+
kvStorage,
|
|
2159
|
+
createdAt: v1State.createdAt
|
|
2160
|
+
};
|
|
2161
|
+
}
|
|
2162
|
+
]
|
|
2163
|
+
]);
|
|
2264
2164
|
var ACTOR_STATE_VERSIONED = createVersionedDataHandler({
|
|
2265
2165
|
currentVersion: CURRENT_VERSION,
|
|
2266
2166
|
migrations,
|
|
@@ -2275,36 +2175,35 @@ var ACTOR_ALARM_VERSIONED = createVersionedDataHandler({
|
|
|
2275
2175
|
});
|
|
2276
2176
|
|
|
2277
2177
|
// src/drivers/file-system/log.ts
|
|
2278
|
-
function
|
|
2178
|
+
function logger4() {
|
|
2279
2179
|
return getLogger("driver-fs");
|
|
2280
2180
|
}
|
|
2281
2181
|
|
|
2282
2182
|
// src/drivers/file-system/utils.ts
|
|
2283
|
-
import * as crypto2 from "crypto";
|
|
2284
|
-
import * as fsSync from "fs";
|
|
2285
|
-
import * as fs from "fs/promises";
|
|
2286
|
-
import * as os from "os";
|
|
2287
|
-
import * as path from "path";
|
|
2288
2183
|
function generateActorId(name, key) {
|
|
2289
2184
|
const jsonString = JSON.stringify([name, key]);
|
|
2185
|
+
const crypto2 = getNodeCrypto();
|
|
2290
2186
|
const hash = crypto2.createHash("sha256").update(jsonString).digest("hex").substring(0, 16);
|
|
2291
2187
|
return hash;
|
|
2292
2188
|
}
|
|
2293
2189
|
function createHashForPath(dirPath) {
|
|
2190
|
+
const path = getNodePath();
|
|
2294
2191
|
const normalizedPath = path.normalize(dirPath);
|
|
2295
2192
|
const lastComponent = path.basename(normalizedPath);
|
|
2193
|
+
const crypto2 = getNodeCrypto();
|
|
2296
2194
|
const hash = crypto2.createHash("sha256").update(normalizedPath).digest("hex").substring(0, 8);
|
|
2297
2195
|
return `${lastComponent}-${hash}`;
|
|
2298
2196
|
}
|
|
2299
|
-
function getStoragePath(
|
|
2197
|
+
function getStoragePath() {
|
|
2300
2198
|
const dataPath = getDataPath("rivetkit");
|
|
2301
|
-
const
|
|
2302
|
-
const
|
|
2199
|
+
const dirHash = createHashForPath(process.cwd());
|
|
2200
|
+
const path = getNodePath();
|
|
2303
2201
|
return path.join(dataPath, dirHash);
|
|
2304
2202
|
}
|
|
2305
|
-
async function pathExists(
|
|
2203
|
+
async function pathExists(path) {
|
|
2306
2204
|
try {
|
|
2307
|
-
|
|
2205
|
+
const fs = getNodeFs();
|
|
2206
|
+
await fs.access(path);
|
|
2308
2207
|
return true;
|
|
2309
2208
|
} catch {
|
|
2310
2209
|
return false;
|
|
@@ -2312,17 +2211,21 @@ async function pathExists(path4) {
|
|
|
2312
2211
|
}
|
|
2313
2212
|
async function ensureDirectoryExists(directoryPath) {
|
|
2314
2213
|
if (!await pathExists(directoryPath)) {
|
|
2214
|
+
const fs = getNodeFs();
|
|
2315
2215
|
await fs.mkdir(directoryPath, { recursive: true });
|
|
2316
2216
|
}
|
|
2317
2217
|
}
|
|
2318
2218
|
function ensureDirectoryExistsSync(directoryPath) {
|
|
2219
|
+
const fsSync = getNodeFsSync();
|
|
2319
2220
|
if (!fsSync.existsSync(directoryPath)) {
|
|
2320
2221
|
fsSync.mkdirSync(directoryPath, { recursive: true });
|
|
2321
2222
|
}
|
|
2322
2223
|
}
|
|
2323
2224
|
function getDataPath(appName) {
|
|
2324
2225
|
const platform = process.platform;
|
|
2226
|
+
const os = getNodeOs();
|
|
2325
2227
|
const homeDir = os.homedir();
|
|
2228
|
+
const path = getNodePath();
|
|
2326
2229
|
switch (platform) {
|
|
2327
2230
|
case "win32":
|
|
2328
2231
|
return path.join(
|
|
@@ -2351,6 +2254,9 @@ var FileSystemGlobalState = class {
|
|
|
2351
2254
|
#dbsDir;
|
|
2352
2255
|
#alarmsDir;
|
|
2353
2256
|
#persist;
|
|
2257
|
+
// IMPORTANT: Never delete from this map. Doing so will result in race
|
|
2258
|
+
// conditions since the actor generation will cease to be tracked
|
|
2259
|
+
// correctly. Always increment generation if a new actor is created.
|
|
2354
2260
|
#actors = /* @__PURE__ */ new Map();
|
|
2355
2261
|
#actorCountOnStartup = 0;
|
|
2356
2262
|
#runnerParams;
|
|
@@ -2365,21 +2271,23 @@ var FileSystemGlobalState = class {
|
|
|
2365
2271
|
}
|
|
2366
2272
|
constructor(persist = true, customPath) {
|
|
2367
2273
|
this.#persist = persist;
|
|
2368
|
-
this.#storagePath = persist ? getStoragePath(
|
|
2369
|
-
|
|
2370
|
-
this.#
|
|
2371
|
-
this.#
|
|
2274
|
+
this.#storagePath = persist ? customPath ?? getStoragePath() : "/tmp";
|
|
2275
|
+
const path = getNodePath();
|
|
2276
|
+
this.#stateDir = path.join(this.#storagePath, "state");
|
|
2277
|
+
this.#dbsDir = path.join(this.#storagePath, "databases");
|
|
2278
|
+
this.#alarmsDir = path.join(this.#storagePath, "alarms");
|
|
2372
2279
|
if (this.#persist) {
|
|
2373
2280
|
ensureDirectoryExistsSync(this.#stateDir);
|
|
2374
2281
|
ensureDirectoryExistsSync(this.#dbsDir);
|
|
2375
2282
|
ensureDirectoryExistsSync(this.#alarmsDir);
|
|
2376
2283
|
try {
|
|
2377
|
-
const
|
|
2284
|
+
const fsSync = getNodeFsSync();
|
|
2285
|
+
const actorIds = fsSync.readdirSync(this.#stateDir);
|
|
2378
2286
|
this.#actorCountOnStartup = actorIds.length;
|
|
2379
2287
|
} catch (error) {
|
|
2380
|
-
|
|
2288
|
+
logger4().error({ msg: "failed to count actors", error });
|
|
2381
2289
|
}
|
|
2382
|
-
|
|
2290
|
+
logger4().debug({
|
|
2383
2291
|
msg: "file system driver ready",
|
|
2384
2292
|
dir: this.#storagePath,
|
|
2385
2293
|
actorCount: this.#actorCountOnStartup
|
|
@@ -2387,28 +2295,29 @@ var FileSystemGlobalState = class {
|
|
|
2387
2295
|
try {
|
|
2388
2296
|
this.#cleanupTempFilesSync();
|
|
2389
2297
|
} catch (err) {
|
|
2390
|
-
|
|
2298
|
+
logger4().error({
|
|
2391
2299
|
msg: "failed to cleanup temp files",
|
|
2392
2300
|
error: err
|
|
2393
2301
|
});
|
|
2394
2302
|
}
|
|
2395
2303
|
} else {
|
|
2396
|
-
|
|
2304
|
+
logger4().debug({ msg: "memory driver ready" });
|
|
2397
2305
|
}
|
|
2398
2306
|
}
|
|
2399
2307
|
getActorStatePath(actorId) {
|
|
2400
|
-
return
|
|
2308
|
+
return getNodePath().join(this.#stateDir, actorId);
|
|
2401
2309
|
}
|
|
2402
2310
|
getActorDbPath(actorId) {
|
|
2403
|
-
return
|
|
2311
|
+
return getNodePath().join(this.#dbsDir, `${actorId}.db`);
|
|
2404
2312
|
}
|
|
2405
2313
|
getActorAlarmPath(actorId) {
|
|
2406
|
-
return
|
|
2314
|
+
return getNodePath().join(this.#alarmsDir, actorId);
|
|
2407
2315
|
}
|
|
2408
2316
|
async *getActorsIterator(params) {
|
|
2409
2317
|
let actorIds = Array.from(this.#actors.keys()).sort();
|
|
2410
|
-
|
|
2411
|
-
|
|
2318
|
+
const fsSync = getNodeFsSync();
|
|
2319
|
+
if (fsSync.existsSync(this.#stateDir)) {
|
|
2320
|
+
actorIds = fsSync.readdirSync(this.#stateDir).filter((id) => !id.includes(".tmp")).sort();
|
|
2412
2321
|
}
|
|
2413
2322
|
const startIndex = params.cursor ? actorIds.indexOf(params.cursor) + 1 : 0;
|
|
2414
2323
|
for (let i = startIndex; i < actorIds.length; i++) {
|
|
@@ -2420,7 +2329,7 @@ var FileSystemGlobalState = class {
|
|
|
2420
2329
|
const state = await this.loadActorStateOrError(actorId);
|
|
2421
2330
|
yield state;
|
|
2422
2331
|
} catch (error) {
|
|
2423
|
-
|
|
2332
|
+
logger4().error({
|
|
2424
2333
|
msg: "failed to load actor state",
|
|
2425
2334
|
actorId,
|
|
2426
2335
|
error
|
|
@@ -2440,7 +2349,8 @@ var FileSystemGlobalState = class {
|
|
|
2440
2349
|
}
|
|
2441
2350
|
entry = {
|
|
2442
2351
|
id: actorId,
|
|
2443
|
-
|
|
2352
|
+
lifecycleState: 0 /* NONEXISTENT */,
|
|
2353
|
+
generation: crypto.randomUUID()
|
|
2444
2354
|
};
|
|
2445
2355
|
this.#actors.set(actorId, entry);
|
|
2446
2356
|
return entry;
|
|
@@ -2449,20 +2359,34 @@ var FileSystemGlobalState = class {
|
|
|
2449
2359
|
* Creates a new actor and writes to file system.
|
|
2450
2360
|
*/
|
|
2451
2361
|
async createActor(actorId, name, key, input) {
|
|
2452
|
-
if (this.#actors.has(actorId)) {
|
|
2453
|
-
throw new ActorAlreadyExists(name, key);
|
|
2454
|
-
}
|
|
2455
2362
|
const entry = this.#upsertEntry(actorId);
|
|
2363
|
+
if (entry.state) {
|
|
2364
|
+
throw new ActorDuplicateKey(name, key);
|
|
2365
|
+
}
|
|
2366
|
+
if (this.isActorStopping(actorId)) {
|
|
2367
|
+
throw new Error(`Actor ${actorId} is stopping`);
|
|
2368
|
+
}
|
|
2369
|
+
if (entry.lifecycleState === 4 /* DESTROYED */) {
|
|
2370
|
+
entry.lifecycleState = 0 /* NONEXISTENT */;
|
|
2371
|
+
entry.generation = crypto.randomUUID();
|
|
2372
|
+
}
|
|
2373
|
+
const kvStorage = [];
|
|
2374
|
+
const initialKvState = getInitialActorKvState(input);
|
|
2375
|
+
for (const [key2, value] of initialKvState) {
|
|
2376
|
+
kvStorage.push({
|
|
2377
|
+
key: bufferToArrayBuffer(key2),
|
|
2378
|
+
value: bufferToArrayBuffer(value)
|
|
2379
|
+
});
|
|
2380
|
+
}
|
|
2456
2381
|
entry.state = {
|
|
2457
2382
|
actorId,
|
|
2458
2383
|
name,
|
|
2459
2384
|
key,
|
|
2460
2385
|
createdAt: BigInt(Date.now()),
|
|
2461
|
-
|
|
2462
|
-
serializeEmptyPersistData(input)
|
|
2463
|
-
)
|
|
2386
|
+
kvStorage
|
|
2464
2387
|
};
|
|
2465
|
-
|
|
2388
|
+
entry.lifecycleState = 1 /* AWAKE */;
|
|
2389
|
+
await this.writeActor(actorId, entry.generation, entry.state);
|
|
2466
2390
|
return entry;
|
|
2467
2391
|
}
|
|
2468
2392
|
/**
|
|
@@ -2470,6 +2394,9 @@ var FileSystemGlobalState = class {
|
|
|
2470
2394
|
*/
|
|
2471
2395
|
async loadActor(actorId) {
|
|
2472
2396
|
const entry = this.#upsertEntry(actorId);
|
|
2397
|
+
if (entry.lifecycleState === 4 /* DESTROYED */) {
|
|
2398
|
+
return entry;
|
|
2399
|
+
}
|
|
2473
2400
|
if (entry.state) {
|
|
2474
2401
|
return entry;
|
|
2475
2402
|
}
|
|
@@ -2486,7 +2413,8 @@ var FileSystemGlobalState = class {
|
|
|
2486
2413
|
async loadActorState(entry) {
|
|
2487
2414
|
const stateFilePath = this.getActorStatePath(entry.id);
|
|
2488
2415
|
try {
|
|
2489
|
-
const
|
|
2416
|
+
const fs = getNodeFs();
|
|
2417
|
+
const stateData = await fs.readFile(stateFilePath);
|
|
2490
2418
|
entry.state = ACTOR_STATE_VERSIONED.deserializeWithEmbeddedVersion(
|
|
2491
2419
|
new Uint8Array(stateData)
|
|
2492
2420
|
);
|
|
@@ -2505,16 +2433,29 @@ var FileSystemGlobalState = class {
|
|
|
2505
2433
|
async loadOrCreateActor(actorId, name, key, input) {
|
|
2506
2434
|
const entry = await this.loadActor(actorId);
|
|
2507
2435
|
if (!entry.state) {
|
|
2436
|
+
if (this.isActorStopping(actorId)) {
|
|
2437
|
+
throw new Error(`Actor ${actorId} stopping`);
|
|
2438
|
+
}
|
|
2439
|
+
if (entry.lifecycleState === 4 /* DESTROYED */) {
|
|
2440
|
+
entry.lifecycleState = 0 /* NONEXISTENT */;
|
|
2441
|
+
entry.generation = crypto.randomUUID();
|
|
2442
|
+
}
|
|
2443
|
+
const kvStorage = [];
|
|
2444
|
+
const initialKvState = getInitialActorKvState(input);
|
|
2445
|
+
for (const [key2, value] of initialKvState) {
|
|
2446
|
+
kvStorage.push({
|
|
2447
|
+
key: bufferToArrayBuffer(key2),
|
|
2448
|
+
value: bufferToArrayBuffer(value)
|
|
2449
|
+
});
|
|
2450
|
+
}
|
|
2508
2451
|
entry.state = {
|
|
2509
2452
|
actorId,
|
|
2510
2453
|
name,
|
|
2511
2454
|
key,
|
|
2512
2455
|
createdAt: BigInt(Date.now()),
|
|
2513
|
-
|
|
2514
|
-
serializeEmptyPersistData(input)
|
|
2515
|
-
)
|
|
2456
|
+
kvStorage
|
|
2516
2457
|
};
|
|
2517
|
-
await this.writeActor(actorId, entry.state);
|
|
2458
|
+
await this.writeActor(actorId, entry.generation, entry.state);
|
|
2518
2459
|
}
|
|
2519
2460
|
return entry;
|
|
2520
2461
|
}
|
|
@@ -2524,35 +2465,127 @@ var FileSystemGlobalState = class {
|
|
|
2524
2465
|
this.#persist,
|
|
2525
2466
|
"cannot sleep actor with memory driver, must use file system driver"
|
|
2526
2467
|
);
|
|
2527
|
-
const actor2 = this.#
|
|
2468
|
+
const actor2 = this.#upsertEntry(actorId);
|
|
2528
2469
|
invariant4(actor2, `tried to sleep ${actorId}, does not exist`);
|
|
2470
|
+
if (this.isActorStopping(actorId)) {
|
|
2471
|
+
return;
|
|
2472
|
+
}
|
|
2473
|
+
actor2.lifecycleState = 2 /* STARTING_SLEEP */;
|
|
2529
2474
|
if (actor2.loadPromise) await actor2.loadPromise.catch();
|
|
2530
2475
|
if ((_a = actor2.startPromise) == null ? void 0 : _a.promise)
|
|
2531
2476
|
await actor2.startPromise.promise.catch();
|
|
2532
|
-
actor2.removed = true;
|
|
2533
2477
|
invariant4(actor2.actor, "actor should be loaded");
|
|
2534
|
-
await actor2.actor.
|
|
2478
|
+
await actor2.actor.onStop("sleep");
|
|
2535
2479
|
this.#actors.delete(actorId);
|
|
2536
2480
|
}
|
|
2481
|
+
async destroyActor(actorId) {
|
|
2482
|
+
var _a;
|
|
2483
|
+
const actor2 = this.#upsertEntry(actorId);
|
|
2484
|
+
if (this.isActorStopping(actorId)) {
|
|
2485
|
+
return;
|
|
2486
|
+
}
|
|
2487
|
+
actor2.lifecycleState = 3 /* STARTING_DESTROY */;
|
|
2488
|
+
if (actor2.loadPromise) await actor2.loadPromise.catch();
|
|
2489
|
+
if ((_a = actor2.startPromise) == null ? void 0 : _a.promise)
|
|
2490
|
+
await actor2.startPromise.promise.catch();
|
|
2491
|
+
if (actor2.actor) {
|
|
2492
|
+
await actor2.actor.onStop("destroy");
|
|
2493
|
+
}
|
|
2494
|
+
if (actor2.alarmTimeout) {
|
|
2495
|
+
actor2.alarmTimeout.abort();
|
|
2496
|
+
}
|
|
2497
|
+
if (this.#persist) {
|
|
2498
|
+
const fs = getNodeFs();
|
|
2499
|
+
await Promise.all([
|
|
2500
|
+
// Delete actor state file
|
|
2501
|
+
(async () => {
|
|
2502
|
+
try {
|
|
2503
|
+
await fs.unlink(this.getActorStatePath(actorId));
|
|
2504
|
+
} catch (err) {
|
|
2505
|
+
if ((err == null ? void 0 : err.code) !== "ENOENT") {
|
|
2506
|
+
logger4().error({
|
|
2507
|
+
msg: "failed to delete actor state file",
|
|
2508
|
+
actorId,
|
|
2509
|
+
error: stringifyError(err)
|
|
2510
|
+
});
|
|
2511
|
+
}
|
|
2512
|
+
}
|
|
2513
|
+
})(),
|
|
2514
|
+
// Delete actor database file
|
|
2515
|
+
(async () => {
|
|
2516
|
+
try {
|
|
2517
|
+
await fs.unlink(this.getActorDbPath(actorId));
|
|
2518
|
+
} catch (err) {
|
|
2519
|
+
if ((err == null ? void 0 : err.code) !== "ENOENT") {
|
|
2520
|
+
logger4().error({
|
|
2521
|
+
msg: "failed to delete actor database file",
|
|
2522
|
+
actorId,
|
|
2523
|
+
error: stringifyError(err)
|
|
2524
|
+
});
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
})(),
|
|
2528
|
+
// Delete actor alarm file
|
|
2529
|
+
(async () => {
|
|
2530
|
+
try {
|
|
2531
|
+
await fs.unlink(this.getActorAlarmPath(actorId));
|
|
2532
|
+
} catch (err) {
|
|
2533
|
+
if ((err == null ? void 0 : err.code) !== "ENOENT") {
|
|
2534
|
+
logger4().error({
|
|
2535
|
+
msg: "failed to delete actor alarm file",
|
|
2536
|
+
actorId,
|
|
2537
|
+
error: stringifyError(err)
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2540
|
+
}
|
|
2541
|
+
})()
|
|
2542
|
+
]);
|
|
2543
|
+
}
|
|
2544
|
+
actor2.state = void 0;
|
|
2545
|
+
actor2.loadPromise = void 0;
|
|
2546
|
+
actor2.actor = void 0;
|
|
2547
|
+
actor2.startPromise = void 0;
|
|
2548
|
+
actor2.alarmTimeout = void 0;
|
|
2549
|
+
actor2.alarmTimeout = void 0;
|
|
2550
|
+
actor2.pendingWriteResolver = void 0;
|
|
2551
|
+
actor2.lifecycleState = 4 /* DESTROYED */;
|
|
2552
|
+
}
|
|
2537
2553
|
/**
|
|
2538
2554
|
* Save actor state to disk.
|
|
2539
2555
|
*/
|
|
2540
|
-
async writeActor(actorId, state) {
|
|
2556
|
+
async writeActor(actorId, generation, state) {
|
|
2541
2557
|
if (!this.#persist) {
|
|
2542
2558
|
return;
|
|
2543
2559
|
}
|
|
2544
2560
|
const entry = this.#actors.get(actorId);
|
|
2545
2561
|
invariant4(entry, "actor entry does not exist");
|
|
2546
|
-
await this.#performWrite(actorId, state);
|
|
2562
|
+
await this.#performWrite(actorId, generation, state);
|
|
2563
|
+
}
|
|
2564
|
+
isGenerationCurrentAndNotDestroyed(actorId, generation) {
|
|
2565
|
+
const entry = this.#upsertEntry(actorId);
|
|
2566
|
+
if (!entry) return false;
|
|
2567
|
+
return entry.generation === generation && entry.lifecycleState !== 3 /* STARTING_DESTROY */;
|
|
2568
|
+
}
|
|
2569
|
+
isActorStopping(actorId) {
|
|
2570
|
+
const entry = this.#upsertEntry(actorId);
|
|
2571
|
+
if (!entry) return false;
|
|
2572
|
+
return entry.lifecycleState === 2 /* STARTING_SLEEP */ || entry.lifecycleState === 3 /* STARTING_DESTROY */;
|
|
2547
2573
|
}
|
|
2548
2574
|
async setActorAlarm(actorId, timestamp) {
|
|
2549
2575
|
const entry = this.#actors.get(actorId);
|
|
2550
2576
|
invariant4(entry, "actor entry does not exist");
|
|
2577
|
+
const writeGeneration = entry.generation;
|
|
2578
|
+
if (this.isActorStopping(actorId)) {
|
|
2579
|
+
logger4().info("skipping set alarm since actor stopping");
|
|
2580
|
+
return;
|
|
2581
|
+
}
|
|
2551
2582
|
if (this.#persist) {
|
|
2552
2583
|
const alarmPath = this.getActorAlarmPath(actorId);
|
|
2553
|
-
const
|
|
2584
|
+
const crypto2 = getNodeCrypto();
|
|
2585
|
+
const tempPath = `${alarmPath}.tmp.${crypto2.randomUUID()}`;
|
|
2554
2586
|
try {
|
|
2555
|
-
|
|
2587
|
+
const path = getNodePath();
|
|
2588
|
+
await ensureDirectoryExists(path.dirname(alarmPath));
|
|
2556
2589
|
const alarmData = {
|
|
2557
2590
|
actorId,
|
|
2558
2591
|
timestamp: BigInt(timestamp)
|
|
@@ -2560,14 +2593,25 @@ var FileSystemGlobalState = class {
|
|
|
2560
2593
|
const data = ACTOR_ALARM_VERSIONED.serializeWithEmbeddedVersion(
|
|
2561
2594
|
alarmData
|
|
2562
2595
|
);
|
|
2563
|
-
|
|
2564
|
-
await
|
|
2596
|
+
const fs = getNodeFs();
|
|
2597
|
+
await fs.writeFile(tempPath, data);
|
|
2598
|
+
if (!this.isGenerationCurrentAndNotDestroyed(
|
|
2599
|
+
actorId,
|
|
2600
|
+
writeGeneration
|
|
2601
|
+
)) {
|
|
2602
|
+
logger4().debug(
|
|
2603
|
+
"skipping writing alarm since actor destroying or new generation"
|
|
2604
|
+
);
|
|
2605
|
+
return;
|
|
2606
|
+
}
|
|
2607
|
+
await fs.rename(tempPath, alarmPath);
|
|
2565
2608
|
} catch (error) {
|
|
2566
2609
|
try {
|
|
2567
|
-
|
|
2610
|
+
const fs = getNodeFs();
|
|
2611
|
+
await fs.unlink(tempPath);
|
|
2568
2612
|
} catch {
|
|
2569
2613
|
}
|
|
2570
|
-
|
|
2614
|
+
logger4().error({
|
|
2571
2615
|
msg: "failed to write alarm",
|
|
2572
2616
|
actorId,
|
|
2573
2617
|
error
|
|
@@ -2580,27 +2624,37 @@ var FileSystemGlobalState = class {
|
|
|
2580
2624
|
/**
|
|
2581
2625
|
* Perform the actual write operation with atomic writes
|
|
2582
2626
|
*/
|
|
2583
|
-
async #performWrite(actorId, state) {
|
|
2627
|
+
async #performWrite(actorId, generation, state) {
|
|
2584
2628
|
const dataPath = this.getActorStatePath(actorId);
|
|
2585
|
-
const
|
|
2629
|
+
const crypto2 = getNodeCrypto();
|
|
2630
|
+
const tempPath = `${dataPath}.tmp.${crypto2.randomUUID()}`;
|
|
2586
2631
|
try {
|
|
2587
|
-
|
|
2632
|
+
const path = getNodePath();
|
|
2633
|
+
await ensureDirectoryExists(path.dirname(dataPath));
|
|
2588
2634
|
const bareState = {
|
|
2589
2635
|
actorId: state.actorId,
|
|
2590
2636
|
name: state.name,
|
|
2591
2637
|
key: state.key,
|
|
2592
2638
|
createdAt: state.createdAt,
|
|
2593
|
-
|
|
2639
|
+
kvStorage: state.kvStorage
|
|
2594
2640
|
};
|
|
2595
2641
|
const serializedState = ACTOR_STATE_VERSIONED.serializeWithEmbeddedVersion(bareState);
|
|
2596
|
-
|
|
2597
|
-
await
|
|
2642
|
+
const fs = getNodeFs();
|
|
2643
|
+
await fs.writeFile(tempPath, serializedState);
|
|
2644
|
+
if (!this.isGenerationCurrentAndNotDestroyed(actorId, generation)) {
|
|
2645
|
+
logger4().debug(
|
|
2646
|
+
"skipping writing alarm since actor destroying or new generation"
|
|
2647
|
+
);
|
|
2648
|
+
return;
|
|
2649
|
+
}
|
|
2650
|
+
await fs.rename(tempPath, dataPath);
|
|
2598
2651
|
} catch (error) {
|
|
2599
2652
|
try {
|
|
2600
|
-
|
|
2653
|
+
const fs = getNodeFs();
|
|
2654
|
+
await fs.unlink(tempPath);
|
|
2601
2655
|
} catch {
|
|
2602
2656
|
}
|
|
2603
|
-
|
|
2657
|
+
logger4().error({
|
|
2604
2658
|
msg: "failed to save actor state",
|
|
2605
2659
|
actorId,
|
|
2606
2660
|
error
|
|
@@ -2628,7 +2682,7 @@ var FileSystemGlobalState = class {
|
|
|
2628
2682
|
try {
|
|
2629
2683
|
this.#loadAlarmsSync();
|
|
2630
2684
|
} catch (err) {
|
|
2631
|
-
|
|
2685
|
+
logger4().error({
|
|
2632
2686
|
msg: "failed to load alarms on startup",
|
|
2633
2687
|
error: err
|
|
2634
2688
|
});
|
|
@@ -2696,12 +2750,14 @@ var FileSystemGlobalState = class {
|
|
|
2696
2750
|
*/
|
|
2697
2751
|
#loadAlarmsSync() {
|
|
2698
2752
|
try {
|
|
2699
|
-
const
|
|
2753
|
+
const fsSync = getNodeFsSync();
|
|
2754
|
+
const files = fsSync.existsSync(this.#alarmsDir) ? fsSync.readdirSync(this.#alarmsDir) : [];
|
|
2700
2755
|
for (const file of files) {
|
|
2701
2756
|
if (file.includes(".tmp.")) continue;
|
|
2702
|
-
const
|
|
2757
|
+
const path = getNodePath();
|
|
2758
|
+
const fullPath = path.join(this.#alarmsDir, file);
|
|
2703
2759
|
try {
|
|
2704
|
-
const buf =
|
|
2760
|
+
const buf = fsSync.readFileSync(fullPath);
|
|
2705
2761
|
const alarmData = ACTOR_ALARM_VERSIONED.deserializeWithEmbeddedVersion(
|
|
2706
2762
|
new Uint8Array(buf)
|
|
2707
2763
|
);
|
|
@@ -2712,13 +2768,13 @@ var FileSystemGlobalState = class {
|
|
|
2712
2768
|
timestamp
|
|
2713
2769
|
);
|
|
2714
2770
|
} else {
|
|
2715
|
-
|
|
2771
|
+
logger4().debug({
|
|
2716
2772
|
msg: "invalid alarm file contents",
|
|
2717
2773
|
file
|
|
2718
2774
|
});
|
|
2719
2775
|
}
|
|
2720
2776
|
} catch (err) {
|
|
2721
|
-
|
|
2777
|
+
logger4().error({
|
|
2722
2778
|
msg: "failed to read alarm file",
|
|
2723
2779
|
file,
|
|
2724
2780
|
error: stringifyError(err)
|
|
@@ -2726,7 +2782,7 @@ var FileSystemGlobalState = class {
|
|
|
2726
2782
|
}
|
|
2727
2783
|
}
|
|
2728
2784
|
} catch (err) {
|
|
2729
|
-
|
|
2785
|
+
logger4().error({
|
|
2730
2786
|
msg: "failed to list alarms directory",
|
|
2731
2787
|
error: err
|
|
2732
2788
|
});
|
|
@@ -2739,7 +2795,7 @@ var FileSystemGlobalState = class {
|
|
|
2739
2795
|
var _a;
|
|
2740
2796
|
const entry = this.#upsertEntry(actorId);
|
|
2741
2797
|
if (entry.alarmTimestamp !== void 0 && timestamp >= entry.alarmTimestamp) {
|
|
2742
|
-
|
|
2798
|
+
logger4().debug({
|
|
2743
2799
|
msg: "skipping alarm schedule (later than existing)",
|
|
2744
2800
|
actorId,
|
|
2745
2801
|
timestamp,
|
|
@@ -2747,7 +2803,7 @@ var FileSystemGlobalState = class {
|
|
|
2747
2803
|
});
|
|
2748
2804
|
return;
|
|
2749
2805
|
}
|
|
2750
|
-
|
|
2806
|
+
logger4().debug({ msg: "scheduling alarm", actorId, timestamp });
|
|
2751
2807
|
(_a = entry.alarmTimeout) == null ? void 0 : _a.abort();
|
|
2752
2808
|
entry.alarmTimestamp = timestamp;
|
|
2753
2809
|
const delay = Math.max(0, timestamp - Date.now());
|
|
@@ -2755,10 +2811,11 @@ var FileSystemGlobalState = class {
|
|
|
2755
2811
|
entry.alarmTimestamp = void 0;
|
|
2756
2812
|
if (this.#persist) {
|
|
2757
2813
|
try {
|
|
2758
|
-
|
|
2814
|
+
const fs = getNodeFs();
|
|
2815
|
+
await fs.unlink(this.getActorAlarmPath(actorId));
|
|
2759
2816
|
} catch (err) {
|
|
2760
2817
|
if ((err == null ? void 0 : err.code) !== "ENOENT") {
|
|
2761
|
-
|
|
2818
|
+
logger4().debug({
|
|
2762
2819
|
msg: "failed to remove alarm file",
|
|
2763
2820
|
actorId,
|
|
2764
2821
|
error: stringifyError(err)
|
|
@@ -2767,7 +2824,7 @@ var FileSystemGlobalState = class {
|
|
|
2767
2824
|
}
|
|
2768
2825
|
}
|
|
2769
2826
|
try {
|
|
2770
|
-
|
|
2827
|
+
logger4().debug({ msg: "triggering alarm", actorId, timestamp });
|
|
2771
2828
|
const loaded = await this.loadActor(actorId);
|
|
2772
2829
|
if (!loaded.state)
|
|
2773
2830
|
throw new Error(`Actor does not exist: ${actorId}`);
|
|
@@ -2783,9 +2840,9 @@ var FileSystemGlobalState = class {
|
|
|
2783
2840
|
);
|
|
2784
2841
|
}
|
|
2785
2842
|
invariant4(loaded.actor, "actor should be loaded after wake");
|
|
2786
|
-
await loaded.actor.
|
|
2843
|
+
await loaded.actor.onAlarm();
|
|
2787
2844
|
} catch (err) {
|
|
2788
|
-
|
|
2845
|
+
logger4().error({
|
|
2789
2846
|
msg: "failed to handle alarm",
|
|
2790
2847
|
actorId,
|
|
2791
2848
|
error: stringifyError(err)
|
|
@@ -2794,12 +2851,14 @@ var FileSystemGlobalState = class {
|
|
|
2794
2851
|
}, delay);
|
|
2795
2852
|
}
|
|
2796
2853
|
getOrCreateInspectorAccessToken() {
|
|
2797
|
-
const
|
|
2798
|
-
|
|
2799
|
-
|
|
2854
|
+
const path = getNodePath();
|
|
2855
|
+
const fsSync = getNodeFsSync();
|
|
2856
|
+
const tokenPath = path.join(this.#storagePath, "inspector-token");
|
|
2857
|
+
if (fsSync.existsSync(tokenPath)) {
|
|
2858
|
+
return fsSync.readFileSync(tokenPath, "utf-8");
|
|
2800
2859
|
}
|
|
2801
2860
|
const newToken = generateRandomString();
|
|
2802
|
-
|
|
2861
|
+
fsSync.writeFileSync(tokenPath, newToken);
|
|
2803
2862
|
return newToken;
|
|
2804
2863
|
}
|
|
2805
2864
|
/**
|
|
@@ -2807,22 +2866,24 @@ var FileSystemGlobalState = class {
|
|
|
2807
2866
|
*/
|
|
2808
2867
|
#cleanupTempFilesSync() {
|
|
2809
2868
|
try {
|
|
2810
|
-
const
|
|
2869
|
+
const fsSync = getNodeFsSync();
|
|
2870
|
+
const files = fsSync.readdirSync(this.#stateDir);
|
|
2811
2871
|
const tempFiles = files.filter((f) => f.includes(".tmp."));
|
|
2812
2872
|
const oneHourAgo = Date.now() - 36e5;
|
|
2813
2873
|
for (const tempFile of tempFiles) {
|
|
2814
2874
|
try {
|
|
2815
|
-
const
|
|
2816
|
-
const
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2875
|
+
const path = getNodePath();
|
|
2876
|
+
const fullPath = path.join(this.#stateDir, tempFile);
|
|
2877
|
+
const stat = fsSync.statSync(fullPath);
|
|
2878
|
+
if (stat.mtimeMs < oneHourAgo) {
|
|
2879
|
+
fsSync.unlinkSync(fullPath);
|
|
2880
|
+
logger4().info({
|
|
2820
2881
|
msg: "cleaned up stale temp file",
|
|
2821
2882
|
file: tempFile
|
|
2822
2883
|
});
|
|
2823
2884
|
}
|
|
2824
2885
|
} catch (err) {
|
|
2825
|
-
|
|
2886
|
+
logger4().debug({
|
|
2826
2887
|
msg: "failed to cleanup temp file",
|
|
2827
2888
|
file: tempFile,
|
|
2828
2889
|
error: err
|
|
@@ -2830,12 +2891,129 @@ var FileSystemGlobalState = class {
|
|
|
2830
2891
|
}
|
|
2831
2892
|
}
|
|
2832
2893
|
} catch (err) {
|
|
2833
|
-
|
|
2894
|
+
logger4().error({
|
|
2834
2895
|
msg: "failed to read actors directory for cleanup",
|
|
2835
2896
|
error: err
|
|
2836
2897
|
});
|
|
2837
2898
|
}
|
|
2838
2899
|
}
|
|
2900
|
+
/**
|
|
2901
|
+
* Batch put KV entries for an actor.
|
|
2902
|
+
*/
|
|
2903
|
+
async kvBatchPut(actorId, entries) {
|
|
2904
|
+
const entry = await this.loadActor(actorId);
|
|
2905
|
+
if (!entry.state) {
|
|
2906
|
+
if (this.isActorStopping(actorId)) {
|
|
2907
|
+
return;
|
|
2908
|
+
} else {
|
|
2909
|
+
throw new Error(`Actor ${actorId} state not loaded`);
|
|
2910
|
+
}
|
|
2911
|
+
}
|
|
2912
|
+
const newKvStorage = [...entry.state.kvStorage];
|
|
2913
|
+
for (const [key, value] of entries) {
|
|
2914
|
+
const existingIndex = newKvStorage.findIndex(
|
|
2915
|
+
(e) => arrayBuffersEqual(e.key, bufferToArrayBuffer(key))
|
|
2916
|
+
);
|
|
2917
|
+
if (existingIndex >= 0) {
|
|
2918
|
+
newKvStorage[existingIndex] = {
|
|
2919
|
+
key: bufferToArrayBuffer(key),
|
|
2920
|
+
value: bufferToArrayBuffer(value)
|
|
2921
|
+
};
|
|
2922
|
+
} else {
|
|
2923
|
+
newKvStorage.push({
|
|
2924
|
+
key: bufferToArrayBuffer(key),
|
|
2925
|
+
value: bufferToArrayBuffer(value)
|
|
2926
|
+
});
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
entry.state = {
|
|
2930
|
+
...entry.state,
|
|
2931
|
+
kvStorage: newKvStorage
|
|
2932
|
+
};
|
|
2933
|
+
await this.writeActor(actorId, entry.generation, entry.state);
|
|
2934
|
+
}
|
|
2935
|
+
/**
|
|
2936
|
+
* Batch get KV entries for an actor.
|
|
2937
|
+
*/
|
|
2938
|
+
async kvBatchGet(actorId, keys) {
|
|
2939
|
+
const entry = await this.loadActor(actorId);
|
|
2940
|
+
if (!entry.state) {
|
|
2941
|
+
if (this.isActorStopping(actorId)) {
|
|
2942
|
+
throw new Error(`Actor ${actorId} is stopping`);
|
|
2943
|
+
} else {
|
|
2944
|
+
throw new Error(`Actor ${actorId} state not loaded`);
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
const results = [];
|
|
2948
|
+
for (const key of keys) {
|
|
2949
|
+
const foundEntry = entry.state.kvStorage.find(
|
|
2950
|
+
(e) => arrayBuffersEqual(e.key, bufferToArrayBuffer(key))
|
|
2951
|
+
);
|
|
2952
|
+
if (foundEntry) {
|
|
2953
|
+
results.push(new Uint8Array(foundEntry.value));
|
|
2954
|
+
} else {
|
|
2955
|
+
results.push(null);
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
return results;
|
|
2959
|
+
}
|
|
2960
|
+
/**
|
|
2961
|
+
* Batch delete KV entries for an actor.
|
|
2962
|
+
*/
|
|
2963
|
+
async kvBatchDelete(actorId, keys) {
|
|
2964
|
+
const entry = await this.loadActor(actorId);
|
|
2965
|
+
if (!entry.state) {
|
|
2966
|
+
if (this.isActorStopping(actorId)) {
|
|
2967
|
+
return;
|
|
2968
|
+
} else {
|
|
2969
|
+
throw new Error(`Actor ${actorId} state not loaded`);
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
const newKvStorage = [...entry.state.kvStorage];
|
|
2973
|
+
for (const key of keys) {
|
|
2974
|
+
const indexToDelete = newKvStorage.findIndex(
|
|
2975
|
+
(e) => arrayBuffersEqual(e.key, bufferToArrayBuffer(key))
|
|
2976
|
+
);
|
|
2977
|
+
if (indexToDelete >= 0) {
|
|
2978
|
+
newKvStorage.splice(indexToDelete, 1);
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
entry.state = {
|
|
2982
|
+
...entry.state,
|
|
2983
|
+
kvStorage: newKvStorage
|
|
2984
|
+
};
|
|
2985
|
+
await this.writeActor(actorId, entry.generation, entry.state);
|
|
2986
|
+
}
|
|
2987
|
+
/**
|
|
2988
|
+
* List KV entries with a given prefix for an actor.
|
|
2989
|
+
*/
|
|
2990
|
+
async kvListPrefix(actorId, prefix) {
|
|
2991
|
+
const entry = await this.loadActor(actorId);
|
|
2992
|
+
if (!entry.state) {
|
|
2993
|
+
if (this.isActorStopping(actorId)) {
|
|
2994
|
+
throw new Error(`Actor ${actorId} is destroying`);
|
|
2995
|
+
} else {
|
|
2996
|
+
throw new Error(`Actor ${actorId} state not loaded`);
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2999
|
+
const results = [];
|
|
3000
|
+
for (const kvEntry of entry.state.kvStorage) {
|
|
3001
|
+
const keyBytes = new Uint8Array(kvEntry.key);
|
|
3002
|
+
if (keyBytes.length >= prefix.length) {
|
|
3003
|
+
let hasPrefix = true;
|
|
3004
|
+
for (let i = 0; i < prefix.length; i++) {
|
|
3005
|
+
if (keyBytes[i] !== prefix[i]) {
|
|
3006
|
+
hasPrefix = false;
|
|
3007
|
+
break;
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
if (hasPrefix) {
|
|
3011
|
+
results.push([keyBytes, new Uint8Array(kvEntry.value)]);
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
return results;
|
|
3016
|
+
}
|
|
2839
3017
|
};
|
|
2840
3018
|
|
|
2841
3019
|
// src/drivers/file-system/manager.ts
|
|
@@ -2994,73 +3172,53 @@ var FileSystemManagerDriver = class {
|
|
|
2994
3172
|
actorId
|
|
2995
3173
|
});
|
|
2996
3174
|
}
|
|
2997
|
-
async openWebSocket(
|
|
2998
|
-
const pathOnly =
|
|
3175
|
+
async openWebSocket(path, actorId, encoding, params) {
|
|
3176
|
+
const pathOnly = path.split("?")[0];
|
|
2999
3177
|
const normalizedPath = pathOnly.startsWith("/") ? pathOnly : `/${pathOnly}`;
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
void 0,
|
|
3017
|
-
path4,
|
|
3018
|
-
this.#actorDriver,
|
|
3019
|
-
actorId,
|
|
3020
|
-
void 0
|
|
3021
|
-
);
|
|
3022
|
-
return new InlineWebSocketAdapter2(wsHandler);
|
|
3023
|
-
} else {
|
|
3024
|
-
throw new Error(`Unreachable path: ${path4}`);
|
|
3025
|
-
}
|
|
3178
|
+
const wsHandler = await routeWebSocket(
|
|
3179
|
+
// TODO: Create fake request
|
|
3180
|
+
void 0,
|
|
3181
|
+
normalizedPath,
|
|
3182
|
+
{},
|
|
3183
|
+
this.#runConfig,
|
|
3184
|
+
this.#actorDriver,
|
|
3185
|
+
actorId,
|
|
3186
|
+
encoding,
|
|
3187
|
+
params,
|
|
3188
|
+
void 0,
|
|
3189
|
+
void 0,
|
|
3190
|
+
false,
|
|
3191
|
+
false
|
|
3192
|
+
);
|
|
3193
|
+
return new InlineWebSocketAdapter(wsHandler);
|
|
3026
3194
|
}
|
|
3027
3195
|
async proxyRequest(c, actorRequest, actorId) {
|
|
3028
3196
|
return await this.#actorRouter.fetch(actorRequest, {
|
|
3029
3197
|
actorId
|
|
3030
3198
|
});
|
|
3031
3199
|
}
|
|
3032
|
-
async proxyWebSocket(c,
|
|
3200
|
+
async proxyWebSocket(c, path, actorId, encoding, params) {
|
|
3033
3201
|
var _a, _b;
|
|
3034
3202
|
const upgradeWebSocket = (_b = (_a = this.#runConfig).getUpgradeWebSocket) == null ? void 0 : _b.call(_a);
|
|
3035
3203
|
invariant5(upgradeWebSocket, "missing getUpgradeWebSocket");
|
|
3036
|
-
const pathOnly =
|
|
3204
|
+
const pathOnly = path.split("?")[0];
|
|
3037
3205
|
const normalizedPath = pathOnly.startsWith("/") ? pathOnly : `/${pathOnly}`;
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
c.req.raw,
|
|
3055
|
-
path4,
|
|
3056
|
-
this.#actorDriver,
|
|
3057
|
-
actorId,
|
|
3058
|
-
void 0
|
|
3059
|
-
);
|
|
3060
|
-
return upgradeWebSocket(() => wsHandler)(c, noopNext());
|
|
3061
|
-
} else {
|
|
3062
|
-
throw new Error(`Unreachable path: ${path4}`);
|
|
3063
|
-
}
|
|
3206
|
+
const wsHandler = await routeWebSocket(
|
|
3207
|
+
// TODO: Create new request with new path
|
|
3208
|
+
c.req.raw,
|
|
3209
|
+
normalizedPath,
|
|
3210
|
+
c.req.header(),
|
|
3211
|
+
this.#runConfig,
|
|
3212
|
+
this.#actorDriver,
|
|
3213
|
+
actorId,
|
|
3214
|
+
encoding,
|
|
3215
|
+
params,
|
|
3216
|
+
void 0,
|
|
3217
|
+
void 0,
|
|
3218
|
+
false,
|
|
3219
|
+
false
|
|
3220
|
+
);
|
|
3221
|
+
return upgradeWebSocket(() => wsHandler)(c, noopNext());
|
|
3064
3222
|
}
|
|
3065
3223
|
async getForId({
|
|
3066
3224
|
actorId
|
|
@@ -3069,6 +3227,9 @@ var FileSystemManagerDriver = class {
|
|
|
3069
3227
|
if (!actor2.state) {
|
|
3070
3228
|
return void 0;
|
|
3071
3229
|
}
|
|
3230
|
+
if (this.#state.isActorStopping(actorId)) {
|
|
3231
|
+
throw new ActorStopping(actorId);
|
|
3232
|
+
}
|
|
3072
3233
|
try {
|
|
3073
3234
|
return {
|
|
3074
3235
|
actorId,
|
|
@@ -3076,7 +3237,7 @@ var FileSystemManagerDriver = class {
|
|
|
3076
3237
|
key: actor2.state.key
|
|
3077
3238
|
};
|
|
3078
3239
|
} catch (error) {
|
|
3079
|
-
|
|
3240
|
+
logger4().error({
|
|
3080
3241
|
msg: "failed to read actor state",
|
|
3081
3242
|
actorId,
|
|
3082
3243
|
error
|
|
@@ -3123,6 +3284,26 @@ var FileSystemManagerDriver = class {
|
|
|
3123
3284
|
key
|
|
3124
3285
|
};
|
|
3125
3286
|
}
|
|
3287
|
+
async listActors({ name }) {
|
|
3288
|
+
const actors = [];
|
|
3289
|
+
const itr = this.#state.getActorsIterator({});
|
|
3290
|
+
for await (const actor2 of itr) {
|
|
3291
|
+
if (actor2.name === name) {
|
|
3292
|
+
actors.push({
|
|
3293
|
+
actorId: actor2.actorId,
|
|
3294
|
+
name: actor2.name,
|
|
3295
|
+
key: actor2.key,
|
|
3296
|
+
createTs: Number(actor2.createdAt)
|
|
3297
|
+
});
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
actors.sort((a, b) => {
|
|
3301
|
+
const aTs = a.createTs ?? 0;
|
|
3302
|
+
const bTs = b.createTs ?? 0;
|
|
3303
|
+
return bTs - aTs;
|
|
3304
|
+
});
|
|
3305
|
+
return actors;
|
|
3306
|
+
}
|
|
3126
3307
|
displayInformation() {
|
|
3127
3308
|
return {
|
|
3128
3309
|
name: this.#state.persist ? "File System" : "Memory",
|
|
@@ -3145,6 +3326,7 @@ var FileSystemManagerDriver = class {
|
|
|
3145
3326
|
|
|
3146
3327
|
// src/drivers/file-system/mod.ts
|
|
3147
3328
|
function createFileSystemOrMemoryDriver(persist = true, customPath) {
|
|
3329
|
+
importNodeDependencies();
|
|
3148
3330
|
const state = new FileSystemGlobalState(persist, customPath);
|
|
3149
3331
|
const driverConfig = {
|
|
3150
3332
|
name: persist ? "file-system" : "memory",
|
|
@@ -3204,16 +3386,8 @@ function chooseDefaultDriver(runConfig) {
|
|
|
3204
3386
|
return createFileSystemOrMemoryDriver(true);
|
|
3205
3387
|
}
|
|
3206
3388
|
|
|
3207
|
-
// src/engine-process/mod.ts
|
|
3208
|
-
import { spawn } from "child_process";
|
|
3209
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
3210
|
-
import { createWriteStream } from "fs";
|
|
3211
|
-
import * as fs3 from "fs/promises";
|
|
3212
|
-
import * as path3 from "path";
|
|
3213
|
-
import { pipeline } from "stream/promises";
|
|
3214
|
-
|
|
3215
3389
|
// src/engine-process/log.ts
|
|
3216
|
-
function
|
|
3390
|
+
function logger5() {
|
|
3217
3391
|
return getLogger("engine-process");
|
|
3218
3392
|
}
|
|
3219
3393
|
|
|
@@ -3223,30 +3397,32 @@ var ENGINE_ENDPOINT = `http://localhost:${ENGINE_PORT}`;
|
|
|
3223
3397
|
var ENGINE_BASE_URL = "https://releases.rivet.gg/engine";
|
|
3224
3398
|
var ENGINE_BINARY_NAME = "rivet-engine";
|
|
3225
3399
|
async function ensureEngineProcess(options) {
|
|
3226
|
-
|
|
3400
|
+
importNodeDependencies();
|
|
3401
|
+
logger5().debug({
|
|
3227
3402
|
msg: "ensuring engine process",
|
|
3228
3403
|
version: options.version
|
|
3229
3404
|
});
|
|
3405
|
+
const path = getNodePath();
|
|
3230
3406
|
const storageRoot = getStoragePath();
|
|
3231
|
-
const binDir =
|
|
3232
|
-
const varDir =
|
|
3233
|
-
const logsDir =
|
|
3407
|
+
const binDir = path.join(storageRoot, "bin");
|
|
3408
|
+
const varDir = path.join(storageRoot, "var");
|
|
3409
|
+
const logsDir = path.join(varDir, "logs", "rivet-engine");
|
|
3234
3410
|
await ensureDirectoryExists(binDir);
|
|
3235
3411
|
await ensureDirectoryExists(varDir);
|
|
3236
3412
|
await ensureDirectoryExists(logsDir);
|
|
3237
3413
|
const executableName = process.platform === "win32" ? `${ENGINE_BINARY_NAME}-${options.version}.exe` : `${ENGINE_BINARY_NAME}-${options.version}`;
|
|
3238
|
-
const binaryPath =
|
|
3414
|
+
const binaryPath = path.join(binDir, executableName);
|
|
3239
3415
|
await downloadEngineBinaryIfNeeded(binaryPath, options.version, varDir);
|
|
3240
3416
|
if (await isEngineRunning()) {
|
|
3241
3417
|
try {
|
|
3242
3418
|
await waitForEngineHealth();
|
|
3243
|
-
|
|
3419
|
+
logger5().debug({
|
|
3244
3420
|
msg: "engine already running and healthy",
|
|
3245
3421
|
version: options.version
|
|
3246
3422
|
});
|
|
3247
3423
|
return;
|
|
3248
3424
|
} catch (error) {
|
|
3249
|
-
|
|
3425
|
+
logger5().warn({
|
|
3250
3426
|
msg: "existing engine process not healthy, cannot restart automatically",
|
|
3251
3427
|
error
|
|
3252
3428
|
});
|
|
@@ -3256,39 +3432,26 @@ async function ensureEngineProcess(options) {
|
|
|
3256
3432
|
}
|
|
3257
3433
|
}
|
|
3258
3434
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-").replace(/\./g, "-");
|
|
3259
|
-
const stdoutLogPath =
|
|
3260
|
-
const stderrLogPath =
|
|
3261
|
-
const
|
|
3262
|
-
const
|
|
3263
|
-
|
|
3435
|
+
const stdoutLogPath = path.join(logsDir, `engine-${timestamp}-stdout.log`);
|
|
3436
|
+
const stderrLogPath = path.join(logsDir, `engine-${timestamp}-stderr.log`);
|
|
3437
|
+
const fsSync = getNodeFsSync();
|
|
3438
|
+
const stdoutStream = fsSync.createWriteStream(stdoutLogPath, {
|
|
3439
|
+
flags: "a"
|
|
3440
|
+
});
|
|
3441
|
+
const stderrStream = fsSync.createWriteStream(stderrLogPath, {
|
|
3442
|
+
flags: "a"
|
|
3443
|
+
});
|
|
3444
|
+
logger5().debug({
|
|
3264
3445
|
msg: "creating engine log files",
|
|
3265
3446
|
stdout: stdoutLogPath,
|
|
3266
3447
|
stderr: stderrLogPath
|
|
3267
3448
|
});
|
|
3268
|
-
const
|
|
3269
|
-
|
|
3449
|
+
const childProcess = getNodeChildProcess();
|
|
3450
|
+
const child = childProcess.spawn(binaryPath, ["start"], {
|
|
3451
|
+
cwd: path.dirname(binaryPath),
|
|
3270
3452
|
stdio: ["inherit", "pipe", "pipe"],
|
|
3271
3453
|
env: {
|
|
3272
|
-
...process.env
|
|
3273
|
-
// In development, runners can be terminated without a graceful
|
|
3274
|
-
// shutdown (i.e. SIGKILL instead of SIGTERM). This is treated as a
|
|
3275
|
-
// crash by Rivet Engine in production and implements a backoff for
|
|
3276
|
-
// rescheduling actors in case of a crash loop.
|
|
3277
|
-
//
|
|
3278
|
-
// This is problematic in development since this will cause actors
|
|
3279
|
-
// to become unresponsive if frequently killing your dev server.
|
|
3280
|
-
//
|
|
3281
|
-
// We reduce the timeouts for resetting a runner as healthy in
|
|
3282
|
-
// order to account for this.
|
|
3283
|
-
RIVET__PEGBOARD__RETRY_RESET_DURATION: "100",
|
|
3284
|
-
RIVET__PEGBOARD__BASE_RETRY_TIMEOUT: "100",
|
|
3285
|
-
// Set max exponent to 1 to have a maximum of base_retry_timeout
|
|
3286
|
-
RIVET__PEGBOARD__RESCHEDULE_BACKOFF_MAX_EXPONENT: "1",
|
|
3287
|
-
// Reduce thresholds for faster development iteration
|
|
3288
|
-
//
|
|
3289
|
-
// Default ping interval is 3s, this gives a 2s & 4s grace
|
|
3290
|
-
RIVET__PEGBOARD__RUNNER_ELIGIBLE_THRESHOLD: "5000",
|
|
3291
|
-
RIVET__PEGBOARD__RUNNER_LOST_THRESHOLD: "7000"
|
|
3454
|
+
...process.env
|
|
3292
3455
|
}
|
|
3293
3456
|
});
|
|
3294
3457
|
if (!child.pid) {
|
|
@@ -3300,23 +3463,24 @@ async function ensureEngineProcess(options) {
|
|
|
3300
3463
|
if (child.stderr) {
|
|
3301
3464
|
child.stderr.pipe(stderrStream);
|
|
3302
3465
|
}
|
|
3303
|
-
|
|
3466
|
+
logger5().debug({
|
|
3304
3467
|
msg: "spawned engine process",
|
|
3305
3468
|
pid: child.pid,
|
|
3306
|
-
cwd:
|
|
3469
|
+
cwd: path.dirname(binaryPath)
|
|
3307
3470
|
});
|
|
3308
3471
|
child.once("exit", (code, signal) => {
|
|
3309
|
-
|
|
3472
|
+
logger5().warn({
|
|
3310
3473
|
msg: "engine process exited, please report this error",
|
|
3311
3474
|
code,
|
|
3312
3475
|
signal,
|
|
3313
|
-
|
|
3476
|
+
issues: "https://github.com/rivet-dev/rivetkit/issues",
|
|
3477
|
+
support: "https://rivet.dev/discord"
|
|
3314
3478
|
});
|
|
3315
3479
|
stdoutStream.end();
|
|
3316
3480
|
stderrStream.end();
|
|
3317
3481
|
});
|
|
3318
3482
|
child.once("error", (error) => {
|
|
3319
|
-
|
|
3483
|
+
logger5().error({
|
|
3320
3484
|
msg: "engine process failed",
|
|
3321
3485
|
error
|
|
3322
3486
|
});
|
|
@@ -3324,7 +3488,7 @@ async function ensureEngineProcess(options) {
|
|
|
3324
3488
|
stderrStream.end();
|
|
3325
3489
|
});
|
|
3326
3490
|
await waitForEngineHealth();
|
|
3327
|
-
|
|
3491
|
+
logger5().info({
|
|
3328
3492
|
msg: "engine process started",
|
|
3329
3493
|
pid: child.pid,
|
|
3330
3494
|
version: options.version,
|
|
@@ -3337,7 +3501,7 @@ async function ensureEngineProcess(options) {
|
|
|
3337
3501
|
async function downloadEngineBinaryIfNeeded(binaryPath, version, varDir) {
|
|
3338
3502
|
const binaryExists = await fileExists(binaryPath);
|
|
3339
3503
|
if (binaryExists) {
|
|
3340
|
-
|
|
3504
|
+
logger5().debug({
|
|
3341
3505
|
msg: "engine binary already cached",
|
|
3342
3506
|
version,
|
|
3343
3507
|
path: binaryPath
|
|
@@ -3347,7 +3511,7 @@ async function downloadEngineBinaryIfNeeded(binaryPath, version, varDir) {
|
|
|
3347
3511
|
const { targetTriplet, extension } = resolveTargetTriplet();
|
|
3348
3512
|
const remoteFile = `${ENGINE_BINARY_NAME}-${targetTriplet}${extension}`;
|
|
3349
3513
|
const downloadUrl = `${ENGINE_BASE_URL}/${version}/${remoteFile}`;
|
|
3350
|
-
|
|
3514
|
+
logger5().info({
|
|
3351
3515
|
msg: "downloading engine binary",
|
|
3352
3516
|
url: downloadUrl,
|
|
3353
3517
|
path: binaryPath,
|
|
@@ -3359,50 +3523,59 @@ async function downloadEngineBinaryIfNeeded(binaryPath, version, varDir) {
|
|
|
3359
3523
|
`failed to download rivet engine binary from ${downloadUrl}: ${response.status} ${response.statusText}`
|
|
3360
3524
|
);
|
|
3361
3525
|
}
|
|
3362
|
-
const
|
|
3526
|
+
const crypto2 = getNodeCrypto();
|
|
3527
|
+
const tempPath = `${binaryPath}.${crypto2.randomUUID()}.tmp`;
|
|
3363
3528
|
const startTime = Date.now();
|
|
3364
|
-
|
|
3529
|
+
logger5().debug({
|
|
3365
3530
|
msg: "starting binary download",
|
|
3366
3531
|
tempPath,
|
|
3367
3532
|
contentLength: response.headers.get("content-length")
|
|
3368
3533
|
});
|
|
3369
3534
|
const slowDownloadWarning = setTimeout(() => {
|
|
3370
|
-
|
|
3535
|
+
logger5().warn({
|
|
3371
3536
|
msg: "engine binary download is taking longer than expected, please be patient",
|
|
3372
3537
|
version
|
|
3373
3538
|
});
|
|
3374
3539
|
}, 5e3);
|
|
3375
3540
|
try {
|
|
3376
|
-
|
|
3541
|
+
const stream = getNodeStream();
|
|
3542
|
+
const fsSync = getNodeFsSync();
|
|
3543
|
+
await stream.pipeline(
|
|
3544
|
+
response.body,
|
|
3545
|
+
fsSync.createWriteStream(tempPath)
|
|
3546
|
+
);
|
|
3377
3547
|
clearTimeout(slowDownloadWarning);
|
|
3378
|
-
const
|
|
3548
|
+
const fs = getNodeFs();
|
|
3549
|
+
const stats = await fs.stat(tempPath);
|
|
3379
3550
|
const downloadDuration = Date.now() - startTime;
|
|
3380
3551
|
if (process.platform !== "win32") {
|
|
3381
|
-
await
|
|
3552
|
+
await fs.chmod(tempPath, 493);
|
|
3382
3553
|
}
|
|
3383
|
-
await
|
|
3384
|
-
|
|
3554
|
+
await fs.rename(tempPath, binaryPath);
|
|
3555
|
+
logger5().debug({
|
|
3385
3556
|
msg: "engine binary download complete",
|
|
3386
3557
|
version,
|
|
3387
3558
|
path: binaryPath,
|
|
3388
3559
|
size: stats.size,
|
|
3389
3560
|
durationMs: downloadDuration
|
|
3390
3561
|
});
|
|
3391
|
-
|
|
3562
|
+
logger5().info({
|
|
3392
3563
|
msg: "engine binary downloaded",
|
|
3393
3564
|
version,
|
|
3394
3565
|
path: binaryPath
|
|
3395
3566
|
});
|
|
3396
3567
|
} catch (error) {
|
|
3397
3568
|
clearTimeout(slowDownloadWarning);
|
|
3398
|
-
|
|
3569
|
+
logger5().warn({
|
|
3399
3570
|
msg: "engine download failed, please report this error",
|
|
3400
3571
|
tempPath,
|
|
3401
3572
|
error,
|
|
3402
|
-
|
|
3573
|
+
issues: "https://github.com/rivet-dev/rivetkit/issues",
|
|
3574
|
+
support: "https://rivet.dev/discord"
|
|
3403
3575
|
});
|
|
3404
3576
|
try {
|
|
3405
|
-
|
|
3577
|
+
const fs = getNodeFs();
|
|
3578
|
+
await fs.unlink(tempPath);
|
|
3406
3579
|
} catch (unlinkError) {
|
|
3407
3580
|
}
|
|
3408
3581
|
throw error;
|
|
@@ -3455,13 +3628,13 @@ async function checkIfEngineAlreadyRunningOnPort(port) {
|
|
|
3455
3628
|
if (response.ok) {
|
|
3456
3629
|
const health = await response.json();
|
|
3457
3630
|
if (health.runtime === "engine") {
|
|
3458
|
-
|
|
3631
|
+
logger5().debug({
|
|
3459
3632
|
msg: "rivet engine already running on port",
|
|
3460
3633
|
port
|
|
3461
3634
|
});
|
|
3462
3635
|
return true;
|
|
3463
3636
|
} else if (health.runtime === "rivetkit") {
|
|
3464
|
-
|
|
3637
|
+
logger5().error({
|
|
3465
3638
|
msg: "another rivetkit process is already running on port",
|
|
3466
3639
|
port
|
|
3467
3640
|
});
|
|
@@ -3478,7 +3651,8 @@ async function checkIfEngineAlreadyRunningOnPort(port) {
|
|
|
3478
3651
|
}
|
|
3479
3652
|
async function fileExists(filePath) {
|
|
3480
3653
|
try {
|
|
3481
|
-
|
|
3654
|
+
const fs = getNodeFs();
|
|
3655
|
+
await fs.access(filePath);
|
|
3482
3656
|
return true;
|
|
3483
3657
|
} catch {
|
|
3484
3658
|
return false;
|
|
@@ -3488,12 +3662,12 @@ var HEALTH_MAX_WAIT = 1e4;
|
|
|
3488
3662
|
var HEALTH_INTERVAL = 100;
|
|
3489
3663
|
async function waitForEngineHealth() {
|
|
3490
3664
|
const maxRetries = Math.ceil(HEALTH_MAX_WAIT / HEALTH_INTERVAL);
|
|
3491
|
-
|
|
3665
|
+
logger5().debug({ msg: "waiting for engine health check" });
|
|
3492
3666
|
for (let i = 0; i < maxRetries; i++) {
|
|
3493
3667
|
try {
|
|
3494
3668
|
const response = await fetch(`${ENGINE_ENDPOINT}/health`);
|
|
3495
3669
|
if (response.ok) {
|
|
3496
|
-
|
|
3670
|
+
logger5().debug({ msg: "engine health check passed" });
|
|
3497
3671
|
return;
|
|
3498
3672
|
}
|
|
3499
3673
|
} catch (error) {
|
|
@@ -3504,7 +3678,7 @@ async function waitForEngineHealth() {
|
|
|
3504
3678
|
}
|
|
3505
3679
|
}
|
|
3506
3680
|
if (i < maxRetries - 1) {
|
|
3507
|
-
|
|
3681
|
+
logger5().trace({
|
|
3508
3682
|
msg: "engine not ready, retrying",
|
|
3509
3683
|
attempt: i + 1,
|
|
3510
3684
|
maxRetries
|
|
@@ -3579,6 +3753,9 @@ var ActorSchema = z4.object({
|
|
|
3579
3753
|
sleep_ts: z4.number().nullable().optional(),
|
|
3580
3754
|
start_ts: z4.number().nullable().optional()
|
|
3581
3755
|
});
|
|
3756
|
+
var ActorNameSchema = z4.object({
|
|
3757
|
+
metadata: z4.record(z4.string(), z4.unknown())
|
|
3758
|
+
});
|
|
3582
3759
|
var ActorsListResponseSchema = z4.object({
|
|
3583
3760
|
actors: z4.array(ActorSchema)
|
|
3584
3761
|
});
|
|
@@ -3606,6 +3783,14 @@ var ActorsGetOrCreateResponseSchema = z4.object({
|
|
|
3606
3783
|
created: z4.boolean()
|
|
3607
3784
|
});
|
|
3608
3785
|
var ActorsDeleteResponseSchema = z4.object({});
|
|
3786
|
+
var ActorsListNamesResponseSchema = z4.object({
|
|
3787
|
+
names: z4.record(z4.string(), ActorNameSchema)
|
|
3788
|
+
});
|
|
3789
|
+
|
|
3790
|
+
// src/manager/log.ts
|
|
3791
|
+
function logger6() {
|
|
3792
|
+
return getLogger("actor-manager");
|
|
3793
|
+
}
|
|
3609
3794
|
|
|
3610
3795
|
// src/manager/gateway.ts
|
|
3611
3796
|
async function handleWebSocketGatewayPathBased(runConfig, managerDriver, c, actorPathInfo) {
|
|
@@ -3617,8 +3802,6 @@ async function handleWebSocketGatewayPathBased(runConfig, managerDriver, c, acto
|
|
|
3617
3802
|
const protocols = c.req.header("sec-websocket-protocol");
|
|
3618
3803
|
let encodingRaw;
|
|
3619
3804
|
let connParamsRaw;
|
|
3620
|
-
let connIdRaw;
|
|
3621
|
-
let connTokenRaw;
|
|
3622
3805
|
if (protocols) {
|
|
3623
3806
|
const protocolList = protocols.split(",").map((p) => p.trim());
|
|
3624
3807
|
for (const protocol of protocolList) {
|
|
@@ -3628,16 +3811,10 @@ async function handleWebSocketGatewayPathBased(runConfig, managerDriver, c, acto
|
|
|
3628
3811
|
connParamsRaw = decodeURIComponent(
|
|
3629
3812
|
protocol.substring(WS_PROTOCOL_CONN_PARAMS.length)
|
|
3630
3813
|
);
|
|
3631
|
-
} else if (protocol.startsWith(WS_PROTOCOL_CONN_ID)) {
|
|
3632
|
-
connIdRaw = protocol.substring(WS_PROTOCOL_CONN_ID.length);
|
|
3633
|
-
} else if (protocol.startsWith(WS_PROTOCOL_CONN_TOKEN)) {
|
|
3634
|
-
connTokenRaw = protocol.substring(
|
|
3635
|
-
WS_PROTOCOL_CONN_TOKEN.length
|
|
3636
|
-
);
|
|
3637
3814
|
}
|
|
3638
3815
|
}
|
|
3639
3816
|
}
|
|
3640
|
-
|
|
3817
|
+
logger6().debug({
|
|
3641
3818
|
msg: "proxying websocket to actor via path-based routing",
|
|
3642
3819
|
actorId: actorPathInfo.actorId,
|
|
3643
3820
|
path: actorPathInfo.remainingPath,
|
|
@@ -3651,13 +3828,11 @@ async function handleWebSocketGatewayPathBased(runConfig, managerDriver, c, acto
|
|
|
3651
3828
|
actorPathInfo.actorId,
|
|
3652
3829
|
encoding,
|
|
3653
3830
|
// Will be validated by driver
|
|
3654
|
-
connParams
|
|
3655
|
-
connIdRaw,
|
|
3656
|
-
connTokenRaw
|
|
3831
|
+
connParams
|
|
3657
3832
|
);
|
|
3658
3833
|
}
|
|
3659
3834
|
async function handleHttpGatewayPathBased(managerDriver, c, actorPathInfo) {
|
|
3660
|
-
|
|
3835
|
+
logger6().debug({
|
|
3661
3836
|
msg: "proxying request to actor via path-based routing",
|
|
3662
3837
|
actorId: actorPathInfo.actorId,
|
|
3663
3838
|
path: actorPathInfo.remainingPath,
|
|
@@ -3692,7 +3867,7 @@ async function actorGateway(runConfig, managerDriver, c, next) {
|
|
|
3692
3867
|
const pathWithQuery = c.req.url.includes("?") ? strippedPath + c.req.url.substring(c.req.url.indexOf("?")) : strippedPath;
|
|
3693
3868
|
const actorPathInfo = parseActorPath(pathWithQuery);
|
|
3694
3869
|
if (actorPathInfo) {
|
|
3695
|
-
|
|
3870
|
+
logger6().debug({
|
|
3696
3871
|
msg: "routing using path-based actor routing",
|
|
3697
3872
|
actorPathInfo
|
|
3698
3873
|
});
|
|
@@ -3732,27 +3907,19 @@ async function handleWebSocketGateway(runConfig, managerDriver, c, strippedPath)
|
|
|
3732
3907
|
let actorId;
|
|
3733
3908
|
let encodingRaw;
|
|
3734
3909
|
let connParamsRaw;
|
|
3735
|
-
let connIdRaw;
|
|
3736
|
-
let connTokenRaw;
|
|
3737
3910
|
if (protocols) {
|
|
3738
3911
|
const protocolList = protocols.split(",").map((p) => p.trim());
|
|
3739
3912
|
for (const protocol of protocolList) {
|
|
3740
3913
|
if (protocol.startsWith(WS_PROTOCOL_TARGET)) {
|
|
3741
3914
|
target = protocol.substring(WS_PROTOCOL_TARGET.length);
|
|
3742
3915
|
} else if (protocol.startsWith(WS_PROTOCOL_ACTOR)) {
|
|
3743
|
-
actorId = protocol.substring(WS_PROTOCOL_ACTOR.length);
|
|
3916
|
+
actorId = decodeURIComponent(protocol.substring(WS_PROTOCOL_ACTOR.length));
|
|
3744
3917
|
} else if (protocol.startsWith(WS_PROTOCOL_ENCODING)) {
|
|
3745
3918
|
encodingRaw = protocol.substring(WS_PROTOCOL_ENCODING.length);
|
|
3746
3919
|
} else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {
|
|
3747
3920
|
connParamsRaw = decodeURIComponent(
|
|
3748
3921
|
protocol.substring(WS_PROTOCOL_CONN_PARAMS.length)
|
|
3749
3922
|
);
|
|
3750
|
-
} else if (protocol.startsWith(WS_PROTOCOL_CONN_ID)) {
|
|
3751
|
-
connIdRaw = protocol.substring(WS_PROTOCOL_CONN_ID.length);
|
|
3752
|
-
} else if (protocol.startsWith(WS_PROTOCOL_CONN_TOKEN)) {
|
|
3753
|
-
connTokenRaw = protocol.substring(
|
|
3754
|
-
WS_PROTOCOL_CONN_TOKEN.length
|
|
3755
|
-
);
|
|
3756
3923
|
}
|
|
3757
3924
|
}
|
|
3758
3925
|
}
|
|
@@ -3762,7 +3929,7 @@ async function handleWebSocketGateway(runConfig, managerDriver, c, strippedPath)
|
|
|
3762
3929
|
if (!actorId) {
|
|
3763
3930
|
throw new MissingActorHeader();
|
|
3764
3931
|
}
|
|
3765
|
-
|
|
3932
|
+
logger6().debug({
|
|
3766
3933
|
msg: "proxying websocket to actor",
|
|
3767
3934
|
actorId,
|
|
3768
3935
|
path: strippedPath,
|
|
@@ -3777,9 +3944,7 @@ async function handleWebSocketGateway(runConfig, managerDriver, c, strippedPath)
|
|
|
3777
3944
|
actorId,
|
|
3778
3945
|
encoding,
|
|
3779
3946
|
// Will be validated by driver
|
|
3780
|
-
connParams
|
|
3781
|
-
connIdRaw,
|
|
3782
|
-
connTokenRaw
|
|
3947
|
+
connParams
|
|
3783
3948
|
);
|
|
3784
3949
|
}
|
|
3785
3950
|
async function handleHttpGateway(managerDriver, c, next, strippedPath) {
|
|
@@ -3791,7 +3956,7 @@ async function handleHttpGateway(managerDriver, c, next, strippedPath) {
|
|
|
3791
3956
|
if (!actorId) {
|
|
3792
3957
|
throw new MissingActorHeader();
|
|
3793
3958
|
}
|
|
3794
|
-
|
|
3959
|
+
logger6().debug({
|
|
3795
3960
|
msg: "proxying request to actor",
|
|
3796
3961
|
actorId,
|
|
3797
3962
|
path: strippedPath,
|
|
@@ -3811,22 +3976,22 @@ async function handleHttpGateway(managerDriver, c, next, strippedPath) {
|
|
|
3811
3976
|
});
|
|
3812
3977
|
return await managerDriver.proxyRequest(c, proxyRequest, actorId);
|
|
3813
3978
|
}
|
|
3814
|
-
function parseActorPath(
|
|
3815
|
-
const queryPos =
|
|
3816
|
-
const fragmentPos =
|
|
3979
|
+
function parseActorPath(path) {
|
|
3980
|
+
const queryPos = path.indexOf("?");
|
|
3981
|
+
const fragmentPos = path.indexOf("#");
|
|
3817
3982
|
let queryString = "";
|
|
3818
3983
|
if (queryPos !== -1) {
|
|
3819
3984
|
if (fragmentPos !== -1 && queryPos < fragmentPos) {
|
|
3820
|
-
queryString =
|
|
3985
|
+
queryString = path.slice(queryPos, fragmentPos);
|
|
3821
3986
|
} else {
|
|
3822
|
-
queryString =
|
|
3987
|
+
queryString = path.slice(queryPos);
|
|
3823
3988
|
}
|
|
3824
3989
|
}
|
|
3825
|
-
let basePath =
|
|
3990
|
+
let basePath = path;
|
|
3826
3991
|
if (queryPos !== -1) {
|
|
3827
|
-
basePath =
|
|
3992
|
+
basePath = path.slice(0, queryPos);
|
|
3828
3993
|
} else if (fragmentPos !== -1) {
|
|
3829
|
-
basePath =
|
|
3994
|
+
basePath = path.slice(0, fragmentPos);
|
|
3830
3995
|
}
|
|
3831
3996
|
if (basePath.includes("//")) {
|
|
3832
3997
|
return null;
|
|
@@ -3895,22 +4060,22 @@ async function createTestWebSocketProxy(clientWsPromise) {
|
|
|
3895
4060
|
reject: serverWsReject
|
|
3896
4061
|
} = promiseWithResolvers();
|
|
3897
4062
|
try {
|
|
3898
|
-
|
|
4063
|
+
logger6().debug({ msg: "awaiting client websocket promise" });
|
|
3899
4064
|
const ws = await clientWsPromise;
|
|
3900
4065
|
clientWs = ws;
|
|
3901
|
-
|
|
4066
|
+
logger6().debug({
|
|
3902
4067
|
msg: "client websocket promise resolved",
|
|
3903
4068
|
constructor: ws == null ? void 0 : ws.constructor.name
|
|
3904
4069
|
});
|
|
3905
4070
|
await new Promise((resolve, reject) => {
|
|
3906
4071
|
const onOpen = () => {
|
|
3907
|
-
|
|
4072
|
+
logger6().debug({
|
|
3908
4073
|
msg: "test websocket connection to actor opened"
|
|
3909
4074
|
});
|
|
3910
4075
|
resolve();
|
|
3911
4076
|
};
|
|
3912
4077
|
const onError = (error) => {
|
|
3913
|
-
|
|
4078
|
+
logger6().error({
|
|
3914
4079
|
msg: "test websocket connection failed",
|
|
3915
4080
|
error
|
|
3916
4081
|
});
|
|
@@ -3926,7 +4091,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
|
|
|
3926
4091
|
ws.addEventListener("message", async (clientEvt) => {
|
|
3927
4092
|
var _a, _b;
|
|
3928
4093
|
const serverWs = await serverWsPromise;
|
|
3929
|
-
|
|
4094
|
+
logger6().debug({
|
|
3930
4095
|
msg: `test websocket connection message from client`,
|
|
3931
4096
|
dataType: typeof clientEvt.data,
|
|
3932
4097
|
isBlob: clientEvt.data instanceof Blob,
|
|
@@ -3937,19 +4102,19 @@ async function createTestWebSocketProxy(clientWsPromise) {
|
|
|
3937
4102
|
if (serverWs.readyState === 1) {
|
|
3938
4103
|
if (clientEvt.data instanceof Blob) {
|
|
3939
4104
|
clientEvt.data.arrayBuffer().then((buffer) => {
|
|
3940
|
-
|
|
4105
|
+
logger6().debug({
|
|
3941
4106
|
msg: "converted client blob to arraybuffer, sending to server",
|
|
3942
4107
|
bufferSize: buffer.byteLength
|
|
3943
4108
|
});
|
|
3944
4109
|
serverWs.send(buffer);
|
|
3945
4110
|
}).catch((error) => {
|
|
3946
|
-
|
|
4111
|
+
logger6().error({
|
|
3947
4112
|
msg: "failed to convert blob to arraybuffer",
|
|
3948
4113
|
error
|
|
3949
4114
|
});
|
|
3950
4115
|
});
|
|
3951
4116
|
} else {
|
|
3952
|
-
|
|
4117
|
+
logger6().debug({
|
|
3953
4118
|
msg: "sending client data directly to server",
|
|
3954
4119
|
dataType: typeof clientEvt.data,
|
|
3955
4120
|
dataLength: typeof clientEvt.data === "string" ? clientEvt.data.length : void 0
|
|
@@ -3960,7 +4125,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
|
|
|
3960
4125
|
});
|
|
3961
4126
|
ws.addEventListener("close", async (clientEvt) => {
|
|
3962
4127
|
const serverWs = await serverWsPromise;
|
|
3963
|
-
|
|
4128
|
+
logger6().debug({
|
|
3964
4129
|
msg: `test websocket connection closed`
|
|
3965
4130
|
});
|
|
3966
4131
|
if (serverWs.readyState !== 3) {
|
|
@@ -3969,7 +4134,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
|
|
|
3969
4134
|
});
|
|
3970
4135
|
ws.addEventListener("error", async () => {
|
|
3971
4136
|
const serverWs = await serverWsPromise;
|
|
3972
|
-
|
|
4137
|
+
logger6().debug({
|
|
3973
4138
|
msg: `test websocket connection error`
|
|
3974
4139
|
});
|
|
3975
4140
|
if (serverWs.readyState !== 3) {
|
|
@@ -3978,7 +4143,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
|
|
|
3978
4143
|
});
|
|
3979
4144
|
});
|
|
3980
4145
|
} catch (error) {
|
|
3981
|
-
|
|
4146
|
+
logger6().error({
|
|
3982
4147
|
msg: `failed to establish client websocket connection`,
|
|
3983
4148
|
error
|
|
3984
4149
|
});
|
|
@@ -3996,10 +4161,10 @@ async function createTestWebSocketProxy(clientWsPromise) {
|
|
|
3996
4161
|
}
|
|
3997
4162
|
return {
|
|
3998
4163
|
onOpen: (_evt, serverWs) => {
|
|
3999
|
-
|
|
4164
|
+
logger6().debug({
|
|
4000
4165
|
msg: `test websocket connection from client opened`
|
|
4001
4166
|
});
|
|
4002
|
-
|
|
4167
|
+
logger6().debug({
|
|
4003
4168
|
msg: "clientWs info",
|
|
4004
4169
|
constructor: clientWs.constructor.name,
|
|
4005
4170
|
hasAddEventListener: typeof clientWs.addEventListener === "function",
|
|
@@ -4009,7 +4174,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
|
|
|
4009
4174
|
},
|
|
4010
4175
|
onMessage: (evt) => {
|
|
4011
4176
|
var _a, _b;
|
|
4012
|
-
|
|
4177
|
+
logger6().debug({
|
|
4013
4178
|
msg: "received message from server",
|
|
4014
4179
|
dataType: typeof evt.data,
|
|
4015
4180
|
isBlob: evt.data instanceof Blob,
|
|
@@ -4020,19 +4185,19 @@ async function createTestWebSocketProxy(clientWsPromise) {
|
|
|
4020
4185
|
if (clientWs.readyState === 1) {
|
|
4021
4186
|
if (evt.data instanceof Blob) {
|
|
4022
4187
|
evt.data.arrayBuffer().then((buffer) => {
|
|
4023
|
-
|
|
4188
|
+
logger6().debug({
|
|
4024
4189
|
msg: "converted blob to arraybuffer, sending",
|
|
4025
4190
|
bufferSize: buffer.byteLength
|
|
4026
4191
|
});
|
|
4027
4192
|
clientWs.send(buffer);
|
|
4028
4193
|
}).catch((error) => {
|
|
4029
|
-
|
|
4194
|
+
logger6().error({
|
|
4030
4195
|
msg: "failed to convert blob to arraybuffer",
|
|
4031
4196
|
error
|
|
4032
4197
|
});
|
|
4033
4198
|
});
|
|
4034
4199
|
} else {
|
|
4035
|
-
|
|
4200
|
+
logger6().debug({
|
|
4036
4201
|
msg: "sending data directly",
|
|
4037
4202
|
dataType: typeof evt.data,
|
|
4038
4203
|
dataLength: typeof evt.data === "string" ? evt.data.length : void 0
|
|
@@ -4042,7 +4207,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
|
|
|
4042
4207
|
}
|
|
4043
4208
|
},
|
|
4044
4209
|
onClose: (event, serverWs) => {
|
|
4045
|
-
|
|
4210
|
+
logger6().debug({
|
|
4046
4211
|
msg: `server websocket closed`,
|
|
4047
4212
|
wasClean: event.wasClean,
|
|
4048
4213
|
code: event.code,
|
|
@@ -4054,7 +4219,7 @@ async function createTestWebSocketProxy(clientWsPromise) {
|
|
|
4054
4219
|
}
|
|
4055
4220
|
},
|
|
4056
4221
|
onError: (error) => {
|
|
4057
|
-
|
|
4222
|
+
logger6().error({
|
|
4058
4223
|
msg: `error in server websocket`,
|
|
4059
4224
|
error
|
|
4060
4225
|
});
|
|
@@ -4103,11 +4268,21 @@ function buildOpenApiResponses(schema) {
|
|
|
4103
4268
|
}
|
|
4104
4269
|
};
|
|
4105
4270
|
}
|
|
4271
|
+
function buildOpenApiRequestBody(schema) {
|
|
4272
|
+
return {
|
|
4273
|
+
required: true,
|
|
4274
|
+
content: {
|
|
4275
|
+
"application/json": {
|
|
4276
|
+
schema
|
|
4277
|
+
}
|
|
4278
|
+
}
|
|
4279
|
+
};
|
|
4280
|
+
}
|
|
4106
4281
|
function createManagerRouter(registryConfig, runConfig, managerDriver, driverConfig, client) {
|
|
4107
4282
|
const router = new OpenAPIHono({ strict: false }).basePath(
|
|
4108
4283
|
runConfig.basePath
|
|
4109
4284
|
);
|
|
4110
|
-
router.use("*", loggerMiddleware(
|
|
4285
|
+
router.use("*", loggerMiddleware(logger6()), cors());
|
|
4111
4286
|
router.use(
|
|
4112
4287
|
"*",
|
|
4113
4288
|
createMiddleware(async (c, next) => {
|
|
@@ -4159,7 +4334,7 @@ function addServerlessRoutes(driverConfig, registryConfig, runConfig, managerDri
|
|
|
4159
4334
|
);
|
|
4160
4335
|
}
|
|
4161
4336
|
const { endpoint, token, totalSlots, runnerName, namespace } = parseResult.data;
|
|
4162
|
-
|
|
4337
|
+
logger6().debug({
|
|
4163
4338
|
msg: "received serverless runner start request",
|
|
4164
4339
|
endpoint,
|
|
4165
4340
|
totalSlots,
|
|
@@ -4173,7 +4348,7 @@ function addServerlessRoutes(driverConfig, registryConfig, runConfig, managerDri
|
|
|
4173
4348
|
newRunConfig.runnerName = runnerName;
|
|
4174
4349
|
newRunConfig.namespace = namespace;
|
|
4175
4350
|
if (newRunConfig.runnerKey) {
|
|
4176
|
-
|
|
4351
|
+
logger6().warn({
|
|
4177
4352
|
msg: "runner keys are not supported by serverless runners, this will be overwritten with a random runner key",
|
|
4178
4353
|
oldRunnerKey: newRunConfig.runnerKey
|
|
4179
4354
|
});
|
|
@@ -4245,15 +4420,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
|
|
|
4245
4420
|
if (key && !name) {
|
|
4246
4421
|
return c.json(
|
|
4247
4422
|
{
|
|
4248
|
-
error: "
|
|
4249
|
-
},
|
|
4250
|
-
400
|
|
4251
|
-
);
|
|
4252
|
-
}
|
|
4253
|
-
if (!actorIdsParsed && !key) {
|
|
4254
|
-
return c.json(
|
|
4255
|
-
{
|
|
4256
|
-
error: "Must provide either 'actor_ids' or both 'name' and 'key'."
|
|
4423
|
+
error: "Name is required when key is provided."
|
|
4257
4424
|
},
|
|
4258
4425
|
400
|
|
4259
4426
|
);
|
|
@@ -4298,7 +4465,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
|
|
|
4298
4465
|
}
|
|
4299
4466
|
}
|
|
4300
4467
|
}
|
|
4301
|
-
} else if (key) {
|
|
4468
|
+
} else if (key && name) {
|
|
4302
4469
|
const actorOutput = await managerDriver.getWithKey({
|
|
4303
4470
|
c,
|
|
4304
4471
|
name,
|
|
@@ -4308,6 +4475,22 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
|
|
|
4308
4475
|
if (actorOutput) {
|
|
4309
4476
|
actors.push(actorOutput);
|
|
4310
4477
|
}
|
|
4478
|
+
} else {
|
|
4479
|
+
if (!name) {
|
|
4480
|
+
return c.json(
|
|
4481
|
+
{
|
|
4482
|
+
error: "Name is required when not using actor_ids."
|
|
4483
|
+
},
|
|
4484
|
+
400
|
|
4485
|
+
);
|
|
4486
|
+
}
|
|
4487
|
+
const actorOutputs = await managerDriver.listActors({
|
|
4488
|
+
c,
|
|
4489
|
+
name,
|
|
4490
|
+
key,
|
|
4491
|
+
includeDestroyed: false
|
|
4492
|
+
});
|
|
4493
|
+
actors.push(...actorOutputs);
|
|
4311
4494
|
}
|
|
4312
4495
|
return c.json({
|
|
4313
4496
|
actors: actors.map(
|
|
@@ -4316,18 +4499,30 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
|
|
|
4316
4499
|
});
|
|
4317
4500
|
});
|
|
4318
4501
|
}
|
|
4502
|
+
{
|
|
4503
|
+
const route = createRoute({
|
|
4504
|
+
method: "get",
|
|
4505
|
+
path: "/actors/names",
|
|
4506
|
+
request: {
|
|
4507
|
+
query: z6.object({
|
|
4508
|
+
namespace: z6.string()
|
|
4509
|
+
})
|
|
4510
|
+
},
|
|
4511
|
+
responses: buildOpenApiResponses(ActorsListNamesResponseSchema)
|
|
4512
|
+
});
|
|
4513
|
+
router.openapi(route, async (c) => {
|
|
4514
|
+
const names = buildActorNames(registryConfig);
|
|
4515
|
+
return c.json({
|
|
4516
|
+
names
|
|
4517
|
+
});
|
|
4518
|
+
});
|
|
4519
|
+
}
|
|
4319
4520
|
{
|
|
4320
4521
|
const route = createRoute({
|
|
4321
4522
|
method: "put",
|
|
4322
4523
|
path: "/actors",
|
|
4323
4524
|
request: {
|
|
4324
|
-
body:
|
|
4325
|
-
content: {
|
|
4326
|
-
"application/json": {
|
|
4327
|
-
schema: ActorsGetOrCreateRequestSchema
|
|
4328
|
-
}
|
|
4329
|
-
}
|
|
4330
|
-
}
|
|
4525
|
+
body: buildOpenApiRequestBody(ActorsGetOrCreateRequestSchema)
|
|
4331
4526
|
},
|
|
4332
4527
|
responses: buildOpenApiResponses(ActorsGetOrCreateResponseSchema)
|
|
4333
4528
|
});
|
|
@@ -4365,13 +4560,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
|
|
|
4365
4560
|
method: "post",
|
|
4366
4561
|
path: "/actors",
|
|
4367
4562
|
request: {
|
|
4368
|
-
body:
|
|
4369
|
-
content: {
|
|
4370
|
-
"application/json": {
|
|
4371
|
-
schema: ActorsCreateRequestSchema
|
|
4372
|
-
}
|
|
4373
|
-
}
|
|
4374
|
-
}
|
|
4563
|
+
body: buildOpenApiRequestBody(ActorsCreateRequestSchema)
|
|
4375
4564
|
},
|
|
4376
4565
|
responses: buildOpenApiResponses(ActorsCreateResponseSchema)
|
|
4377
4566
|
});
|
|
@@ -4393,18 +4582,10 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
|
|
|
4393
4582
|
if (registryConfig.test.enabled) {
|
|
4394
4583
|
router.post(".test/inline-driver/call", async (c) => {
|
|
4395
4584
|
const buffer = await c.req.arrayBuffer();
|
|
4396
|
-
const {
|
|
4397
|
-
|
|
4398
|
-
transport,
|
|
4399
|
-
method,
|
|
4400
|
-
args
|
|
4401
|
-
} = cbor4.decode(
|
|
4402
|
-
new Uint8Array(buffer)
|
|
4403
|
-
);
|
|
4404
|
-
logger().debug({
|
|
4585
|
+
const { encoding, method, args } = cbor4.decode(new Uint8Array(buffer));
|
|
4586
|
+
logger6().debug({
|
|
4405
4587
|
msg: "received inline request",
|
|
4406
4588
|
encoding,
|
|
4407
|
-
transport,
|
|
4408
4589
|
method,
|
|
4409
4590
|
args
|
|
4410
4591
|
});
|
|
@@ -4415,7 +4596,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
|
|
|
4415
4596
|
);
|
|
4416
4597
|
response = { ok: output };
|
|
4417
4598
|
} catch (rawErr) {
|
|
4418
|
-
const err = deconstructError(rawErr,
|
|
4599
|
+
const err = deconstructError(rawErr, logger6(), {}, true);
|
|
4419
4600
|
response = { err };
|
|
4420
4601
|
}
|
|
4421
4602
|
return c.body(cbor4.encode(response));
|
|
@@ -4432,54 +4613,38 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
|
|
|
4432
4613
|
const protocols = protocolHeader.split(/,\s*/);
|
|
4433
4614
|
let actorId = "";
|
|
4434
4615
|
let encoding = "bare";
|
|
4435
|
-
let
|
|
4436
|
-
let path4 = "";
|
|
4616
|
+
let path = "";
|
|
4437
4617
|
let params;
|
|
4438
|
-
let connId;
|
|
4439
|
-
let connToken;
|
|
4440
4618
|
for (const protocol of protocols) {
|
|
4441
4619
|
if (protocol.startsWith(WS_PROTOCOL_ACTOR)) {
|
|
4442
|
-
actorId = protocol.substring(WS_PROTOCOL_ACTOR.length);
|
|
4620
|
+
actorId = decodeURIComponent(protocol.substring(WS_PROTOCOL_ACTOR.length));
|
|
4443
4621
|
} else if (protocol.startsWith(WS_PROTOCOL_ENCODING)) {
|
|
4444
4622
|
encoding = protocol.substring(
|
|
4445
4623
|
WS_PROTOCOL_ENCODING.length
|
|
4446
4624
|
);
|
|
4447
|
-
} else if (protocol.startsWith(
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
);
|
|
4451
|
-
} else if (protocol.startsWith(WS_PROTOCOL_PATH)) {
|
|
4452
|
-
path4 = decodeURIComponent(
|
|
4453
|
-
protocol.substring(WS_PROTOCOL_PATH.length)
|
|
4625
|
+
} else if (protocol.startsWith(WS_TEST_PROTOCOL_PATH)) {
|
|
4626
|
+
path = decodeURIComponent(
|
|
4627
|
+
protocol.substring(WS_TEST_PROTOCOL_PATH.length)
|
|
4454
4628
|
);
|
|
4455
4629
|
} else if (protocol.startsWith(WS_PROTOCOL_CONN_PARAMS)) {
|
|
4456
4630
|
const paramsRaw = decodeURIComponent(
|
|
4457
4631
|
protocol.substring(WS_PROTOCOL_CONN_PARAMS.length)
|
|
4458
4632
|
);
|
|
4459
4633
|
params = JSON.parse(paramsRaw);
|
|
4460
|
-
} else if (protocol.startsWith(WS_PROTOCOL_CONN_ID)) {
|
|
4461
|
-
connId = protocol.substring(WS_PROTOCOL_CONN_ID.length);
|
|
4462
|
-
} else if (protocol.startsWith(WS_PROTOCOL_CONN_TOKEN)) {
|
|
4463
|
-
connToken = protocol.substring(
|
|
4464
|
-
WS_PROTOCOL_CONN_TOKEN.length
|
|
4465
|
-
);
|
|
4466
4634
|
}
|
|
4467
4635
|
}
|
|
4468
|
-
|
|
4636
|
+
logger6().debug({
|
|
4469
4637
|
msg: "received test inline driver websocket",
|
|
4470
4638
|
actorId,
|
|
4471
4639
|
params,
|
|
4472
4640
|
encodingKind: encoding,
|
|
4473
|
-
|
|
4474
|
-
path: path4
|
|
4641
|
+
path
|
|
4475
4642
|
});
|
|
4476
4643
|
const clientWsPromise = managerDriver.openWebSocket(
|
|
4477
|
-
|
|
4644
|
+
path,
|
|
4478
4645
|
actorId,
|
|
4479
4646
|
encoding,
|
|
4480
|
-
params
|
|
4481
|
-
connId,
|
|
4482
|
-
connToken
|
|
4647
|
+
params
|
|
4483
4648
|
);
|
|
4484
4649
|
return await createTestWebSocketProxy(clientWsPromise);
|
|
4485
4650
|
})(c, noopNext());
|
|
@@ -4492,7 +4657,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
|
|
|
4492
4657
|
const pathOnly = c.req.path.split("/.test/inline-driver/send-request/")[1] || "";
|
|
4493
4658
|
const url = new URL(c.req.url);
|
|
4494
4659
|
const pathWithQuery = pathOnly + url.search;
|
|
4495
|
-
|
|
4660
|
+
logger6().debug({
|
|
4496
4661
|
msg: "received test inline driver raw http",
|
|
4497
4662
|
actorId,
|
|
4498
4663
|
path: pathWithQuery,
|
|
@@ -4510,11 +4675,11 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
|
|
|
4510
4675
|
);
|
|
4511
4676
|
return response;
|
|
4512
4677
|
} catch (error) {
|
|
4513
|
-
|
|
4678
|
+
logger6().error({
|
|
4514
4679
|
msg: "error in test inline raw http",
|
|
4515
4680
|
error: stringifyError(error)
|
|
4516
4681
|
});
|
|
4517
|
-
const err = deconstructError(error,
|
|
4682
|
+
const err = deconstructError(error, logger6(), {}, true);
|
|
4518
4683
|
return c.json(
|
|
4519
4684
|
{
|
|
4520
4685
|
error: {
|
|
@@ -4533,7 +4698,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
|
|
|
4533
4698
|
if (!actorId || !connId) {
|
|
4534
4699
|
return c.text("Missing actor or conn query parameters", 400);
|
|
4535
4700
|
}
|
|
4536
|
-
|
|
4701
|
+
logger6().debug({
|
|
4537
4702
|
msg: "forcing unclean disconnect",
|
|
4538
4703
|
actorId,
|
|
4539
4704
|
connId
|
|
@@ -4557,7 +4722,7 @@ function addManagerRoutes(registryConfig, runConfig, managerDriver, router) {
|
|
|
4557
4722
|
}
|
|
4558
4723
|
return c.json({ success: true });
|
|
4559
4724
|
} catch (error) {
|
|
4560
|
-
|
|
4725
|
+
logger6().error({
|
|
4561
4726
|
msg: "error forcing disconnect",
|
|
4562
4727
|
error: stringifyError(error)
|
|
4563
4728
|
});
|
|
@@ -4584,7 +4749,7 @@ function createApiActor(actor2, runnerName = "default") {
|
|
|
4584
4749
|
namespace_id: "default",
|
|
4585
4750
|
// Assert default namespace
|
|
4586
4751
|
runner_name_selector: runnerName,
|
|
4587
|
-
create_ts: Date.now(),
|
|
4752
|
+
create_ts: actor2.createTs ?? Date.now(),
|
|
4588
4753
|
connectable_ts: null,
|
|
4589
4754
|
destroy_ts: null,
|
|
4590
4755
|
sleep_ts: null,
|
|
@@ -4598,14 +4763,13 @@ function logger7() {
|
|
|
4598
4763
|
}
|
|
4599
4764
|
|
|
4600
4765
|
// src/registry/serve.ts
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
const app = userRouter ?? new Hono4();
|
|
4766
|
+
async function crossPlatformServe(runConfig, app) {
|
|
4767
|
+
const nodeServerModule = "@hono/node-server";
|
|
4604
4768
|
let serve;
|
|
4605
4769
|
try {
|
|
4606
4770
|
const dep = await import(
|
|
4607
4771
|
/* webpackIgnore: true */
|
|
4608
|
-
|
|
4772
|
+
nodeServerModule
|
|
4609
4773
|
);
|
|
4610
4774
|
serve = dep.serve;
|
|
4611
4775
|
} catch (err) {
|
|
@@ -4614,12 +4778,12 @@ async function crossPlatformServe(runConfig, rivetKitRouter, userRouter) {
|
|
|
4614
4778
|
);
|
|
4615
4779
|
process.exit(1);
|
|
4616
4780
|
}
|
|
4617
|
-
|
|
4781
|
+
const nodeWsModule = "@hono/node-ws";
|
|
4618
4782
|
let createNodeWebSocket;
|
|
4619
4783
|
try {
|
|
4620
4784
|
const dep = await import(
|
|
4621
4785
|
/* webpackIgnore: true */
|
|
4622
|
-
|
|
4786
|
+
nodeWsModule
|
|
4623
4787
|
);
|
|
4624
4788
|
createNodeWebSocket = dep.createNodeWebSocket;
|
|
4625
4789
|
} catch (err) {
|
|
@@ -4663,7 +4827,7 @@ var Registry = class {
|
|
|
4663
4827
|
const readyPromises = [];
|
|
4664
4828
|
if (config2.runnerKind === "serverless") {
|
|
4665
4829
|
logger7().debug("disabling health check since using serverless");
|
|
4666
|
-
config2.
|
|
4830
|
+
config2.disableMetadataLookup = true;
|
|
4667
4831
|
}
|
|
4668
4832
|
if (process.env.NODE_ENV !== "production" && config2.runnerKind === "serverless") {
|
|
4669
4833
|
if ((inputConfig == null ? void 0 : inputConfig.runEngine) === void 0) config2.runEngine = true;
|
|
@@ -4753,17 +4917,6 @@ var Registry = class {
|
|
|
4753
4917
|
}
|
|
4754
4918
|
console.log();
|
|
4755
4919
|
}
|
|
4756
|
-
if (!config2.disableActorDriver) {
|
|
4757
|
-
Promise.all(readyPromises).then(async () => {
|
|
4758
|
-
logger7().debug("starting actor driver");
|
|
4759
|
-
driver.actor(this.#config, config2, managerDriver, client);
|
|
4760
|
-
});
|
|
4761
|
-
}
|
|
4762
|
-
if (config2.runnerKind === "serverless" && config2.autoConfigureServerless) {
|
|
4763
|
-
Promise.all(readyPromises).then(async () => {
|
|
4764
|
-
await configureServerlessRunner(config2);
|
|
4765
|
-
});
|
|
4766
|
-
}
|
|
4767
4920
|
const { router: hono } = createManagerRouter(
|
|
4768
4921
|
this.#config,
|
|
4769
4922
|
config2,
|
|
@@ -4772,10 +4925,22 @@ var Registry = class {
|
|
|
4772
4925
|
client
|
|
4773
4926
|
);
|
|
4774
4927
|
if (!config2.disableDefaultServer) {
|
|
4775
|
-
(async () => {
|
|
4776
|
-
const out = await crossPlatformServe(config2, hono
|
|
4928
|
+
const serverPromise = (async () => {
|
|
4929
|
+
const out = await crossPlatformServe(config2, hono);
|
|
4777
4930
|
upgradeWebSocket = out.upgradeWebSocket;
|
|
4778
4931
|
})();
|
|
4932
|
+
readyPromises.push(serverPromise);
|
|
4933
|
+
}
|
|
4934
|
+
if (!config2.disableActorDriver) {
|
|
4935
|
+
Promise.all(readyPromises).then(async () => {
|
|
4936
|
+
logger7().debug("starting actor driver");
|
|
4937
|
+
driver.actor(this.#config, config2, managerDriver, client);
|
|
4938
|
+
});
|
|
4939
|
+
}
|
|
4940
|
+
if (config2.runnerKind === "serverless" && config2.autoConfigureServerless) {
|
|
4941
|
+
Promise.all(readyPromises).then(async () => {
|
|
4942
|
+
await configureServerlessRunner(config2);
|
|
4943
|
+
});
|
|
4779
4944
|
}
|
|
4780
4945
|
return {
|
|
4781
4946
|
client,
|
|
@@ -4808,10 +4973,9 @@ async function configureServerlessRunner(config2) {
|
|
|
4808
4973
|
namespace: config2.namespace,
|
|
4809
4974
|
runnerName: config2.runnerName,
|
|
4810
4975
|
encoding: config2.encoding,
|
|
4811
|
-
transport: config2.transport,
|
|
4812
4976
|
headers: config2.headers,
|
|
4813
4977
|
getUpgradeWebSocket: config2.getUpgradeWebSocket,
|
|
4814
|
-
|
|
4978
|
+
disableMetadataLookup: true
|
|
4815
4979
|
// We don't need health check for this operation
|
|
4816
4980
|
};
|
|
4817
4981
|
logger7().debug({
|
|
@@ -4859,12 +5023,11 @@ function setup(input) {
|
|
|
4859
5023
|
}
|
|
4860
5024
|
|
|
4861
5025
|
export {
|
|
4862
|
-
handleWebSocketConnect,
|
|
4863
|
-
handleRawWebSocketHandler,
|
|
4864
5026
|
RegistryConfigSchema,
|
|
5027
|
+
routeWebSocket,
|
|
4865
5028
|
createActorRouter,
|
|
4866
5029
|
actor,
|
|
4867
|
-
|
|
5030
|
+
InlineWebSocketAdapter,
|
|
4868
5031
|
createEngineDriver,
|
|
4869
5032
|
createFileSystemOrMemoryDriver,
|
|
4870
5033
|
createFileSystemDriver,
|
|
@@ -4874,4 +5037,4 @@ export {
|
|
|
4874
5037
|
setup
|
|
4875
5038
|
};
|
|
4876
5039
|
//! These configs configs hold anything that's not platform-specific about running actors.
|
|
4877
|
-
//# sourceMappingURL=chunk-
|
|
5040
|
+
//# sourceMappingURL=chunk-MBBJUHSP.js.map
|