@mml-io/delta-net-web 0.0.0-experimental-bcf0b7c-20250715
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/README.md +7 -0
- package/build/DeltaNetClientState.d.ts +52 -0
- package/build/DeltaNetClientWebsocket.d.ts +78 -0
- package/build/DeltaNetClientWebsocketV01Adapter.d.ts +37 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +798 -0
- package/build/index.js.map +7 -0
- package/package.json +31 -0
package/README.md
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
# DeltaNet Web
|
2
|
+
#### `@mml-io/delta-net-web`
|
3
|
+
|
4
|
+
[](https://www.npmjs.com/package/@mml-io/delta-net-web)
|
5
|
+
|
6
|
+
This package contains the `DeltaNetClientWebsocket` class which can connect to a WebSocket server using the `delta-net-v0.1` protocol and interact with a `DeltaNetServer`.
|
7
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import { DeltaNetClientWebsocketInitialCheckout, DeltaNetClientWebsocketTick } from "./DeltaNetClientWebsocket";
|
2
|
+
export type EntityStateUpdate = {
|
3
|
+
stableId: number;
|
4
|
+
stateId: number;
|
5
|
+
state: Uint8Array;
|
6
|
+
};
|
7
|
+
export type EntityInfo = {
|
8
|
+
stableId: number;
|
9
|
+
components: Map<number, bigint>;
|
10
|
+
states: Map<number, Uint8Array>;
|
11
|
+
};
|
12
|
+
export type DeltaNetClientComponent = {
|
13
|
+
values: BigInt64Array;
|
14
|
+
deltas: BigInt64Array;
|
15
|
+
deltaDeltas: BigInt64Array;
|
16
|
+
};
|
17
|
+
export declare class DeltaNetClientState {
|
18
|
+
private componentValues;
|
19
|
+
private allStates;
|
20
|
+
byStableId: Map<number, EntityInfo>;
|
21
|
+
private localClientIndex;
|
22
|
+
private indicesCount;
|
23
|
+
private stableIdToIndex;
|
24
|
+
private stableIds;
|
25
|
+
private stableIdCounter;
|
26
|
+
constructor();
|
27
|
+
/**
|
28
|
+
* Reset all state to initial values. This should be called when reconnecting
|
29
|
+
* to ensure that stale data from previous connections doesn't interfere.
|
30
|
+
*/
|
31
|
+
reset(): void;
|
32
|
+
getComponentValues(): Map<number, DeltaNetClientComponent>;
|
33
|
+
getStateById(stateId: number): Array<Uint8Array | null> | null;
|
34
|
+
getAllStates(): Map<number, Array<Uint8Array | null>>;
|
35
|
+
getLocalClientIndex(): number;
|
36
|
+
getIndicesCount(): number;
|
37
|
+
getStableIds(): Array<number>;
|
38
|
+
getComponentValueForStableId(stableId: number, componentId: number): bigint | null;
|
39
|
+
getComponentsForStableId(stableId: number): Map<number, bigint> | null;
|
40
|
+
handleInitialCheckout(initialCheckout: DeltaNetClientWebsocketInitialCheckout): {
|
41
|
+
addedStableIds: Array<number>;
|
42
|
+
};
|
43
|
+
handleTick(tick: DeltaNetClientWebsocketTick): {
|
44
|
+
stateUpdates: Array<EntityStateUpdate>;
|
45
|
+
removedStableIds: Array<number>;
|
46
|
+
addedStableIds: Array<number>;
|
47
|
+
};
|
48
|
+
setLocalIndex(index: number): void;
|
49
|
+
private removeIndices;
|
50
|
+
private removeIndicesFromBigInt64Array;
|
51
|
+
private removeIndicesFromState;
|
52
|
+
}
|
@@ -0,0 +1,78 @@
|
|
1
|
+
export type DeltaNetClientWebsocketFactory = (url: string) => WebSocket;
|
2
|
+
export declare enum DeltaNetClientWebsocketStatus {
|
3
|
+
Connecting = 0,
|
4
|
+
ConnectionOpen = 1,// The websocket is open and connected, but no messages have been received yet
|
5
|
+
Connected = 2,// The websocket is open and connected, and messages are being received
|
6
|
+
Reconnecting = 3,
|
7
|
+
Disconnected = 4
|
8
|
+
}
|
9
|
+
export declare function DeltaNetClientWebsocketStatusToString(status: DeltaNetClientWebsocketStatus): string;
|
10
|
+
export type DeltaNetClientWebsocketInitialCheckout = {
|
11
|
+
indicesCount: number;
|
12
|
+
initialComponents: Map<number, {
|
13
|
+
values: BigInt64Array;
|
14
|
+
deltas: BigInt64Array;
|
15
|
+
}>;
|
16
|
+
initialStates: Map<number, Array<Uint8Array>>;
|
17
|
+
};
|
18
|
+
export type DeltaNetClientWebsocketTick = {
|
19
|
+
unoccupying: Array<number>;
|
20
|
+
indicesCount: number;
|
21
|
+
componentDeltaDeltas: Map<number, BigInt64Array>;
|
22
|
+
stateChanges: Map<number, Map<number, Uint8Array>>;
|
23
|
+
};
|
24
|
+
export type DeltaNetClientWebsocketUserIndex = {
|
25
|
+
userIndex: number;
|
26
|
+
};
|
27
|
+
export type DeltaNetClientWebsocketOptions = {
|
28
|
+
ignoreData?: boolean;
|
29
|
+
observer?: boolean;
|
30
|
+
onUserIndex: (userIndex: DeltaNetClientWebsocketUserIndex) => void;
|
31
|
+
onInitialCheckout: (initialCheckout: DeltaNetClientWebsocketInitialCheckout) => void;
|
32
|
+
onTick: (tick: DeltaNetClientWebsocketTick) => void;
|
33
|
+
onError: (errorType: string, errorMessage: string, retryable: boolean) => void;
|
34
|
+
onWarning: (warning: string) => void;
|
35
|
+
onServerCustom?: (customType: number, contents: string) => void;
|
36
|
+
};
|
37
|
+
export type DeltaNetClientWebsocketAdapter = {
|
38
|
+
receiveMessage: (message: MessageEvent) => void;
|
39
|
+
setUserComponents: (components: Map<number, bigint>, changedStates: Map<number, Uint8Array>) => void;
|
40
|
+
sendCustomMessage: (customType: number, contents: string) => void;
|
41
|
+
didConnect: () => boolean;
|
42
|
+
dispose: () => void;
|
43
|
+
};
|
44
|
+
/**
|
45
|
+
* DeltaNetClientWebsocket is a client for a DeltaNetServer. It connects to a server on the provided url and receives
|
46
|
+
* updates to the DOM. It also sends events to the server for interactions with the DOM.
|
47
|
+
*
|
48
|
+
* The DeltaNetClientWebsocket is attached to a parentElement and synchronizes the received DOM under that element.
|
49
|
+
*/
|
50
|
+
export declare class DeltaNetClientWebsocket {
|
51
|
+
private url;
|
52
|
+
private websocketFactory;
|
53
|
+
private token;
|
54
|
+
private options;
|
55
|
+
private timeCallback?;
|
56
|
+
private statusUpdateCallback?;
|
57
|
+
private websocket;
|
58
|
+
private websocketAdapter;
|
59
|
+
private stopped;
|
60
|
+
private backoffTime;
|
61
|
+
private status;
|
62
|
+
bandwidthPerSecond: number;
|
63
|
+
lastSecondMessageSizes: Array<[number, number]>;
|
64
|
+
componentBytesPerSecond: number;
|
65
|
+
lastSecondComponentBufferSizes: Array<[number, number]>;
|
66
|
+
stateBytesPerSecond: number;
|
67
|
+
lastSecondStateBufferSizes: Array<[number, number]>;
|
68
|
+
static createWebSocket(url: string): WebSocket;
|
69
|
+
constructor(url: string, websocketFactory: DeltaNetClientWebsocketFactory, token: string, options: DeltaNetClientWebsocketOptions, timeCallback?: ((time: number) => void) | undefined, statusUpdateCallback?: ((status: DeltaNetClientWebsocketStatus) => void) | undefined);
|
70
|
+
private setStatus;
|
71
|
+
getStatus(): DeltaNetClientWebsocketStatus;
|
72
|
+
private createWebsocketWithTimeout;
|
73
|
+
private waitBackoffTime;
|
74
|
+
private startWebSocketConnectionAttempt;
|
75
|
+
stop(): void;
|
76
|
+
setUserComponents(components: Map<number, bigint>, changedStates: Map<number, Uint8Array>): void;
|
77
|
+
sendCustomMessage(customType: number, contents: string): void;
|
78
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import { DeltaNetClientWebsocketAdapter, DeltaNetClientWebsocketOptions } from "./DeltaNetClientWebsocket";
|
2
|
+
export declare class DeltaNetClientWebsocketV01Adapter implements DeltaNetClientWebsocketAdapter {
|
3
|
+
private websocket;
|
4
|
+
private connectedCallback;
|
5
|
+
private options;
|
6
|
+
private token;
|
7
|
+
private internalOptions;
|
8
|
+
private timeCallback?;
|
9
|
+
private gotInitialCheckout;
|
10
|
+
private sentUserConnect;
|
11
|
+
private receivedUserIndex;
|
12
|
+
private queuedStateUpdates;
|
13
|
+
private states;
|
14
|
+
private disposed;
|
15
|
+
private isObserver;
|
16
|
+
constructor(websocket: WebSocket, connectedCallback: () => void, options: DeltaNetClientWebsocketOptions, token: string, internalOptions: {
|
17
|
+
receivedBytes: (bytes: number, now: number) => void;
|
18
|
+
receivedComponentBytes: (bytes: number, now: number) => void;
|
19
|
+
receivedStateBytes: (bytes: number, now: number) => void;
|
20
|
+
onError: (errorType: string, errorMessage: string, retryable: boolean) => void;
|
21
|
+
onWarning: (warning: string) => void;
|
22
|
+
}, timeCallback?: ((time: number) => void) | undefined);
|
23
|
+
private sendConnectUser;
|
24
|
+
setUserComponents(components: Map<number, bigint>, changedStates: Map<number, Uint8Array>): void;
|
25
|
+
private send;
|
26
|
+
sendCustomMessage(customType: number, contents: string): void;
|
27
|
+
receiveMessage(event: MessageEvent): void;
|
28
|
+
private applyMessage;
|
29
|
+
private handleUserIndex;
|
30
|
+
private sendQueuedUpdates;
|
31
|
+
private handlePing;
|
32
|
+
private handleServerCustom;
|
33
|
+
didConnect(): boolean;
|
34
|
+
private handleInitialCheckout;
|
35
|
+
private handleTick;
|
36
|
+
dispose(): void;
|
37
|
+
}
|
package/build/index.d.ts
ADDED
package/build/index.js
ADDED
@@ -0,0 +1,798 @@
|
|
1
|
+
// src/DeltaNetClientState.ts
|
2
|
+
var DeltaNetClientState = class {
|
3
|
+
// Start at 1000 to avoid confusion with indices
|
4
|
+
constructor() {
|
5
|
+
this.componentValues = /* @__PURE__ */ new Map();
|
6
|
+
this.allStates = /* @__PURE__ */ new Map();
|
7
|
+
this.byStableId = /* @__PURE__ */ new Map();
|
8
|
+
this.localClientIndex = -1;
|
9
|
+
this.indicesCount = 0;
|
10
|
+
this.stableIdToIndex = /* @__PURE__ */ new Map();
|
11
|
+
this.stableIds = [];
|
12
|
+
this.stableIdCounter = 1e3;
|
13
|
+
this.reset();
|
14
|
+
}
|
15
|
+
/**
|
16
|
+
* Reset all state to initial values. This should be called when reconnecting
|
17
|
+
* to ensure that stale data from previous connections doesn't interfere.
|
18
|
+
*/
|
19
|
+
reset() {
|
20
|
+
this.componentValues.clear();
|
21
|
+
this.allStates.clear();
|
22
|
+
this.byStableId.clear();
|
23
|
+
this.localClientIndex = -1;
|
24
|
+
this.indicesCount = 0;
|
25
|
+
this.stableIdToIndex.clear();
|
26
|
+
this.stableIds.length = 0;
|
27
|
+
this.stableIdCounter = 1e3;
|
28
|
+
}
|
29
|
+
getComponentValues() {
|
30
|
+
return this.componentValues;
|
31
|
+
}
|
32
|
+
getStateById(stateId) {
|
33
|
+
return this.allStates.get(stateId) ?? null;
|
34
|
+
}
|
35
|
+
getAllStates() {
|
36
|
+
return this.allStates;
|
37
|
+
}
|
38
|
+
getLocalClientIndex() {
|
39
|
+
return this.localClientIndex;
|
40
|
+
}
|
41
|
+
getIndicesCount() {
|
42
|
+
return this.indicesCount;
|
43
|
+
}
|
44
|
+
getStableIds() {
|
45
|
+
return this.stableIds;
|
46
|
+
}
|
47
|
+
getComponentValueForStableId(stableId, componentId) {
|
48
|
+
const index = this.stableIdToIndex.get(stableId);
|
49
|
+
if (index === void 0) {
|
50
|
+
return null;
|
51
|
+
}
|
52
|
+
const componentValue = this.componentValues.get(componentId);
|
53
|
+
if (!componentValue) {
|
54
|
+
return null;
|
55
|
+
}
|
56
|
+
return componentValue.values[index] ?? null;
|
57
|
+
}
|
58
|
+
getComponentsForStableId(stableId) {
|
59
|
+
const index = this.stableIdToIndex.get(stableId);
|
60
|
+
if (index === void 0) {
|
61
|
+
return null;
|
62
|
+
}
|
63
|
+
const componentMap = /* @__PURE__ */ new Map();
|
64
|
+
for (const [key, componentValue] of this.componentValues) {
|
65
|
+
if (componentValue === void 0) {
|
66
|
+
throw new Error(`Component value for key ${key} is undefined`);
|
67
|
+
}
|
68
|
+
componentMap.set(key, componentValue.values[index]);
|
69
|
+
}
|
70
|
+
return componentMap;
|
71
|
+
}
|
72
|
+
handleInitialCheckout(initialCheckout) {
|
73
|
+
const { indicesCount, initialComponents, initialStates } = initialCheckout;
|
74
|
+
const addedStableIds = [];
|
75
|
+
for (let i = 0; i < indicesCount; i++) {
|
76
|
+
const stableId = this.stableIdCounter++;
|
77
|
+
this.stableIds.push(stableId);
|
78
|
+
this.stableIdToIndex.set(stableId, i);
|
79
|
+
const entityInfo = {
|
80
|
+
stableId,
|
81
|
+
components: /* @__PURE__ */ new Map(),
|
82
|
+
states: /* @__PURE__ */ new Map()
|
83
|
+
};
|
84
|
+
this.byStableId.set(stableId, entityInfo);
|
85
|
+
addedStableIds.push(stableId);
|
86
|
+
}
|
87
|
+
this.indicesCount = indicesCount;
|
88
|
+
const deltaDeltas = new BigInt64Array(indicesCount);
|
89
|
+
for (let i = 0; i < deltaDeltas.length; i++) {
|
90
|
+
deltaDeltas[i] = BigInt(0);
|
91
|
+
}
|
92
|
+
for (const [key, value] of initialComponents) {
|
93
|
+
this.componentValues.set(key, {
|
94
|
+
values: value.values,
|
95
|
+
deltas: value.deltas,
|
96
|
+
deltaDeltas
|
97
|
+
});
|
98
|
+
for (let i = 0; i < this.stableIds.length; i++) {
|
99
|
+
const stableId = this.stableIds[i];
|
100
|
+
const entityInfo = this.byStableId.get(stableId);
|
101
|
+
if (entityInfo) {
|
102
|
+
entityInfo.components.set(key, value.values[i]);
|
103
|
+
}
|
104
|
+
}
|
105
|
+
}
|
106
|
+
for (const [stateId, values] of initialStates) {
|
107
|
+
this.allStates.set(stateId, values);
|
108
|
+
for (let i = 0; i < this.stableIds.length; i++) {
|
109
|
+
const stableId = this.stableIds[i];
|
110
|
+
const entityInfo = this.byStableId.get(stableId);
|
111
|
+
const stateValue = values[i];
|
112
|
+
if (entityInfo) {
|
113
|
+
entityInfo.states.set(stateId, stateValue);
|
114
|
+
}
|
115
|
+
}
|
116
|
+
}
|
117
|
+
return { addedStableIds };
|
118
|
+
}
|
119
|
+
handleTick(tick) {
|
120
|
+
const { unoccupying, indicesCount, componentDeltaDeltas, stateChanges } = tick;
|
121
|
+
let removedStableIds = [];
|
122
|
+
if (unoccupying.length > 0) {
|
123
|
+
const stableIdsToRemove = unoccupying.map((index) => this.stableIds[index]);
|
124
|
+
removedStableIds = stableIdsToRemove.filter((stableId) => stableId !== void 0);
|
125
|
+
for (const [componentId, component] of this.componentValues) {
|
126
|
+
this.removeIndicesFromBigInt64Array(unoccupying, component.values);
|
127
|
+
this.removeIndicesFromBigInt64Array(unoccupying, component.deltas);
|
128
|
+
}
|
129
|
+
for (const [stateId, state] of this.allStates) {
|
130
|
+
this.removeIndicesFromState(unoccupying, state);
|
131
|
+
}
|
132
|
+
let decrementIndex = 0;
|
133
|
+
for (const index of unoccupying) {
|
134
|
+
if (index <= this.localClientIndex) {
|
135
|
+
decrementIndex++;
|
136
|
+
}
|
137
|
+
}
|
138
|
+
this.localClientIndex -= decrementIndex;
|
139
|
+
this.indicesCount -= unoccupying.length;
|
140
|
+
this.removeIndices(unoccupying);
|
141
|
+
for (const stableId of stableIdsToRemove) {
|
142
|
+
if (stableId === void 0) {
|
143
|
+
throw new Error(`stableId is undefined`);
|
144
|
+
}
|
145
|
+
this.byStableId.delete(stableId);
|
146
|
+
}
|
147
|
+
}
|
148
|
+
const addedStableIds = [];
|
149
|
+
if (indicesCount > this.indicesCount) {
|
150
|
+
const addedIndices = indicesCount - this.indicesCount;
|
151
|
+
for (let i = 0; i < addedIndices; i++) {
|
152
|
+
const stableId = this.stableIdCounter++;
|
153
|
+
this.stableIds.push(stableId);
|
154
|
+
this.stableIdToIndex.set(stableId, this.stableIds.length - 1);
|
155
|
+
const entityInfo = {
|
156
|
+
stableId,
|
157
|
+
components: /* @__PURE__ */ new Map(),
|
158
|
+
states: /* @__PURE__ */ new Map()
|
159
|
+
};
|
160
|
+
this.byStableId.set(stableId, entityInfo);
|
161
|
+
addedStableIds.push(stableId);
|
162
|
+
}
|
163
|
+
}
|
164
|
+
this.indicesCount = indicesCount;
|
165
|
+
for (const [key, deltaDeltas] of componentDeltaDeltas) {
|
166
|
+
if (deltaDeltas.length !== indicesCount) {
|
167
|
+
throw new Error(
|
168
|
+
`DeltaDeltas length (${deltaDeltas.length}) does not match indices count (${indicesCount})`
|
169
|
+
);
|
170
|
+
}
|
171
|
+
const existingComponent = this.componentValues.get(key);
|
172
|
+
if (!existingComponent) {
|
173
|
+
const values = new BigInt64Array(deltaDeltas);
|
174
|
+
const deltas = new BigInt64Array(deltaDeltas);
|
175
|
+
this.componentValues.set(key, { values, deltas, deltaDeltas });
|
176
|
+
} else {
|
177
|
+
if (existingComponent.values.length < deltaDeltas.length) {
|
178
|
+
const newValues = new BigInt64Array(deltaDeltas.length);
|
179
|
+
newValues.set(existingComponent.values);
|
180
|
+
const newDeltas = new BigInt64Array(deltaDeltas.length);
|
181
|
+
newDeltas.set(existingComponent.deltas);
|
182
|
+
const newDeltaDelta = new BigInt64Array(deltaDeltas.length);
|
183
|
+
newDeltaDelta.set(existingComponent.deltaDeltas);
|
184
|
+
for (let i = existingComponent.values.length; i < deltaDeltas.length; i++) {
|
185
|
+
newValues[i] = BigInt(0);
|
186
|
+
newDeltas[i] = BigInt(0);
|
187
|
+
newDeltaDelta[i] = BigInt(0);
|
188
|
+
}
|
189
|
+
existingComponent.values = newValues;
|
190
|
+
existingComponent.deltas = newDeltas;
|
191
|
+
existingComponent.deltaDeltas = newDeltaDelta;
|
192
|
+
}
|
193
|
+
for (let i = 0; i < deltaDeltas.length; i++) {
|
194
|
+
const deltaDelta = deltaDeltas[i];
|
195
|
+
const stableId = this.stableIds[i];
|
196
|
+
existingComponent.deltaDeltas[i] = deltaDelta;
|
197
|
+
existingComponent.deltas[i] += deltaDelta;
|
198
|
+
existingComponent.values[i] += existingComponent.deltas[i];
|
199
|
+
const entityInfo = this.byStableId.get(stableId);
|
200
|
+
if (entityInfo) {
|
201
|
+
entityInfo.components.set(key, existingComponent.values[i]);
|
202
|
+
}
|
203
|
+
}
|
204
|
+
}
|
205
|
+
}
|
206
|
+
const stateUpdates = [];
|
207
|
+
for (const [stateId, states] of stateChanges) {
|
208
|
+
let state = this.allStates.get(stateId);
|
209
|
+
if (!state) {
|
210
|
+
state = [];
|
211
|
+
this.allStates.set(stateId, state);
|
212
|
+
}
|
213
|
+
for (const [index, value] of states) {
|
214
|
+
const stableId = this.stableIds[index];
|
215
|
+
if (stableId === void 0) {
|
216
|
+
throw new Error(`Stable ID is undefined for index ${index} in state ${stateId}`);
|
217
|
+
}
|
218
|
+
stateUpdates.push({
|
219
|
+
stableId,
|
220
|
+
stateId,
|
221
|
+
state: value
|
222
|
+
});
|
223
|
+
state[index] = value;
|
224
|
+
const entityInfo = this.byStableId.get(stableId);
|
225
|
+
if (entityInfo) {
|
226
|
+
entityInfo.states.set(stateId, value);
|
227
|
+
}
|
228
|
+
}
|
229
|
+
}
|
230
|
+
return { stateUpdates, removedStableIds, addedStableIds };
|
231
|
+
}
|
232
|
+
setLocalIndex(index) {
|
233
|
+
this.localClientIndex = index;
|
234
|
+
}
|
235
|
+
removeIndices(removing) {
|
236
|
+
if (removing.length === 0) {
|
237
|
+
return;
|
238
|
+
}
|
239
|
+
let writeIndex = 0;
|
240
|
+
let skipIndex = 0;
|
241
|
+
for (let readIndex = 0; readIndex < this.stableIds.length; readIndex++) {
|
242
|
+
if (skipIndex < removing.length && readIndex === removing[skipIndex]) {
|
243
|
+
skipIndex++;
|
244
|
+
continue;
|
245
|
+
}
|
246
|
+
const stableId = this.stableIds[readIndex];
|
247
|
+
if (writeIndex !== readIndex) {
|
248
|
+
this.stableIds[writeIndex] = this.stableIds[readIndex];
|
249
|
+
}
|
250
|
+
this.stableIdToIndex.set(stableId, writeIndex);
|
251
|
+
writeIndex++;
|
252
|
+
}
|
253
|
+
this.stableIds.length = writeIndex;
|
254
|
+
}
|
255
|
+
removeIndicesFromBigInt64Array(removing, array) {
|
256
|
+
if (removing.length === 0) {
|
257
|
+
return;
|
258
|
+
}
|
259
|
+
let writeIndex = 0;
|
260
|
+
let skipIndex = 0;
|
261
|
+
for (let readIndex = 0; readIndex < array.length; readIndex++) {
|
262
|
+
if (skipIndex < removing.length && readIndex === removing[skipIndex]) {
|
263
|
+
skipIndex++;
|
264
|
+
continue;
|
265
|
+
}
|
266
|
+
if (writeIndex !== readIndex) {
|
267
|
+
array[writeIndex] = array[readIndex];
|
268
|
+
}
|
269
|
+
writeIndex++;
|
270
|
+
}
|
271
|
+
for (let i = writeIndex; i < array.length; i++) {
|
272
|
+
array[i] = BigInt(0);
|
273
|
+
}
|
274
|
+
}
|
275
|
+
removeIndicesFromState(removing, state) {
|
276
|
+
if (removing.length === 0) {
|
277
|
+
return;
|
278
|
+
}
|
279
|
+
let writeIndex = 0;
|
280
|
+
let skipIndex = 0;
|
281
|
+
for (let readIndex = 0; readIndex < state.length; readIndex++) {
|
282
|
+
if (skipIndex < removing.length && readIndex === removing[skipIndex]) {
|
283
|
+
skipIndex++;
|
284
|
+
continue;
|
285
|
+
}
|
286
|
+
if (writeIndex !== readIndex) {
|
287
|
+
state[writeIndex] = state[readIndex];
|
288
|
+
}
|
289
|
+
writeIndex++;
|
290
|
+
}
|
291
|
+
}
|
292
|
+
};
|
293
|
+
|
294
|
+
// src/DeltaNetClientWebsocket.ts
|
295
|
+
import { deltaNetProtocolSubProtocol_v0_1 } from "/Users/marcuslongmuir/mml/3d-web-experience/packages/deltanet/delta-net-protocol/build/index.js";
|
296
|
+
|
297
|
+
// src/DeltaNetClientWebsocketV01Adapter.ts
|
298
|
+
import {
|
299
|
+
BufferReader,
|
300
|
+
BufferWriter,
|
301
|
+
decodeServerMessages,
|
302
|
+
encodeClientMessage,
|
303
|
+
lastInitialCheckoutDebugData,
|
304
|
+
lastTickDebugData
|
305
|
+
} from "/Users/marcuslongmuir/mml/3d-web-experience/packages/deltanet/delta-net-protocol/build/index.js";
|
306
|
+
function areUint8ArraysEqual(a, b) {
|
307
|
+
if (a.length !== b.length) return false;
|
308
|
+
for (let i = 0; i < a.length; i++) {
|
309
|
+
if (a[i] !== b[i]) return false;
|
310
|
+
}
|
311
|
+
return true;
|
312
|
+
}
|
313
|
+
var DeltaNetClientWebsocketV01Adapter = class {
|
314
|
+
constructor(websocket, connectedCallback, options, token, internalOptions, timeCallback) {
|
315
|
+
this.websocket = websocket;
|
316
|
+
this.connectedCallback = connectedCallback;
|
317
|
+
this.options = options;
|
318
|
+
this.token = token;
|
319
|
+
this.internalOptions = internalOptions;
|
320
|
+
this.timeCallback = timeCallback;
|
321
|
+
this.gotInitialCheckout = false;
|
322
|
+
this.sentUserConnect = false;
|
323
|
+
this.receivedUserIndex = false;
|
324
|
+
this.queuedStateUpdates = /* @__PURE__ */ new Map();
|
325
|
+
this.states = /* @__PURE__ */ new Map();
|
326
|
+
this.disposed = false;
|
327
|
+
this.websocket.binaryType = "arraybuffer";
|
328
|
+
this.isObserver = options.observer ?? false;
|
329
|
+
if (this.isObserver) {
|
330
|
+
this.sendConnectUser([], []);
|
331
|
+
}
|
332
|
+
}
|
333
|
+
sendConnectUser(components, states) {
|
334
|
+
if (this.sentUserConnect) {
|
335
|
+
return;
|
336
|
+
}
|
337
|
+
this.sentUserConnect = true;
|
338
|
+
this.send({
|
339
|
+
type: "connectUser",
|
340
|
+
token: this.token,
|
341
|
+
observer: this.isObserver,
|
342
|
+
components: this.isObserver ? [] : components,
|
343
|
+
states: this.isObserver ? [] : states
|
344
|
+
});
|
345
|
+
}
|
346
|
+
setUserComponents(components, changedStates) {
|
347
|
+
if (this.disposed) {
|
348
|
+
throw new Error("DeltaNetClientWebsocketV01Adapter is disposed");
|
349
|
+
}
|
350
|
+
const messageComponents = [];
|
351
|
+
for (const [componentId, value] of components) {
|
352
|
+
messageComponents.push([componentId, value]);
|
353
|
+
}
|
354
|
+
const messageStates = [];
|
355
|
+
for (const [stateId, value] of changedStates) {
|
356
|
+
const currentState = this.states.get(stateId);
|
357
|
+
if (currentState && areUint8ArraysEqual(currentState, value)) {
|
358
|
+
continue;
|
359
|
+
}
|
360
|
+
this.states.set(stateId, value);
|
361
|
+
messageStates.push([stateId, value]);
|
362
|
+
}
|
363
|
+
if (!this.sentUserConnect) {
|
364
|
+
this.sendConnectUser(messageComponents, messageStates);
|
365
|
+
return;
|
366
|
+
}
|
367
|
+
if (this.isObserver) {
|
368
|
+
return;
|
369
|
+
}
|
370
|
+
let messageStatesToSend = [];
|
371
|
+
if (this.receivedUserIndex) {
|
372
|
+
messageStatesToSend = messageStates;
|
373
|
+
} else {
|
374
|
+
for (const [stateId, value] of messageStates) {
|
375
|
+
this.queuedStateUpdates.set(stateId, value);
|
376
|
+
}
|
377
|
+
}
|
378
|
+
if (messageComponents.length > 0 || messageStatesToSend.length > 0) {
|
379
|
+
const setUserComponents = {
|
380
|
+
type: "setUserComponents",
|
381
|
+
components: messageComponents,
|
382
|
+
states: messageStatesToSend
|
383
|
+
};
|
384
|
+
this.send(setUserComponents);
|
385
|
+
}
|
386
|
+
}
|
387
|
+
send(message) {
|
388
|
+
const writer = new BufferWriter(256);
|
389
|
+
encodeClientMessage(message, writer);
|
390
|
+
this.websocket.send(writer.getBuffer());
|
391
|
+
}
|
392
|
+
sendCustomMessage(customType, contents) {
|
393
|
+
if (this.disposed) {
|
394
|
+
return;
|
395
|
+
}
|
396
|
+
const customMessage = {
|
397
|
+
type: "clientCustom",
|
398
|
+
customType,
|
399
|
+
contents
|
400
|
+
};
|
401
|
+
this.send(customMessage);
|
402
|
+
}
|
403
|
+
receiveMessage(event) {
|
404
|
+
if (this.disposed) {
|
405
|
+
return;
|
406
|
+
}
|
407
|
+
const buffer = new Uint8Array(event.data);
|
408
|
+
const now = Date.now();
|
409
|
+
this.internalOptions.receivedBytes(buffer.byteLength, now);
|
410
|
+
const reader = new BufferReader(buffer);
|
411
|
+
const messages = decodeServerMessages(reader, {
|
412
|
+
ignoreData: this.options.ignoreData
|
413
|
+
});
|
414
|
+
for (const message of messages) {
|
415
|
+
this.applyMessage(message, now);
|
416
|
+
}
|
417
|
+
}
|
418
|
+
applyMessage(message, now) {
|
419
|
+
switch (message.type) {
|
420
|
+
case "error":
|
421
|
+
console.error("Error from server", message);
|
422
|
+
this.internalOptions.onError(message.errorType, message.message, message.retryable);
|
423
|
+
break;
|
424
|
+
case "warning":
|
425
|
+
console.warn("Warning from server", message);
|
426
|
+
this.internalOptions.onWarning(message.message);
|
427
|
+
break;
|
428
|
+
case "initialCheckout":
|
429
|
+
this.handleInitialCheckout(message, now);
|
430
|
+
this.connectedCallback();
|
431
|
+
break;
|
432
|
+
case "tick":
|
433
|
+
this.handleTick(message, now);
|
434
|
+
break;
|
435
|
+
case "userIndex":
|
436
|
+
this.handleUserIndex(message);
|
437
|
+
break;
|
438
|
+
case "ping":
|
439
|
+
this.handlePing(message);
|
440
|
+
break;
|
441
|
+
case "serverCustom":
|
442
|
+
this.handleServerCustom(message);
|
443
|
+
break;
|
444
|
+
default:
|
445
|
+
console.warn("unknown message type", message);
|
446
|
+
break;
|
447
|
+
}
|
448
|
+
}
|
449
|
+
handleUserIndex(message) {
|
450
|
+
this.receivedUserIndex = true;
|
451
|
+
this.options.onUserIndex({
|
452
|
+
userIndex: message.index
|
453
|
+
});
|
454
|
+
this.sendQueuedUpdates();
|
455
|
+
}
|
456
|
+
sendQueuedUpdates() {
|
457
|
+
if (this.queuedStateUpdates.size > 0) {
|
458
|
+
const queuedStatesArray = [];
|
459
|
+
for (const [stateId, value] of this.queuedStateUpdates) {
|
460
|
+
queuedStatesArray.push([stateId, value]);
|
461
|
+
}
|
462
|
+
const setUserComponents = {
|
463
|
+
type: "setUserComponents",
|
464
|
+
components: [],
|
465
|
+
states: queuedStatesArray
|
466
|
+
};
|
467
|
+
this.send(setUserComponents);
|
468
|
+
this.queuedStateUpdates.clear();
|
469
|
+
}
|
470
|
+
}
|
471
|
+
handlePing(message) {
|
472
|
+
this.send({
|
473
|
+
type: "pong",
|
474
|
+
pong: message.ping
|
475
|
+
});
|
476
|
+
}
|
477
|
+
handleServerCustom(message) {
|
478
|
+
var _a, _b;
|
479
|
+
(_b = (_a = this.options).onServerCustom) == null ? void 0 : _b.call(_a, message.customType, message.contents);
|
480
|
+
}
|
481
|
+
didConnect() {
|
482
|
+
return this.gotInitialCheckout;
|
483
|
+
}
|
484
|
+
handleInitialCheckout(message, now) {
|
485
|
+
this.gotInitialCheckout = true;
|
486
|
+
if (this.options.ignoreData) {
|
487
|
+
return;
|
488
|
+
}
|
489
|
+
const components = /* @__PURE__ */ new Map();
|
490
|
+
for (const { componentId, deltas, values } of message.components) {
|
491
|
+
components.set(componentId, { values, deltas });
|
492
|
+
}
|
493
|
+
const allStates = /* @__PURE__ */ new Map();
|
494
|
+
for (const { stateId, values } of message.states) {
|
495
|
+
allStates.set(stateId, values);
|
496
|
+
}
|
497
|
+
this.internalOptions.receivedComponentBytes(
|
498
|
+
lastInitialCheckoutDebugData.componentsByteLength,
|
499
|
+
now
|
500
|
+
);
|
501
|
+
this.internalOptions.receivedStateBytes(lastInitialCheckoutDebugData.statesByteLength, now);
|
502
|
+
this.options.onInitialCheckout({
|
503
|
+
indicesCount: message.indicesCount,
|
504
|
+
initialComponents: components,
|
505
|
+
initialStates: allStates
|
506
|
+
});
|
507
|
+
}
|
508
|
+
handleTick(message, now) {
|
509
|
+
var _a;
|
510
|
+
if (this.options.ignoreData) {
|
511
|
+
return;
|
512
|
+
}
|
513
|
+
(_a = this.timeCallback) == null ? void 0 : _a.call(this, message.serverTime);
|
514
|
+
const components = /* @__PURE__ */ new Map();
|
515
|
+
for (const { componentId, deltaDeltas } of message.componentDeltaDeltas) {
|
516
|
+
components.set(componentId, deltaDeltas);
|
517
|
+
}
|
518
|
+
const stateChanges = /* @__PURE__ */ new Map();
|
519
|
+
for (const stateChange of message.states) {
|
520
|
+
const updatedStates = /* @__PURE__ */ new Map();
|
521
|
+
for (const [index, value] of stateChange.updatedStates) {
|
522
|
+
updatedStates.set(index, value);
|
523
|
+
}
|
524
|
+
stateChanges.set(stateChange.stateId, updatedStates);
|
525
|
+
}
|
526
|
+
this.internalOptions.receivedComponentBytes(lastTickDebugData.componentsByteLength, now);
|
527
|
+
this.internalOptions.receivedStateBytes(lastTickDebugData.statesByteLength, now);
|
528
|
+
this.options.onTick({
|
529
|
+
unoccupying: message.removedIndices,
|
530
|
+
indicesCount: message.indicesCount,
|
531
|
+
componentDeltaDeltas: components,
|
532
|
+
stateChanges
|
533
|
+
});
|
534
|
+
}
|
535
|
+
dispose() {
|
536
|
+
this.disposed = true;
|
537
|
+
}
|
538
|
+
};
|
539
|
+
|
540
|
+
// src/DeltaNetClientWebsocket.ts
|
541
|
+
var startingBackoffTimeMilliseconds = 100;
|
542
|
+
var maximumBackoffTimeMilliseconds = 1e4;
|
543
|
+
var maximumWebsocketConnectionTimeout = 5e3;
|
544
|
+
var DeltaNetClientWebsocketStatus = /* @__PURE__ */ ((DeltaNetClientWebsocketStatus2) => {
|
545
|
+
DeltaNetClientWebsocketStatus2[DeltaNetClientWebsocketStatus2["Connecting"] = 0] = "Connecting";
|
546
|
+
DeltaNetClientWebsocketStatus2[DeltaNetClientWebsocketStatus2["ConnectionOpen"] = 1] = "ConnectionOpen";
|
547
|
+
DeltaNetClientWebsocketStatus2[DeltaNetClientWebsocketStatus2["Connected"] = 2] = "Connected";
|
548
|
+
DeltaNetClientWebsocketStatus2[DeltaNetClientWebsocketStatus2["Reconnecting"] = 3] = "Reconnecting";
|
549
|
+
DeltaNetClientWebsocketStatus2[DeltaNetClientWebsocketStatus2["Disconnected"] = 4] = "Disconnected";
|
550
|
+
return DeltaNetClientWebsocketStatus2;
|
551
|
+
})(DeltaNetClientWebsocketStatus || {});
|
552
|
+
function DeltaNetClientWebsocketStatusToString(status) {
|
553
|
+
switch (status) {
|
554
|
+
case 0 /* Connecting */:
|
555
|
+
return "Connecting...";
|
556
|
+
case 1 /* ConnectionOpen */:
|
557
|
+
return "Connection Open";
|
558
|
+
case 2 /* Connected */:
|
559
|
+
return "Connected";
|
560
|
+
case 3 /* Reconnecting */:
|
561
|
+
return "Reconnecting...";
|
562
|
+
case 4 /* Disconnected */:
|
563
|
+
return "Disconnected";
|
564
|
+
default:
|
565
|
+
return "Unknown";
|
566
|
+
}
|
567
|
+
}
|
568
|
+
function updateLastSecondArray(records, size, time) {
|
569
|
+
let sizeChange = size;
|
570
|
+
const oneSecondAgo = time - 1e3;
|
571
|
+
records.push([time, size]);
|
572
|
+
let i;
|
573
|
+
for (i = 0; i < records.length; i++) {
|
574
|
+
if (records[i][0] < oneSecondAgo) {
|
575
|
+
sizeChange -= records[i][1];
|
576
|
+
} else {
|
577
|
+
break;
|
578
|
+
}
|
579
|
+
}
|
580
|
+
records.splice(0, i);
|
581
|
+
return sizeChange;
|
582
|
+
}
|
583
|
+
var DeltaNetClientWebsocket = class {
|
584
|
+
constructor(url, websocketFactory, token, options, timeCallback, statusUpdateCallback) {
|
585
|
+
this.url = url;
|
586
|
+
this.websocketFactory = websocketFactory;
|
587
|
+
this.token = token;
|
588
|
+
this.options = options;
|
589
|
+
this.timeCallback = timeCallback;
|
590
|
+
this.statusUpdateCallback = statusUpdateCallback;
|
591
|
+
this.websocket = null;
|
592
|
+
this.websocketAdapter = null;
|
593
|
+
this.stopped = false;
|
594
|
+
this.backoffTime = startingBackoffTimeMilliseconds;
|
595
|
+
this.status = 0 /* Connecting */;
|
596
|
+
this.bandwidthPerSecond = 0;
|
597
|
+
this.lastSecondMessageSizes = [];
|
598
|
+
// Timestamp in ms, size in bytes
|
599
|
+
this.componentBytesPerSecond = 0;
|
600
|
+
this.lastSecondComponentBufferSizes = [];
|
601
|
+
// Timestamp in ms, size in bytes
|
602
|
+
this.stateBytesPerSecond = 0;
|
603
|
+
this.lastSecondStateBufferSizes = [];
|
604
|
+
this.setStatus(0 /* Connecting */);
|
605
|
+
this.startWebSocketConnectionAttempt();
|
606
|
+
}
|
607
|
+
// Timestamp in ms, size in bytes
|
608
|
+
static createWebSocket(url) {
|
609
|
+
return new WebSocket(url, [deltaNetProtocolSubProtocol_v0_1]);
|
610
|
+
}
|
611
|
+
setStatus(status) {
|
612
|
+
if (this.status !== status) {
|
613
|
+
this.status = status;
|
614
|
+
if (this.statusUpdateCallback) {
|
615
|
+
this.statusUpdateCallback(status);
|
616
|
+
}
|
617
|
+
}
|
618
|
+
}
|
619
|
+
getStatus() {
|
620
|
+
return this.status;
|
621
|
+
}
|
622
|
+
async createWebsocketWithTimeout(timeout) {
|
623
|
+
return new Promise((resolve, reject) => {
|
624
|
+
const websocket = this.websocketFactory(this.url);
|
625
|
+
const timeoutId = setTimeout(() => {
|
626
|
+
reject(new Error("websocket connection timed out"));
|
627
|
+
websocket.close();
|
628
|
+
}, timeout);
|
629
|
+
websocket.binaryType = "arraybuffer";
|
630
|
+
websocket.addEventListener("open", () => {
|
631
|
+
clearTimeout(timeoutId);
|
632
|
+
this.websocket = websocket;
|
633
|
+
const websocketAdapter = new DeltaNetClientWebsocketV01Adapter(
|
634
|
+
websocket,
|
635
|
+
() => {
|
636
|
+
this.backoffTime = startingBackoffTimeMilliseconds;
|
637
|
+
this.setStatus(2 /* Connected */);
|
638
|
+
},
|
639
|
+
this.options,
|
640
|
+
this.token,
|
641
|
+
{
|
642
|
+
receivedBytes: (bytes, now) => {
|
643
|
+
this.bandwidthPerSecond += updateLastSecondArray(
|
644
|
+
this.lastSecondMessageSizes,
|
645
|
+
bytes,
|
646
|
+
now
|
647
|
+
);
|
648
|
+
},
|
649
|
+
receivedComponentBytes: (bytes, now) => {
|
650
|
+
this.componentBytesPerSecond += updateLastSecondArray(
|
651
|
+
this.lastSecondComponentBufferSizes,
|
652
|
+
bytes,
|
653
|
+
now
|
654
|
+
);
|
655
|
+
},
|
656
|
+
receivedStateBytes: (bytes, now) => {
|
657
|
+
this.stateBytesPerSecond += updateLastSecondArray(
|
658
|
+
this.lastSecondStateBufferSizes,
|
659
|
+
bytes,
|
660
|
+
now
|
661
|
+
);
|
662
|
+
},
|
663
|
+
onError: (errorType, errorMessage, retryable) => {
|
664
|
+
var _a, _b;
|
665
|
+
this.options.onError(errorType, errorMessage, retryable);
|
666
|
+
if (this.websocket === websocket) {
|
667
|
+
(_a = this.websocket) == null ? void 0 : _a.close();
|
668
|
+
this.websocket = null;
|
669
|
+
(_b = this.websocketAdapter) == null ? void 0 : _b.dispose();
|
670
|
+
this.websocketAdapter = null;
|
671
|
+
onWebsocketClose(retryable);
|
672
|
+
}
|
673
|
+
},
|
674
|
+
onWarning: (warning) => {
|
675
|
+
this.options.onWarning(warning);
|
676
|
+
}
|
677
|
+
},
|
678
|
+
this.timeCallback
|
679
|
+
);
|
680
|
+
this.websocketAdapter = websocketAdapter;
|
681
|
+
websocket.addEventListener("message", (event) => {
|
682
|
+
if (websocket !== this.websocket) {
|
683
|
+
console.log("Ignoring websocket message event because it is no longer current");
|
684
|
+
websocket.close();
|
685
|
+
return;
|
686
|
+
}
|
687
|
+
if (this.stopped) {
|
688
|
+
console.warn("Ignoring websocket message event because the client is stopped");
|
689
|
+
return;
|
690
|
+
}
|
691
|
+
websocketAdapter.receiveMessage(event);
|
692
|
+
});
|
693
|
+
const onWebsocketClose = async (retryable = true) => {
|
694
|
+
let didConnect = false;
|
695
|
+
if (this.websocketAdapter) {
|
696
|
+
didConnect = this.websocketAdapter.didConnect();
|
697
|
+
}
|
698
|
+
if (this.stopped) {
|
699
|
+
this.setStatus(4 /* Disconnected */);
|
700
|
+
return;
|
701
|
+
}
|
702
|
+
if (retryable) {
|
703
|
+
if (!didConnect) {
|
704
|
+
await this.waitBackoffTime();
|
705
|
+
}
|
706
|
+
this.setStatus(3 /* Reconnecting */);
|
707
|
+
this.startWebSocketConnectionAttempt();
|
708
|
+
} else {
|
709
|
+
this.setStatus(4 /* Disconnected */);
|
710
|
+
}
|
711
|
+
};
|
712
|
+
websocket.addEventListener("close", () => {
|
713
|
+
var _a;
|
714
|
+
if (websocket !== this.websocket) {
|
715
|
+
console.warn("Ignoring websocket close event because it is no longer current");
|
716
|
+
return;
|
717
|
+
}
|
718
|
+
this.websocket = null;
|
719
|
+
(_a = this.websocketAdapter) == null ? void 0 : _a.dispose();
|
720
|
+
this.websocketAdapter = null;
|
721
|
+
onWebsocketClose();
|
722
|
+
});
|
723
|
+
websocket.addEventListener("error", (e) => {
|
724
|
+
var _a;
|
725
|
+
if (websocket !== this.websocket) {
|
726
|
+
console.log("Ignoring websocket error event because it is no longer current");
|
727
|
+
return;
|
728
|
+
}
|
729
|
+
console.error("DeltaNetClientWebsocket error", e);
|
730
|
+
this.websocket = null;
|
731
|
+
(_a = this.websocketAdapter) == null ? void 0 : _a.dispose();
|
732
|
+
this.websocketAdapter = null;
|
733
|
+
onWebsocketClose();
|
734
|
+
});
|
735
|
+
this.setStatus(1 /* ConnectionOpen */);
|
736
|
+
resolve(websocket);
|
737
|
+
});
|
738
|
+
websocket.addEventListener("error", (e) => {
|
739
|
+
clearTimeout(timeoutId);
|
740
|
+
reject(e);
|
741
|
+
});
|
742
|
+
});
|
743
|
+
}
|
744
|
+
async waitBackoffTime() {
|
745
|
+
console.warn(`Websocket connection to '${this.url}' failed: retrying in ${this.backoffTime}ms`);
|
746
|
+
await new Promise((resolve) => setTimeout(resolve, this.backoffTime));
|
747
|
+
this.backoffTime = Math.min(
|
748
|
+
// Introduce a small amount of randomness to prevent clients from retrying in lockstep
|
749
|
+
this.backoffTime * (1.5 + Math.random() * 0.5),
|
750
|
+
maximumBackoffTimeMilliseconds
|
751
|
+
);
|
752
|
+
}
|
753
|
+
async startWebSocketConnectionAttempt() {
|
754
|
+
if (this.stopped) {
|
755
|
+
return;
|
756
|
+
}
|
757
|
+
while (true) {
|
758
|
+
if (this.stopped) {
|
759
|
+
return;
|
760
|
+
}
|
761
|
+
try {
|
762
|
+
await this.createWebsocketWithTimeout(maximumWebsocketConnectionTimeout);
|
763
|
+
break;
|
764
|
+
} catch (e) {
|
765
|
+
console.error("Websocket connection failed", e);
|
766
|
+
this.setStatus(3 /* Reconnecting */);
|
767
|
+
await this.waitBackoffTime();
|
768
|
+
}
|
769
|
+
}
|
770
|
+
}
|
771
|
+
stop() {
|
772
|
+
var _a;
|
773
|
+
this.stopped = true;
|
774
|
+
if (this.websocket !== null) {
|
775
|
+
this.websocket.close();
|
776
|
+
this.websocket = null;
|
777
|
+
}
|
778
|
+
(_a = this.websocketAdapter) == null ? void 0 : _a.dispose();
|
779
|
+
this.websocketAdapter = null;
|
780
|
+
}
|
781
|
+
setUserComponents(components, changedStates) {
|
782
|
+
if (this.websocketAdapter) {
|
783
|
+
this.websocketAdapter.setUserComponents(components, changedStates);
|
784
|
+
}
|
785
|
+
}
|
786
|
+
sendCustomMessage(customType, contents) {
|
787
|
+
if (this.websocketAdapter) {
|
788
|
+
this.websocketAdapter.sendCustomMessage(customType, contents);
|
789
|
+
}
|
790
|
+
}
|
791
|
+
};
|
792
|
+
export {
|
793
|
+
DeltaNetClientState,
|
794
|
+
DeltaNetClientWebsocket,
|
795
|
+
DeltaNetClientWebsocketStatus,
|
796
|
+
DeltaNetClientWebsocketStatusToString
|
797
|
+
};
|
798
|
+
//# sourceMappingURL=index.js.map
|
@@ -0,0 +1,7 @@
|
|
1
|
+
{
|
2
|
+
"version": 3,
|
3
|
+
"sources": ["../src/DeltaNetClientState.ts", "../src/DeltaNetClientWebsocket.ts", "../src/DeltaNetClientWebsocketV01Adapter.ts"],
|
4
|
+
"sourcesContent": ["import {\n DeltaNetClientWebsocketInitialCheckout,\n DeltaNetClientWebsocketTick,\n} from \"./DeltaNetClientWebsocket\";\n\nexport type EntityStateUpdate = { stableId: number; stateId: number; state: Uint8Array };\n\nexport type EntityInfo = {\n stableId: number;\n components: Map<number, bigint>;\n states: Map<number, Uint8Array>;\n};\n\nexport type DeltaNetClientComponent = {\n values: BigInt64Array;\n deltas: BigInt64Array;\n deltaDeltas: BigInt64Array;\n};\n\nexport class DeltaNetClientState {\n private componentValues = new Map<number, DeltaNetClientComponent>();\n private allStates = new Map<number, Array<Uint8Array>>();\n\n public byStableId: Map<number, EntityInfo> = new Map();\n\n private localClientIndex: number = -1;\n\n private indicesCount: number = 0;\n\n private stableIdToIndex = new Map<number, number>();\n private stableIds: Array<number> = [];\n private stableIdCounter = 1000; // Start at 1000 to avoid confusion with indices\n\n constructor() {\n this.reset();\n }\n\n /**\n * Reset all state to initial values. This should be called when reconnecting\n * to ensure that stale data from previous connections doesn't interfere.\n */\n public reset() {\n this.componentValues.clear();\n this.allStates.clear();\n this.byStableId.clear();\n this.localClientIndex = -1;\n this.indicesCount = 0;\n this.stableIdToIndex.clear();\n this.stableIds.length = 0;\n this.stableIdCounter = 1000;\n }\n\n public getComponentValues(): Map<number, DeltaNetClientComponent> {\n return this.componentValues;\n }\n\n public getStateById(stateId: number): Array<Uint8Array | null> | null {\n return this.allStates.get(stateId) ?? null;\n }\n\n public getAllStates(): Map<number, Array<Uint8Array | null>> {\n return this.allStates;\n }\n\n public getLocalClientIndex(): number {\n return this.localClientIndex;\n }\n\n public getIndicesCount(): number {\n return this.indicesCount;\n }\n\n public getStableIds(): Array<number> {\n return this.stableIds;\n }\n\n public getComponentValueForStableId(stableId: number, componentId: number): bigint | null {\n const index = this.stableIdToIndex.get(stableId);\n if (index === undefined) {\n return null;\n }\n const componentValue = this.componentValues.get(componentId);\n if (!componentValue) {\n return null;\n }\n return componentValue.values[index] ?? null;\n }\n\n public getComponentsForStableId(stableId: number): Map<number, bigint> | null {\n const index = this.stableIdToIndex.get(stableId);\n if (index === undefined) {\n return null;\n }\n const componentMap = new Map<number, bigint>();\n for (const [key, componentValue] of this.componentValues) {\n if (componentValue === undefined) {\n throw new Error(`Component value for key ${key} is undefined`);\n }\n componentMap.set(key, componentValue.values[index]);\n }\n return componentMap;\n }\n\n public handleInitialCheckout(initialCheckout: DeltaNetClientWebsocketInitialCheckout): {\n addedStableIds: Array<number>;\n } {\n const { indicesCount, initialComponents, initialStates } = initialCheckout;\n const addedStableIds: Array<number> = [];\n for (let i = 0; i < indicesCount; i++) {\n const stableId = this.stableIdCounter++;\n this.stableIds.push(stableId);\n this.stableIdToIndex.set(stableId, i);\n const entityInfo: EntityInfo = {\n stableId,\n components: new Map(),\n states: new Map(),\n };\n this.byStableId.set(stableId, entityInfo);\n addedStableIds.push(stableId);\n }\n this.indicesCount = indicesCount;\n\n const deltaDeltas = new BigInt64Array(indicesCount);\n for (let i = 0; i < deltaDeltas.length; i++) {\n deltaDeltas[i] = BigInt(0);\n }\n\n for (const [key, value] of initialComponents) {\n this.componentValues.set(key, {\n values: value.values,\n deltas: value.deltas,\n deltaDeltas,\n });\n\n for (let i = 0; i < this.stableIds.length; i++) {\n const stableId = this.stableIds[i];\n const entityInfo = this.byStableId.get(stableId);\n if (entityInfo) {\n entityInfo.components.set(key, value.values[i]);\n }\n }\n }\n\n for (const [stateId, values] of initialStates) {\n this.allStates.set(stateId, values);\n\n for (let i = 0; i < this.stableIds.length; i++) {\n const stableId = this.stableIds[i];\n const entityInfo = this.byStableId.get(stableId);\n const stateValue = values[i];\n if (entityInfo) {\n entityInfo.states.set(stateId, stateValue);\n }\n }\n }\n\n return { addedStableIds };\n }\n\n public handleTick(tick: DeltaNetClientWebsocketTick): {\n stateUpdates: Array<EntityStateUpdate>;\n removedStableIds: Array<number>;\n addedStableIds: Array<number>;\n } {\n const { unoccupying, indicesCount, componentDeltaDeltas, stateChanges } = tick;\n\n let removedStableIds: Array<number> = [];\n\n if (unoccupying.length > 0) {\n // Collect stableIds to remove before mutating stableIds\n const stableIdsToRemove = unoccupying.map((index) => this.stableIds[index]);\n removedStableIds = stableIdsToRemove.filter((stableId) => stableId !== undefined);\n\n // Remove unoccupying indices from component values\n for (const [componentId, component] of this.componentValues) {\n this.removeIndicesFromBigInt64Array(unoccupying, component.values);\n this.removeIndicesFromBigInt64Array(unoccupying, component.deltas);\n }\n\n // Remove unoccupying indices from states\n for (const [stateId, state] of this.allStates) {\n this.removeIndicesFromState(unoccupying, state);\n }\n\n // Update localClientIndex\n let decrementIndex = 0;\n for (const index of unoccupying) {\n if (index <= this.localClientIndex) {\n decrementIndex++;\n }\n }\n this.localClientIndex -= decrementIndex;\n\n // Update indices count\n this.indicesCount -= unoccupying.length;\n\n // Update stable indices and stableIds array\n this.removeIndices(unoccupying);\n\n // Remove unoccupied stables from byStableId\n for (const stableId of stableIdsToRemove) {\n if (stableId === undefined) {\n throw new Error(`stableId is undefined`);\n }\n this.byStableId.delete(stableId);\n }\n }\n\n const addedStableIds: Array<number> = [];\n\n if (indicesCount > this.indicesCount) {\n const addedIndices = indicesCount - this.indicesCount;\n\n for (let i = 0; i < addedIndices; i++) {\n const stableId = this.stableIdCounter++;\n this.stableIds.push(stableId);\n this.stableIdToIndex.set(stableId, this.stableIds.length - 1);\n const entityInfo: EntityInfo = {\n stableId,\n components: new Map(),\n states: new Map(),\n };\n this.byStableId.set(stableId, entityInfo);\n addedStableIds.push(stableId);\n }\n }\n\n this.indicesCount = indicesCount;\n\n // Update component values\n for (const [key, deltaDeltas] of componentDeltaDeltas) {\n if (deltaDeltas.length !== indicesCount) {\n throw new Error(\n `DeltaDeltas length (${deltaDeltas.length}) does not match indices count (${indicesCount})`,\n );\n }\n const existingComponent = this.componentValues.get(key);\n if (!existingComponent) {\n const values = new BigInt64Array(deltaDeltas);\n const deltas = new BigInt64Array(deltaDeltas);\n this.componentValues.set(key, { values, deltas, deltaDeltas });\n } else {\n if (existingComponent.values.length < deltaDeltas.length) {\n // Resize the arrays\n const newValues = new BigInt64Array(deltaDeltas.length);\n newValues.set(existingComponent.values);\n const newDeltas = new BigInt64Array(deltaDeltas.length);\n newDeltas.set(existingComponent.deltas);\n const newDeltaDelta = new BigInt64Array(deltaDeltas.length);\n newDeltaDelta.set(existingComponent.deltaDeltas);\n for (let i = existingComponent.values.length; i < deltaDeltas.length; i++) {\n newValues[i] = BigInt(0);\n newDeltas[i] = BigInt(0);\n newDeltaDelta[i] = BigInt(0);\n }\n existingComponent.values = newValues;\n existingComponent.deltas = newDeltas;\n existingComponent.deltaDeltas = newDeltaDelta;\n }\n\n for (let i = 0; i < deltaDeltas.length; i++) {\n const deltaDelta = deltaDeltas[i];\n const stableId = this.stableIds[i];\n\n existingComponent.deltaDeltas[i] = deltaDelta;\n existingComponent.deltas[i] += deltaDelta;\n existingComponent.values[i] += existingComponent.deltas[i];\n\n // Update byStableId map with new component values\n const entityInfo = this.byStableId.get(stableId);\n if (entityInfo) {\n entityInfo.components.set(key, existingComponent.values[i]);\n }\n }\n }\n }\n\n const stateUpdates: Array<EntityStateUpdate> = [];\n\n // Update states\n for (const [stateId, states] of stateChanges) {\n let state = this.allStates.get(stateId);\n if (!state) {\n state = [];\n this.allStates.set(stateId, state);\n }\n\n for (const [index, value] of states) {\n const stableId = this.stableIds[index];\n\n if (stableId === undefined) {\n throw new Error(`Stable ID is undefined for index ${index} in state ${stateId}`);\n }\n\n stateUpdates.push({\n stableId,\n stateId,\n state: value,\n });\n state[index] = value;\n\n // Update byStableId map with new state values\n const entityInfo = this.byStableId.get(stableId);\n if (entityInfo) {\n entityInfo.states.set(stateId, value);\n }\n }\n }\n\n return { stateUpdates, removedStableIds, addedStableIds };\n }\n\n public setLocalIndex(index: number) {\n this.localClientIndex = index;\n }\n\n private removeIndices(removing: Array<number>) {\n if (removing.length === 0) {\n return;\n }\n\n let writeIndex = 0;\n let skipIndex = 0;\n\n for (let readIndex = 0; readIndex < this.stableIds.length; readIndex++) {\n if (skipIndex < removing.length && readIndex === removing[skipIndex]) {\n skipIndex++;\n continue;\n }\n\n const stableId = this.stableIds[readIndex];\n if (writeIndex !== readIndex) {\n this.stableIds[writeIndex] = this.stableIds[readIndex];\n }\n // Update the mapping for all remaining elements to their new indices\n this.stableIdToIndex.set(stableId, writeIndex);\n\n writeIndex++;\n }\n\n // Actually shrink the array to the correct size\n this.stableIds.length = writeIndex;\n }\n\n private removeIndicesFromBigInt64Array(removing: Array<number>, array: BigInt64Array) {\n if (removing.length === 0) {\n return;\n }\n\n let writeIndex = 0;\n let skipIndex = 0;\n\n for (let readIndex = 0; readIndex < array.length; readIndex++) {\n if (skipIndex < removing.length && readIndex === removing[skipIndex]) {\n skipIndex++;\n continue;\n }\n\n if (writeIndex !== readIndex) {\n array[writeIndex] = array[readIndex];\n }\n\n writeIndex++;\n }\n for (let i = writeIndex; i < array.length; i++) {\n array[i] = BigInt(0);\n }\n }\n\n private removeIndicesFromState(removing: Array<number>, state: Array<Uint8Array | null>) {\n if (removing.length === 0) {\n return;\n }\n\n let writeIndex = 0;\n let skipIndex = 0;\n\n for (let readIndex = 0; readIndex < state.length; readIndex++) {\n if (skipIndex < removing.length && readIndex === removing[skipIndex]) {\n skipIndex++;\n continue;\n }\n\n if (writeIndex !== readIndex) {\n state[writeIndex] = state[readIndex];\n }\n\n writeIndex++;\n }\n }\n}\n", "import { deltaNetProtocolSubProtocol_v0_1 } from \"@mml-io/delta-net-protocol\";\n\nimport { DeltaNetClientWebsocketV01Adapter } from \"./DeltaNetClientWebsocketV01Adapter\";\n\nconst startingBackoffTimeMilliseconds = 100;\nconst maximumBackoffTimeMilliseconds = 10000;\nconst maximumWebsocketConnectionTimeout = 5000;\n\nexport type DeltaNetClientWebsocketFactory = (url: string) => WebSocket;\n\nexport enum DeltaNetClientWebsocketStatus {\n Connecting,\n ConnectionOpen, // The websocket is open and connected, but no messages have been received yet\n Connected, // The websocket is open and connected, and messages are being received\n Reconnecting,\n Disconnected,\n}\n\nexport function DeltaNetClientWebsocketStatusToString(\n status: DeltaNetClientWebsocketStatus,\n): string {\n switch (status) {\n case DeltaNetClientWebsocketStatus.Connecting:\n return \"Connecting...\";\n case DeltaNetClientWebsocketStatus.ConnectionOpen:\n return \"Connection Open\";\n case DeltaNetClientWebsocketStatus.Connected:\n return \"Connected\";\n case DeltaNetClientWebsocketStatus.Reconnecting:\n return \"Reconnecting...\";\n case DeltaNetClientWebsocketStatus.Disconnected:\n return \"Disconnected\";\n default:\n return \"Unknown\";\n }\n}\n\nexport type DeltaNetClientWebsocketInitialCheckout = {\n indicesCount: number;\n initialComponents: Map<number, { values: BigInt64Array; deltas: BigInt64Array }>;\n initialStates: Map<number, Array<Uint8Array>>;\n};\n\nexport type DeltaNetClientWebsocketTick = {\n unoccupying: Array<number>;\n indicesCount: number;\n componentDeltaDeltas: Map<number, BigInt64Array>;\n stateChanges: Map<number, Map<number, Uint8Array>>;\n};\n\nexport type DeltaNetClientWebsocketUserIndex = {\n userIndex: number;\n};\n\nexport type DeltaNetClientWebsocketOptions = {\n ignoreData?: boolean;\n observer?: boolean;\n onUserIndex: (userIndex: DeltaNetClientWebsocketUserIndex) => void;\n onInitialCheckout: (initialCheckout: DeltaNetClientWebsocketInitialCheckout) => void;\n onTick: (tick: DeltaNetClientWebsocketTick) => void;\n onError: (errorType: string, errorMessage: string, retryable: boolean) => void;\n onWarning: (warning: string) => void;\n onServerCustom?: (customType: number, contents: string) => void;\n};\n\nexport type DeltaNetClientWebsocketAdapter = {\n receiveMessage: (message: MessageEvent) => void;\n setUserComponents: (\n components: Map<number, bigint>,\n changedStates: Map<number, Uint8Array>,\n ) => void;\n sendCustomMessage: (customType: number, contents: string) => void;\n didConnect: () => boolean;\n dispose: () => void;\n};\n\nfunction updateLastSecondArray(\n records: Array<[number, number]>,\n size: number,\n time: number,\n): number {\n let sizeChange = size;\n const oneSecondAgo = time - 1000;\n records.push([time, size]);\n let i;\n for (i = 0; i < records.length; i++) {\n if (records[i][0] < oneSecondAgo) {\n sizeChange -= records[i][1];\n } else {\n break;\n }\n }\n records.splice(0, i);\n return sizeChange;\n}\n\n/**\n * DeltaNetClientWebsocket is a client for a DeltaNetServer. It connects to a server on the provided url and receives\n * updates to the DOM. It also sends events to the server for interactions with the DOM.\n *\n * The DeltaNetClientWebsocket is attached to a parentElement and synchronizes the received DOM under that element.\n */\nexport class DeltaNetClientWebsocket {\n private websocket: WebSocket | null = null;\n private websocketAdapter: DeltaNetClientWebsocketAdapter | null = null;\n\n private stopped = false;\n private backoffTime = startingBackoffTimeMilliseconds;\n private status: DeltaNetClientWebsocketStatus = DeltaNetClientWebsocketStatus.Connecting;\n\n public bandwidthPerSecond = 0;\n public lastSecondMessageSizes: Array<[number, number]> = []; // Timestamp in ms, size in bytes\n public componentBytesPerSecond = 0;\n public lastSecondComponentBufferSizes: Array<[number, number]> = []; // Timestamp in ms, size in bytes\n public stateBytesPerSecond = 0;\n public lastSecondStateBufferSizes: Array<[number, number]> = []; // Timestamp in ms, size in bytes\n\n public static createWebSocket(url: string): WebSocket {\n return new WebSocket(url, [deltaNetProtocolSubProtocol_v0_1]);\n }\n\n constructor(\n private url: string,\n private websocketFactory: DeltaNetClientWebsocketFactory,\n private token: string,\n private options: DeltaNetClientWebsocketOptions,\n private timeCallback?: (time: number) => void,\n private statusUpdateCallback?: (status: DeltaNetClientWebsocketStatus) => void,\n ) {\n this.setStatus(DeltaNetClientWebsocketStatus.Connecting);\n this.startWebSocketConnectionAttempt();\n }\n\n private setStatus(status: DeltaNetClientWebsocketStatus) {\n if (this.status !== status) {\n this.status = status;\n if (this.statusUpdateCallback) {\n this.statusUpdateCallback(status);\n }\n }\n }\n\n public getStatus(): DeltaNetClientWebsocketStatus {\n return this.status;\n }\n\n private async createWebsocketWithTimeout(timeout: number): Promise<WebSocket> {\n return new Promise((resolve, reject) => {\n const websocket = this.websocketFactory(this.url);\n const timeoutId = setTimeout(() => {\n reject(new Error(\"websocket connection timed out\"));\n websocket.close();\n }, timeout);\n websocket.binaryType = \"arraybuffer\";\n websocket.addEventListener(\"open\", () => {\n clearTimeout(timeoutId);\n\n this.websocket = websocket;\n const websocketAdapter: DeltaNetClientWebsocketAdapter =\n new DeltaNetClientWebsocketV01Adapter(\n websocket,\n () => {\n this.backoffTime = startingBackoffTimeMilliseconds;\n this.setStatus(DeltaNetClientWebsocketStatus.Connected);\n },\n this.options,\n this.token,\n {\n receivedBytes: (bytes: number, now: number) => {\n this.bandwidthPerSecond += updateLastSecondArray(\n this.lastSecondMessageSizes,\n bytes,\n now,\n );\n },\n receivedComponentBytes: (bytes: number, now: number) => {\n this.componentBytesPerSecond += updateLastSecondArray(\n this.lastSecondComponentBufferSizes,\n bytes,\n now,\n );\n },\n receivedStateBytes: (bytes: number, now: number) => {\n this.stateBytesPerSecond += updateLastSecondArray(\n this.lastSecondStateBufferSizes,\n bytes,\n now,\n );\n },\n onError: (errorType: string, errorMessage: string, retryable: boolean) => {\n this.options.onError(errorType, errorMessage, retryable);\n if (this.websocket === websocket) {\n this.websocket?.close();\n this.websocket = null;\n this.websocketAdapter?.dispose();\n this.websocketAdapter = null;\n onWebsocketClose(retryable);\n }\n },\n onWarning: (warning: string) => {\n this.options.onWarning(warning);\n },\n },\n this.timeCallback,\n );\n\n this.websocketAdapter = websocketAdapter;\n\n websocket.addEventListener(\"message\", (event) => {\n if (websocket !== this.websocket) {\n console.log(\"Ignoring websocket message event because it is no longer current\");\n websocket.close();\n return;\n }\n if (this.stopped) {\n console.warn(\"Ignoring websocket message event because the client is stopped\");\n return;\n }\n\n websocketAdapter.receiveMessage(event);\n });\n\n const onWebsocketClose = async (retryable: boolean = true) => {\n let didConnect = false;\n if (this.websocketAdapter) {\n didConnect = this.websocketAdapter.didConnect();\n }\n if (this.stopped) {\n // This closing is expected. The client closed the websocket.\n this.setStatus(DeltaNetClientWebsocketStatus.Disconnected);\n return;\n }\n if (retryable) {\n if (!didConnect) {\n // The websocket did not deliver any contents.\n // It may have been successfully opened, but immediately closed.\n // This client should back off to prevent this happening in a rapid loop.\n await this.waitBackoffTime();\n }\n // The websocket closed unexpectedly. Try to reconnect.\n this.setStatus(DeltaNetClientWebsocketStatus.Reconnecting);\n this.startWebSocketConnectionAttempt();\n } else {\n this.setStatus(DeltaNetClientWebsocketStatus.Disconnected);\n }\n };\n\n websocket.addEventListener(\"close\", () => {\n if (websocket !== this.websocket) {\n console.warn(\"Ignoring websocket close event because it is no longer current\");\n return;\n }\n this.websocket = null;\n this.websocketAdapter?.dispose();\n this.websocketAdapter = null;\n onWebsocketClose();\n });\n websocket.addEventListener(\"error\", (e) => {\n if (websocket !== this.websocket) {\n console.log(\"Ignoring websocket error event because it is no longer current\");\n return;\n }\n console.error(\"DeltaNetClientWebsocket error\", e);\n this.websocket = null;\n this.websocketAdapter?.dispose();\n this.websocketAdapter = null;\n onWebsocketClose();\n });\n\n this.setStatus(DeltaNetClientWebsocketStatus.ConnectionOpen);\n resolve(websocket);\n });\n websocket.addEventListener(\"error\", (e) => {\n clearTimeout(timeoutId);\n reject(e);\n });\n });\n }\n\n private async waitBackoffTime(): Promise<void> {\n console.warn(`Websocket connection to '${this.url}' failed: retrying in ${this.backoffTime}ms`);\n await new Promise((resolve) => setTimeout(resolve, this.backoffTime));\n this.backoffTime = Math.min(\n // Introduce a small amount of randomness to prevent clients from retrying in lockstep\n this.backoffTime * (1.5 + Math.random() * 0.5),\n maximumBackoffTimeMilliseconds,\n );\n }\n\n private async startWebSocketConnectionAttempt() {\n if (this.stopped) {\n return;\n }\n while (true) {\n if (this.stopped) {\n return;\n }\n try {\n await this.createWebsocketWithTimeout(maximumWebsocketConnectionTimeout);\n break;\n } catch (e) {\n console.error(\"Websocket connection failed\", e);\n // Connection failed, retry with backoff\n this.setStatus(DeltaNetClientWebsocketStatus.Reconnecting);\n await this.waitBackoffTime();\n }\n }\n }\n\n public stop() {\n this.stopped = true;\n if (this.websocket !== null) {\n this.websocket.close();\n this.websocket = null;\n }\n this.websocketAdapter?.dispose();\n this.websocketAdapter = null;\n }\n\n public setUserComponents(\n components: Map<number, bigint>,\n changedStates: Map<number, Uint8Array>,\n ) {\n if (this.websocketAdapter) {\n this.websocketAdapter.setUserComponents(components, changedStates);\n }\n }\n\n public sendCustomMessage(customType: number, contents: string) {\n if (this.websocketAdapter) {\n this.websocketAdapter.sendCustomMessage(customType, contents);\n }\n }\n}\n", "import {\n BufferReader,\n BufferWriter,\n decodeServerMessages,\n DeltaNetV01ClientMessage,\n DeltaNetV01ClientCustomMessage,\n DeltaNetV01InitialCheckoutMessage,\n DeltaNetV01PingMessage,\n DeltaNetV01ServerMessage,\n DeltaNetV01ServerCustomMessage,\n DeltaNetV01SetUserComponentsMessage,\n DeltaNetV01Tick,\n DeltaNetV01UserIndexMessage,\n encodeClientMessage,\n lastInitialCheckoutDebugData,\n lastTickDebugData,\n} from \"@mml-io/delta-net-protocol\";\n\nimport {\n DeltaNetClientWebsocketAdapter,\n DeltaNetClientWebsocketOptions,\n} from \"./DeltaNetClientWebsocket\";\n\nfunction areUint8ArraysEqual(a: Uint8Array, b: Uint8Array): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\nexport class DeltaNetClientWebsocketV01Adapter implements DeltaNetClientWebsocketAdapter {\n private gotInitialCheckout = false;\n private sentUserConnect = false;\n private receivedUserIndex = false;\n private queuedStateUpdates = new Map<number, Uint8Array>();\n private states = new Map<number, Uint8Array>();\n private disposed = false;\n private isObserver: boolean;\n\n constructor(\n private websocket: WebSocket,\n private connectedCallback: () => void,\n private options: DeltaNetClientWebsocketOptions,\n private token: string,\n private internalOptions: {\n receivedBytes: (bytes: number, now: number) => void;\n receivedComponentBytes: (bytes: number, now: number) => void;\n receivedStateBytes: (bytes: number, now: number) => void;\n onError: (errorType: string, errorMessage: string, retryable: boolean) => void;\n onWarning: (warning: string) => void;\n },\n private timeCallback?: (time: number) => void,\n ) {\n this.websocket.binaryType = \"arraybuffer\";\n this.isObserver = options.observer ?? false;\n\n // Observers need to send connectUser message immediately since they won't call setUserComponents\n if (this.isObserver) {\n this.sendConnectUser([], []);\n }\n }\n\n private sendConnectUser(\n components: Array<[number, bigint]>,\n states: Array<[number, Uint8Array]>,\n ) {\n if (this.sentUserConnect) {\n return;\n }\n\n this.sentUserConnect = true;\n this.send({\n type: \"connectUser\",\n token: this.token,\n observer: this.isObserver,\n components: this.isObserver ? [] : components,\n states: this.isObserver ? [] : states,\n });\n }\n\n public setUserComponents(\n components: Map<number, bigint>,\n changedStates: Map<number, Uint8Array>,\n ) {\n if (this.disposed) {\n throw new Error(\"DeltaNetClientWebsocketV01Adapter is disposed\");\n }\n\n const messageComponents: Array<[number, bigint]> = [];\n for (const [componentId, value] of components) {\n messageComponents.push([componentId, value]);\n }\n\n const messageStates: Array<[number, Uint8Array]> = [];\n for (const [stateId, value] of changedStates) {\n const currentState = this.states.get(stateId);\n if (currentState && areUint8ArraysEqual(currentState, value)) {\n continue;\n }\n this.states.set(stateId, value);\n messageStates.push([stateId, value]);\n }\n\n if (!this.sentUserConnect) {\n this.sendConnectUser(messageComponents, messageStates);\n return;\n }\n\n // Observers should not send component updates after initial connection\n if (this.isObserver) {\n return;\n }\n\n let messageStatesToSend: Array<[number, Uint8Array]> = [];\n if (this.receivedUserIndex) {\n messageStatesToSend = messageStates;\n } else {\n for (const [stateId, value] of messageStates) {\n this.queuedStateUpdates.set(stateId, value);\n }\n }\n\n if (messageComponents.length > 0 || messageStatesToSend.length > 0) {\n const setUserComponents: DeltaNetV01SetUserComponentsMessage = {\n type: \"setUserComponents\",\n components: messageComponents,\n states: messageStatesToSend,\n };\n\n this.send(setUserComponents);\n }\n }\n\n private send(message: DeltaNetV01ClientMessage) {\n const writer = new BufferWriter(256);\n encodeClientMessage(message, writer);\n this.websocket.send(writer.getBuffer());\n }\n\n public sendCustomMessage(customType: number, contents: string) {\n if (this.disposed) {\n return;\n }\n\n const customMessage: DeltaNetV01ClientCustomMessage = {\n type: \"clientCustom\",\n customType,\n contents,\n };\n\n this.send(customMessage);\n }\n\n public receiveMessage(event: MessageEvent) {\n if (this.disposed) {\n return;\n }\n\n const buffer = new Uint8Array(event.data);\n const now = Date.now();\n this.internalOptions.receivedBytes(buffer.byteLength, now);\n const reader = new BufferReader(buffer);\n const messages = decodeServerMessages(reader, {\n ignoreData: this.options.ignoreData,\n });\n for (const message of messages) {\n this.applyMessage(message, now);\n }\n }\n\n private applyMessage(message: DeltaNetV01ServerMessage, now: number) {\n switch (message.type) {\n case \"error\":\n console.error(\"Error from server\", message);\n this.internalOptions.onError(message.errorType, message.message, message.retryable);\n break;\n case \"warning\":\n console.warn(\"Warning from server\", message);\n this.internalOptions.onWarning(message.message);\n break;\n case \"initialCheckout\":\n this.handleInitialCheckout(message, now);\n this.connectedCallback();\n break;\n case \"tick\":\n this.handleTick(message, now);\n break;\n case \"userIndex\":\n this.handleUserIndex(message);\n break;\n case \"ping\":\n this.handlePing(message);\n break;\n case \"serverCustom\":\n this.handleServerCustom(message);\n break;\n default:\n console.warn(\"unknown message type\", message);\n break;\n }\n }\n\n private handleUserIndex(message: DeltaNetV01UserIndexMessage) {\n this.receivedUserIndex = true;\n\n this.options.onUserIndex({\n userIndex: message.index,\n });\n\n this.sendQueuedUpdates();\n }\n\n private sendQueuedUpdates() {\n if (this.queuedStateUpdates.size > 0) {\n const queuedStatesArray: Array<[number, Uint8Array]> = [];\n for (const [stateId, value] of this.queuedStateUpdates) {\n queuedStatesArray.push([stateId, value]);\n }\n const setUserComponents: DeltaNetV01SetUserComponentsMessage = {\n type: \"setUserComponents\",\n components: [],\n states: queuedStatesArray,\n };\n this.send(setUserComponents);\n this.queuedStateUpdates.clear();\n }\n }\n\n private handlePing(message: DeltaNetV01PingMessage) {\n this.send({\n type: \"pong\",\n pong: message.ping,\n });\n }\n\n private handleServerCustom(message: DeltaNetV01ServerCustomMessage) {\n this.options.onServerCustom?.(message.customType, message.contents);\n }\n\n public didConnect(): boolean {\n return this.gotInitialCheckout;\n }\n\n private handleInitialCheckout(message: DeltaNetV01InitialCheckoutMessage, now: number) {\n this.gotInitialCheckout = true;\n\n if (this.options.ignoreData) {\n return;\n }\n\n const components = new Map<number, { values: BigInt64Array; deltas: BigInt64Array }>();\n for (const { componentId, deltas, values } of message.components) {\n components.set(componentId, { values, deltas });\n }\n\n const allStates = new Map<number, Array<Uint8Array>>();\n for (const { stateId, values } of message.states) {\n allStates.set(stateId, values);\n }\n\n this.internalOptions.receivedComponentBytes(\n lastInitialCheckoutDebugData.componentsByteLength,\n now,\n );\n this.internalOptions.receivedStateBytes(lastInitialCheckoutDebugData.statesByteLength, now);\n\n this.options.onInitialCheckout({\n indicesCount: message.indicesCount,\n initialComponents: components,\n initialStates: allStates,\n });\n }\n\n private handleTick(message: DeltaNetV01Tick, now: number) {\n if (this.options.ignoreData) {\n return;\n }\n this.timeCallback?.(message.serverTime);\n const components = new Map<number, BigInt64Array>();\n for (const { componentId, deltaDeltas } of message.componentDeltaDeltas) {\n components.set(componentId, deltaDeltas);\n }\n\n const stateChanges = new Map<number, Map<number, Uint8Array>>();\n for (const stateChange of message.states) {\n const updatedStates = new Map<number, Uint8Array>();\n for (const [index, value] of stateChange.updatedStates) {\n updatedStates.set(index, value);\n }\n stateChanges.set(stateChange.stateId, updatedStates);\n }\n\n this.internalOptions.receivedComponentBytes(lastTickDebugData.componentsByteLength, now);\n this.internalOptions.receivedStateBytes(lastTickDebugData.statesByteLength, now);\n\n this.options.onTick({\n unoccupying: message.removedIndices,\n indicesCount: message.indicesCount,\n componentDeltaDeltas: components,\n stateChanges,\n });\n }\n\n dispose() {\n this.disposed = true;\n }\n}\n"],
|
5
|
+
"mappings": "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",
|
6
|
+
"names": ["DeltaNetClientWebsocketStatus"]
|
7
|
+
}
|
package/package.json
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
{
|
2
|
+
"name": "@mml-io/delta-net-web",
|
3
|
+
"version": "0.0.0-experimental-bcf0b7c-20250715",
|
4
|
+
"publishConfig": {
|
5
|
+
"access": "public"
|
6
|
+
},
|
7
|
+
"main": "./build/index.js",
|
8
|
+
"types": "./build/index.d.ts",
|
9
|
+
"type": "module",
|
10
|
+
"files": [
|
11
|
+
"/build"
|
12
|
+
],
|
13
|
+
"scripts": {
|
14
|
+
"type-check": "tsc --noEmit",
|
15
|
+
"build": "tsx ./build.ts --build",
|
16
|
+
"iterate": "tsx ./build.ts --watch",
|
17
|
+
"lint": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --max-warnings 0",
|
18
|
+
"lint-fix": "eslint \"./{src,test}/**/*.{js,jsx,ts,tsx}\" --fix",
|
19
|
+
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
|
20
|
+
"test-iterate": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch"
|
21
|
+
},
|
22
|
+
"dependencies": {
|
23
|
+
"@mml-io/delta-net-protocol": "0.0.0-experimental-bcf0b7c-20250715"
|
24
|
+
},
|
25
|
+
"devDependencies": {
|
26
|
+
"jest-canvas-mock": "2.5.2",
|
27
|
+
"jest-environment-jsdom": "29.7.0",
|
28
|
+
"jest-expect-message": "1.1.3",
|
29
|
+
"jest-junit": "16.0.0"
|
30
|
+
}
|
31
|
+
}
|