atom.io 0.46.5 → 0.46.7
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/realtime/index.d.ts +7 -6
- package/dist/realtime/index.d.ts.map +1 -1
- package/dist/realtime/index.js +19 -10
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime-client/index.d.ts +13 -13
- package/dist/realtime-client/index.d.ts.map +1 -1
- package/dist/realtime-client/index.js +10 -3
- package/dist/realtime-client/index.js.map +1 -1
- package/dist/realtime-server/index.d.ts +49 -41
- package/dist/realtime-server/index.d.ts.map +1 -1
- package/dist/realtime-server/index.js +126 -97
- package/dist/realtime-server/index.js.map +1 -1
- package/dist/realtime-testing/index.js +2 -2
- package/dist/realtime-testing/index.js.map +1 -1
- package/package.json +18 -17
- package/src/realtime/realtime-continuity.ts +2 -2
- package/src/realtime/shared-room-store.ts +38 -17
- package/src/realtime/socket-interface.ts +1 -1
- package/src/realtime-client/continuity/register-and-attempt-confirmed-update.ts +3 -1
- package/src/realtime-client/continuity/use-conceal-state.ts +2 -1
- package/src/realtime-client/pull-atom-family-member.ts +1 -1
- package/src/realtime-client/pull-atom.ts +1 -1
- package/src/realtime-client/pull-mutable-atom-family-member.ts +1 -1
- package/src/realtime-client/pull-mutable-atom.ts +1 -1
- package/src/realtime-client/pull-selector-family-member.ts +1 -1
- package/src/realtime-client/pull-selector-roots.ts +1 -1
- package/src/realtime-client/pull-selector.ts +1 -1
- package/src/realtime-client/push-state.ts +1 -1
- package/src/realtime-client/realtime-client-stores/client-main-store.ts +16 -3
- package/src/realtime-client/sync-continuity.ts +1 -2
- package/src/realtime-server/continuity/provide-outcomes.ts +1 -1
- package/src/realtime-server/ipc-sockets/child-socket.ts +6 -9
- package/src/realtime-server/ipc-sockets/parent-socket.ts +1 -8
- package/src/realtime-server/provide-rooms.ts +64 -16
- package/src/realtime-server/realtime-family-provider.ts +51 -35
- package/src/realtime-server/realtime-mutable-family-provider.ts +50 -34
- package/src/realtime-server/realtime-mutable-provider.ts +4 -4
- package/src/realtime-server/realtime-state-provider.ts +7 -7
- package/src/realtime-server/realtime-state-receiver.ts +2 -2
- package/src/realtime-server/server-config.ts +20 -13
- package/src/realtime-server/server-socket-state.ts +3 -3
- package/src/realtime-testing/setup-realtime-test.tsx +2 -2
|
@@ -23,7 +23,7 @@ export type RoomSocketInterface<RoomNames extends string> = {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
export const roomKeysAtom: MutableAtomToken<UList<RoomKey>> = mutableAtom({
|
|
26
|
-
key: `
|
|
26
|
+
key: `roomKeys`,
|
|
27
27
|
class: UList,
|
|
28
28
|
})
|
|
29
29
|
|
|
@@ -43,10 +43,10 @@ export const usersInRooms: JoinToken<`room`, RoomKey, `user`, UserKey, `1:n`> =
|
|
|
43
43
|
})
|
|
44
44
|
|
|
45
45
|
export const visibleUsersInRoomsSelector: PureSelectorFamilyToken<
|
|
46
|
-
|
|
46
|
+
[self: UserKey, ...RoomKey[]],
|
|
47
47
|
UserKey
|
|
48
48
|
> = selectorFamily({
|
|
49
|
-
key: `
|
|
49
|
+
key: `visibleUsersInRooms`,
|
|
50
50
|
get:
|
|
51
51
|
(userKey) =>
|
|
52
52
|
({ get }) => {
|
|
@@ -56,6 +56,41 @@ export const visibleUsersInRoomsSelector: PureSelectorFamilyToken<
|
|
|
56
56
|
},
|
|
57
57
|
})
|
|
58
58
|
|
|
59
|
+
export const visibilityFromRoomSelector: PureSelectorFamilyToken<
|
|
60
|
+
[self: RoomKey, ...UserKey[]],
|
|
61
|
+
RoomKey
|
|
62
|
+
> = selectorFamily({
|
|
63
|
+
key: `visibilityFromRoom`,
|
|
64
|
+
get:
|
|
65
|
+
(roomKey) =>
|
|
66
|
+
({ get }) => {
|
|
67
|
+
const [usersOfRoomsAtoms] = getInternalRelations(usersInRooms, `split`)
|
|
68
|
+
const users = get(usersOfRoomsAtoms, roomKey)
|
|
69
|
+
return [roomKey, ...users]
|
|
70
|
+
},
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
export const mutualUsersSelector: ReadonlyPureSelectorFamilyToken<
|
|
74
|
+
UserKey[],
|
|
75
|
+
UserKey
|
|
76
|
+
> = selectorFamily({
|
|
77
|
+
key: `mutualUsers`,
|
|
78
|
+
get:
|
|
79
|
+
(userKey) =>
|
|
80
|
+
({ get }) => {
|
|
81
|
+
const [usersOfRoomsAtoms, roomsOfUsersAtoms] = getInternalRelations(
|
|
82
|
+
usersInRooms,
|
|
83
|
+
`split`,
|
|
84
|
+
)
|
|
85
|
+
const rooms = get(roomsOfUsersAtoms, userKey)
|
|
86
|
+
for (const room of rooms) {
|
|
87
|
+
const users = get(usersOfRoomsAtoms, room)
|
|
88
|
+
return [...users]
|
|
89
|
+
}
|
|
90
|
+
return []
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
|
|
59
94
|
export const ownersOfRooms: JoinToken<`user`, UserKey, `room`, RoomKey, `1:n`> =
|
|
60
95
|
join({
|
|
61
96
|
key: `ownersOfRooms`,
|
|
@@ -64,17 +99,3 @@ export const ownersOfRooms: JoinToken<`user`, UserKey, `room`, RoomKey, `1:n`> =
|
|
|
64
99
|
isAType: isUserKey,
|
|
65
100
|
isBType: isRoomKey,
|
|
66
101
|
})
|
|
67
|
-
|
|
68
|
-
export const usersInMyRoomView: ReadonlyPureSelectorFamilyToken<
|
|
69
|
-
MutableAtomToken<UList<RoomKey>>[],
|
|
70
|
-
UserKey
|
|
71
|
-
> = selectorFamily({
|
|
72
|
-
key: `usersInMyRoomView`,
|
|
73
|
-
get:
|
|
74
|
-
(myUsername) =>
|
|
75
|
-
({ find }) => {
|
|
76
|
-
const [, roomsOfUsersAtoms] = getInternalRelations(usersInRooms, `split`)
|
|
77
|
-
const myRoomIndex = find(roomsOfUsersAtoms, myUsername)
|
|
78
|
-
return [myRoomIndex]
|
|
79
|
-
},
|
|
80
|
-
})
|
|
@@ -48,7 +48,7 @@ export type Socket = {
|
|
|
48
48
|
onAnyOutgoing: (
|
|
49
49
|
listener: (event: string, ...args: Json.Serializable[]) => void,
|
|
50
50
|
) => void
|
|
51
|
-
off: (event: string, listener
|
|
51
|
+
off: (event: string, listener?: (...args: Json.Serializable[]) => void) => void
|
|
52
52
|
offAny: (
|
|
53
53
|
listener: (event: string, ...args: Json.Serializable[]) => void,
|
|
54
54
|
) => void
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
setEpochNumberOfContinuity,
|
|
8
8
|
setIntoStore,
|
|
9
9
|
} from "atom.io/internal"
|
|
10
|
+
import type { Json } from "atom.io/json"
|
|
10
11
|
import type { Socket } from "atom.io/realtime"
|
|
11
12
|
|
|
12
13
|
import {
|
|
@@ -27,7 +28,8 @@ export const useRegisterAndAttemptConfirmedUpdate =
|
|
|
27
28
|
>[],
|
|
28
29
|
) =>
|
|
29
30
|
(
|
|
30
|
-
confirmed: AtomIO.TransactionOutcomeEvent<AtomIO.TransactionToken<Fn
|
|
31
|
+
confirmed: AtomIO.TransactionOutcomeEvent<AtomIO.TransactionToken<Fn>> &
|
|
32
|
+
Json.Serializable,
|
|
31
33
|
): void => {
|
|
32
34
|
function reconcileEpoch(
|
|
33
35
|
optimisticUpdate: AtomIO.TransactionOutcomeEvent<
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { AtomToken } from "atom.io"
|
|
2
2
|
import type { Store } from "atom.io/internal"
|
|
3
3
|
import { disposeAtom } from "atom.io/internal"
|
|
4
|
+
import type { Json } from "atom.io/json"
|
|
4
5
|
|
|
5
6
|
export function useConcealState(store: Store) {
|
|
6
|
-
return (concealed: AtomToken<
|
|
7
|
+
return (concealed: AtomToken<Json.Serializable>[]): void => {
|
|
7
8
|
for (const token of concealed) {
|
|
8
9
|
disposeAtom(store, token)
|
|
9
10
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type * as AtomIO from "atom.io"
|
|
2
2
|
import { findInStore, setIntoStore, type Store } from "atom.io/internal"
|
|
3
3
|
import type { Canonical, Json } from "atom.io/json"
|
|
4
|
-
import type { Socket } from "
|
|
4
|
+
import type { Socket } from "atom.io/realtime"
|
|
5
5
|
|
|
6
6
|
export function pullAtomFamilyMember<
|
|
7
7
|
J extends Json.Serializable,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type * as AtomIO from "atom.io"
|
|
2
2
|
import { setIntoStore, type Store } from "atom.io/internal"
|
|
3
3
|
import type { Json } from "atom.io/json"
|
|
4
|
-
import type { Socket } from "
|
|
4
|
+
import type { Socket } from "atom.io/realtime"
|
|
5
5
|
|
|
6
6
|
export function pullAtom<J extends Json.Serializable>(
|
|
7
7
|
store: Store,
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
setIntoStore,
|
|
8
8
|
} from "atom.io/internal"
|
|
9
9
|
import type { Canonical } from "atom.io/json"
|
|
10
|
-
import type { Socket } from "
|
|
10
|
+
import type { Socket } from "atom.io/realtime"
|
|
11
11
|
|
|
12
12
|
export function pullMutableAtomFamilyMember<
|
|
13
13
|
T extends Transceiver<any, any, any>,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type * as AtomIO from "atom.io"
|
|
2
2
|
import type { AsJSON, SignalFrom, Store, Transceiver } from "atom.io/internal"
|
|
3
3
|
import { getJsonToken, getUpdateToken, setIntoStore } from "atom.io/internal"
|
|
4
|
-
import type { Socket } from "
|
|
4
|
+
import type { Socket } from "atom.io/realtime"
|
|
5
5
|
|
|
6
6
|
export function pullMutableAtom<T extends Transceiver<any, any, any>>(
|
|
7
7
|
store: Store,
|
|
@@ -2,7 +2,7 @@ import type * as AtomIO from "atom.io"
|
|
|
2
2
|
import type { Store } from "atom.io/internal"
|
|
3
3
|
import { findInStore } from "atom.io/internal"
|
|
4
4
|
import type { Canonical } from "atom.io/json"
|
|
5
|
-
import type { Socket } from "
|
|
5
|
+
import type { Socket } from "atom.io/realtime"
|
|
6
6
|
|
|
7
7
|
import { pullSelectorRoots } from "./pull-selector-roots"
|
|
8
8
|
|
|
@@ -2,7 +2,7 @@ import type { AtomToken, SelectorToken } from "atom.io"
|
|
|
2
2
|
import type { Store } from "atom.io/internal"
|
|
3
3
|
import { getFamilyOfToken, subscribeToState } from "atom.io/internal"
|
|
4
4
|
import { parseJson } from "atom.io/json"
|
|
5
|
-
import type { Socket } from "
|
|
5
|
+
import type { Socket } from "atom.io/realtime"
|
|
6
6
|
|
|
7
7
|
import { pullAtom } from "./pull-atom"
|
|
8
8
|
import { pullAtomFamilyMember } from "./pull-atom-family-member"
|
|
@@ -2,8 +2,8 @@ import type { WritableToken } from "atom.io"
|
|
|
2
2
|
import type { Store } from "atom.io/internal"
|
|
3
3
|
import { setIntoStore, subscribeToState } from "atom.io/internal"
|
|
4
4
|
import type { Json } from "atom.io/json"
|
|
5
|
+
import type { Socket } from "atom.io/realtime"
|
|
5
6
|
import { employSocket, mutexAtoms } from "atom.io/realtime"
|
|
6
|
-
import type { Socket } from "socket.io-client"
|
|
7
7
|
|
|
8
8
|
export function pushState<J extends Json.Serializable>(
|
|
9
9
|
store: Store,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as AtomIO from "atom.io"
|
|
2
|
-
import type { SocketKey, UserKey } from "atom.io/realtime"
|
|
3
|
-
import { storageSync } from "atom.io/web"
|
|
2
|
+
import type { RoomKey, SocketKey, UserKey } from "atom.io/realtime"
|
|
4
3
|
|
|
5
4
|
export const mySocketKeyAtom: AtomIO.RegularAtomToken<SocketKey | undefined> =
|
|
6
5
|
AtomIO.atom<SocketKey | undefined>({
|
|
@@ -12,5 +11,19 @@ export const myUserKeyAtom: AtomIO.RegularAtomToken<UserKey | null> =
|
|
|
12
11
|
AtomIO.atom<UserKey | null>({
|
|
13
12
|
key: `myUserKey`,
|
|
14
13
|
default: null,
|
|
15
|
-
effects: [
|
|
14
|
+
effects: [
|
|
15
|
+
(userKey) => {
|
|
16
|
+
if (typeof window !== `undefined`) {
|
|
17
|
+
void import(`atom.io/web`).then(({ storageSync }) => {
|
|
18
|
+
storageSync(globalThis.localStorage, JSON, `myUserKey`)(userKey)
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
export const myRoomKeyAtom: AtomIO.RegularAtomToken<RoomKey | null> =
|
|
26
|
+
AtomIO.atom<RoomKey | null>({
|
|
27
|
+
key: `myRoomKey`,
|
|
28
|
+
default: null,
|
|
16
29
|
})
|
|
@@ -8,8 +8,7 @@ import {
|
|
|
8
8
|
subscribeToTransaction,
|
|
9
9
|
} from "atom.io/internal"
|
|
10
10
|
import type { Json } from "atom.io/json"
|
|
11
|
-
import type { ContinuityToken } from "atom.io/realtime"
|
|
12
|
-
import type { Socket } from "socket.io-client"
|
|
11
|
+
import type { ContinuityToken, Socket } from "atom.io/realtime"
|
|
13
12
|
|
|
14
13
|
import { useRegisterAndAttemptConfirmedUpdate } from "./continuity/register-and-attempt-confirmed-update"
|
|
15
14
|
import { useConcealState } from "./continuity/use-conceal-state"
|
|
@@ -58,18 +58,10 @@ export class ChildSocket<
|
|
|
58
58
|
) {
|
|
59
59
|
super((event, ...args) => {
|
|
60
60
|
const stringifiedEvent = JSON.stringify([event, ...args]) + `\x03`
|
|
61
|
-
const errorHandler = (err: { code: string }) => {
|
|
62
|
-
if (err.code === `EPIPE`) {
|
|
63
|
-
console.error(`EPIPE error during write`, this.proc.stdin)
|
|
64
|
-
}
|
|
65
|
-
this.proc.stdin.removeListener(`error`, errorHandler)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
this.proc.stdin.once(`error`, errorHandler)
|
|
69
61
|
this.proc.stdin.write(stringifiedEvent)
|
|
70
|
-
|
|
71
62
|
return this
|
|
72
63
|
})
|
|
64
|
+
|
|
73
65
|
this.proc = proc
|
|
74
66
|
this.key = key
|
|
75
67
|
this.logger = logger ?? {
|
|
@@ -208,6 +200,11 @@ export class ChildSocket<
|
|
|
208
200
|
++idx
|
|
209
201
|
}
|
|
210
202
|
})
|
|
203
|
+
this.proc.stdin.once(`error`, (err: { code: string }) => {
|
|
204
|
+
if (err.code === `EPIPE`) {
|
|
205
|
+
console.error(`EPIPE error during write`, this.proc.stdin)
|
|
206
|
+
}
|
|
207
|
+
})
|
|
211
208
|
if (proc.pid) {
|
|
212
209
|
this.id = proc.pid.toString()
|
|
213
210
|
}
|
|
@@ -179,18 +179,11 @@ export class ParentSocket<
|
|
|
179
179
|
this.logger.info(`👤`, userKey, `joined`)
|
|
180
180
|
const relay = new SubjectSocket(userKey)
|
|
181
181
|
this.relays.set(userKey, relay)
|
|
182
|
-
this.logger.info(
|
|
183
|
-
`🔗`,
|
|
184
|
-
`attaching services for user`,
|
|
185
|
-
userKey,
|
|
186
|
-
// `[${[...this.initRelay.keys()].join(`, `)}]`,
|
|
187
|
-
)
|
|
188
|
-
// for (const attachRelay of this.initRelay) {
|
|
182
|
+
this.logger.info(`🔗`, `attaching services for user`, userKey)
|
|
189
183
|
const cleanupRelay = this.initRelay(relay, userKey)
|
|
190
184
|
if (cleanupRelay) {
|
|
191
185
|
relay.disposalFunctions.push(cleanupRelay)
|
|
192
186
|
}
|
|
193
|
-
// }
|
|
194
187
|
this.on(userKey, (...data) => {
|
|
195
188
|
relay.in.next(data)
|
|
196
189
|
})
|
|
@@ -29,13 +29,15 @@ import {
|
|
|
29
29
|
ownersOfRooms,
|
|
30
30
|
roomKeysAtom,
|
|
31
31
|
usersInRooms,
|
|
32
|
+
visibilityFromRoomSelector,
|
|
32
33
|
visibleUsersInRoomsSelector,
|
|
33
34
|
} from "atom.io/realtime"
|
|
35
|
+
import { myRoomKeyAtom } from "atom.io/realtime-client"
|
|
34
36
|
|
|
35
37
|
import { ChildSocket, PROOF_OF_LIFE_SIGNAL } from "./ipc-sockets"
|
|
36
38
|
import { realtimeMutableFamilyProvider } from "./realtime-mutable-family-provider"
|
|
37
39
|
import { realtimeMutableProvider } from "./realtime-mutable-provider"
|
|
38
|
-
import
|
|
40
|
+
import { realtimeStateProvider } from "./realtime-state-provider"
|
|
39
41
|
|
|
40
42
|
export type RoomMap = Map<
|
|
41
43
|
string,
|
|
@@ -87,19 +89,47 @@ export function spawnRoom<RoomNames extends string>({
|
|
|
87
89
|
room.stdout.on(`data`, resolver)
|
|
88
90
|
},
|
|
89
91
|
)
|
|
90
|
-
const roomSocket = new ChildSocket(child, roomKey)
|
|
91
|
-
ROOMS.set(roomKey, roomSocket)
|
|
92
|
-
setIntoStore(store, roomKeysAtom, (index) => (index.add(roomKey), index))
|
|
93
92
|
|
|
93
|
+
const room = new ChildSocket(child, roomKey)
|
|
94
|
+
ROOMS.set(roomKey, room)
|
|
95
|
+
setIntoStore(store, roomKeysAtom, (index) => (index.add(roomKey), index))
|
|
94
96
|
editRelationsInStore(store, ownersOfRooms, (relations) => {
|
|
95
97
|
relations.set({ room: roomKey, user: userKey })
|
|
96
98
|
})
|
|
97
99
|
|
|
98
|
-
|
|
100
|
+
const provideMutableFamily = realtimeMutableFamilyProvider({
|
|
101
|
+
socket: room,
|
|
102
|
+
consumer: roomKey,
|
|
103
|
+
store,
|
|
104
|
+
})
|
|
105
|
+
const provideState = realtimeStateProvider({
|
|
106
|
+
socket: room,
|
|
107
|
+
consumer: roomKey,
|
|
108
|
+
store,
|
|
109
|
+
})
|
|
110
|
+
const unsubFromRoomKey = provideState(myRoomKeyAtom, roomKey)
|
|
111
|
+
|
|
112
|
+
const ownersOfRoomsAtoms = getInternalRelationsFromStore(
|
|
113
|
+
store,
|
|
114
|
+
ownersOfRooms,
|
|
115
|
+
)
|
|
116
|
+
const unsubFromOwnerKeys = provideMutableFamily(ownersOfRoomsAtoms, [
|
|
117
|
+
roomKey,
|
|
118
|
+
])
|
|
119
|
+
const usersInRoomsAtoms = getInternalRelationsFromStore(store, usersInRooms)
|
|
120
|
+
const unsubFromUsersInRooms = provideMutableFamily(
|
|
121
|
+
usersInRoomsAtoms,
|
|
122
|
+
findInStore(store, visibilityFromRoomSelector, roomKey),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
room.on(`close`, () => {
|
|
126
|
+
unsubFromRoomKey()
|
|
127
|
+
unsubFromOwnerKeys()
|
|
128
|
+
unsubFromUsersInRooms()
|
|
99
129
|
destroyRoom({ store, socket, userKey })(roomKey)
|
|
100
130
|
})
|
|
101
131
|
|
|
102
|
-
return
|
|
132
|
+
return room
|
|
103
133
|
}
|
|
104
134
|
}
|
|
105
135
|
|
|
@@ -115,7 +145,7 @@ export function provideEnterAndExit({
|
|
|
115
145
|
roomSocket,
|
|
116
146
|
userKey,
|
|
117
147
|
}: ProvideEnterAndExitConfig): (roomKey: RoomKey) => void {
|
|
118
|
-
const enterRoom = (roomKey: RoomKey) => {
|
|
148
|
+
const enterRoom = (roomKey: RoomKey): void => {
|
|
119
149
|
store.logger.info(
|
|
120
150
|
`📡`,
|
|
121
151
|
`socket`,
|
|
@@ -123,6 +153,10 @@ export function provideEnterAndExit({
|
|
|
123
153
|
`👤 ${userKey} enters room ${roomKey}`,
|
|
124
154
|
)
|
|
125
155
|
|
|
156
|
+
const dcUserFromRoom = () => {
|
|
157
|
+
toRoom([`user-leaves`])
|
|
158
|
+
}
|
|
159
|
+
|
|
126
160
|
const exitRoom = () => {
|
|
127
161
|
store.logger.info(
|
|
128
162
|
`📡`,
|
|
@@ -131,17 +165,15 @@ export function provideEnterAndExit({
|
|
|
131
165
|
`👤 ${userKey} leaves room ${roomKey}`,
|
|
132
166
|
)
|
|
133
167
|
socket.offAny(forward)
|
|
134
|
-
|
|
168
|
+
dcUserFromRoom()
|
|
135
169
|
editRelationsInStore(store, usersInRooms, (relations) => {
|
|
136
170
|
relations.delete({ room: roomKey, user: userKey })
|
|
137
171
|
})
|
|
172
|
+
|
|
138
173
|
roomSocket.off(`leaveRoom`, exitRoom)
|
|
139
174
|
roomSocket.on(`joinRoom`, enterRoom)
|
|
140
175
|
}
|
|
141
176
|
|
|
142
|
-
roomSocket.on(`leaveRoom`, exitRoom)
|
|
143
|
-
roomSocket.off(`joinRoom`, enterRoom)
|
|
144
|
-
|
|
145
177
|
const roomQueue: [string, ...Json.Array][] = []
|
|
146
178
|
const pushToRoomQueue = (payload: [string, ...Json.Array]): void => {
|
|
147
179
|
roomQueue.push(payload)
|
|
@@ -158,7 +190,7 @@ export function provideEnterAndExit({
|
|
|
158
190
|
const childSocket = ROOMS.get(roomKey)
|
|
159
191
|
if (!childSocket) {
|
|
160
192
|
store.logger.error(`❌`, `unknown`, roomKey, `no room found with this id`)
|
|
161
|
-
return
|
|
193
|
+
return
|
|
162
194
|
}
|
|
163
195
|
childSocket.onAny((...payload) => {
|
|
164
196
|
socket.emit(...payload)
|
|
@@ -172,6 +204,10 @@ export function provideEnterAndExit({
|
|
|
172
204
|
const payload = roomQueue.shift()
|
|
173
205
|
if (payload) toRoom(payload)
|
|
174
206
|
}
|
|
207
|
+
|
|
208
|
+
socket.on(`disconnect`, dcUserFromRoom)
|
|
209
|
+
roomSocket.on(`leaveRoom`, exitRoom)
|
|
210
|
+
roomSocket.off(`joinRoom`, enterRoom)
|
|
175
211
|
}
|
|
176
212
|
roomSocket.on(`joinRoom`, enterRoom)
|
|
177
213
|
return enterRoom
|
|
@@ -229,6 +265,9 @@ export type ProvideRoomsConfig<RoomNames extends string> = {
|
|
|
229
265
|
resolveRoomScript: (path: RoomNames) => [string, string[]]
|
|
230
266
|
roomNames: RoomNames[]
|
|
231
267
|
roomTimeLimit?: number
|
|
268
|
+
userKey: UserKey
|
|
269
|
+
store: RootStore
|
|
270
|
+
socket: Socket
|
|
232
271
|
}
|
|
233
272
|
export function provideRooms<RoomNames extends string>({
|
|
234
273
|
store = IMPLICIT.STORE,
|
|
@@ -236,11 +275,15 @@ export function provideRooms<RoomNames extends string>({
|
|
|
236
275
|
resolveRoomScript,
|
|
237
276
|
roomNames,
|
|
238
277
|
userKey,
|
|
239
|
-
}: ProvideRoomsConfig<RoomNames>
|
|
278
|
+
}: ProvideRoomsConfig<RoomNames>): () => void {
|
|
240
279
|
const roomSocket = castSocket<
|
|
241
280
|
TypedSocket<RoomSocketInterface<RoomNames>, never>
|
|
242
281
|
>(socket, createRoomSocketGuard(roomNames))
|
|
243
|
-
const exposeMutable = realtimeMutableProvider({
|
|
282
|
+
const exposeMutable = realtimeMutableProvider({
|
|
283
|
+
socket,
|
|
284
|
+
store,
|
|
285
|
+
consumer: userKey,
|
|
286
|
+
})
|
|
244
287
|
const unsubFromRoomKeys = exposeMutable(roomKeysAtom)
|
|
245
288
|
const usersInRoomsAtoms = getInternalRelationsFromStore(store, usersInRooms)
|
|
246
289
|
const [, usersInRoomsAtomsUsersOnly] = getInternalRelationsFromStore(
|
|
@@ -257,7 +300,7 @@ export function provideRooms<RoomNames extends string>({
|
|
|
257
300
|
const exposeMutableFamily = realtimeMutableFamilyProvider({
|
|
258
301
|
socket,
|
|
259
302
|
store,
|
|
260
|
-
userKey,
|
|
303
|
+
consumer: userKey,
|
|
261
304
|
})
|
|
262
305
|
const unsubFromUsersInRooms = exposeMutableFamily(
|
|
263
306
|
usersInRoomsAtoms,
|
|
@@ -267,7 +310,12 @@ export function provideRooms<RoomNames extends string>({
|
|
|
267
310
|
ownersOfRoomsAtoms,
|
|
268
311
|
usersWhoseRoomsCanBeSeenSelector,
|
|
269
312
|
)
|
|
270
|
-
const enterRoom = provideEnterAndExit({
|
|
313
|
+
const enterRoom = provideEnterAndExit({
|
|
314
|
+
store,
|
|
315
|
+
socket,
|
|
316
|
+
roomSocket,
|
|
317
|
+
userKey,
|
|
318
|
+
})
|
|
271
319
|
|
|
272
320
|
const userRoomSet = getFromStore(store, usersInRoomsAtomsUsersOnly, userKey)
|
|
273
321
|
for (const userRoomKey of userRoomSet) {
|
|
@@ -14,7 +14,7 @@ import type { ServerConfig } from "."
|
|
|
14
14
|
export type FamilyProvider = ReturnType<typeof realtimeAtomFamilyProvider>
|
|
15
15
|
export function realtimeAtomFamilyProvider({
|
|
16
16
|
socket,
|
|
17
|
-
|
|
17
|
+
consumer,
|
|
18
18
|
store = IMPLICIT.STORE,
|
|
19
19
|
}: ServerConfig) {
|
|
20
20
|
return function familyProvider<
|
|
@@ -22,8 +22,17 @@ export function realtimeAtomFamilyProvider({
|
|
|
22
22
|
K extends Canonical,
|
|
23
23
|
>(
|
|
24
24
|
family: AtomIO.RegularAtomFamilyToken<J, K>,
|
|
25
|
-
index: AtomIO.ReadableToken<Iterable<NoInfer<K
|
|
25
|
+
index: AtomIO.ReadableToken<Iterable<NoInfer<K>>> | Iterable<NoInfer<K>>,
|
|
26
26
|
): () => void {
|
|
27
|
+
const [dynamicIndex, staticIndex]:
|
|
28
|
+
| [AtomIO.ReadableToken<Iterable<NoInfer<K>>>, undefined]
|
|
29
|
+
| [undefined, Iterable<NoInfer<K>>] = (() => {
|
|
30
|
+
if (typeof index === `object` && `key` in index && `type` in index) {
|
|
31
|
+
return [index, undefined] as const
|
|
32
|
+
}
|
|
33
|
+
return [undefined, index] as const
|
|
34
|
+
})()
|
|
35
|
+
|
|
27
36
|
const coreSubscriptions = new Set<() => void>()
|
|
28
37
|
const clearCoreSubscriptions = () => {
|
|
29
38
|
for (const unsub of coreSubscriptions) unsub()
|
|
@@ -70,7 +79,7 @@ export function realtimeAtomFamilyProvider({
|
|
|
70
79
|
store.logger.info(
|
|
71
80
|
`🙈`,
|
|
72
81
|
`user`,
|
|
73
|
-
|
|
82
|
+
consumer,
|
|
74
83
|
`unsubscribed from state "${token.key}"`,
|
|
75
84
|
)
|
|
76
85
|
fillUnsubRequest(token.key)
|
|
@@ -91,18 +100,23 @@ export function realtimeAtomFamilyProvider({
|
|
|
91
100
|
store.logger.info(
|
|
92
101
|
`👀`,
|
|
93
102
|
`user`,
|
|
94
|
-
|
|
103
|
+
consumer,
|
|
95
104
|
`can subscribe to family "${family.key}"`,
|
|
96
105
|
)
|
|
97
106
|
coreSubscriptions.add(
|
|
98
107
|
employSocket(socket, `sub:${family.key}`, (subKey: K) => {
|
|
99
|
-
|
|
108
|
+
let exposedSubKeys: Iterable<K>
|
|
109
|
+
if (dynamicIndex) {
|
|
110
|
+
exposedSubKeys = getFromStore(store, dynamicIndex)
|
|
111
|
+
} else {
|
|
112
|
+
exposedSubKeys = staticIndex
|
|
113
|
+
}
|
|
100
114
|
const shouldExpose = isAvailable(exposedSubKeys, subKey)
|
|
101
115
|
if (shouldExpose) {
|
|
102
116
|
store.logger.info(
|
|
103
117
|
`👀`,
|
|
104
118
|
`user`,
|
|
105
|
-
|
|
119
|
+
consumer,
|
|
106
120
|
`is approved for a subscription to`,
|
|
107
121
|
subKey,
|
|
108
122
|
`in family "${family.key}"`,
|
|
@@ -112,7 +126,7 @@ export function realtimeAtomFamilyProvider({
|
|
|
112
126
|
store.logger.info(
|
|
113
127
|
`❌`,
|
|
114
128
|
`user`,
|
|
115
|
-
|
|
129
|
+
consumer,
|
|
116
130
|
`is denied for a subscription to`,
|
|
117
131
|
subKey,
|
|
118
132
|
`in family "${family.key}"`,
|
|
@@ -122,35 +136,37 @@ export function realtimeAtomFamilyProvider({
|
|
|
122
136
|
}
|
|
123
137
|
}),
|
|
124
138
|
)
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
139
|
+
if (dynamicIndex) {
|
|
140
|
+
coreSubscriptions.add(
|
|
141
|
+
subscribeToState(
|
|
142
|
+
store,
|
|
143
|
+
dynamicIndex,
|
|
144
|
+
`expose-family:${family.key}:${socket.id}`,
|
|
145
|
+
({ newValue: newExposedSubKeys }) => {
|
|
146
|
+
store.logger.info(
|
|
147
|
+
`👀`,
|
|
148
|
+
`user`,
|
|
149
|
+
consumer,
|
|
150
|
+
`has the following keys available for family "${family.key}"`,
|
|
151
|
+
newExposedSubKeys,
|
|
152
|
+
)
|
|
153
|
+
for (const subKey of newExposedSubKeys) {
|
|
154
|
+
if (familyMemberSubscriptionsWanted.has(stringifyJson(subKey))) {
|
|
155
|
+
store.logger.info(
|
|
156
|
+
`👀`,
|
|
157
|
+
`user`,
|
|
158
|
+
consumer,
|
|
159
|
+
`is retroactively approved for a subscription to`,
|
|
160
|
+
subKey,
|
|
161
|
+
`in family "${family.key}"`,
|
|
162
|
+
)
|
|
163
|
+
exposeFamilyMembers(subKey)
|
|
164
|
+
}
|
|
149
165
|
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
)
|
|
153
|
-
|
|
166
|
+
},
|
|
167
|
+
),
|
|
168
|
+
)
|
|
169
|
+
}
|
|
154
170
|
}
|
|
155
171
|
|
|
156
172
|
start()
|