@dittolive/ditto 4.4.4 → 4.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DittoReactNative.podspec +27 -0
- package/README.md +68 -51
- package/node/ditto.cjs.js +1639 -851
- package/node/ditto.darwin-arm64.node +0 -0
- package/node/ditto.darwin-x64.node +0 -0
- package/node/ditto.linux-arm.node +0 -0
- package/node/ditto.linux-x64.node +0 -0
- package/node/ditto.win32-x64.node +0 -0
- package/node/transports.darwin-arm64.node +0 -0
- package/node/transports.darwin-x64.node +0 -0
- package/package.json +34 -38
- package/react-native/android/CMakeLists.txt +37 -0
- package/react-native/android/build.gradle +203 -0
- package/react-native/android/cpp-adapter.cpp +254 -0
- package/react-native/android/gradle.properties +5 -0
- package/react-native/android/src/main/AndroidManifest.xml +4 -0
- package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKModule.java +85 -0
- package/react-native/android/src/main/java/com/dittolive/rnsdk/DittoRNSDKPackage.java +28 -0
- package/react-native/boost/boost/assert.hpp +85 -0
- package/react-native/boost/boost/config/abi/borland_prefix.hpp +27 -0
- package/react-native/boost/boost/config/abi/borland_suffix.hpp +12 -0
- package/react-native/boost/boost/config/abi/msvc_prefix.hpp +22 -0
- package/react-native/boost/boost/config/abi/msvc_suffix.hpp +8 -0
- package/react-native/boost/boost/config/abi_prefix.hpp +25 -0
- package/react-native/boost/boost/config/abi_suffix.hpp +25 -0
- package/react-native/boost/boost/config/assert_cxx03.hpp +211 -0
- package/react-native/boost/boost/config/assert_cxx11.hpp +209 -0
- package/react-native/boost/boost/config/assert_cxx14.hpp +47 -0
- package/react-native/boost/boost/config/assert_cxx17.hpp +62 -0
- package/react-native/boost/boost/config/assert_cxx20.hpp +59 -0
- package/react-native/boost/boost/config/assert_cxx98.hpp +23 -0
- package/react-native/boost/boost/config/auto_link.hpp +525 -0
- package/react-native/boost/boost/config/compiler/borland.hpp +339 -0
- package/react-native/boost/boost/config/compiler/clang.hpp +366 -0
- package/react-native/boost/boost/config/compiler/clang_version.hpp +83 -0
- package/react-native/boost/boost/config/compiler/codegear.hpp +385 -0
- package/react-native/boost/boost/config/compiler/comeau.hpp +59 -0
- package/react-native/boost/boost/config/compiler/common_edg.hpp +183 -0
- package/react-native/boost/boost/config/compiler/compaq_cxx.hpp +19 -0
- package/react-native/boost/boost/config/compiler/cray.hpp +446 -0
- package/react-native/boost/boost/config/compiler/diab.hpp +26 -0
- package/react-native/boost/boost/config/compiler/digitalmars.hpp +143 -0
- package/react-native/boost/boost/config/compiler/gcc.hpp +383 -0
- package/react-native/boost/boost/config/compiler/gcc_xml.hpp +114 -0
- package/react-native/boost/boost/config/compiler/greenhills.hpp +28 -0
- package/react-native/boost/boost/config/compiler/hp_acc.hpp +149 -0
- package/react-native/boost/boost/config/compiler/intel.hpp +577 -0
- package/react-native/boost/boost/config/compiler/kai.hpp +33 -0
- package/react-native/boost/boost/config/compiler/metrowerks.hpp +198 -0
- package/react-native/boost/boost/config/compiler/mpw.hpp +140 -0
- package/react-native/boost/boost/config/compiler/nvcc.hpp +61 -0
- package/react-native/boost/boost/config/compiler/pathscale.hpp +138 -0
- package/react-native/boost/boost/config/compiler/pgi.hpp +23 -0
- package/react-native/boost/boost/config/compiler/sgi_mipspro.hpp +29 -0
- package/react-native/boost/boost/config/compiler/sunpro_cc.hpp +222 -0
- package/react-native/boost/boost/config/compiler/vacpp.hpp +186 -0
- package/react-native/boost/boost/config/compiler/visualc.hpp +391 -0
- package/react-native/boost/boost/config/compiler/xlcpp.hpp +299 -0
- package/react-native/boost/boost/config/compiler/xlcpp_zos.hpp +173 -0
- package/react-native/boost/boost/config/detail/cxx_composite.hpp +203 -0
- package/react-native/boost/boost/config/detail/posix_features.hpp +95 -0
- package/react-native/boost/boost/config/detail/select_compiler_config.hpp +157 -0
- package/react-native/boost/boost/config/detail/select_platform_config.hpp +147 -0
- package/react-native/boost/boost/config/detail/select_stdlib_config.hpp +121 -0
- package/react-native/boost/boost/config/detail/suffix.hpp +1294 -0
- package/react-native/boost/boost/config/header_deprecated.hpp +26 -0
- package/react-native/boost/boost/config/helper_macros.hpp +37 -0
- package/react-native/boost/boost/config/no_tr1/cmath.hpp +28 -0
- package/react-native/boost/boost/config/no_tr1/complex.hpp +28 -0
- package/react-native/boost/boost/config/no_tr1/functional.hpp +28 -0
- package/react-native/boost/boost/config/no_tr1/memory.hpp +28 -0
- package/react-native/boost/boost/config/no_tr1/utility.hpp +28 -0
- package/react-native/boost/boost/config/platform/aix.hpp +33 -0
- package/react-native/boost/boost/config/platform/amigaos.hpp +15 -0
- package/react-native/boost/boost/config/platform/beos.hpp +26 -0
- package/react-native/boost/boost/config/platform/bsd.hpp +83 -0
- package/react-native/boost/boost/config/platform/cloudabi.hpp +18 -0
- package/react-native/boost/boost/config/platform/cray.hpp +18 -0
- package/react-native/boost/boost/config/platform/cygwin.hpp +71 -0
- package/react-native/boost/boost/config/platform/haiku.hpp +31 -0
- package/react-native/boost/boost/config/platform/hpux.hpp +87 -0
- package/react-native/boost/boost/config/platform/irix.hpp +31 -0
- package/react-native/boost/boost/config/platform/linux.hpp +106 -0
- package/react-native/boost/boost/config/platform/macos.hpp +87 -0
- package/react-native/boost/boost/config/platform/qnxnto.hpp +31 -0
- package/react-native/boost/boost/config/platform/solaris.hpp +31 -0
- package/react-native/boost/boost/config/platform/symbian.hpp +97 -0
- package/react-native/boost/boost/config/platform/vms.hpp +25 -0
- package/react-native/boost/boost/config/platform/vxworks.hpp +422 -0
- package/react-native/boost/boost/config/platform/wasm.hpp +23 -0
- package/react-native/boost/boost/config/platform/win32.hpp +90 -0
- package/react-native/boost/boost/config/platform/zos.hpp +32 -0
- package/react-native/boost/boost/config/pragma_message.hpp +31 -0
- package/react-native/boost/boost/config/requires_threads.hpp +92 -0
- package/react-native/boost/boost/config/stdlib/dinkumware.hpp +324 -0
- package/react-native/boost/boost/config/stdlib/libcomo.hpp +93 -0
- package/react-native/boost/boost/config/stdlib/libcpp.hpp +180 -0
- package/react-native/boost/boost/config/stdlib/libstdcpp3.hpp +482 -0
- package/react-native/boost/boost/config/stdlib/modena.hpp +79 -0
- package/react-native/boost/boost/config/stdlib/msl.hpp +98 -0
- package/react-native/boost/boost/config/stdlib/roguewave.hpp +208 -0
- package/react-native/boost/boost/config/stdlib/sgi.hpp +168 -0
- package/react-native/boost/boost/config/stdlib/stlport.hpp +258 -0
- package/react-native/boost/boost/config/stdlib/vacpp.hpp +74 -0
- package/react-native/boost/boost/config/stdlib/xlcpp_zos.hpp +61 -0
- package/react-native/boost/boost/config/user.hpp +133 -0
- package/react-native/boost/boost/config/warning_disable.hpp +47 -0
- package/react-native/boost/boost/config/workaround.hpp +305 -0
- package/react-native/boost/boost/config.hpp +67 -0
- package/react-native/boost/boost/cstdint.hpp +556 -0
- package/react-native/boost/boost/intrusive_ptr.hpp +18 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count.hpp +103 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_gcc.hpp +79 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_gcc_atomic.hpp +63 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_gcc_x86.hpp +88 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_nt.hpp +66 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_pt.hpp +104 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_spin.hpp +69 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_std_atomic.hpp +67 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_sync.hpp +72 -0
- package/react-native/boost/boost/smart_ptr/detail/atomic_count_win32.hpp +70 -0
- package/react-native/boost/boost/smart_ptr/detail/local_counted_base.hpp +148 -0
- package/react-native/boost/boost/smart_ptr/detail/local_sp_deleter.hpp +91 -0
- package/react-native/boost/boost/smart_ptr/detail/operator_bool.hpp +64 -0
- package/react-native/boost/boost/smart_ptr/detail/requires_cxx11.hpp +23 -0
- package/react-native/boost/boost/smart_ptr/detail/shared_count.hpp +707 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_convertible.hpp +92 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base.hpp +92 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_acc_ia64.hpp +163 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_aix.hpp +152 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_cw_ppc.hpp +185 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_atomic.hpp +148 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_ia64.hpp +170 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_mips.hpp +200 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_ppc.hpp +194 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_sparc.hpp +179 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_gcc_x86.hpp +186 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_nt.hpp +119 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_pt.hpp +147 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_snc_ps3.hpp +174 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_spin.hpp +141 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_std_atomic.hpp +147 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_sync.hpp +165 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_vacpp_ppc.hpp +163 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_base_w32.hpp +140 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_counted_impl.hpp +309 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_disable_deprecated.hpp +40 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_forward.hpp +52 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_has_gcc_intrinsics.hpp +27 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_has_sync_intrinsics.hpp +69 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_interlocked.hpp +173 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_noexcept.hpp +48 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_nullptr_t.hpp +45 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_obsolete.hpp +32 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_thread_pause.hpp +51 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_thread_sleep.hpp +104 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_thread_yield.hpp +100 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_typeinfo_.hpp +58 -0
- package/react-native/boost/boost/smart_ptr/detail/sp_win32_sleep.hpp +49 -0
- package/react-native/boost/boost/smart_ptr/intrusive_ptr.hpp +409 -0
- package/react-native/boost/boost/smart_ptr/intrusive_ref_counter.hpp +188 -0
- package/react-native/cpp/include/Attachment.h +16 -0
- package/react-native/cpp/include/Authentication.h +23 -0
- package/react-native/cpp/include/Collection.h +13 -0
- package/react-native/cpp/include/DQL.h +21 -0
- package/react-native/cpp/include/Document.h +17 -0
- package/react-native/cpp/include/Identity.h +17 -0
- package/react-native/cpp/include/Lifecycle.h +16 -0
- package/react-native/cpp/include/LiveQuery.h +17 -0
- package/react-native/cpp/include/Logger.h +22 -0
- package/react-native/cpp/include/Misc.h +26 -0
- package/react-native/cpp/include/Presence.h +14 -0
- package/react-native/cpp/include/RetainableState.h +24 -0
- package/react-native/cpp/include/SmallPeerInfo.h +17 -0
- package/react-native/cpp/include/Transports.h +25 -0
- package/react-native/cpp/include/TypedArray.hpp +167 -0
- package/react-native/cpp/include/Utils.h +61 -0
- package/react-native/cpp/include/main.h +10 -0
- package/react-native/cpp/src/Attachment.cpp +86 -0
- package/react-native/cpp/src/Authentication.cpp +224 -0
- package/react-native/cpp/src/Collection.cpp +54 -0
- package/react-native/cpp/src/DQL.cpp +254 -0
- package/react-native/cpp/src/Document.cpp +146 -0
- package/react-native/cpp/src/Identity.cpp +123 -0
- package/react-native/cpp/src/Lifecycle.cpp +75 -0
- package/react-native/cpp/src/LiveQuery.cpp +64 -0
- package/react-native/cpp/src/Logger.cpp +200 -0
- package/react-native/cpp/src/Misc.cpp +271 -0
- package/react-native/cpp/src/Presence.cpp +77 -0
- package/react-native/cpp/src/RetainableState.cpp +15 -0
- package/react-native/cpp/src/SmallPeerInfo.cpp +108 -0
- package/react-native/cpp/src/Transports.cpp +270 -0
- package/react-native/cpp/src/TypedArray.cpp +303 -0
- package/react-native/cpp/src/Utils.cpp +138 -0
- package/react-native/cpp/src/main.cpp +149 -0
- package/react-native/dittoffi/dittoffi.h +4698 -0
- package/react-native/dittoffi/ifaddrs.cpp +385 -0
- package/react-native/dittoffi/ifaddrs.h +206 -0
- package/react-native/ios/DittoRNSDK.h +7 -0
- package/react-native/ios/DittoRNSDK.mm +107 -0
- package/react-native/ios/YeetJSIUtils.h +60 -0
- package/react-native/ios/YeetJSIUtils.mm +196 -0
- package/react-native/lib/commonjs/ditto.rn.js +93 -0
- package/react-native/lib/commonjs/ditto.rn.js.map +1 -0
- package/react-native/lib/commonjs/index.js +14 -0
- package/react-native/lib/commonjs/index.js.map +1 -0
- package/react-native/lib/module/ditto.rn.js +83 -0
- package/react-native/lib/module/ditto.rn.js.map +1 -0
- package/react-native/lib/module/index.js +13 -0
- package/react-native/lib/module/index.js.map +1 -0
- package/react-native/lib/typescript/ditto.rn.d.ts +15 -0
- package/react-native/lib/typescript/ditto.rn.d.ts.map +1 -0
- package/react-native/lib/typescript/index.d.ts +1 -0
- package/react-native/lib/typescript/index.d.ts.map +1 -0
- package/react-native/scripts/ruby/include_local_boost.rb +78 -0
- package/react-native/src/ditto.rn.ts +91 -0
- package/react-native/src/environment/environment.fallback.ts +4 -0
- package/react-native/src/index.ts +26 -0
- package/react-native/src/sources/@cbor-redux.ts +2 -0
- package/react-native/src/sources/@ditto.core.ts +1 -0
- package/react-native/src/sources/@environment.ts +2 -0
- package/react-native/src/sources/attachment-fetch-event.ts +54 -0
- package/react-native/src/sources/attachment-fetcher-manager.ts +129 -0
- package/react-native/src/sources/attachment-fetcher.ts +124 -0
- package/react-native/src/sources/attachment-token.ts +48 -0
- package/react-native/src/sources/attachment.ts +59 -0
- package/react-native/src/sources/augment.ts +89 -0
- package/react-native/src/sources/authenticator.ts +314 -0
- package/react-native/src/sources/base-pending-cursor-operation.ts +237 -0
- package/react-native/src/sources/base-pending-id-specific-operation.ts +109 -0
- package/react-native/src/sources/bridge.ts +549 -0
- package/react-native/src/sources/build-time-constants.ts +4 -0
- package/react-native/src/sources/cbor.ts +35 -0
- package/react-native/src/sources/collection-interface.ts +67 -0
- package/react-native/src/sources/collection.ts +212 -0
- package/react-native/src/sources/collections-event.ts +99 -0
- package/react-native/src/sources/counter.ts +77 -0
- package/react-native/src/sources/ditto.ts +945 -0
- package/react-native/src/sources/document-id.ts +159 -0
- package/react-native/src/sources/document-path.ts +303 -0
- package/react-native/src/sources/document.ts +192 -0
- package/react-native/src/sources/epilogue.ts +24 -0
- package/react-native/src/sources/error-codes.ts +52 -0
- package/react-native/src/sources/error.ts +203 -0
- package/react-native/src/sources/essentials.ts +53 -0
- package/react-native/src/sources/ffi-error.ts +117 -0
- package/react-native/src/sources/ffi.ts +1972 -0
- package/react-native/src/sources/identity.ts +163 -0
- package/react-native/src/sources/init.ts +70 -0
- package/react-native/src/sources/internal.ts +113 -0
- package/react-native/src/sources/keep-alive.ts +69 -0
- package/react-native/src/sources/key-path.ts +195 -0
- package/react-native/src/sources/live-query-event.ts +208 -0
- package/react-native/src/sources/live-query-manager.ts +101 -0
- package/react-native/src/sources/live-query.ts +164 -0
- package/react-native/src/sources/logger.ts +196 -0
- package/react-native/src/sources/observer-manager.ts +175 -0
- package/react-native/src/sources/observer.ts +77 -0
- package/react-native/src/sources/pending-collections-operation.ts +232 -0
- package/react-native/src/sources/pending-cursor-operation.ts +218 -0
- package/react-native/src/sources/pending-id-specific-operation.ts +216 -0
- package/react-native/src/sources/presence-manager.ts +160 -0
- package/react-native/src/sources/presence.ts +238 -0
- package/react-native/src/sources/query-result-item.ts +116 -0
- package/react-native/src/sources/query-result.ts +55 -0
- package/react-native/src/sources/register.ts +92 -0
- package/react-native/src/sources/small-peer-info.ts +176 -0
- package/react-native/src/sources/static-tcp-client.ts +6 -0
- package/react-native/src/sources/store-observer.ts +176 -0
- package/react-native/src/sources/store.ts +365 -0
- package/react-native/src/sources/subscription-manager.ts +98 -0
- package/react-native/src/sources/subscription.ts +88 -0
- package/react-native/src/sources/sync-subscription.ts +90 -0
- package/react-native/src/sources/sync.ts +495 -0
- package/react-native/src/sources/test-helpers.ts +24 -0
- package/react-native/src/sources/transport-conditions-manager.ts +104 -0
- package/react-native/src/sources/transport-config.ts +428 -0
- package/react-native/src/sources/update-result.ts +66 -0
- package/react-native/src/sources/update-results-map.ts +57 -0
- package/react-native/src/sources/websocket-client.ts +6 -0
- package/react-native/src/sources/write-transaction-collection.ts +122 -0
- package/react-native/src/sources/write-transaction-pending-cursor-operation.ts +101 -0
- package/react-native/src/sources/write-transaction-pending-id-specific-operation.ts +72 -0
- package/react-native/src/sources/write-transaction.ts +119 -0
- package/react-native.config.js +9 -0
- package/types/ditto.d.ts +1230 -798
- package/web/ditto.es6.js +1 -1
- package/web/ditto.umd.js +1 -1
- package/web/ditto.wasm +0 -0
|
@@ -0,0 +1,216 @@
|
|
|
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 { Subscription } from './subscription'
|
|
9
|
+
import { LiveQuery } from './live-query'
|
|
10
|
+
import { Document, MutableDocument } from './document'
|
|
11
|
+
import { performAsyncToWorkaroundNonAsyncFFIAPI } from './internal'
|
|
12
|
+
import { BasePendingIDSpecificOperation } from './base-pending-id-specific-operation'
|
|
13
|
+
import { SingleDocumentLiveQueryEvent } from './live-query-event'
|
|
14
|
+
|
|
15
|
+
import type { DocumentID } from './document-id'
|
|
16
|
+
import type { UpdateResult } from './update-result'
|
|
17
|
+
import type { Collection } from './collection'
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The closure that is called whenever a single documunent covered by a
|
|
22
|
+
* live query changes.
|
|
23
|
+
*/
|
|
24
|
+
export type SingleObservationHandler = (document: Document | null, event: SingleDocumentLiveQueryEvent, signalNext?: () => void) => void | Promise<void>
|
|
25
|
+
|
|
26
|
+
// -----------------------------------------------------------------------------
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* These objects are returned when using {@link Collection.findByID | findByID()}
|
|
30
|
+
* functionality on {@link Collection | collections}.
|
|
31
|
+
*
|
|
32
|
+
* You can either call {@link exec | exec()} on the object to get an immediate
|
|
33
|
+
* return value, or you can establish either a live query or a subscription,
|
|
34
|
+
* which both work over time.
|
|
35
|
+
*
|
|
36
|
+
* A live query, established by calling
|
|
37
|
+
* {@link PendingIDSpecificOperation.observeLocal | observeLocal()}, will notify
|
|
38
|
+
* you every time there's an update to the document with the ID you provided in
|
|
39
|
+
* the preceding {@link Collection.findByID | findByID()} call.
|
|
40
|
+
*
|
|
41
|
+
* A subscription, established by calling {@link PendingIDSpecificOperation.subscribe | subscribe()}, will
|
|
42
|
+
* act as a signal to other peers that you would like to receive updates from
|
|
43
|
+
* them about the document with the ID you provided in the preceding
|
|
44
|
+
* {@link Collection.findByID | findByID()} call.
|
|
45
|
+
*
|
|
46
|
+
* Update and remove functionality is also exposed through this object.
|
|
47
|
+
*/
|
|
48
|
+
export class PendingIDSpecificOperation extends BasePendingIDSpecificOperation {
|
|
49
|
+
async remove(): Promise<boolean> {
|
|
50
|
+
const ditto = this.collection.store.ditto
|
|
51
|
+
const dittoHandle = Bridge.ditto.handleFor(ditto)
|
|
52
|
+
|
|
53
|
+
return ditto.deferCloseAsync(async () => {
|
|
54
|
+
return await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
|
|
55
|
+
const writeTransactionX = await FFI.writeTransaction(dittoHandle.deref())
|
|
56
|
+
const didRemove = await FFI.collectionRemove(dittoHandle.deref(), this.collection.name, writeTransactionX, this.documentIDCBOR)
|
|
57
|
+
await FFI.writeTransactionCommit(dittoHandle.deref(), writeTransactionX)
|
|
58
|
+
return didRemove
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async evict(): Promise<boolean> {
|
|
64
|
+
const ditto = this.collection.store.ditto
|
|
65
|
+
const dittoHandle = Bridge.ditto.handleFor(ditto)
|
|
66
|
+
|
|
67
|
+
return ditto.deferCloseAsync(async () => {
|
|
68
|
+
return await performAsyncToWorkaroundNonAsyncFFIAPI(async () => {
|
|
69
|
+
const writeTransactionX = await FFI.writeTransaction(dittoHandle.deref())
|
|
70
|
+
const didEvict = await FFI.collectionEvict(dittoHandle.deref(), this.collection.name, writeTransactionX, this.documentIDCBOR)
|
|
71
|
+
await FFI.writeTransactionCommit(dittoHandle.deref(), writeTransactionX)
|
|
72
|
+
return didEvict
|
|
73
|
+
})
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async update(closure: (document: MutableDocument) => void): Promise<UpdateResult[]> {
|
|
78
|
+
const ditto = this.collection.store.ditto
|
|
79
|
+
const dittoHandle = Bridge.ditto.handleFor(ditto)
|
|
80
|
+
|
|
81
|
+
return ditto.deferCloseAsync(async () => {
|
|
82
|
+
const readTransactionX = await FFI.readTransaction(dittoHandle.deref())
|
|
83
|
+
const documentX = await FFI.collectionGet(dittoHandle.deref(), this.collection.name, this.documentIDCBOR, readTransactionX)
|
|
84
|
+
FFI.readTransactionFree(readTransactionX)
|
|
85
|
+
|
|
86
|
+
if (!documentX) throw new Error(`Can't update, document with ID '${this.documentID.toString()}' not found in collection named '${this.collection.name}'`)
|
|
87
|
+
|
|
88
|
+
const mutableDocument = Bridge.mutableDocument.bridge(documentX, () => new MutableDocument())
|
|
89
|
+
closure(mutableDocument)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
Bridge.mutableDocument.unregister(mutableDocument)
|
|
93
|
+
|
|
94
|
+
const writeTransactionX = await FFI.writeTransaction(dittoHandle.deref())
|
|
95
|
+
await FFI.collectionUpdate(dittoHandle.deref(), this.collection.name, writeTransactionX, documentX)
|
|
96
|
+
await FFI.writeTransactionCommit(dittoHandle.deref(), writeTransactionX)
|
|
97
|
+
|
|
98
|
+
return mutableDocument['@ditto.updateResults'].slice()
|
|
99
|
+
})
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Enables you to subscribe to changes that occur in relation to a document
|
|
104
|
+
* remotely.
|
|
105
|
+
*
|
|
106
|
+
* Having a subscription acts as a signal to other peers that you are
|
|
107
|
+
* interested in receiving updates when local or remote changes are made to
|
|
108
|
+
* the relevant document.
|
|
109
|
+
*
|
|
110
|
+
* The returned {@link Subscription} object must be kept in scope for as long
|
|
111
|
+
* as you want to keep receiving updates.
|
|
112
|
+
*
|
|
113
|
+
* @returns A {@link Subscription} object that must be kept in scope for as
|
|
114
|
+
* long as you want to keep receiving updates for the document.
|
|
115
|
+
*/
|
|
116
|
+
subscribe(): Subscription {
|
|
117
|
+
const subscription = new Subscription(this.collection as Collection, this.query, null, [], -1, 0)
|
|
118
|
+
this.collection.store.ditto.subscriptionManager.add(subscription)
|
|
119
|
+
return subscription
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Enables you to listen for changes that occur in relation to a document
|
|
124
|
+
* locally.
|
|
125
|
+
*
|
|
126
|
+
* This won't subscribe to receive changes made remotely by others and so it
|
|
127
|
+
* will only fire updates when a local change is made. If you want to receive
|
|
128
|
+
* remotely performed updates as well, you'll have to create a subscription
|
|
129
|
+
* via {@link PendingIDSpecificOperation.subscribe | subscribe()} for the same
|
|
130
|
+
* document ID.
|
|
131
|
+
*
|
|
132
|
+
* The returned {@link LiveQuery} object must be kept in scope for as long
|
|
133
|
+
* as you want the provided `handler` to be called when an update
|
|
134
|
+
* occurs.
|
|
135
|
+
*
|
|
136
|
+
* @param handler A block that will be called every time there is a
|
|
137
|
+
* transaction committed to the store that involves a modification to the
|
|
138
|
+
* document with the relevant ID in the collection that
|
|
139
|
+
* {@link PendingIDSpecificOperation.observeLocal | observeLocal()} was called on.
|
|
140
|
+
*
|
|
141
|
+
* @returns A {@link LiveQuery} object that must be kept in scope for as long
|
|
142
|
+
* as you want to keep receiving updates.
|
|
143
|
+
*/
|
|
144
|
+
observeLocal(handler: SingleObservationHandler): LiveQuery {
|
|
145
|
+
return this._observe(handler, false)
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Enables you to listen for changes that occur in relation to a document
|
|
150
|
+
* locally and to signal when you are ready for the live query to deliver
|
|
151
|
+
* the next event.
|
|
152
|
+
*
|
|
153
|
+
* This won't subscribe to receive changes made remotely by others and so it
|
|
154
|
+
* will only fire updates when a local change is made. If you want to receive
|
|
155
|
+
* remotely performed updates as well, you'll have to create a subscription
|
|
156
|
+
* via {@link PendingIDSpecificOperation.subscribe | subscribe()} for the same
|
|
157
|
+
* document ID.
|
|
158
|
+
*
|
|
159
|
+
* The returned {@link LiveQuery} object must be kept in scope for as long
|
|
160
|
+
* as you want the provided `handler` to be called when an update
|
|
161
|
+
* occurs.
|
|
162
|
+
*
|
|
163
|
+
* @param handler A block that will be called every time there is a
|
|
164
|
+
* transaction committed to the store that involves a modification to the
|
|
165
|
+
* document with the relevant ID in the collection that
|
|
166
|
+
* {@link PendingIDSpecificOperation.observeLocal | observeLocal()} was called on.
|
|
167
|
+
*
|
|
168
|
+
* @returns A {@link LiveQuery} object that must be kept in scope for as long
|
|
169
|
+
* as you want to keep receiving updates.
|
|
170
|
+
*/
|
|
171
|
+
observeLocalWithNextSignal(handler: SingleObservationHandler): LiveQuery {
|
|
172
|
+
return this._observe(handler, true)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** @internal */
|
|
176
|
+
constructor(documentID: DocumentID, collection: Collection) {
|
|
177
|
+
super(documentID, collection)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/** @internal */
|
|
181
|
+
_observe(handler: SingleObservationHandler, waitForNextSignal: boolean): LiveQuery {
|
|
182
|
+
const liveQuery = new LiveQuery(this.query, null, null, [], -1, 0, this.collection as Collection, (documents, event, signalNext) => {
|
|
183
|
+
if (documents.length > 1) {
|
|
184
|
+
const documentIDsAsBase64Strings = documents.map((document) => document.id.toBase64String())
|
|
185
|
+
throw new Error(`Internal inconsistency, single document live query returned more than one document. Query: ${this.query}, documentIDs: ${documentIDsAsBase64Strings.join(', ')}.`)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (event.isInitial === false && event.oldDocuments.length > 1) throw new Error(`Internal inconsistency, single document live query returned an update event with more than one old documents. Query ${this.query}.`)
|
|
189
|
+
if (event.isInitial === false && event.insertions.length > 1) throw new Error(`Internal inconsistency, single document live query returned an update event with more than one insertion, which doesn't make sense for single document observations. Query ${this.query}.`)
|
|
190
|
+
if (event.isInitial === false && event.deletions.length > 1) throw new Error(`Internal inconsistency, single document live query returned an update event with more than one deletion, which doesn't make sense for single document observations. Query ${this.query}.`)
|
|
191
|
+
if (event.isInitial === false && event.updates.length > 1) throw new Error(`Internal inconsistency, single document live query returned an update event with more than one update, which doesn't make sense for single document observations. Query ${this.query}.`)
|
|
192
|
+
if (event.isInitial === false && event.moves.length > 0) throw new Error(`Internal inconsistency, single document live query returned an update event with moves, which doesn't make sense for single document observations. Query ${this.query}.`)
|
|
193
|
+
|
|
194
|
+
const totalNumberOfManipulations = event.isInitial === true ? 0 : event.insertions.length + event.deletions.length + event.updates.length
|
|
195
|
+
if (totalNumberOfManipulations > 1) throw new Error(`Internal inconsistency, single document live query returned a combination of inserts, updates, and/or deletes, which doesn't make sense for single document observation. Query ${this.query}.`)
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
const document = documents[0] || null
|
|
199
|
+
const oldDocument = event.isInitial === true ? undefined : event.oldDocuments[0]
|
|
200
|
+
|
|
201
|
+
const singleDocumentEvent = new SingleDocumentLiveQueryEvent(event.isInitial, oldDocument)
|
|
202
|
+
if (waitForNextSignal) {
|
|
203
|
+
handler(document, singleDocumentEvent, signalNext)
|
|
204
|
+
} else {
|
|
205
|
+
try {
|
|
206
|
+
handler(document, singleDocumentEvent)
|
|
207
|
+
} finally {
|
|
208
|
+
signalNext()
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
this.collection.store.ditto.liveQueryManager.startLiveQuery(liveQuery)
|
|
214
|
+
return liveQuery
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright © 2021 DittoLive Incorporated. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as FFI from './ffi'
|
|
6
|
+
import { Bridge } from './bridge'
|
|
7
|
+
import { generateEphemeralToken } from './internal'
|
|
8
|
+
|
|
9
|
+
import type { Ditto, RemotePeer } from './ditto'
|
|
10
|
+
|
|
11
|
+
/** @internal */
|
|
12
|
+
export type PresenceToken = string
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @internal
|
|
16
|
+
* @deprecated Replaced by `Presence`.
|
|
17
|
+
*/
|
|
18
|
+
export class PresenceManager {
|
|
19
|
+
readonly ditto: Ditto
|
|
20
|
+
|
|
21
|
+
constructor(ditto: Ditto) {
|
|
22
|
+
this.ditto = ditto
|
|
23
|
+
this.isClosed = false
|
|
24
|
+
this.isRegistered = false
|
|
25
|
+
this.currentRemotePeers = []
|
|
26
|
+
this.callbacksByPresenceToken = {}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** @internal */
|
|
30
|
+
addObserver(callback: (remotePeers: RemotePeer[]) => void): PresenceToken {
|
|
31
|
+
if (this.isClosed) {
|
|
32
|
+
|
|
33
|
+
throw new Error(`Internal inconsistency, can't add presence observer, observer mananger close()-ed.`)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
this.registerIfNeeded()
|
|
37
|
+
|
|
38
|
+
const token = generateEphemeralToken()
|
|
39
|
+
this.callbacksByPresenceToken[token] = callback
|
|
40
|
+
this.ditto.keepAlive.retain(`PresenceObservation.${token}`)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
callback(this.currentRemotePeers)
|
|
44
|
+
|
|
45
|
+
return token
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** @internal */
|
|
49
|
+
removeObserver(token: PresenceToken) {
|
|
50
|
+
const callback = this.callbacksByPresenceToken[token]
|
|
51
|
+
|
|
52
|
+
if (typeof callback === 'undefined') {
|
|
53
|
+
throw new Error(`Can't remove presence observer, token '${token}' has never been registered before.`)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (callback === null) {
|
|
57
|
+
// Observer has already been removed, no-op.
|
|
58
|
+
return
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (typeof this.callbacksByPresenceToken[token] != 'undefined') {
|
|
62
|
+
this.ditto.keepAlive.release(`PresenceObservation.${token}`)
|
|
63
|
+
|
|
64
|
+
this.callbacksByPresenceToken[token] = null
|
|
65
|
+
this.unregisterIfNeeded()
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** @internal */
|
|
70
|
+
hasObserver(token: PresenceToken): boolean {
|
|
71
|
+
return typeof this.callbacksByPresenceToken[token] != 'undefined'
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/** @internal */
|
|
75
|
+
close() {
|
|
76
|
+
this.isClosed = true
|
|
77
|
+
for (const token in this.callbacksByPresenceToken) {
|
|
78
|
+
this.removeObserver(token)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ------------------------------------------------------------ Private ------
|
|
83
|
+
|
|
84
|
+
private isClosed: boolean
|
|
85
|
+
private isRegistered: boolean
|
|
86
|
+
private currentRemotePeers: RemotePeer[]
|
|
87
|
+
private callbacksByPresenceToken: { [key: string]: ((remotePeers: RemotePeer[]) => void) | null }
|
|
88
|
+
|
|
89
|
+
private hasObservers(): boolean {
|
|
90
|
+
return Object.keys(this.callbacksByPresenceToken).length > 0
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
private registerIfNeeded() {
|
|
94
|
+
const ditto = this.ditto
|
|
95
|
+
const dittoHandle = Bridge.ditto.handleFor(this.ditto)
|
|
96
|
+
ditto.deferClose(() => {
|
|
97
|
+
const needsToRegister = !this.isRegistered
|
|
98
|
+
if (needsToRegister) {
|
|
99
|
+
this.isRegistered = true
|
|
100
|
+
const remotePeersJSONString = FFI.dittoPresenceV1(dittoHandle.deref())
|
|
101
|
+
this.currentRemotePeers = this.decode(remotePeersJSONString).sort(this.compareRemotePeers)
|
|
102
|
+
FFI.dittoRegisterPresenceV1Callback(dittoHandle.deref(), this.handlePresenceV1Callback.bind(this))
|
|
103
|
+
}
|
|
104
|
+
})
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
private unregisterIfNeeded() {
|
|
108
|
+
const ditto = this.ditto
|
|
109
|
+
const dittoHandle = Bridge.ditto.handleFor(ditto)
|
|
110
|
+
ditto.deferClose(() => {
|
|
111
|
+
const needsToUnregister = !this.hasObservers() && this.isRegistered
|
|
112
|
+
if (needsToUnregister) {
|
|
113
|
+
this.isRegistered = false
|
|
114
|
+
FFI.dittoClearPresenceCallback(dittoHandle.deref())
|
|
115
|
+
this.currentRemotePeers = []
|
|
116
|
+
}
|
|
117
|
+
})
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
private handlePresenceV1Callback(remotePeersJSONString: string) {
|
|
121
|
+
const remotePeers = this.decode(remotePeersJSONString).sort(this.compareRemotePeers)
|
|
122
|
+
this.currentRemotePeers = remotePeers
|
|
123
|
+
this.notify()
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
private notify() {
|
|
127
|
+
if (this.isClosed) {
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
for (const token in this.callbacksByPresenceToken) {
|
|
132
|
+
const callback = this.callbacksByPresenceToken[token]
|
|
133
|
+
if (callback) callback(this.currentRemotePeers)
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
private decode(remotePeersJSONString: string): RemotePeer[] {
|
|
138
|
+
const remotePeersJSON: any[] = JSON.parse(remotePeersJSONString)
|
|
139
|
+
return remotePeersJSON.map((remotePeerJSON) => {
|
|
140
|
+
return {
|
|
141
|
+
networkID: remotePeerJSON['network_id'],
|
|
142
|
+
deviceName: remotePeerJSON['device_name'],
|
|
143
|
+
rssi: remotePeerJSON['rssi'] ?? undefined,
|
|
144
|
+
approximateDistanceInMeters: remotePeerJSON['approximate_distance_in_meters'] ?? undefined,
|
|
145
|
+
connections: remotePeerJSON['connections'],
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private compareRemotePeers(left: RemotePeer, right: RemotePeer) {
|
|
151
|
+
|
|
152
|
+
if (left.connections.length === 0 && right.connections.length > 0) return +1
|
|
153
|
+
if (left.connections.length > 0 && right.connections.length === 0) return -1
|
|
154
|
+
|
|
155
|
+
if (left.deviceName < right.deviceName) return -1
|
|
156
|
+
if (left.deviceName > right.deviceName) return +1
|
|
157
|
+
|
|
158
|
+
return 0
|
|
159
|
+
}
|
|
160
|
+
}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright © 2021 DittoLive Incorporated. All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as FFI from './ffi'
|
|
6
|
+
import { Bridge } from './bridge'
|
|
7
|
+
import { Observer } from './observer'
|
|
8
|
+
import { ObserverManager } from './observer-manager'
|
|
9
|
+
import type { Ditto } from './ditto'
|
|
10
|
+
|
|
11
|
+
/** Types of connections that can be established between two peers. */
|
|
12
|
+
export type ConnectionType = 'P2PWiFi' | 'WebSocket' | 'AccessPoint' | 'Bluetooth'
|
|
13
|
+
|
|
14
|
+
// -----------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* An opaque address uniquely identifying another peer on the Ditto mesh
|
|
18
|
+
* network.
|
|
19
|
+
*
|
|
20
|
+
* IMPORTANT: You should not rely on the individual components of the address,
|
|
21
|
+
* those can change at any time. Please use
|
|
22
|
+
* {@link addressToString | addressToString()} to compare individual addresses
|
|
23
|
+
* with each other.
|
|
24
|
+
*/
|
|
25
|
+
export type Address = {
|
|
26
|
+
siteId: number | BigInt
|
|
27
|
+
pubkey: Uint8Array
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// -----------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Returns a string representation of the given address. Use this function
|
|
34
|
+
* to compare multiple addresses or whenever you need the address to be a key
|
|
35
|
+
* in a hash object.
|
|
36
|
+
*/
|
|
37
|
+
export function addressToString(address: Address) {
|
|
38
|
+
return `${address.siteId}-${address.pubkey}`
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// -----------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
/** Represents a connection between two peers on the Ditto mesh network. */
|
|
44
|
+
export type Connection = {
|
|
45
|
+
/** Unique identifier for the connection.
|
|
46
|
+
*
|
|
47
|
+
* These IDs are stable for any two peer keys and a given connection type.
|
|
48
|
+
*
|
|
49
|
+
* **Example ID**
|
|
50
|
+
*
|
|
51
|
+
* "1<->2:Bluetooth"
|
|
52
|
+
*/
|
|
53
|
+
id: string
|
|
54
|
+
|
|
55
|
+
/** Type of transport enabling this connection. */
|
|
56
|
+
connectionType: ConnectionType
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Peer key of the peer at one end of the connection.
|
|
60
|
+
*
|
|
61
|
+
* This peer key is lexicographically smaller than `peer2`.
|
|
62
|
+
*/
|
|
63
|
+
peer1: Uint8Array
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Peer key of the peer at the other end of the connection.
|
|
67
|
+
*
|
|
68
|
+
* This peer key is lexicographically larger than `peer1`.
|
|
69
|
+
*/
|
|
70
|
+
peer2: Uint8Array
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
* Gets an estimate of distance to the remote peer. This value is inaccurate.
|
|
74
|
+
* The environment, hardware, and several other factors can greatly affect
|
|
75
|
+
* this value. It is currently derived from RSSI. Can be (yet) unknown and
|
|
76
|
+
* therefore not set.
|
|
77
|
+
*/
|
|
78
|
+
approximateDistanceInMeters?: number
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// -----------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
/** An instance of Ditto taking part in the Ditto mesh network. */
|
|
84
|
+
export type Peer = {
|
|
85
|
+
/**
|
|
86
|
+
* Address to contact this peer via Ditto Bus, unique with a Ditto mesh
|
|
87
|
+
* network.
|
|
88
|
+
*/
|
|
89
|
+
address: Address
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* The peer key is a unique identifier for a given peer, equal to or derived
|
|
93
|
+
* from the cryptographic public key used to authenticate it.
|
|
94
|
+
*
|
|
95
|
+
* NOTE: This will be be empty when a peer is not updated to the latest
|
|
96
|
+
* version of the SDK.
|
|
97
|
+
*/
|
|
98
|
+
peerKey: Uint8Array
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* The human-readable device name of the peer. This defaults to the hostname
|
|
102
|
+
* but can be manually set by the application developer of the other peer.
|
|
103
|
+
* It is not necessarily unique.
|
|
104
|
+
*/
|
|
105
|
+
deviceName: string
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Currently active connections of the peer.
|
|
109
|
+
*/
|
|
110
|
+
connections: Connection[]
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Indicates whether the peer is connected to Ditto Cloud.
|
|
114
|
+
*/
|
|
115
|
+
isConnectedToDittoCloud: boolean
|
|
116
|
+
|
|
117
|
+
/** The operating system the peer is running on, `undefined` if (yet) unknown. */
|
|
118
|
+
os?: string
|
|
119
|
+
|
|
120
|
+
/** The Ditto SDK version the peer is running with, `undefined` if (yet) unknown. */
|
|
121
|
+
dittoSDKVersion?: string
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// -----------------------------------------------------------------------------
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Represents the Ditto mesh network of peers and their connections between each
|
|
128
|
+
* other. The `localPeer` is the entry point, all others are remote peers known
|
|
129
|
+
* by the local peer (either directly or via other remote peers).
|
|
130
|
+
*/
|
|
131
|
+
export type PresenceGraph = {
|
|
132
|
+
/**
|
|
133
|
+
* Returns the local peer (usually the peer that is represented by the
|
|
134
|
+
* currently running Ditto instance). The `localPeer` is the entry point, all
|
|
135
|
+
* others are remote peers known by the local peer (either directly or via
|
|
136
|
+
* other remote peers).
|
|
137
|
+
*/
|
|
138
|
+
localPeer: Peer
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Returns all remote peers known by the `localPeer`, either directly or via
|
|
142
|
+
* other remote peers.
|
|
143
|
+
*/
|
|
144
|
+
remotePeers: Peer[]
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Returns the underlying CBOR data if the presence graph has been initialized
|
|
148
|
+
* with CBOR. All of Ditto API returning a presence graph has this property
|
|
149
|
+
* set.
|
|
150
|
+
*/
|
|
151
|
+
underlyingCBOR?: Uint8Array
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// -----------------------------------------------------------------------------
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* The entrypoint for all actions that relate presence of other peers known by
|
|
158
|
+
* the current peer, either directly or through other peers.
|
|
159
|
+
*
|
|
160
|
+
* You don't create one directly but can access it from a particular `Ditto`
|
|
161
|
+
* instance via its `presence` property.
|
|
162
|
+
*/
|
|
163
|
+
export class Presence {
|
|
164
|
+
/** The Ditto instance this object belongs to. */
|
|
165
|
+
readonly ditto: Ditto
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Returns the current presence graph capturing all known peers and
|
|
169
|
+
* connections between them.
|
|
170
|
+
*/
|
|
171
|
+
get graph(): PresenceGraph {
|
|
172
|
+
const ditto = this.ditto
|
|
173
|
+
const dittoHandle = Bridge.ditto.handleFor(ditto)
|
|
174
|
+
return ditto.deferClose(() => {
|
|
175
|
+
const graphJSONString = FFI.dittoPresenceV3(dittoHandle.deref())
|
|
176
|
+
return JSON.parse(graphJSONString)
|
|
177
|
+
})
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Request information about Ditto peers in range of this device.
|
|
182
|
+
*
|
|
183
|
+
* This method returns an observer which should be held as long as updates are
|
|
184
|
+
* required. A newly registered observer will have a peers update delivered to
|
|
185
|
+
* it immediately. From then on it will be invoked repeatedly when Ditto
|
|
186
|
+
* devices come and go, or the active connections to them change.
|
|
187
|
+
*/
|
|
188
|
+
observe(didChangeHandler: (presenceGraph: PresenceGraph) => void): Observer {
|
|
189
|
+
const observerToken = this.observerManager.addObserver(didChangeHandler)
|
|
190
|
+
const observer = new Observer(this.observerManager, observerToken, { stopsWhenFinalized: true })
|
|
191
|
+
|
|
192
|
+
// REFACTOR: make the initial callback call async, too (othewise we'd be
|
|
193
|
+
// mixing sync with async, which is a bit problematic in general but might
|
|
194
|
+
// be OK with single-threaded JS). This is a bit tricky, simply
|
|
195
|
+
// setTimeout(..., 0) here could lead us to a situation where the initial
|
|
196
|
+
// call would be sent AFTER the regular notification.
|
|
197
|
+
didChangeHandler(this.graph)
|
|
198
|
+
|
|
199
|
+
return observer
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/** @internal */
|
|
203
|
+
constructor(ditto: Ditto) {
|
|
204
|
+
this.ditto = ditto
|
|
205
|
+
|
|
206
|
+
this.observerManager = new ObserverManager('PresenceObservation', {
|
|
207
|
+
keepAlive: ditto.keepAlive,
|
|
208
|
+
|
|
209
|
+
register: (callback) => {
|
|
210
|
+
const ditto = this.ditto
|
|
211
|
+
const dittoHandle = Bridge.ditto.handleFor(ditto)
|
|
212
|
+
ditto.deferClose(() => {
|
|
213
|
+
FFI.dittoRegisterPresenceV3Callback(dittoHandle.deref(), callback)
|
|
214
|
+
})
|
|
215
|
+
},
|
|
216
|
+
|
|
217
|
+
unregister: () => {
|
|
218
|
+
const ditto = this.ditto
|
|
219
|
+
const dittoHandle = Bridge.ditto.handleFor(ditto)
|
|
220
|
+
ditto.deferClose(() => {
|
|
221
|
+
FFI.dittoClearPresenceV3Callback(dittoHandle.deref())
|
|
222
|
+
})
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
process: (presenceGraphJSONString) => {
|
|
226
|
+
const presenceGraph = JSON.parse(presenceGraphJSONString)
|
|
227
|
+
return [presenceGraph]
|
|
228
|
+
},
|
|
229
|
+
})
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** @internal */
|
|
233
|
+
close() {
|
|
234
|
+
this.observerManager.close()
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private observerManager: ObserverManager
|
|
238
|
+
}
|