@dittolive/ditto 4.7.4 → 4.7.5-rc.2

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.
Files changed (160) hide show
  1. package/README.md +2 -2
  2. package/node/ditto.cjs.js +1 -1
  3. package/node/ditto.darwin-arm64.node +0 -0
  4. package/node/ditto.darwin-x64.node +0 -0
  5. package/node/ditto.linux-arm.node +0 -0
  6. package/node/ditto.linux-arm64.node +0 -0
  7. package/node/ditto.linux-x64.node +0 -0
  8. package/node/ditto.win32-x64.node +0 -0
  9. package/node/transports.darwin-arm64.node +0 -0
  10. package/node/transports.darwin-x64.node +0 -0
  11. package/package.json +2 -5
  12. package/web/ditto.es6.js +1 -1
  13. package/web/ditto.umd.js +1 -1
  14. package/web/ditto.wasm +0 -0
  15. package/DittoReactNative.podspec +0 -27
  16. package/react-native/android/.gradle/8.9/checksums/checksums.lock +0 -0
  17. package/react-native/android/.gradle/8.9/dependencies-accessors/gc.properties +0 -0
  18. package/react-native/android/.gradle/8.9/fileChanges/last-build.bin +0 -0
  19. package/react-native/android/.gradle/8.9/fileHashes/fileHashes.lock +0 -0
  20. package/react-native/android/.gradle/8.9/gc.properties +0 -0
  21. package/react-native/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  22. package/react-native/android/.gradle/buildOutputCleanup/cache.properties +0 -2
  23. package/react-native/android/.gradle/vcs-1/gc.properties +0 -0
  24. package/react-native/android/CMakeLists.txt +0 -36
  25. package/react-native/android/build.gradle +0 -190
  26. package/react-native/android/cpp-adapter.cpp +0 -259
  27. package/react-native/android/gradle.properties +0 -5
  28. package/react-native/android/src/main/AndroidManifest.xml +0 -4
  29. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +0 -120
  30. package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKPackage.java +0 -28
  31. package/react-native/cpp/include/Arc.hpp +0 -159
  32. package/react-native/cpp/include/Attachment.h +0 -20
  33. package/react-native/cpp/include/Authentication.h +0 -23
  34. package/react-native/cpp/include/Collection.h +0 -13
  35. package/react-native/cpp/include/ConnectionRequest.h +0 -18
  36. package/react-native/cpp/include/DQL.h +0 -21
  37. package/react-native/cpp/include/Document.h +0 -17
  38. package/react-native/cpp/include/FFIUtils.h +0 -16
  39. package/react-native/cpp/include/IO.h +0 -13
  40. package/react-native/cpp/include/Identity.h +0 -17
  41. package/react-native/cpp/include/Lifecycle.h +0 -16
  42. package/react-native/cpp/include/LiveQuery.h +0 -17
  43. package/react-native/cpp/include/Logger.h +0 -22
  44. package/react-native/cpp/include/Misc.h +0 -30
  45. package/react-native/cpp/include/Presence.h +0 -18
  46. package/react-native/cpp/include/SmallPeerInfo.h +0 -19
  47. package/react-native/cpp/include/Transports.h +0 -25
  48. package/react-native/cpp/include/TypedArray.hpp +0 -167
  49. package/react-native/cpp/include/Utils.h +0 -70
  50. package/react-native/cpp/include/main.h +0 -10
  51. package/react-native/cpp/src/Attachment.cpp +0 -272
  52. package/react-native/cpp/src/Authentication.cpp +0 -227
  53. package/react-native/cpp/src/Collection.cpp +0 -56
  54. package/react-native/cpp/src/ConnectionRequest.cpp +0 -123
  55. package/react-native/cpp/src/DQL.cpp +0 -256
  56. package/react-native/cpp/src/Document.cpp +0 -146
  57. package/react-native/cpp/src/FFIUtils.cpp +0 -122
  58. package/react-native/cpp/src/IO.cpp +0 -35
  59. package/react-native/cpp/src/Identity.cpp +0 -122
  60. package/react-native/cpp/src/Lifecycle.cpp +0 -93
  61. package/react-native/cpp/src/LiveQuery.cpp +0 -63
  62. package/react-native/cpp/src/Logger.cpp +0 -199
  63. package/react-native/cpp/src/Misc.cpp +0 -322
  64. package/react-native/cpp/src/Presence.cpp +0 -166
  65. package/react-native/cpp/src/SmallPeerInfo.cpp +0 -142
  66. package/react-native/cpp/src/Transports.cpp +0 -275
  67. package/react-native/cpp/src/TypedArray.cpp +0 -303
  68. package/react-native/cpp/src/Utils.cpp +0 -139
  69. package/react-native/cpp/src/main.cpp +0 -178
  70. package/react-native/dittoffi/dittoffi.h +0 -4873
  71. package/react-native/dittoffi/ifaddrs.cpp +0 -385
  72. package/react-native/dittoffi/ifaddrs.h +0 -206
  73. package/react-native/ios/DittoRNSDK.h +0 -7
  74. package/react-native/ios/DittoRNSDK.mm +0 -159
  75. package/react-native/ios/YeetJSIUtils.h +0 -60
  76. package/react-native/ios/YeetJSIUtils.mm +0 -196
  77. package/react-native/lib/commonjs/ditto.rn.js +0 -93
  78. package/react-native/lib/commonjs/ditto.rn.js.map +0 -1
  79. package/react-native/lib/commonjs/index.js +0 -61
  80. package/react-native/lib/commonjs/index.js.map +0 -1
  81. package/react-native/lib/module/ditto.rn.js +0 -89
  82. package/react-native/lib/module/ditto.rn.js.map +0 -1
  83. package/react-native/lib/module/index.js +0 -27
  84. package/react-native/lib/module/index.js.map +0 -1
  85. package/react-native/lib/typescript/ditto.rn.d.ts +0 -15
  86. package/react-native/lib/typescript/ditto.rn.d.ts.map +0 -1
  87. package/react-native/lib/typescript/index.d.ts +0 -1
  88. package/react-native/lib/typescript/index.d.ts.map +0 -1
  89. package/react-native/src/ditto.rn.ts +0 -123
  90. package/react-native/src/environment/environment.fallback.ts +0 -4
  91. package/react-native/src/index.ts +0 -29
  92. package/react-native/src/sources/@cbor-redux.ts +0 -2
  93. package/react-native/src/sources/@ditto.core.ts +0 -1
  94. package/react-native/src/sources/@environment.ts +0 -1
  95. package/react-native/src/sources/attachment-fetch-event.ts +0 -54
  96. package/react-native/src/sources/attachment-fetcher-manager.ts +0 -145
  97. package/react-native/src/sources/attachment-fetcher.ts +0 -265
  98. package/react-native/src/sources/attachment-token.ts +0 -129
  99. package/react-native/src/sources/attachment.ts +0 -121
  100. package/react-native/src/sources/augment.ts +0 -108
  101. package/react-native/src/sources/authenticator.ts +0 -314
  102. package/react-native/src/sources/base-pending-cursor-operation.ts +0 -255
  103. package/react-native/src/sources/base-pending-id-specific-operation.ts +0 -112
  104. package/react-native/src/sources/bridge.ts +0 -557
  105. package/react-native/src/sources/build-time-constants.ts +0 -8
  106. package/react-native/src/sources/cbor.ts +0 -20
  107. package/react-native/src/sources/collection-interface.ts +0 -73
  108. package/react-native/src/sources/collection.ts +0 -219
  109. package/react-native/src/sources/collections-event.ts +0 -99
  110. package/react-native/src/sources/connection-request.ts +0 -142
  111. package/react-native/src/sources/counter.ts +0 -82
  112. package/react-native/src/sources/ditto.ts +0 -991
  113. package/react-native/src/sources/document-id.ts +0 -163
  114. package/react-native/src/sources/document-path.ts +0 -308
  115. package/react-native/src/sources/document.ts +0 -237
  116. package/react-native/src/sources/epilogue.ts +0 -32
  117. package/react-native/src/sources/error-codes.ts +0 -114
  118. package/react-native/src/sources/error.ts +0 -256
  119. package/react-native/src/sources/essentials.ts +0 -81
  120. package/react-native/src/sources/ffi-error.ts +0 -134
  121. package/react-native/src/sources/ffi.ts +0 -2190
  122. package/react-native/src/sources/identity.ts +0 -163
  123. package/react-native/src/sources/init.ts +0 -71
  124. package/react-native/src/sources/internal.ts +0 -143
  125. package/react-native/src/sources/keep-alive.ts +0 -73
  126. package/react-native/src/sources/key-path.ts +0 -198
  127. package/react-native/src/sources/live-query-event.ts +0 -208
  128. package/react-native/src/sources/live-query-manager.ts +0 -110
  129. package/react-native/src/sources/live-query.ts +0 -167
  130. package/react-native/src/sources/logger.ts +0 -196
  131. package/react-native/src/sources/main.ts +0 -61
  132. package/react-native/src/sources/observer-manager.ts +0 -185
  133. package/react-native/src/sources/observer.ts +0 -79
  134. package/react-native/src/sources/pending-collections-operation.ts +0 -241
  135. package/react-native/src/sources/pending-cursor-operation.ts +0 -218
  136. package/react-native/src/sources/pending-id-specific-operation.ts +0 -218
  137. package/react-native/src/sources/presence-manager.ts +0 -170
  138. package/react-native/src/sources/presence.ts +0 -427
  139. package/react-native/src/sources/query-result-item.ts +0 -131
  140. package/react-native/src/sources/query-result.ts +0 -55
  141. package/react-native/src/sources/register.ts +0 -95
  142. package/react-native/src/sources/small-peer-info.ts +0 -166
  143. package/react-native/src/sources/static-tcp-client.ts +0 -8
  144. package/react-native/src/sources/store-observer.ts +0 -170
  145. package/react-native/src/sources/store.ts +0 -630
  146. package/react-native/src/sources/subscription-manager.ts +0 -99
  147. package/react-native/src/sources/subscription.ts +0 -89
  148. package/react-native/src/sources/sync-subscription.ts +0 -90
  149. package/react-native/src/sources/sync.ts +0 -561
  150. package/react-native/src/sources/test-helpers.ts +0 -24
  151. package/react-native/src/sources/transport-conditions-manager.ts +0 -104
  152. package/react-native/src/sources/transport-config.ts +0 -430
  153. package/react-native/src/sources/update-result.ts +0 -66
  154. package/react-native/src/sources/update-results-map.ts +0 -65
  155. package/react-native/src/sources/websocket-client.ts +0 -7
  156. package/react-native/src/sources/write-transaction-collection.ts +0 -122
  157. package/react-native/src/sources/write-transaction-pending-cursor-operation.ts +0 -101
  158. package/react-native/src/sources/write-transaction-pending-id-specific-operation.ts +0 -74
  159. package/react-native/src/sources/write-transaction.ts +0 -121
  160. package/react-native.config.js +0 -9
@@ -1,561 +0,0 @@
1
- //
2
- // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
- //
4
-
5
- import * as FFI from './ffi'
6
- import * as Environment from './@environment'
7
-
8
- import { desugarJSObject } from './augment'
9
- import { Bridge } from './bridge'
10
- import { CBOR } from './cbor'
11
- import { defaultDittoCloudURL } from './internal'
12
- import { SyncSubscription } from './sync-subscription'
13
- import { TransportConfig } from './transport-config'
14
- import { DittoError, mapFFIErrors } from './error'
15
-
16
- import type { Ditto } from './ditto'
17
- import type { Identity } from './identity'
18
- import type { DQLQueryArguments } from './essentials'
19
-
20
- /** @internal */
21
- export type SyncParameters = {
22
- readonly isSyncActive: boolean
23
- readonly isX509Valid: boolean
24
- readonly isWebValid: boolean
25
- readonly ditto: Ditto
26
- readonly identity: Identity
27
- readonly transportConfig: TransportConfig
28
- }
29
-
30
- /** @internal */
31
- export type SyncState = {
32
- // NOTE: we can get away with just an effective transport config for now,
33
- // but this is meant to carry more state if need be. Whenever possible,
34
- // prefer putting logic into the `stateFrom()` function together with some
35
- // flags here and keep the `updateXXX()` to just diffing and updating the
36
- // low-level transports machinery.
37
- readonly underlyingSyncParameters: SyncParameters
38
- readonly effectiveTransportConfig: TransportConfig
39
- }
40
-
41
- /**
42
- * Provides access to sync related functionality of Ditto.
43
- *
44
- * Access this object via {@link Ditto.sync | Ditto.sync} on any Ditto instance.
45
- */
46
- export class Sync {
47
- /**
48
- * The {@link Ditto} instance managed by this sync object.
49
- */
50
- readonly ditto: Ditto
51
-
52
- /**
53
- * All currently active sync subscriptions.
54
- *
55
- * **Note:** Manage sync subscriptions using
56
- * {@link registerSubscription | registerSubscription()} to register a new
57
- * sync subscription and
58
- * {@link SyncSubscription.cancel | SyncSubscription.cancel()} to remove an
59
- * existing sync subscription.
60
- */
61
- readonly subscriptions: Readonly<Array<SyncSubscription>> = Object.freeze([])
62
-
63
- /**
64
- * Installs and returns a sync subscription for a query, configuring Ditto to
65
- * receive updates from other peers for documents matching that query. The
66
- * passed in query must be a `SELECT` query, otherwise an error is thrown.
67
- *
68
- * @param query a string containing a valid query expressed in DQL.
69
- * @param queryArguments an object containing the arguments for the query.
70
- * Example: `{mileage: 123}` for a query with `:mileage` placeholder.
71
- * @returns An active `SyncSubscription` for the passed in query and
72
- * arguments. It will remain active until it is
73
- * {@link SyncSubscription.cancel | cancelled} or the {@link Ditto} instance
74
- * managing the sync subscription has been closed.
75
- * @throws {@link DittoError} `query/invalid`: if `query` argument is not a
76
- * string or not valid DQL.
77
- * @throws {@link DittoError} `query/arguments-invalid`: if `queryArguments`
78
- * argument is invalid (e.g. contains unsupported types).
79
- * @throws {@link DittoError} `query/unsupported`: if the query is not a
80
- * `SELECT` query.
81
- * @throws {@link DittoError} may throw other errors.
82
- */
83
- registerSubscription(query: string, queryArguments?: DQLQueryArguments): SyncSubscription {
84
- if (typeof query !== 'string') {
85
- throw new DittoError('query/invalid', `Expected parameter 'query' to be of type 'string', found: ${typeof query}`)
86
- }
87
-
88
- let queryArgumentsCBOR: Uint8Array | null = null
89
- if (queryArguments != null) {
90
- try {
91
- const queryArgumentsJSON = desugarJSObject(queryArguments)
92
- queryArgumentsCBOR = CBOR.encode(queryArgumentsJSON)
93
- } catch (error: any) {
94
- throw new DittoError('query/arguments-invalid', `Unable to encode query arguments: ${error.message}`)
95
- }
96
- }
97
-
98
- const dittoHandle = Bridge.ditto.handleFor(this.ditto)
99
- this.ditto.deferClose(() => {
100
- mapFFIErrors(() => FFI.tryAddSyncSubscription(dittoHandle.deref(), query, queryArgumentsCBOR))
101
- })
102
-
103
- const subscription = new SyncSubscription(this.ditto, query, queryArguments || null, queryArgumentsCBOR)
104
-
105
- // @ts-expect-error modifying readonly property
106
- this.subscriptions = Object.freeze([...this.subscriptions, subscription])
107
-
108
- return subscription
109
- }
110
-
111
- // ---------------------------------------------------------- Internal ------
112
-
113
- /** @internal */
114
- get parameters(): SyncParameters {
115
- return this.state.underlyingSyncParameters
116
- }
117
-
118
- /** @internal */
119
- constructor(ditto: Ditto) {
120
- const identity = ditto.identity
121
- const transportConfig = new TransportConfig()
122
- const parameters = { identity, transportConfig, ditto, isWebValid: false, isX509Valid: false, isSyncActive: false }
123
-
124
- this.ditto = ditto
125
- this.state = stateFrom(parameters)
126
-
127
- FFI.transportsInit()
128
- }
129
-
130
- /**
131
- * Removes the passed in `syncSubscription`, configuring Ditto to not receive
132
- * updates for documents matching the corresponding query anymore. No-op if
133
- * the passed in `syncSubscription` has already been removed.
134
- *
135
- * This must only be called by the sync subscription itself.
136
- *
137
- * @param syncSubscription the sync subscription to remove
138
- * @returns `true` if the passed in sync subscription could be found and has
139
- * been removed, otherwise returns `false`.
140
- * @throws {@link DittoError} `internal`: if the replication subscription does not
141
- * belong to this store
142
- * @throws {@link DittoError} `internal`: if the replication subscription has not
143
- * been cancelled yet
144
- * @internal
145
- */
146
- unregisterSubscription(syncSubscription: SyncSubscription): boolean {
147
- if (syncSubscription.ditto !== this.ditto) {
148
- throw new DittoError('internal', `Can't remove replication subscription that does not belong to this store`)
149
- }
150
-
151
- if (!syncSubscription.isCancelled) {
152
- throw new DittoError('internal', "Internal inconsistency, can't remove replication subscription that has not been cancelled")
153
- }
154
-
155
- const indexToDelete = this.subscriptions.findIndex((s) => s === syncSubscription)
156
- if (indexToDelete === -1) {
157
- return false
158
- }
159
-
160
- const newSyncSubscriptions = [...this.subscriptions]
161
- newSyncSubscriptions.splice(indexToDelete, 1)
162
- // @ts-expect-error modifying readonly property
163
- this.subscriptions = Object.freeze(newSyncSubscriptions)
164
-
165
- const dittoHandle = Bridge.ditto.handleFor(this.ditto)
166
- this.ditto.deferClose(() => {
167
- // prettier-ignore
168
- mapFFIErrors(
169
- () => FFI.tryRemoveSyncSubscription(dittoHandle.deref(), syncSubscription.queryString, syncSubscription.queryArgumentsCBOR)
170
- )
171
- })
172
- return true
173
- }
174
-
175
- /** @internal */
176
- update(parameters: SyncParameters) {
177
- // NOTE: updating is a two-step process. Given all parameters, we
178
- // first compute the final "state" we want the transports stuff to
179
- // be in via the `stateFrom()` function. We then take that "desired" state
180
- // and feed it into the various update methods, which essentially perform
181
- // a diff on the state before and after, and update the low-level transports
182
- // machinery accordingly.
183
-
184
- const stateOld = this.state
185
- const stateNew = stateFrom(parameters)
186
-
187
- this.updatePeerToPeerBluetoothLE(stateOld, stateNew)
188
- this.updatePeerToPeerAWDL(stateOld, stateNew)
189
- this.updatePeerToPeerLAN(stateOld, stateNew)
190
- this.updateListenTCP(stateOld, stateNew)
191
- this.updateListenHTTP(stateOld, stateNew)
192
- this.updateConnectTCPServers(stateOld, stateNew)
193
- this.updateConnectWebsocketURLs(stateOld, stateNew)
194
- this.updateGlobal(stateOld, stateNew)
195
- this.updateConnectRetryInterval(stateOld, stateNew)
196
-
197
- this.state = stateNew
198
- }
199
-
200
- /** @internal */
201
- close() {
202
- if (this.parameters.isSyncActive) {
203
- throw new Error(`Internal inconsistency, can't close sync object while sync is active, please 'stopSync()' first.`)
204
- }
205
-
206
- for (const subscription of this.subscriptions) {
207
- subscription.cancel()
208
- }
209
-
210
- // Nothing to do, when sync is stopped, this object should be
211
- // already be cleaned up properly.
212
- }
213
-
214
- // ------------------------------------------------------------ Private ------
215
-
216
- private state: SyncState
217
-
218
- private bluetoothLETransportPointer: FFI.Pointer<'DittoTransportsBLE_t'> | null = null
219
- private awdlTransportPointer: FFI.Pointer<'DittoTransportsAWDL_t'> | null = null
220
- private lanTransportPointer: FFI.Pointer<'DittoTransportsLAN_t'> | null = null
221
- private mdnsClientTransportPointer: FFI.Pointer<'DittoTransportsMdnsClient_t'> | null = null
222
- private mdnsServerAdvertiserPointer: FFI.Pointer<'DittoTransportsMdnsServer_t'> | null = null
223
-
224
- private updatePeerToPeerBluetoothLE(stateOld: SyncState, stateNew: SyncState) {
225
- // Updating BLE transport is a no-op outside of Node.js & React Native.
226
- if (!Environment.isNodeBuild && !Environment.isReactNativeBuild) return
227
-
228
- const ditto = this.ditto
229
- const dittoHandle = Bridge.ditto.handleFor(ditto)
230
- ditto.deferClose(() => {
231
- const bluetoothLEOld = stateOld.effectiveTransportConfig.peerToPeer.bluetoothLE
232
- const bluetoothLENew = stateNew.effectiveTransportConfig.peerToPeer.bluetoothLE
233
-
234
- const shouldStart = !bluetoothLEOld.isEnabled && bluetoothLENew.isEnabled
235
- const shouldStop = bluetoothLEOld.isEnabled && !bluetoothLENew.isEnabled
236
-
237
- if (shouldStart && this.bluetoothLETransportPointer) throw new Error(`Internal inconsistency, when starting BLE transport, no BLE transport pointer should exist.`)
238
- if (shouldStop && !this.bluetoothLETransportPointer) throw new Error(`Internal inconsistency, when stopping BLE transport, a BLE transport pointer should exist.`)
239
-
240
- if (process.platform === 'linux' || process.platform === 'win32') {
241
- if (shouldStart) {
242
- const clientTransport = FFI.dittoAddInternalBLEClientTransport(dittoHandle.deref())
243
- const serverTransport = FFI.dittoAddInternalBLEServerTransport(dittoHandle.deref())
244
- const blePlatform = { clientTransport, serverTransport } as any
245
- this.bluetoothLETransportPointer = blePlatform
246
- }
247
-
248
- if (shouldStop) {
249
- const blePlatform = this.bluetoothLETransportPointer as any
250
- const { clientTransport, serverTransport } = blePlatform
251
- FFI.bleServerFreeHandle(serverTransport)
252
- FFI.bleClientFreeHandle(clientTransport)
253
- this.bluetoothLETransportPointer = null
254
- }
255
-
256
- return
257
- }
258
-
259
- if (shouldStart) {
260
- this.bluetoothLETransportPointer = FFI.transportsBLECreate(dittoHandle.deref()) as FFI.Pointer<FFI.TransportBluetooth> | null
261
- }
262
-
263
- if (shouldStop) {
264
- // null check is performed above
265
- FFI.transportsBLEDestroy(this.bluetoothLETransportPointer as FFI.Pointer<FFI.TransportBluetooth>)
266
- this.bluetoothLETransportPointer = null
267
- }
268
- })
269
- }
270
-
271
- private updatePeerToPeerAWDL(stateOld: SyncState, stateNew: SyncState) {
272
- // Updating AWDL transport is a no-op outside of Node.js & React Native.
273
- if (!Environment.isNodeBuild && !Environment.isReactNativeBuild) return
274
-
275
- const ditto = this.ditto
276
- const dittoHandle = Bridge.ditto.handleFor(ditto)
277
- ditto.deferClose(() => {
278
- const awdlOld = stateOld.effectiveTransportConfig.peerToPeer.awdl
279
- const awdlNew = stateNew.effectiveTransportConfig.peerToPeer.awdl
280
-
281
- const shouldStart = !awdlOld.isEnabled && awdlNew.isEnabled
282
- const shouldStop = awdlOld.isEnabled && !awdlNew.isEnabled
283
-
284
- if (shouldStart && this.awdlTransportPointer) throw new Error(`Internal inconsistency, when starting AWDL transport, no AWDL transport pointer should exist.`)
285
- if (shouldStop && !this.awdlTransportPointer) throw new Error(`Internal inconsistency, when stopping AWDL transport, an AWDL transport pointer should exist.`)
286
-
287
- if (shouldStart) {
288
- this.awdlTransportPointer = FFI.transportsAWDLCreate(dittoHandle.deref()) as FFI.Pointer<FFI.TransportAWDL> | null
289
- }
290
-
291
- if (shouldStop) {
292
- // null check is performed above
293
- FFI.transportsAWDLDestroy(this.awdlTransportPointer as FFI.Pointer<FFI.TransportAWDL>)
294
- this.awdlTransportPointer = null
295
- }
296
- })
297
- }
298
-
299
- private updatePeerToPeerLAN(stateOld: SyncState, stateNew: SyncState) {
300
- // Updating LAN transport currently only works with Node.js & React Native.
301
- if (!Environment.isNodeBuild && !Environment.isReactNativeBuild) return
302
-
303
- const ditto = this.ditto
304
- const dittoHandle = Bridge.ditto.handleFor(ditto)
305
- ditto.deferClose(() => {
306
- const lanOld = stateOld.effectiveTransportConfig.peerToPeer.lan
307
- const lanNew = stateNew.effectiveTransportConfig.peerToPeer.lan
308
-
309
-
310
- if (process.platform === 'win32' || process.platform === 'linux') {
311
- if (lanOld.isEnabled) {
312
- if (lanOld.isMdnsEnabled) {
313
- if (this.mdnsClientTransportPointer == null) throw new Error(`Internal inconsistency, when stopping LAN transport, a LAN transport pointer should exist.`)
314
- FFI.mdnsClientFreeHandle(this.mdnsClientTransportPointer)
315
- this.mdnsClientTransportPointer = null
316
-
317
- if (this.mdnsServerAdvertiserPointer == null) throw new Error(`Internal inconsistency, when stopping LAN transport, a LAN transport pointer should exist.`)
318
- FFI.mdnsServerFreeHandle(this.mdnsServerAdvertiserPointer)
319
- this.mdnsServerAdvertiserPointer = null
320
- }
321
-
322
- if (lanOld.isMulticastEnabled) {
323
- FFI.dittoRemoveMulticastTransport(dittoHandle.deref())
324
- }
325
- }
326
-
327
- if (lanNew.isEnabled) {
328
- if (lanNew.isMdnsEnabled) {
329
- this.mdnsClientTransportPointer = FFI.dittoAddInternalMdnsTransport(dittoHandle.deref())
330
- this.mdnsServerAdvertiserPointer = FFI.dittoAddInternalMdnsAdvertiser(dittoHandle.deref())
331
- }
332
-
333
- if (lanNew.isMulticastEnabled) {
334
- FFI.dittoAddMulticastTransport(dittoHandle.deref())
335
- }
336
- }
337
-
338
- return
339
- }
340
-
341
- // IDEA: move the logic for this dance into stateFrom() signal
342
- // via some additional state signaling the actions here.
343
-
344
- if (lanOld.isEnabled) {
345
- if (lanOld.isMdnsEnabled) {
346
- if (this.lanTransportPointer == null) throw new Error(`Internal inconsistency, when stopping LAN transport, a LAN transport pointer should exist.`)
347
- FFI.transportsLANDestroy(this.lanTransportPointer as FFI.Pointer<FFI.TransportLAN>)
348
- this.lanTransportPointer = null
349
- }
350
-
351
- if (lanOld.isMulticastEnabled) {
352
- FFI.dittoRemoveMulticastTransport(dittoHandle.deref())
353
- }
354
- }
355
-
356
- if (lanNew.isEnabled) {
357
- if (lanNew.isMdnsEnabled) {
358
- if (this.lanTransportPointer != null) throw new Error(`Internal inconsistency, when starting LAN transport, no LAN transport pointer should exist.`)
359
- this.lanTransportPointer = FFI.transportsLANCreate(dittoHandle.deref()) as FFI.Pointer<FFI.TransportLAN>
360
- }
361
-
362
- if (lanNew.isMulticastEnabled) {
363
- FFI.dittoAddMulticastTransport(dittoHandle.deref())
364
- }
365
- }
366
- })
367
- }
368
-
369
- private updateListenTCP(stateOld: SyncState, stateNew: SyncState) {
370
- const ditto = this.ditto
371
- const dittoHandle = Bridge.ditto.handleFor(ditto)
372
- ditto.deferClose(() => {
373
- const tcpOld = stateOld.effectiveTransportConfig.listen.tcp
374
- const tcpNew = stateNew.effectiveTransportConfig.listen.tcp
375
-
376
- if (TransportConfig.areListenTCPsEqual(tcpNew, tcpOld)) return
377
-
378
- if (tcpOld.isEnabled) FFI.dittoStopTCPServer(dittoHandle.deref())
379
- if (tcpNew.isEnabled) FFI.dittoStartTCPServer(dittoHandle.deref(), `${tcpNew.interfaceIP}:${tcpNew.port}`)
380
- })
381
- }
382
-
383
- private updateListenHTTP(stateOld: SyncState, stateNew: SyncState) {
384
- const ditto = this.ditto
385
- const dittoHandle = Bridge.ditto.handleFor(ditto)
386
- ditto.deferClose(() => {
387
- const httpOld = stateOld.effectiveTransportConfig.listen.http
388
- const httpNew = stateNew.effectiveTransportConfig.listen.http
389
-
390
- if (TransportConfig.areListenHTTPsEqual(httpOld, httpNew)) return
391
- if (httpOld.isEnabled) FFI.dittoStopHTTPServer(dittoHandle.deref())
392
-
393
- /* eslint-disable */
394
- if (httpNew.isEnabled) {
395
- FFI.dittoStartHTTPServer(dittoHandle.deref(), `${httpNew.interfaceIP}:${httpNew.port}`, httpNew.staticContentPath || null, httpNew.websocketSync ? 'Enabled' : 'Disabled', httpNew.tlsCertificatePath || null, httpNew.tlsKeyPath || null)
396
- }
397
- /* eslint-enable */
398
- })
399
- }
400
-
401
- private updateConnectTCPServers(stateOld: SyncState, stateNew: SyncState) {
402
- const ditto = this.ditto
403
- const dittoHandle = Bridge.ditto.handleFor(ditto)
404
- ditto.deferClose(() => {
405
- const tcpServers = stateNew.effectiveTransportConfig.connect.tcpServers
406
- FFI.dittoSetStaticTCPClients(dittoHandle.deref(), tcpServers)
407
- })
408
- }
409
-
410
- private updateConnectWebsocketURLs(stateOld: SyncState, stateNew: SyncState) {
411
- const ditto = this.ditto
412
- const dittoHandle = Bridge.ditto.handleFor(ditto)
413
- ditto.deferClose(() => {
414
- const websocketURLs = stateNew.effectiveTransportConfig.connect.websocketURLs
415
- const routingHint = stateNew.effectiveTransportConfig.global.routingHint
416
- FFI.dittoSetStaticWebsocketClients(dittoHandle.deref(), websocketURLs, routingHint)
417
- })
418
- }
419
-
420
- private updateGlobal(stateOld: SyncState, stateNew: SyncState) {
421
- const ditto = this.ditto
422
- const dittoHandle = Bridge.ditto.handleFor(ditto)
423
- ditto.deferClose(() => {
424
- if (stateOld.effectiveTransportConfig.global.syncGroup !== stateNew.effectiveTransportConfig.global.syncGroup) {
425
- FFI.dittoSetSyncGroup(dittoHandle.deref(), stateNew.effectiveTransportConfig.global.syncGroup)
426
- }
427
- })
428
- }
429
-
430
- private updateConnectRetryInterval(stateOld: SyncState, stateNew: SyncState) {
431
- const ditto = this.ditto
432
- const dittoHandle = Bridge.ditto.handleFor(ditto)
433
- ditto.deferClose(() => {
434
- FFI.dittoSetConnectRetryInterval(dittoHandle.deref(), stateNew.effectiveTransportConfig.connect.retryInterval)
435
- })
436
- }
437
- }
438
-
439
- /**
440
- * Computes the effective transport config given a desired transport config and
441
- * some additional state.
442
- *
443
- * Disables all transports that are unavailable due to the runtime environment
444
- * or authentication requirements. Adds websocket URL for Ditto Cloud if
445
- * enabled.
446
- *
447
- * Throws if the target transport config enables sync but contains transports
448
- * that are not available in the current environment. Does not throw when
449
- * transports are enabled but not available due to authentication requirements.
450
- *
451
- * @private
452
- */
453
- function stateFrom(parameters: SyncParameters): SyncState {
454
- // IMPORTANT: this function maps a set of sync parameters to an effective
455
- // transport config plus some extra state where need be. Make sure
456
- // to keep this function free of side-effects.
457
-
458
- const identity = parameters.identity
459
-
460
- const isSyncActive = parameters.isSyncActive
461
- const isX509Valid = parameters.isX509Valid
462
- const isWebValid = parameters.isWebValid
463
-
464
- let appID
465
- let customDittoCloudURL
466
- let isDittoCloudSyncEnabled = false
467
-
468
- if (identity.type === 'onlinePlayground' || identity.type === 'onlineWithAuthentication') {
469
- // NOTE: enableDittoCloudSync is true by default for any online identity.
470
- appID = identity.appID
471
- customDittoCloudURL = identity.customDittoCloudURL ?? null
472
- isDittoCloudSyncEnabled = identity.enableDittoCloudSync ?? true
473
- }
474
-
475
- validateEnabledTransportsAvailable(parameters.ditto, parameters.transportConfig)
476
-
477
- const transportConfig = parameters.transportConfig.copy()
478
-
479
- if (!isSyncActive || !isX509Valid) {
480
- transportConfig.peerToPeer.bluetoothLE.isEnabled = false
481
- transportConfig.peerToPeer.awdl.isEnabled = false
482
- transportConfig.peerToPeer.lan.isEnabled = false
483
- transportConfig.listen.tcp.isEnabled = false
484
- transportConfig.connect.tcpServers = []
485
- }
486
-
487
- if (!isSyncActive || !isWebValid) {
488
- transportConfig.connect.websocketURLs = []
489
- }
490
-
491
- if (!isSyncActive) {
492
- transportConfig.listen.http.isEnabled = false
493
- }
494
-
495
- // NOTE: we have to smuggle in an additional Ditto Cloud websocket URL to
496
- // connect to if cloud sync is enabled.
497
- if (isSyncActive && isWebValid && isDittoCloudSyncEnabled) {
498
- // @ts-ignore To fix this type error, refactor using a switch
499
- // statement, c.f.
500
- // https://github.com/getditto/ditto/blob/d35b6c1cb280cdd6368d14137c97609b9b9b9296/js/sources/sync.ts#L488
501
- const dittoCloudURL = customDittoCloudURL ?? defaultDittoCloudURL(appID)
502
- transportConfig.connect.websocketURLs.push(dittoCloudURL)
503
- }
504
-
505
- return {
506
- underlyingSyncParameters: parameters,
507
- effectiveTransportConfig: transportConfig.freeze(),
508
- }
509
- }
510
-
511
- /**
512
- * Validate that all enabled transports are available in the current environment
513
- * and throw an error if not.
514
- *
515
- * @private
516
- */
517
- function validateEnabledTransportsAvailable(ditto: Ditto, transportConfig: TransportConfig) {
518
- const dittoHandle = Bridge.ditto.handleFor(ditto)
519
- return ditto.deferClose(() => {
520
- // - BLE
521
- // - AWDL
522
- // - LAN / mDNS
523
-
524
- const unavailableButEnabledP2PTransports = []
525
-
526
- const isBLEAvailable = FFI.transportsBLEIsAvailable(dittoHandle.deref())
527
- const isAWDLAvailable = FFI.transportsAWDLIsAvailable(dittoHandle.deref())
528
- const isLANAvailable = FFI.transportsLANIsAvailable(dittoHandle.deref())
529
-
530
- if (transportConfig.peerToPeer.bluetoothLE.isEnabled && !isBLEAvailable) {
531
- unavailableButEnabledP2PTransports.push('BluetoothLE')
532
- }
533
-
534
- if (transportConfig.peerToPeer.awdl.isEnabled && !isAWDLAvailable) {
535
- unavailableButEnabledP2PTransports.push('AWDL')
536
- }
537
-
538
- if (transportConfig.peerToPeer.lan.isEnabled && !isLANAvailable) {
539
- unavailableButEnabledP2PTransports.push('LAN')
540
- }
541
-
542
- if (unavailableButEnabledP2PTransports.length > 0) {
543
- throw new Error(`The following P2P transports are enabled in the transport config but are not supported in the current environment: ${unavailableButEnabledP2PTransports.join(', ')}`)
544
- }
545
-
546
- // - Websocket / HTTP
547
- // - TCP
548
-
549
- if (transportConfig.connect.tcpServers.length > 0 && Environment.isWebBuild) {
550
- throw new Error(`The transport config contains TCP servers, but this transport is not supported in web environments`)
551
- }
552
-
553
- if (transportConfig.listen.http.isEnabled && Environment.isWebBuild) {
554
- throw new Error(`The transport config contains an HTTP listener, which is not supported in web environments`)
555
- }
556
-
557
- if (transportConfig.listen.tcp.isEnabled && Environment.isWebBuild) {
558
- throw new Error(`The transport config contains a TCP listener, which is not supported in web environments`)
559
- }
560
- })
561
- }
@@ -1,24 +0,0 @@
1
- import { Bridge } from './bridge'
2
-
3
- /**
4
- * Get a count of bridged objects binned by bridge type.
5
- *
6
- * Use this in testing to ensure that all objects are properly garbage collected at the end of tests.
7
- *
8
- * @returns an object with a key per bridge type, set to the count of registered
9
- * objects.
10
- */
11
- export function getBridgeLoad(): { [bridgeName: string]: number } {
12
- const countsByType: { [bridgeName: string]: number } = {}
13
- Bridge.all.map((bridgeWeakRef) => {
14
- const bridge = bridgeWeakRef.deref()
15
- if (!bridge) {
16
- return null
17
- }
18
- if (bridge.count === 0) {
19
- return null
20
- }
21
- countsByType[bridge.type.name] = bridge.count
22
- })
23
- return countsByType
24
- }
@@ -1,104 +0,0 @@
1
- //
2
- // Copyright © 2021 DittoLive Incorporated. All rights reserved.
3
- //
4
-
5
- import * as FFI from './ffi'
6
-
7
- import { Bridge } from './bridge'
8
- import { ObserverManager } from './observer-manager'
9
-
10
- import type { Ditto, TransportCondition, ConditionSource } from './ditto'
11
-
12
- /** @internal */
13
- export class TransportConditionsManager extends ObserverManager {
14
- readonly ditto: Ditto
15
-
16
- constructor(ditto: Ditto) {
17
- const keepAlive = ditto.keepAlive
18
- super('TransportConditionsObservation', { keepAlive })
19
- this.ditto = ditto
20
- }
21
-
22
- protected register(callback: (...args: any[]) => void) {
23
- const ditto = this.ditto
24
- const dittoHandle = Bridge.ditto.handleFor(ditto)
25
- return ditto.deferClose(() => {
26
- return FFI.dittoRegisterTransportConditionChangedCallback(dittoHandle.deref(), callback)
27
- })
28
- }
29
-
30
- protected unregister() {
31
- const ditto = this.ditto
32
- const dittoHandle = Bridge.ditto.handleFor(ditto)
33
- return ditto.deferClose(() => {
34
- return FFI.dittoRegisterTransportConditionChangedCallback(dittoHandle.deref(), null)
35
- })
36
- }
37
-
38
- protected process(conditionSource: FFI.ConditionSource, transportCondition: FFI.TransportCondition): [TransportCondition, ConditionSource] {
39
- /* eslint-disable */
40
- let apiConditionSource: ConditionSource
41
- switch (conditionSource) {
42
- case 'Bluetooth':
43
- apiConditionSource = 'BLE'
44
- break
45
- case 'Tcp':
46
- apiConditionSource = 'TCP'
47
- break
48
- case 'Awdl':
49
- apiConditionSource = 'AWDL'
50
- break
51
- case 'Mdns':
52
- apiConditionSource = 'MDNS'
53
- break
54
- }
55
- /* eslint-enable */
56
-
57
- /* eslint-disable */
58
- let apiTransportCondition: TransportCondition
59
- switch (transportCondition) {
60
- case 'Unknown':
61
- apiTransportCondition = 'Unknown'
62
- break
63
- case 'Ok':
64
- apiTransportCondition = 'OK'
65
- break
66
- case 'GenericFailure':
67
- apiTransportCondition = 'GenericFailure'
68
- break
69
- case 'AppInBackground':
70
- apiTransportCondition = 'AppInBackground'
71
- break
72
- case 'MdnsFailure':
73
- apiTransportCondition = 'MDNSFailure'
74
- break
75
- case 'TcpListenFailure':
76
- apiTransportCondition = 'TCPListenFailure'
77
- break
78
- case 'NoBleCentralPermission':
79
- apiTransportCondition = 'NoBLECentralPermission'
80
- break
81
- case 'NoBlePeripheralPermission':
82
- apiTransportCondition = 'NoBLEPeripheralPermission'
83
- break
84
- case 'CannotEstablishConnection':
85
- apiTransportCondition = 'CannotEstablishConnection'
86
- break
87
- case 'BleDisabled':
88
- apiTransportCondition = 'BLEDisabled'
89
- break
90
- case 'NoBleHardware':
91
- apiTransportCondition = 'NoBLEHardware'
92
- break
93
- case 'WifiDisabled':
94
- apiTransportCondition = 'WiFiDisabled'
95
- break
96
- case 'TemporarilyUnavailable':
97
- apiTransportCondition = 'TemporarilyUnavailable'
98
- break
99
- }
100
- /* eslint-enable */
101
-
102
- return [apiTransportCondition, apiConditionSource]
103
- }
104
- }