matrix-js-sdk 41.8.0 → 41.9.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/CHANGELOG.md +11 -0
- package/README.md +1 -1
- package/lib/@types/AESEncryptedSecretStoragePayload.js +3 -1
- package/lib/@types/IIdentityServerProvider.js +3 -1
- package/lib/@types/PushRules.js +7 -7
- package/lib/@types/PushRules.js.map +1 -1
- package/lib/@types/auth.js +4 -4
- package/lib/@types/auth.js.map +1 -1
- package/lib/@types/beacon.js +2 -2
- package/lib/@types/beacon.js.map +1 -1
- package/lib/@types/common.js +3 -1
- package/lib/@types/crypto.js +3 -1
- package/lib/@types/event.js +20 -20
- package/lib/@types/event.js.map +1 -1
- package/lib/@types/events.js +3 -1
- package/lib/@types/extensible_events.js +6 -6
- package/lib/@types/extensible_events.js.map +1 -1
- package/lib/@types/global.d.js.map +1 -1
- package/lib/@types/json.js +3 -1
- package/lib/@types/local_notifications.js +3 -1
- package/lib/@types/location.js +4 -4
- package/lib/@types/location.js.map +1 -1
- package/lib/@types/matrix-sdk-crypto-wasm.d.js +3 -1
- package/lib/@types/media.js +3 -1
- package/lib/@types/membership.js +1 -1
- package/lib/@types/membership.js.map +1 -1
- package/lib/@types/partials.js +6 -6
- package/lib/@types/partials.js.map +1 -1
- package/lib/@types/polls.js +5 -5
- package/lib/@types/polls.js.map +1 -1
- package/lib/@types/read_receipts.js +2 -2
- package/lib/@types/read_receipts.js.map +1 -1
- package/lib/@types/registration.js +3 -1
- package/lib/@types/requests.js +1 -1
- package/lib/@types/requests.js.map +1 -1
- package/lib/@types/retention.js +1 -1
- package/lib/@types/retention.js.map +1 -1
- package/lib/@types/search.js +1 -1
- package/lib/@types/search.js.map +1 -1
- package/lib/@types/signed.js +3 -1
- package/lib/@types/spaces.js +3 -1
- package/lib/@types/state_events.js +3 -1
- package/lib/@types/synapse.js +3 -1
- package/lib/@types/sync.js +1 -1
- package/lib/@types/sync.js.map +1 -1
- package/lib/@types/threepids.js +1 -1
- package/lib/@types/threepids.js.map +1 -1
- package/lib/@types/topic.js +1 -1
- package/lib/@types/topic.js.map +1 -1
- package/lib/@types/uia.js +3 -1
- package/lib/NamespacedValue.js +8 -8
- package/lib/NamespacedValue.js.map +1 -1
- package/lib/ReEmitter.js +9 -16
- package/lib/ReEmitter.js.map +1 -1
- package/lib/ToDeviceMessageQueue.js +49 -57
- package/lib/ToDeviceMessageQueue.js.map +1 -1
- package/lib/autodiscovery.js +232 -247
- package/lib/autodiscovery.js.map +1 -1
- package/lib/base64.js +1 -1
- package/lib/base64.js.map +1 -1
- package/lib/browser-index.d.ts +2 -2
- package/lib/browser-index.d.ts.map +1 -1
- package/lib/browser-index.js +5 -5
- package/lib/browser-index.js.map +1 -1
- package/lib/capabilityPoller.js +19 -22
- package/lib/capabilityPoller.js.map +1 -1
- package/lib/client.d.ts +2 -8
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +2043 -2487
- package/lib/client.js.map +1 -1
- package/lib/common-crypto/CryptoBackend.js +2 -2
- package/lib/common-crypto/CryptoBackend.js.map +1 -1
- package/lib/common-crypto/key-passphrase.js.map +1 -1
- package/lib/content-helpers.js +43 -48
- package/lib/content-helpers.js.map +1 -1
- package/lib/content-repo.js +14 -24
- package/lib/content-repo.js.map +1 -1
- package/lib/crypto/store/base.js +6 -6
- package/lib/crypto/store/base.js.map +1 -1
- package/lib/crypto/store/indexeddb-crypto-store-backend.js +190 -238
- package/lib/crypto/store/indexeddb-crypto-store-backend.js.map +1 -1
- package/lib/crypto/store/indexeddb-crypto-store.js +25 -30
- package/lib/crypto/store/indexeddb-crypto-store.js.map +1 -1
- package/lib/crypto/store/localStorage-crypto-store.js +113 -145
- package/lib/crypto/store/localStorage-crypto-store.js.map +1 -1
- package/lib/crypto/store/memory-crypto-store.js +74 -105
- package/lib/crypto/store/memory-crypto-store.js.map +1 -1
- package/lib/crypto-api/CryptoEvent.js +1 -1
- package/lib/crypto-api/CryptoEvent.js.map +1 -1
- package/lib/crypto-api/CryptoEventHandlerMap.js +3 -1
- package/lib/crypto-api/index.d.ts +15 -6
- package/lib/crypto-api/index.d.ts.map +1 -1
- package/lib/crypto-api/index.js +22 -22
- package/lib/crypto-api/index.js.map +1 -1
- package/lib/crypto-api/key-passphrase.js +15 -23
- package/lib/crypto-api/key-passphrase.js.map +1 -1
- package/lib/crypto-api/keybackup.js +3 -1
- package/lib/crypto-api/recovery-key.js +11 -12
- package/lib/crypto-api/recovery-key.js.map +1 -1
- package/lib/crypto-api/verification.js +3 -3
- package/lib/crypto-api/verification.js.map +1 -1
- package/lib/digest.js +7 -14
- package/lib/digest.js.map +1 -1
- package/lib/embedded.d.ts.map +1 -1
- package/lib/embedded.js +380 -505
- package/lib/embedded.js.map +1 -1
- package/lib/errors.js +2 -2
- package/lib/errors.js.map +1 -1
- package/lib/event-mapper.js +10 -12
- package/lib/event-mapper.js.map +1 -1
- package/lib/extensible_events_v1/ExtensibleEvent.js.map +1 -1
- package/lib/extensible_events_v1/InvalidEventError.js.map +1 -1
- package/lib/extensible_events_v1/MessageEvent.js +11 -13
- package/lib/extensible_events_v1/MessageEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollEndEvent.js +3 -4
- package/lib/extensible_events_v1/PollEndEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollResponseEvent.js +5 -6
- package/lib/extensible_events_v1/PollResponseEvent.js.map +1 -1
- package/lib/extensible_events_v1/PollStartEvent.js +8 -10
- package/lib/extensible_events_v1/PollStartEvent.js.map +1 -1
- package/lib/extensible_events_v1/utilities.js.map +1 -1
- package/lib/feature.js +18 -31
- package/lib/feature.js.map +1 -1
- package/lib/filter-component.d.ts.map +1 -1
- package/lib/filter-component.js +20 -26
- package/lib/filter-component.js.map +1 -1
- package/lib/filter.js +14 -17
- package/lib/filter.js.map +1 -1
- package/lib/http-api/errors.js +28 -43
- package/lib/http-api/errors.js.map +1 -1
- package/lib/http-api/fetch.js +141 -159
- package/lib/http-api/fetch.js.map +1 -1
- package/lib/http-api/index.js +17 -20
- package/lib/http-api/index.js.map +1 -1
- package/lib/http-api/interface.js +1 -1
- package/lib/http-api/interface.js.map +1 -1
- package/lib/http-api/method.js +1 -1
- package/lib/http-api/method.js.map +1 -1
- package/lib/http-api/prefix.js +3 -3
- package/lib/http-api/prefix.js.map +1 -1
- package/lib/http-api/refresh.js +74 -94
- package/lib/http-api/refresh.js.map +1 -1
- package/lib/http-api/utils.d.ts +1 -1
- package/lib/http-api/utils.d.ts.map +1 -1
- package/lib/http-api/utils.js +34 -42
- package/lib/http-api/utils.js.map +1 -1
- package/lib/index.js.map +1 -1
- package/lib/indexeddb-helpers.js +3 -3
- package/lib/indexeddb-helpers.js.map +1 -1
- package/lib/indexeddb-worker.js.map +1 -1
- package/lib/interactive-auth.d.ts +5 -5
- package/lib/interactive-auth.d.ts.map +1 -1
- package/lib/interactive-auth.js +172 -204
- package/lib/interactive-auth.js.map +1 -1
- package/lib/logger.js +21 -57
- package/lib/logger.js.map +1 -1
- package/lib/matrix.js +7 -11
- package/lib/matrix.js.map +1 -1
- package/lib/matrixrtc/CallMembership.js +80 -74
- package/lib/matrixrtc/CallMembership.js.map +1 -1
- package/lib/matrixrtc/EncryptionManager.js +1 -1
- package/lib/matrixrtc/EncryptionManager.js.map +1 -1
- package/lib/matrixrtc/IKeyTransport.js +1 -1
- package/lib/matrixrtc/IKeyTransport.js.map +1 -1
- package/lib/matrixrtc/IMembershipManager.js +1 -1
- package/lib/matrixrtc/IMembershipManager.js.map +1 -1
- package/lib/matrixrtc/LivekitTransport.d.ts +1 -1
- package/lib/matrixrtc/LivekitTransport.js +4 -4
- package/lib/matrixrtc/LivekitTransport.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSession.js +137 -187
- package/lib/matrixrtc/MatrixRTCSession.js.map +1 -1
- package/lib/matrixrtc/MatrixRTCSessionManager.js +36 -41
- package/lib/matrixrtc/MatrixRTCSessionManager.js.map +1 -1
- package/lib/matrixrtc/MembershipManager.js +332 -378
- package/lib/matrixrtc/MembershipManager.js.map +1 -1
- package/lib/matrixrtc/MembershipManagerActionScheduler.js +54 -63
- package/lib/matrixrtc/MembershipManagerActionScheduler.js.map +1 -1
- package/lib/matrixrtc/RTCEncryptionManager.js +119 -143
- package/lib/matrixrtc/RTCEncryptionManager.js.map +1 -1
- package/lib/matrixrtc/ToDeviceKeyTransport.js +53 -58
- package/lib/matrixrtc/ToDeviceKeyTransport.js.map +1 -1
- package/lib/matrixrtc/index.js.map +1 -1
- package/lib/matrixrtc/membershipData/common.js +1 -1
- package/lib/matrixrtc/membershipData/common.js.map +1 -1
- package/lib/matrixrtc/membershipData/index.js.map +1 -1
- package/lib/matrixrtc/membershipData/rtc.js +15 -23
- package/lib/matrixrtc/membershipData/rtc.js.map +1 -1
- package/lib/matrixrtc/membershipData/session.js +4 -5
- package/lib/matrixrtc/membershipData/session.js.map +1 -1
- package/lib/matrixrtc/types.js +4 -6
- package/lib/matrixrtc/types.js.map +1 -1
- package/lib/matrixrtc/utils.js +4 -11
- package/lib/matrixrtc/utils.js.map +1 -1
- package/lib/models/MSC3089Branch.js +91 -116
- package/lib/models/MSC3089Branch.js.map +1 -1
- package/lib/models/MSC3089TreeSpace.js +209 -245
- package/lib/models/MSC3089TreeSpace.js.map +1 -1
- package/lib/models/ToDeviceMessage.js +3 -1
- package/lib/models/beacon.js +14 -13
- package/lib/models/beacon.js.map +1 -1
- package/lib/models/compare-event-ordering.js +13 -13
- package/lib/models/compare-event-ordering.js.map +1 -1
- package/lib/models/device.js +3 -3
- package/lib/models/device.js.map +1 -1
- package/lib/models/event-context.js +5 -8
- package/lib/models/event-context.js.map +1 -1
- package/lib/models/event-status.js +1 -1
- package/lib/models/event-status.js.map +1 -1
- package/lib/models/event-timeline-set.js +88 -94
- package/lib/models/event-timeline-set.js.map +1 -1
- package/lib/models/event-timeline.js +28 -30
- package/lib/models/event-timeline.js.map +1 -1
- package/lib/models/event.js +182 -226
- package/lib/models/event.js.map +1 -1
- package/lib/models/invites-ignorer-types.js +4 -4
- package/lib/models/invites-ignorer-types.js.map +1 -1
- package/lib/models/invites-ignorer.js +159 -179
- package/lib/models/invites-ignorer.js.map +1 -1
- package/lib/models/poll.js +71 -81
- package/lib/models/poll.js.map +1 -1
- package/lib/models/profile-keys.js +2 -2
- package/lib/models/profile-keys.js.map +1 -1
- package/lib/models/read-receipt.js +40 -56
- package/lib/models/read-receipt.js.map +1 -1
- package/lib/models/related-relations.js.map +1 -1
- package/lib/models/relations-container.js +22 -23
- package/lib/models/relations-container.js.map +1 -1
- package/lib/models/relations.js +133 -159
- package/lib/models/relations.js.map +1 -1
- package/lib/models/room-member.js +24 -29
- package/lib/models/room-member.js.map +1 -1
- package/lib/models/room-receipts.js +29 -43
- package/lib/models/room-receipts.js.map +1 -1
- package/lib/models/room-retention.js +74 -83
- package/lib/models/room-retention.js.map +1 -1
- package/lib/models/room-state.js +143 -172
- package/lib/models/room-state.js.map +1 -1
- package/lib/models/room-sticky-events.d.ts +1 -0
- package/lib/models/room-sticky-events.d.ts.map +1 -1
- package/lib/models/room-sticky-events.js +45 -65
- package/lib/models/room-sticky-events.js.map +1 -1
- package/lib/models/room-summary.js.map +1 -1
- package/lib/models/room.d.ts.map +1 -1
- package/lib/models/room.js +765 -909
- package/lib/models/room.js.map +1 -1
- package/lib/models/search-result.js +5 -5
- package/lib/models/search-result.js.map +1 -1
- package/lib/models/thread.js +225 -285
- package/lib/models/thread.js.map +1 -1
- package/lib/models/typed-event-emitter.js +7 -18
- package/lib/models/typed-event-emitter.js.map +1 -1
- package/lib/models/user.js +8 -8
- package/lib/models/user.js.map +1 -1
- package/lib/oidc/authorize.js +208 -241
- package/lib/oidc/authorize.js.map +1 -1
- package/lib/oidc/discovery.js +23 -36
- package/lib/oidc/discovery.js.map +1 -1
- package/lib/oidc/error.js +1 -1
- package/lib/oidc/error.js.map +1 -1
- package/lib/oidc/index.js +1 -0
- package/lib/oidc/index.js.map +1 -1
- package/lib/oidc/register.js +60 -66
- package/lib/oidc/register.js.map +1 -1
- package/lib/oidc/tokenRefresher.js +77 -91
- package/lib/oidc/tokenRefresher.js.map +1 -1
- package/lib/oidc/validate.js +18 -18
- package/lib/oidc/validate.js.map +1 -1
- package/lib/pushprocessor.js +71 -82
- package/lib/pushprocessor.js.map +1 -1
- package/lib/randomstring.js +9 -9
- package/lib/randomstring.js.map +1 -1
- package/lib/realtime-callbacks.js +25 -28
- package/lib/realtime-callbacks.js.map +1 -1
- package/lib/receipt-accumulator.d.ts +2 -0
- package/lib/receipt-accumulator.d.ts.map +1 -1
- package/lib/receipt-accumulator.js +14 -22
- package/lib/receipt-accumulator.js.map +1 -1
- package/lib/rendezvous/MSC4108SignInWithQR.js +271 -302
- package/lib/rendezvous/MSC4108SignInWithQR.js.map +1 -1
- package/lib/rendezvous/RendezvousChannel.js +3 -1
- package/lib/rendezvous/RendezvousCode.js +3 -1
- package/lib/rendezvous/RendezvousError.js.map +1 -1
- package/lib/rendezvous/RendezvousFailureReason.js +2 -2
- package/lib/rendezvous/RendezvousFailureReason.js.map +1 -1
- package/lib/rendezvous/RendezvousIntent.js +1 -1
- package/lib/rendezvous/RendezvousIntent.js.map +1 -1
- package/lib/rendezvous/RendezvousTransport.js +3 -1
- package/lib/rendezvous/channels/MSC4108SecureChannel.js +123 -147
- package/lib/rendezvous/channels/MSC4108SecureChannel.js.map +1 -1
- package/lib/rendezvous/index.js +44 -69
- package/lib/rendezvous/index.js.map +1 -1
- package/lib/rendezvous/transports/MSC4108RendezvousSession.d.ts +1 -1
- package/lib/rendezvous/transports/MSC4108RendezvousSession.js +134 -152
- package/lib/rendezvous/transports/MSC4108RendezvousSession.js.map +1 -1
- package/lib/retentionPolicy.js +6 -9
- package/lib/retentionPolicy.js.map +1 -1
- package/lib/room-hierarchy.js +52 -60
- package/lib/room-hierarchy.js.map +1 -1
- package/lib/rust-crypto/CrossSigningIdentity.js +94 -104
- package/lib/rust-crypto/CrossSigningIdentity.js.map +1 -1
- package/lib/rust-crypto/DehydratedDeviceManager.js +157 -190
- package/lib/rust-crypto/DehydratedDeviceManager.js.map +1 -1
- package/lib/rust-crypto/KeyClaimManager.js +18 -22
- package/lib/rust-crypto/KeyClaimManager.js.map +1 -1
- package/lib/rust-crypto/OutgoingRequestProcessor.js +109 -139
- package/lib/rust-crypto/OutgoingRequestProcessor.js.map +1 -1
- package/lib/rust-crypto/OutgoingRequestsManager.js +66 -80
- package/lib/rust-crypto/OutgoingRequestsManager.js.map +1 -1
- package/lib/rust-crypto/PerSessionKeyBackupDownloader.d.ts +1 -1
- package/lib/rust-crypto/PerSessionKeyBackupDownloader.js +196 -224
- package/lib/rust-crypto/PerSessionKeyBackupDownloader.js.map +1 -1
- package/lib/rust-crypto/RoomEncryptor.js +127 -143
- package/lib/rust-crypto/RoomEncryptor.js.map +1 -1
- package/lib/rust-crypto/backup.js +453 -549
- package/lib/rust-crypto/backup.js.map +1 -1
- package/lib/rust-crypto/constants.js +1 -1
- package/lib/rust-crypto/constants.js.map +1 -1
- package/lib/rust-crypto/device-converter.js +15 -28
- package/lib/rust-crypto/device-converter.js.map +1 -1
- package/lib/rust-crypto/index.js +103 -116
- package/lib/rust-crypto/index.js.map +1 -1
- package/lib/rust-crypto/libolm_migration.js +303 -365
- package/lib/rust-crypto/libolm_migration.js.map +1 -1
- package/lib/rust-crypto/rust-crypto.d.ts +5 -1
- package/lib/rust-crypto/rust-crypto.d.ts.map +1 -1
- package/lib/rust-crypto/rust-crypto.js +1067 -1332
- package/lib/rust-crypto/rust-crypto.js.map +1 -1
- package/lib/rust-crypto/secret-storage.js +12 -25
- package/lib/rust-crypto/secret-storage.js.map +1 -1
- package/lib/rust-crypto/verification.js +137 -189
- package/lib/rust-crypto/verification.js.map +1 -1
- package/lib/scheduler.js +44 -19
- package/lib/scheduler.js.map +1 -1
- package/lib/secret-storage.js +179 -213
- package/lib/secret-storage.js.map +1 -1
- package/lib/serverCapabilities.js +6 -9
- package/lib/serverCapabilities.js.map +1 -1
- package/lib/service-types.js +1 -1
- package/lib/service-types.js.map +1 -1
- package/lib/sliding-sync-sdk.d.ts.map +1 -1
- package/lib/sliding-sync-sdk.js +368 -424
- package/lib/sliding-sync-sdk.js.map +1 -1
- package/lib/sliding-sync.js +135 -171
- package/lib/sliding-sync.js.map +1 -1
- package/lib/store/index.js +3 -1
- package/lib/store/indexeddb-backend.js +3 -1
- package/lib/store/indexeddb-local-backend.js +194 -253
- package/lib/store/indexeddb-local-backend.js.map +1 -1
- package/lib/store/indexeddb-remote-backend.js +33 -63
- package/lib/store/indexeddb-remote-backend.js.map +1 -1
- package/lib/store/indexeddb-store-worker.js +22 -23
- package/lib/store/indexeddb-store-worker.js.map +1 -1
- package/lib/store/indexeddb.js +44 -71
- package/lib/store/indexeddb.js.map +1 -1
- package/lib/store/local-storage-events-emitter.js +2 -2
- package/lib/store/local-storage-events-emitter.js.map +1 -1
- package/lib/store/memory.js +34 -57
- package/lib/store/memory.js.map +1 -1
- package/lib/store/stub.js +22 -35
- package/lib/store/stub.js.map +1 -1
- package/lib/sync-accumulator.js +54 -66
- package/lib/sync-accumulator.js.map +1 -1
- package/lib/sync.d.ts.map +1 -1
- package/lib/sync.js +905 -998
- package/lib/sync.js.map +1 -1
- package/lib/testing.js +63 -105
- package/lib/testing.js.map +1 -1
- package/lib/thread-utils.js +1 -4
- package/lib/thread-utils.js.map +1 -1
- package/lib/timeline-window.js +89 -102
- package/lib/timeline-window.js.map +1 -1
- package/lib/types.js +1 -1
- package/lib/types.js.map +1 -1
- package/lib/utils/decryptAESSecretStorageItem.js +14 -25
- package/lib/utils/decryptAESSecretStorageItem.js.map +1 -1
- package/lib/utils/encryptAESSecretStorageItem.js +27 -38
- package/lib/utils/encryptAESSecretStorageItem.js.map +1 -1
- package/lib/utils/internal/deriveKeys.js +25 -32
- package/lib/utils/internal/deriveKeys.js.map +1 -1
- package/lib/utils/roomVersion.js +1 -1
- package/lib/utils/roomVersion.js.map +1 -1
- package/lib/utils.js +83 -135
- package/lib/utils.js.map +1 -1
- package/lib/version-support.js +3 -3
- package/lib/version-support.js.map +1 -1
- package/lib/webrtc/audioContext.js +5 -6
- package/lib/webrtc/audioContext.js.map +1 -1
- package/lib/webrtc/call.js +1081 -1250
- package/lib/webrtc/call.js.map +1 -1
- package/lib/webrtc/callEventHandler.js +202 -214
- package/lib/webrtc/callEventHandler.js.map +1 -1
- package/lib/webrtc/callEventTypes.js +2 -2
- package/lib/webrtc/callEventTypes.js.map +1 -1
- package/lib/webrtc/callFeed.js +18 -20
- package/lib/webrtc/callFeed.js.map +1 -1
- package/lib/webrtc/groupCall.js +513 -602
- package/lib/webrtc/groupCall.js.map +1 -1
- package/lib/webrtc/groupCallEventHandler.js +59 -62
- package/lib/webrtc/groupCallEventHandler.js.map +1 -1
- package/lib/webrtc/mediaHandler.js +198 -232
- package/lib/webrtc/mediaHandler.js.map +1 -1
- package/lib/webrtc/stats/callFeedStatsReporter.js +16 -20
- package/lib/webrtc/stats/callFeedStatsReporter.js.map +1 -1
- package/lib/webrtc/stats/callStatsReportGatherer.js +67 -75
- package/lib/webrtc/stats/callStatsReportGatherer.js.map +1 -1
- package/lib/webrtc/stats/callStatsReportSummary.js +3 -1
- package/lib/webrtc/stats/connectionStats.js.map +1 -1
- package/lib/webrtc/stats/connectionStatsBuilder.js +2 -2
- package/lib/webrtc/stats/connectionStatsBuilder.js.map +1 -1
- package/lib/webrtc/stats/connectionStatsReportBuilder.js +20 -24
- package/lib/webrtc/stats/connectionStatsReportBuilder.js.map +1 -1
- package/lib/webrtc/stats/groupCallStats.js +6 -8
- package/lib/webrtc/stats/groupCallStats.js.map +1 -1
- package/lib/webrtc/stats/media/mediaSsrcHandler.js +7 -8
- package/lib/webrtc/stats/media/mediaSsrcHandler.js.map +1 -1
- package/lib/webrtc/stats/media/mediaTrackHandler.js +7 -9
- package/lib/webrtc/stats/media/mediaTrackHandler.js.map +1 -1
- package/lib/webrtc/stats/media/mediaTrackStats.js +3 -3
- package/lib/webrtc/stats/media/mediaTrackStats.js.map +1 -1
- package/lib/webrtc/stats/media/mediaTrackStatsHandler.js +7 -7
- package/lib/webrtc/stats/media/mediaTrackStatsHandler.js.map +1 -1
- package/lib/webrtc/stats/statsReport.js +1 -1
- package/lib/webrtc/stats/statsReport.js.map +1 -1
- package/lib/webrtc/stats/statsReportEmitter.js.map +1 -1
- package/lib/webrtc/stats/summaryStatsReportGatherer.js +14 -14
- package/lib/webrtc/stats/summaryStatsReportGatherer.js.map +1 -1
- package/lib/webrtc/stats/trackStatsBuilder.js +32 -34
- package/lib/webrtc/stats/trackStatsBuilder.js.map +1 -1
- package/lib/webrtc/stats/transportStats.js +3 -1
- package/lib/webrtc/stats/transportStatsBuilder.js +9 -9
- package/lib/webrtc/stats/transportStatsBuilder.js.map +1 -1
- package/lib/webrtc/stats/valueFormatter.js +1 -1
- package/lib/webrtc/stats/valueFormatter.js.map +1 -1
- package/package.json +18 -33
- package/src/@types/global.d.ts +2 -2
- package/src/ToDeviceMessageQueue.ts +2 -2
- package/src/browser-index.ts +4 -4
- package/src/client.ts +15 -20
- package/src/crypto-api/index.ts +17 -6
- package/src/embedded.ts +4 -6
- package/src/filter-component.ts +1 -0
- package/src/http-api/utils.ts +1 -1
- package/src/interactive-auth.ts +11 -5
- package/src/matrixrtc/LivekitTransport.ts +1 -1
- package/src/matrixrtc/MatrixRTCSession.ts +1 -1
- package/src/models/MSC3089Branch.ts +1 -1
- package/src/models/room-sticky-events.ts +1 -0
- package/src/models/room.ts +9 -11
- package/src/receipt-accumulator.ts +2 -0
- package/src/rendezvous/index.ts +1 -1
- package/src/rendezvous/transports/MSC4108RendezvousSession.ts +2 -2
- package/src/rust-crypto/PerSessionKeyBackupDownloader.ts +1 -1
- package/src/rust-crypto/index.ts +6 -6
- package/src/rust-crypto/rust-crypto.ts +31 -7
- package/src/rust-crypto/verification.ts +1 -1
- package/src/sliding-sync-sdk.ts +5 -7
- package/src/store/indexeddb-local-backend.ts +3 -3
- package/src/sync.ts +6 -8
package/lib/sync.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
|
|
2
|
-
import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
|
|
3
1
|
import _defineProperty from "@babel/runtime/helpers/defineProperty";
|
|
4
|
-
|
|
5
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
2
|
+
import _objectSpread from "@babel/runtime/helpers/objectSpread2";
|
|
6
3
|
/*
|
|
7
4
|
Copyright 2015 - 2023 The Matrix.org Foundation C.I.C.
|
|
8
5
|
|
|
@@ -49,13 +46,13 @@ import { KnownMembership } from "./@types/membership.js";
|
|
|
49
46
|
// beyond that and wedge forever, so we need to track how long we are willing
|
|
50
47
|
// to keep open the connection. This constant is *ADDED* to the timeout= value
|
|
51
48
|
// to determine the max time we're willing to wait.
|
|
52
|
-
|
|
49
|
+
const BUFFER_PERIOD_MS = 80 * 1000;
|
|
53
50
|
|
|
54
51
|
// Number of consecutive failed syncs that will lead to a syncState of ERROR as opposed
|
|
55
52
|
// to RECONNECTING. This is needed to inform the client of server issues when the
|
|
56
53
|
// keepAlive is successful but the server /sync fails.
|
|
57
|
-
|
|
58
|
-
export
|
|
54
|
+
const FAILED_SYNC_ERROR_THRESHOLD = 3;
|
|
55
|
+
export let SyncState = /*#__PURE__*/function (SyncState) {
|
|
59
56
|
/** Emitted after we try to sync more than `FAILED_SYNC_ERROR_THRESHOLD`
|
|
60
57
|
* times and are still failing. Or when we enounter a hard error like the
|
|
61
58
|
* token being invalid. */
|
|
@@ -79,18 +76,18 @@ export var SyncState = /*#__PURE__*/function (SyncState) {
|
|
|
79
76
|
// Room versions where "insertion", "batch", and "marker" events are controlled
|
|
80
77
|
// by power-levels. MSC2716 is supported in existing room versions but they
|
|
81
78
|
// should only have special meaning when the room creator sends them.
|
|
82
|
-
|
|
79
|
+
const MSC2716_ROOM_VERSIONS = ["org.matrix.msc2716v3"];
|
|
83
80
|
function getFilterName(userId, suffix) {
|
|
84
81
|
// scope this on the user ID because people may login on many accounts
|
|
85
82
|
// and they all need to be stored!
|
|
86
|
-
return
|
|
83
|
+
return `FILTER_SYNC_${userId}` + (suffix ? "_" + suffix : "");
|
|
87
84
|
}
|
|
88
85
|
|
|
89
86
|
/**
|
|
90
87
|
* Options passed into the constructor of SyncApi by MatrixClient
|
|
91
88
|
*/
|
|
92
89
|
|
|
93
|
-
export
|
|
90
|
+
export let SetPresence = /*#__PURE__*/function (SetPresence) {
|
|
94
91
|
SetPresence["Offline"] = "offline";
|
|
95
92
|
SetPresence["Online"] = "online";
|
|
96
93
|
SetPresence["Unavailable"] = "unavailable";
|
|
@@ -120,8 +117,6 @@ export class SyncApi {
|
|
|
120
117
|
* @internal
|
|
121
118
|
*/
|
|
122
119
|
constructor(client, opts, syncOpts) {
|
|
123
|
-
var _this = this;
|
|
124
|
-
this.client = client;
|
|
125
120
|
_defineProperty(this, "opts", void 0);
|
|
126
121
|
_defineProperty(this, "syncOpts", void 0);
|
|
127
122
|
_defineProperty(this, "_peekRoom", null);
|
|
@@ -141,24 +136,24 @@ export class SyncApi {
|
|
|
141
136
|
_defineProperty(this, "storeIsInvalid", false);
|
|
142
137
|
// flag set if the store needs to be cleared before we can start
|
|
143
138
|
_defineProperty(this, "presence", void 0);
|
|
144
|
-
_defineProperty(this, "getPushRules",
|
|
139
|
+
_defineProperty(this, "getPushRules", async () => {
|
|
145
140
|
try {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
141
|
+
this.syncOpts.logger.debug("Getting push rules...");
|
|
142
|
+
const result = await this.client.getPushRules();
|
|
143
|
+
this.syncOpts.logger.debug("Got push rules");
|
|
144
|
+
this.client.pushRules = result;
|
|
150
145
|
} catch (err) {
|
|
151
|
-
|
|
152
|
-
if (
|
|
146
|
+
this.syncOpts.logger.error("Getting push rules failed", err);
|
|
147
|
+
if (this.shouldAbortSync(err)) return;
|
|
153
148
|
// wait for saved sync to complete before doing anything else,
|
|
154
149
|
// otherwise the sync state will end up being incorrect
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
return
|
|
150
|
+
this.syncOpts.logger.debug("Waiting for saved sync before retrying push rules...");
|
|
151
|
+
await this.recoverFromSyncStartupError(this.savedSyncPromise, err);
|
|
152
|
+
return this.getPushRules(); // try again
|
|
158
153
|
}
|
|
159
|
-
})
|
|
154
|
+
});
|
|
160
155
|
_defineProperty(this, "buildDefaultFilter", () => {
|
|
161
|
-
|
|
156
|
+
const filter = new Filter(this.client.credentials.userId);
|
|
162
157
|
if (this.client.canSupport.get(Feature.ThreadUnreadNotifications) !== ServerSupport.Unsupported) {
|
|
163
158
|
filter.setUnreadThreadNotifications(true);
|
|
164
159
|
}
|
|
@@ -184,51 +179,50 @@ export class SyncApi {
|
|
|
184
179
|
/**
|
|
185
180
|
* Preare sync filter options for the unstable MSC4429 user profile fields if enabled.
|
|
186
181
|
*/
|
|
187
|
-
_defineProperty(this, "prepareSyncFilterUserProfiles",
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
_this.opts.filter = _this.buildDefaultFilter();
|
|
182
|
+
_defineProperty(this, "prepareSyncFilterUserProfiles", async () => {
|
|
183
|
+
if (this.opts.unstableMSC4429SyncUserProfileFields?.length) {
|
|
184
|
+
this.syncOpts.logger.debug("Enabling EXPERIMENTAL user profiles on sync filter...");
|
|
185
|
+
if (!this.opts.filter) {
|
|
186
|
+
this.opts.filter = this.buildDefaultFilter();
|
|
193
187
|
}
|
|
194
|
-
|
|
188
|
+
this.opts.filter.setUnstableMSC4429SyncUserProfiles(this.opts.unstableMSC4429SyncUserProfileFields, await this.client.doesServerSupportUnstableFeature("org.matrix.msc4429.stable"));
|
|
195
189
|
}
|
|
196
|
-
})
|
|
197
|
-
_defineProperty(this, "storeClientOptions",
|
|
190
|
+
});
|
|
191
|
+
_defineProperty(this, "storeClientOptions", async () => {
|
|
198
192
|
try {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
193
|
+
this.syncOpts.logger.debug("Storing client options...");
|
|
194
|
+
await this.client.storeClientOptions();
|
|
195
|
+
this.syncOpts.logger.debug("Stored client options");
|
|
202
196
|
} catch (err) {
|
|
203
|
-
|
|
197
|
+
this.syncOpts.logger.error("Storing client options failed", err);
|
|
204
198
|
throw err;
|
|
205
199
|
}
|
|
206
|
-
})
|
|
207
|
-
_defineProperty(this, "getFilter",
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if (
|
|
211
|
-
filter =
|
|
200
|
+
});
|
|
201
|
+
_defineProperty(this, "getFilter", async () => {
|
|
202
|
+
this.syncOpts.logger.debug("Getting filter...");
|
|
203
|
+
let filter;
|
|
204
|
+
if (this.opts.filter) {
|
|
205
|
+
filter = this.opts.filter;
|
|
212
206
|
} else {
|
|
213
|
-
filter =
|
|
207
|
+
filter = this.buildDefaultFilter();
|
|
214
208
|
}
|
|
215
|
-
|
|
209
|
+
let filterId;
|
|
216
210
|
try {
|
|
217
|
-
filterId =
|
|
211
|
+
filterId = await this.client.getOrCreateFilter(getFilterName(this.client.credentials.userId), filter);
|
|
218
212
|
} catch (err) {
|
|
219
|
-
|
|
220
|
-
if (
|
|
213
|
+
this.syncOpts.logger.error("Getting filter failed", err);
|
|
214
|
+
if (this.shouldAbortSync(err)) return {};
|
|
221
215
|
// wait for saved sync to complete before doing anything else,
|
|
222
216
|
// otherwise the sync state will end up being incorrect
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
return
|
|
217
|
+
this.syncOpts.logger.debug("Waiting for saved sync before retrying filter...");
|
|
218
|
+
await this.recoverFromSyncStartupError(this.savedSyncPromise, err);
|
|
219
|
+
return this.getFilter(); // try again
|
|
226
220
|
}
|
|
227
221
|
return {
|
|
228
222
|
filter,
|
|
229
223
|
filterId
|
|
230
224
|
};
|
|
231
|
-
})
|
|
225
|
+
});
|
|
232
226
|
_defineProperty(this, "savedSyncPromise", void 0);
|
|
233
227
|
/**
|
|
234
228
|
* Event handler for the 'online' event
|
|
@@ -240,6 +234,7 @@ export class SyncApi {
|
|
|
240
234
|
this.syncOpts.logger.debug("Browser thinks we are back online");
|
|
241
235
|
this.startKeepAlives(0);
|
|
242
236
|
});
|
|
237
|
+
this.client = client;
|
|
243
238
|
this.opts = defaultClientOpts(opts);
|
|
244
239
|
this.syncOpts = defaultSyncApiOpts(syncOpts);
|
|
245
240
|
if (client.getNotifTimelineSet()) {
|
|
@@ -247,7 +242,7 @@ export class SyncApi {
|
|
|
247
242
|
}
|
|
248
243
|
}
|
|
249
244
|
createRoom(roomId) {
|
|
250
|
-
|
|
245
|
+
const room = _createAndReEmitRoom(this.client, roomId, this.opts);
|
|
251
246
|
room.on(RoomStateEvent.Marker, (markerEvent, markerFoundOptions) => {
|
|
252
247
|
this.onMarkerStateEvent(room, markerEvent, markerFoundOptions);
|
|
253
248
|
});
|
|
@@ -263,19 +258,19 @@ export class SyncApi {
|
|
|
263
258
|
* @param setStateOptions - When `timelineWasEmpty` is set
|
|
264
259
|
* as `true`, the given marker event will be ignored
|
|
265
260
|
*/
|
|
266
|
-
onMarkerStateEvent(room, markerEvent
|
|
267
|
-
|
|
268
|
-
|
|
261
|
+
onMarkerStateEvent(room, markerEvent, {
|
|
262
|
+
timelineWasEmpty
|
|
263
|
+
} = {}) {
|
|
269
264
|
// We don't need to refresh the timeline if it was empty before the
|
|
270
265
|
// marker arrived. This could be happen in a variety of cases:
|
|
271
266
|
// 1. From the initial sync
|
|
272
267
|
// 2. If it's from the first state we're seeing after joining the room
|
|
273
268
|
// 3. Or whether it's coming from `syncFromCache`
|
|
274
269
|
if (timelineWasEmpty) {
|
|
275
|
-
this.syncOpts.logger.debug(
|
|
270
|
+
this.syncOpts.logger.debug(`MarkerState: Ignoring markerEventId=${markerEvent.getId()} in roomId=${room.roomId} ` + `because the timeline was empty before the marker arrived which means there is nothing to refresh.`);
|
|
276
271
|
return;
|
|
277
272
|
}
|
|
278
|
-
|
|
273
|
+
const isValidMsc2716Event =
|
|
279
274
|
// Check whether the room version directly supports MSC2716, in
|
|
280
275
|
// which case, "marker" events are already auth'ed by
|
|
281
276
|
// power_levels
|
|
@@ -300,11 +295,11 @@ export class SyncApi {
|
|
|
300
295
|
if (isValidMsc2716Event) {
|
|
301
296
|
// Saw new marker event, let's let the clients know they should
|
|
302
297
|
// refresh the timeline.
|
|
303
|
-
this.syncOpts.logger.debug(
|
|
298
|
+
this.syncOpts.logger.debug(`MarkerState: Timeline needs to be refreshed because ` + `a new markerEventId=${markerEvent.getId()} was sent in roomId=${room.roomId}`);
|
|
304
299
|
room.setTimelineNeedsRefresh(true);
|
|
305
300
|
room.emit(RoomEvent.HistoryImportedWithinTimeline, markerEvent, room);
|
|
306
301
|
} else {
|
|
307
|
-
this.syncOpts.logger.debug(
|
|
302
|
+
this.syncOpts.logger.debug(`MarkerState: Ignoring markerEventId=${markerEvent.getId()} in roomId=${room.roomId} because ` + `MSC2716 is not supported in the room version or for any room version, the marker wasn't sent ` + `by the room creator.`);
|
|
308
303
|
}
|
|
309
304
|
}
|
|
310
305
|
|
|
@@ -312,67 +307,59 @@ export class SyncApi {
|
|
|
312
307
|
* Sync rooms the user has left.
|
|
313
308
|
* @returns Resolved when they've been added to the store.
|
|
314
309
|
*/
|
|
315
|
-
syncLeftRooms() {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
310
|
+
async syncLeftRooms() {
|
|
311
|
+
const client = this.client;
|
|
312
|
+
|
|
313
|
+
// grab a filter with limit=1 and include_leave=true
|
|
314
|
+
const filter = new Filter(this.client.credentials.userId);
|
|
315
|
+
filter.setTimelineLimit(1);
|
|
316
|
+
filter.setIncludeLeaveRooms(true);
|
|
317
|
+
const localTimeoutMs = this.opts.pollTimeout + BUFFER_PERIOD_MS;
|
|
318
|
+
const filterId = await client.getOrCreateFilter(getFilterName(client.credentials.userId, "LEFT_ROOMS"), filter);
|
|
319
|
+
const qps = {
|
|
320
|
+
"timeout": 0,
|
|
321
|
+
// don't want to block since this is a single isolated req
|
|
322
|
+
"filter": filterId,
|
|
323
|
+
"org.matrix.msc4222.use_state_after": true
|
|
324
|
+
};
|
|
325
|
+
const data = await client.http.authedRequest(Method.Get, "/sync", qps, undefined, {
|
|
326
|
+
localTimeoutMs
|
|
327
|
+
});
|
|
328
|
+
let leaveRooms = [];
|
|
329
|
+
if (data.rooms?.leave) {
|
|
330
|
+
leaveRooms = this.mapSyncResponseToRoomArray(data.rooms.leave);
|
|
331
|
+
}
|
|
332
|
+
const rooms = await Promise.all(leaveRooms.map(async leaveObj => {
|
|
333
|
+
const room = leaveObj.room;
|
|
334
|
+
if (!leaveObj.isBrandNewRoom) {
|
|
335
|
+
// the intention behind syncLeftRooms is to add in rooms which were
|
|
336
|
+
// *omitted* from the initial /sync. Rooms the user were joined to
|
|
337
|
+
// but then left whilst the app is running will appear in this list
|
|
338
|
+
// and we do not want to bother with them since they will have the
|
|
339
|
+
// current state already (and may get dupe messages if we add
|
|
340
|
+
// yet more timeline events!), so skip them.
|
|
341
|
+
// NB: When we persist rooms to localStorage this will be more
|
|
342
|
+
// complicated...
|
|
343
|
+
return;
|
|
339
344
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
// set the back-pagination token. Do this *before* adding any
|
|
360
|
-
// events so that clients can start back-paginating.
|
|
361
|
-
room.getLiveTimeline().setPaginationToken(leaveObj.timeline.prev_batch, EventTimeline.BACKWARDS);
|
|
362
|
-
var _yield$_this2$mapAndI = yield _this2.mapAndInjectRoomEvents(leaveObj),
|
|
363
|
-
timelineEvents = _yield$_this2$mapAndI.timelineEvents;
|
|
364
|
-
room.recalculate();
|
|
365
|
-
client.store.storeRoom(room);
|
|
366
|
-
client.emit(ClientEvent.Room, room);
|
|
367
|
-
_this2.processEventsForNotifs(room, timelineEvents);
|
|
368
|
-
return room;
|
|
369
|
-
});
|
|
370
|
-
return function (_x) {
|
|
371
|
-
return _ref6.apply(this, arguments);
|
|
372
|
-
};
|
|
373
|
-
}()));
|
|
374
|
-
return rooms.filter(Boolean);
|
|
375
|
-
})();
|
|
345
|
+
leaveObj.timeline = leaveObj.timeline || {
|
|
346
|
+
prev_batch: null,
|
|
347
|
+
events: []
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
// set the back-pagination token. Do this *before* adding any
|
|
351
|
+
// events so that clients can start back-paginating.
|
|
352
|
+
room.getLiveTimeline().setPaginationToken(leaveObj.timeline.prev_batch, EventTimeline.BACKWARDS);
|
|
353
|
+
const {
|
|
354
|
+
timelineEvents
|
|
355
|
+
} = await this.mapAndInjectRoomEvents(leaveObj);
|
|
356
|
+
room.recalculate();
|
|
357
|
+
client.store.storeRoom(room);
|
|
358
|
+
client.emit(ClientEvent.Room, room);
|
|
359
|
+
this.processEventsForNotifs(room, timelineEvents);
|
|
360
|
+
return room;
|
|
361
|
+
}));
|
|
362
|
+
return rooms.filter(Boolean);
|
|
376
363
|
}
|
|
377
364
|
|
|
378
365
|
/**
|
|
@@ -383,17 +370,14 @@ export class SyncApi {
|
|
|
383
370
|
* @returns A promise which resolves once the room has been added to the
|
|
384
371
|
* store.
|
|
385
372
|
*/
|
|
386
|
-
peek(roomId) {
|
|
387
|
-
|
|
388
|
-
var limit = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 20;
|
|
389
|
-
if (((_this$_peekRoom = this._peekRoom) === null || _this$_peekRoom === void 0 ? void 0 : _this$_peekRoom.roomId) === roomId) {
|
|
373
|
+
peek(roomId, limit = 20) {
|
|
374
|
+
if (this._peekRoom?.roomId === roomId) {
|
|
390
375
|
return Promise.resolve(this._peekRoom);
|
|
391
376
|
}
|
|
392
|
-
|
|
377
|
+
const client = this.client;
|
|
393
378
|
this._peekRoom = this.createRoom(roomId);
|
|
394
379
|
return this.client.roomInitialSync(roomId, limit).then(response => {
|
|
395
|
-
|
|
396
|
-
if (((_this$_peekRoom2 = this._peekRoom) === null || _this$_peekRoom2 === void 0 ? void 0 : _this$_peekRoom2.roomId) !== roomId) {
|
|
380
|
+
if (this._peekRoom?.roomId !== roomId) {
|
|
397
381
|
throw new Error("Peeking aborted");
|
|
398
382
|
}
|
|
399
383
|
|
|
@@ -406,15 +390,15 @@ export class SyncApi {
|
|
|
406
390
|
|
|
407
391
|
// FIXME: Mostly duplicated from injectRoomEvents but not entirely
|
|
408
392
|
// because "state" in this API is at the BEGINNING of the chunk
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
393
|
+
const oldStateEvents = deepCopy(response.state).map(client.getEventMapper());
|
|
394
|
+
const stateEvents = response.state.map(client.getEventMapper());
|
|
395
|
+
const messages = response.messages.chunk.map(client.getEventMapper());
|
|
412
396
|
|
|
413
397
|
// XXX: copypasted from /sync until we kill off this minging v1 API stuff)
|
|
414
398
|
// handle presence events (User objects)
|
|
415
399
|
if (Array.isArray(response.presence)) {
|
|
416
400
|
response.presence.map(client.getEventMapper()).forEach(function (presenceEvent) {
|
|
417
|
-
|
|
401
|
+
let user = client.store.getUser(presenceEvent.getContent().user_id);
|
|
418
402
|
if (user) {
|
|
419
403
|
user.setPresenceEvent(presenceEvent);
|
|
420
404
|
} else {
|
|
@@ -463,8 +447,6 @@ export class SyncApi {
|
|
|
463
447
|
* @param token - from= token
|
|
464
448
|
*/
|
|
465
449
|
peekPoll(peekRoom, token) {
|
|
466
|
-
var _this$abortController,
|
|
467
|
-
_this3 = this;
|
|
468
450
|
if (this._peekRoom !== peekRoom) {
|
|
469
451
|
this.syncOpts.logger.debug("Stopped peeking in room %s", peekRoom.roomId);
|
|
470
452
|
return;
|
|
@@ -477,51 +459,46 @@ export class SyncApi {
|
|
|
477
459
|
from: token
|
|
478
460
|
}, undefined, {
|
|
479
461
|
localTimeoutMs: 50 * 1000,
|
|
480
|
-
abortSignal:
|
|
481
|
-
}).then(
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
462
|
+
abortSignal: this.abortController?.signal
|
|
463
|
+
}).then(async res => {
|
|
464
|
+
if (this._peekRoom !== peekRoom) {
|
|
465
|
+
this.syncOpts.logger.debug("Stopped peeking in room %s", peekRoom.roomId);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
// We have a problem that we get presence both from /events and /sync
|
|
469
|
+
// however, /sync only returns presence for users in rooms
|
|
470
|
+
// you're actually joined to.
|
|
471
|
+
// in order to be sure to get presence for all of the users in the
|
|
472
|
+
// peeked room, we handle presence explicitly here. This may result
|
|
473
|
+
// in duplicate presence events firing for some users, which is a
|
|
474
|
+
// performance drain, but such is life.
|
|
475
|
+
// XXX: copypasted from /sync until we can kill this minging v1 stuff.
|
|
476
|
+
|
|
477
|
+
res.chunk.filter(function (e) {
|
|
478
|
+
return e.type === "m.presence";
|
|
479
|
+
}).map(this.client.getEventMapper()).forEach(presenceEvent => {
|
|
480
|
+
let user = this.client.store.getUser(presenceEvent.getContent().user_id);
|
|
481
|
+
if (user) {
|
|
482
|
+
user.setPresenceEvent(presenceEvent);
|
|
483
|
+
} else {
|
|
484
|
+
user = User.createUser(presenceEvent.getContent().user_id, this.client);
|
|
485
|
+
user.setPresenceEvent(presenceEvent);
|
|
486
|
+
this.client.store.storeUser(user);
|
|
486
487
|
}
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
// you're actually joined to.
|
|
490
|
-
// in order to be sure to get presence for all of the users in the
|
|
491
|
-
// peeked room, we handle presence explicitly here. This may result
|
|
492
|
-
// in duplicate presence events firing for some users, which is a
|
|
493
|
-
// performance drain, but such is life.
|
|
494
|
-
// XXX: copypasted from /sync until we can kill this minging v1 stuff.
|
|
495
|
-
|
|
496
|
-
res.chunk.filter(function (e) {
|
|
497
|
-
return e.type === "m.presence";
|
|
498
|
-
}).map(_this3.client.getEventMapper()).forEach(presenceEvent => {
|
|
499
|
-
var user = _this3.client.store.getUser(presenceEvent.getContent().user_id);
|
|
500
|
-
if (user) {
|
|
501
|
-
user.setPresenceEvent(presenceEvent);
|
|
502
|
-
} else {
|
|
503
|
-
user = User.createUser(presenceEvent.getContent().user_id, _this3.client);
|
|
504
|
-
user.setPresenceEvent(presenceEvent);
|
|
505
|
-
_this3.client.store.storeUser(user);
|
|
506
|
-
}
|
|
507
|
-
_this3.client.emit(ClientEvent.Event, presenceEvent);
|
|
508
|
-
});
|
|
488
|
+
this.client.emit(ClientEvent.Event, presenceEvent);
|
|
489
|
+
});
|
|
509
490
|
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
});
|
|
519
|
-
_this3.peekPoll(peekRoom, res.end);
|
|
491
|
+
// strip out events which aren't for the given room_id (e.g presence)
|
|
492
|
+
// and also ephemeral events (which we're assuming is anything without
|
|
493
|
+
// and event ID because the /events API doesn't separate them).
|
|
494
|
+
const events = res.chunk.filter(function (e) {
|
|
495
|
+
return e.room_id === peekRoom.roomId && e.event_id;
|
|
496
|
+
}).map(this.client.getEventMapper());
|
|
497
|
+
await peekRoom.addLiveEvents(events, {
|
|
498
|
+
addToState: true
|
|
520
499
|
});
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
};
|
|
524
|
-
}(), err => {
|
|
500
|
+
this.peekPoll(peekRoom, res.end);
|
|
501
|
+
}, err => {
|
|
525
502
|
this.syncOpts.logger.error("[%s] Peek poll failed: %s", peekRoom.roomId, err);
|
|
526
503
|
setTimeout(() => {
|
|
527
504
|
this.peekPoll(peekRoom, token);
|
|
@@ -545,23 +522,19 @@ export class SyncApi {
|
|
|
545
522
|
* this object.
|
|
546
523
|
*/
|
|
547
524
|
getSyncStateData() {
|
|
548
|
-
|
|
549
|
-
return (_this$syncStateData = this.syncStateData) !== null && _this$syncStateData !== void 0 ? _this$syncStateData : null;
|
|
525
|
+
return this.syncStateData ?? null;
|
|
550
526
|
}
|
|
551
|
-
recoverFromSyncStartupError(savedSyncPromise, error) {
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
});
|
|
563
|
-
yield keepaliveProm;
|
|
564
|
-
})();
|
|
527
|
+
async recoverFromSyncStartupError(savedSyncPromise, error) {
|
|
528
|
+
// Wait for the saved sync to complete - we send the pushrules and filter requests
|
|
529
|
+
// before the saved sync has finished so they can run in parallel, but only process
|
|
530
|
+
// the results after the saved sync is done. Equivalently, we wait for it to finish
|
|
531
|
+
// before reporting failures from these functions.
|
|
532
|
+
await savedSyncPromise;
|
|
533
|
+
const keepaliveProm = this.startKeepAlives();
|
|
534
|
+
this.updateSyncState(SyncState.Error, {
|
|
535
|
+
error
|
|
536
|
+
});
|
|
537
|
+
await keepaliveProm;
|
|
565
538
|
}
|
|
566
539
|
shouldAbortSync(error) {
|
|
567
540
|
if (error.errcode === "M_UNKNOWN_TOKEN") {
|
|
@@ -578,104 +551,100 @@ export class SyncApi {
|
|
|
578
551
|
/**
|
|
579
552
|
* Main entry point
|
|
580
553
|
*/
|
|
581
|
-
sync() {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
// no push rules for guests, no access to POST filter for guests.
|
|
590
|
-
return _this5.doSync({});
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
// Pull the saved sync token out first, before the worker starts sending
|
|
594
|
-
// all the sync data which could take a while. This will let us send our
|
|
595
|
-
// first incremental sync request before we've processed our saved data.
|
|
596
|
-
_this5.syncOpts.logger.debug("Getting saved sync token...");
|
|
597
|
-
var savedSyncTokenPromise = _this5.client.store.getSavedSyncToken().then(tok => {
|
|
598
|
-
_this5.syncOpts.logger.debug("Got saved sync token");
|
|
599
|
-
return tok;
|
|
600
|
-
});
|
|
601
|
-
_this5.savedSyncPromise = _this5.client.store.getSavedSync().then(savedSync => {
|
|
602
|
-
_this5.syncOpts.logger.debug("Got reply from saved sync, exists? ".concat(!!savedSync));
|
|
603
|
-
if (savedSync) {
|
|
604
|
-
return _this5.syncFromCache(savedSync);
|
|
605
|
-
}
|
|
606
|
-
}).catch(err => {
|
|
607
|
-
_this5.syncOpts.logger.error("Getting saved sync failed", err);
|
|
608
|
-
});
|
|
554
|
+
async sync() {
|
|
555
|
+
this.running = true;
|
|
556
|
+
this.abortController = new AbortController();
|
|
557
|
+
globalThis.window?.addEventListener?.("online", this.onOnline, false);
|
|
558
|
+
if (this.client.isGuest()) {
|
|
559
|
+
// no push rules for guests, no access to POST filter for guests.
|
|
560
|
+
return this.doSync({});
|
|
561
|
+
}
|
|
609
562
|
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
filterId = _yield$_this5$getFilt.filterId,
|
|
627
|
-
filter = _yield$_this5$getFilt.filter;
|
|
628
|
-
if (!filter) return; // bail, getFilter failed
|
|
629
|
-
|
|
630
|
-
// reset the notifications timeline to prepare it to paginate from
|
|
631
|
-
// the current point in time.
|
|
632
|
-
// The right solution would be to tie /sync pagination tokens into
|
|
633
|
-
// /notifications API somehow.
|
|
634
|
-
_this5.client.resetNotifTimelineSet();
|
|
635
|
-
if (!_this5.currentSyncRequest) {
|
|
636
|
-
var firstSyncFilter = filterId;
|
|
637
|
-
var savedSyncToken = yield savedSyncTokenPromise;
|
|
638
|
-
if (savedSyncToken) {
|
|
639
|
-
_this5.syncOpts.logger.debug("Sending first sync request...");
|
|
640
|
-
} else {
|
|
641
|
-
_this5.syncOpts.logger.debug("Sending initial sync request...");
|
|
642
|
-
var initialFilter = _this5.buildDefaultFilter();
|
|
643
|
-
initialFilter.setDefinition(filter.getDefinition());
|
|
644
|
-
initialFilter.setTimelineLimit(_this5.opts.initialSyncLimit);
|
|
645
|
-
// Use an inline filter, no point uploading it for a single usage
|
|
646
|
-
firstSyncFilter = JSON.stringify(initialFilter.getDefinition());
|
|
647
|
-
}
|
|
563
|
+
// Pull the saved sync token out first, before the worker starts sending
|
|
564
|
+
// all the sync data which could take a while. This will let us send our
|
|
565
|
+
// first incremental sync request before we've processed our saved data.
|
|
566
|
+
this.syncOpts.logger.debug("Getting saved sync token...");
|
|
567
|
+
const savedSyncTokenPromise = this.client.store.getSavedSyncToken().then(tok => {
|
|
568
|
+
this.syncOpts.logger.debug("Got saved sync token");
|
|
569
|
+
return tok;
|
|
570
|
+
});
|
|
571
|
+
this.savedSyncPromise = this.client.store.getSavedSync().then(savedSync => {
|
|
572
|
+
this.syncOpts.logger.debug(`Got reply from saved sync, exists? ${!!savedSync}`);
|
|
573
|
+
if (savedSync) {
|
|
574
|
+
return this.syncFromCache(savedSync);
|
|
575
|
+
}
|
|
576
|
+
}).catch(err => {
|
|
577
|
+
this.syncOpts.logger.error("Getting saved sync failed", err);
|
|
578
|
+
});
|
|
648
579
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
580
|
+
// We need to do one-off checks before we can begin the /sync loop.
|
|
581
|
+
// These are:
|
|
582
|
+
// 1) We need to get push rules so we can check if events should bing as we get
|
|
583
|
+
// them from /sync.
|
|
584
|
+
// 2) We need to get/create a filter which we can use for /sync.
|
|
585
|
+
// 3) We need to prepare lazy loading for sync
|
|
586
|
+
// 4) We need to store the client options
|
|
587
|
+
|
|
588
|
+
// Now start the first incremental sync request: this can also
|
|
589
|
+
// take a while so if we set it going now, we can wait for it
|
|
590
|
+
// to finish while we process our saved sync data.
|
|
591
|
+
await this.getPushRules();
|
|
592
|
+
this.prepareSyncFilterLazyLoading();
|
|
593
|
+
await this.prepareSyncFilterUserProfiles();
|
|
594
|
+
await this.storeClientOptions();
|
|
595
|
+
const {
|
|
596
|
+
filterId,
|
|
597
|
+
filter
|
|
598
|
+
} = await this.getFilter();
|
|
599
|
+
if (!filter) return; // bail, getFilter failed
|
|
600
|
+
|
|
601
|
+
// reset the notifications timeline to prepare it to paginate from
|
|
602
|
+
// the current point in time.
|
|
603
|
+
// The right solution would be to tie /sync pagination tokens into
|
|
604
|
+
// /notifications API somehow.
|
|
605
|
+
this.client.resetNotifTimelineSet();
|
|
606
|
+
if (!this.currentSyncRequest) {
|
|
607
|
+
let firstSyncFilter = filterId;
|
|
608
|
+
const savedSyncToken = await savedSyncTokenPromise;
|
|
609
|
+
if (savedSyncToken) {
|
|
610
|
+
this.syncOpts.logger.debug("Sending first sync request...");
|
|
611
|
+
} else {
|
|
612
|
+
this.syncOpts.logger.debug("Sending initial sync request...");
|
|
613
|
+
const initialFilter = this.buildDefaultFilter();
|
|
614
|
+
initialFilter.setDefinition(filter.getDefinition());
|
|
615
|
+
initialFilter.setTimelineLimit(this.opts.initialSyncLimit);
|
|
616
|
+
// Use an inline filter, no point uploading it for a single usage
|
|
617
|
+
firstSyncFilter = JSON.stringify(initialFilter.getDefinition());
|
|
654
618
|
}
|
|
655
619
|
|
|
656
|
-
//
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
620
|
+
// Send this first sync request here so we can then wait for the saved
|
|
621
|
+
// sync data to finish processing before we process the results of this one.
|
|
622
|
+
this.currentSyncRequest = this.doSyncRequest({
|
|
623
|
+
filter: firstSyncFilter
|
|
624
|
+
}, savedSyncToken);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// Now wait for the saved sync to finish...
|
|
628
|
+
this.syncOpts.logger.debug("Waiting for saved sync before starting sync processing...");
|
|
629
|
+
await this.savedSyncPromise;
|
|
630
|
+
// process the first sync request and continue syncing with the normal filterId
|
|
631
|
+
return this.doSync({
|
|
632
|
+
filter: filterId
|
|
633
|
+
});
|
|
664
634
|
}
|
|
665
635
|
|
|
666
636
|
/**
|
|
667
637
|
* Stops the sync object from syncing.
|
|
668
638
|
*/
|
|
669
639
|
stop() {
|
|
670
|
-
var _globalThis$window2, _globalThis$window2$r, _this$abortController2;
|
|
671
640
|
this.syncOpts.logger.debug("SyncApi.stop");
|
|
672
641
|
// It is necessary to check for the existance of
|
|
673
642
|
// globalThis.window AND globalThis.window.removeEventListener.
|
|
674
643
|
// Some platforms (e.g. React Native) register globalThis.window,
|
|
675
644
|
// but do not have globalThis.window.removeEventListener.
|
|
676
|
-
|
|
645
|
+
globalThis.window?.removeEventListener?.("online", this.onOnline, false);
|
|
677
646
|
this.running = false;
|
|
678
|
-
|
|
647
|
+
this.abortController?.abort();
|
|
679
648
|
if (this.keepAliveTimer) {
|
|
680
649
|
clearTimeout(this.keepAliveTimer);
|
|
681
650
|
this.keepAliveTimer = undefined;
|
|
@@ -699,134 +668,127 @@ export class SyncApi {
|
|
|
699
668
|
* @param savedSync - a saved sync that was persisted by a store. This
|
|
700
669
|
* should have been acquired via client.store.getSavedSync().
|
|
701
670
|
*/
|
|
702
|
-
syncFromCache(savedSync) {
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
account_data: {
|
|
721
|
-
events: savedSync.accountData
|
|
722
|
-
}
|
|
723
|
-
};
|
|
724
|
-
try {
|
|
725
|
-
yield _this6.processSyncResponse(syncEventData, data);
|
|
726
|
-
} catch (e) {
|
|
727
|
-
_this6.syncOpts.logger.error("Error processing cached sync", e);
|
|
671
|
+
async syncFromCache(savedSync) {
|
|
672
|
+
this.syncOpts.logger.debug("sync(): not doing HTTP hit, instead returning stored /sync data");
|
|
673
|
+
const nextSyncToken = savedSync.nextBatch;
|
|
674
|
+
|
|
675
|
+
// Set sync token for future incremental syncing
|
|
676
|
+
this.client.store.setSyncToken(nextSyncToken);
|
|
677
|
+
|
|
678
|
+
// No previous sync, set old token to null
|
|
679
|
+
const syncEventData = {
|
|
680
|
+
nextSyncToken,
|
|
681
|
+
catchingUp: false,
|
|
682
|
+
fromCache: true
|
|
683
|
+
};
|
|
684
|
+
const data = {
|
|
685
|
+
next_batch: nextSyncToken,
|
|
686
|
+
rooms: savedSync.roomsData,
|
|
687
|
+
account_data: {
|
|
688
|
+
events: savedSync.accountData
|
|
728
689
|
}
|
|
690
|
+
};
|
|
691
|
+
try {
|
|
692
|
+
await this.processSyncResponse(syncEventData, data);
|
|
693
|
+
} catch (e) {
|
|
694
|
+
this.syncOpts.logger.error("Error processing cached sync", e);
|
|
695
|
+
}
|
|
729
696
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
})();
|
|
697
|
+
// Don't emit a prepared if we've bailed because the store is invalid:
|
|
698
|
+
// in this case the client will not be usable until stopped & restarted
|
|
699
|
+
// so this would be useless and misleading.
|
|
700
|
+
if (!this.storeIsInvalid) {
|
|
701
|
+
this.updateSyncState(SyncState.Prepared, syncEventData);
|
|
702
|
+
}
|
|
737
703
|
}
|
|
738
704
|
|
|
739
705
|
/**
|
|
740
706
|
* Invoke me to do /sync calls
|
|
741
707
|
*/
|
|
742
|
-
doSync(syncOptions) {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
if (!_this7.currentSyncRequest) {
|
|
750
|
-
_this7.currentSyncRequest = _this7.doSyncRequest(syncOptions, syncToken);
|
|
751
|
-
}
|
|
752
|
-
data = yield _this7.currentSyncRequest;
|
|
753
|
-
} catch (e) {
|
|
754
|
-
var abort = yield _this7.onSyncError(e);
|
|
755
|
-
if (abort) return;
|
|
756
|
-
continue;
|
|
757
|
-
} finally {
|
|
758
|
-
_this7.currentSyncRequest = undefined;
|
|
708
|
+
async doSync(syncOptions) {
|
|
709
|
+
while (this.running) {
|
|
710
|
+
const syncToken = this.client.store.getSyncToken();
|
|
711
|
+
let data;
|
|
712
|
+
try {
|
|
713
|
+
if (!this.currentSyncRequest) {
|
|
714
|
+
this.currentSyncRequest = this.doSyncRequest(syncOptions, syncToken);
|
|
759
715
|
}
|
|
716
|
+
data = await this.currentSyncRequest;
|
|
717
|
+
} catch (e) {
|
|
718
|
+
const abort = await this.onSyncError(e);
|
|
719
|
+
if (abort) return;
|
|
720
|
+
continue;
|
|
721
|
+
} finally {
|
|
722
|
+
this.currentSyncRequest = undefined;
|
|
723
|
+
}
|
|
760
724
|
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
// Emit the exception for client handling
|
|
781
|
-
_this7.client.emit(ClientEvent.SyncUnexpectedError, e);
|
|
782
|
-
}
|
|
725
|
+
// set the sync token NOW *before* processing the events. We do this so
|
|
726
|
+
// if something barfs on an event we can skip it rather than constantly
|
|
727
|
+
// polling with the same token.
|
|
728
|
+
this.client.store.setSyncToken(data.next_batch);
|
|
729
|
+
|
|
730
|
+
// Reset after a successful sync
|
|
731
|
+
this.failedSyncCount = 0;
|
|
732
|
+
const syncEventData = {
|
|
733
|
+
oldSyncToken: syncToken ?? undefined,
|
|
734
|
+
nextSyncToken: data.next_batch,
|
|
735
|
+
catchingUp: this.catchingUp
|
|
736
|
+
};
|
|
737
|
+
try {
|
|
738
|
+
await this.processSyncResponse(syncEventData, data);
|
|
739
|
+
} catch (e) {
|
|
740
|
+
// log the exception with stack if we have it, else fall back
|
|
741
|
+
// to the plain description
|
|
742
|
+
this.syncOpts.logger.error("Caught /sync error", e);
|
|
783
743
|
|
|
784
|
-
//
|
|
785
|
-
|
|
786
|
-
|
|
744
|
+
// Emit the exception for client handling
|
|
745
|
+
this.client.emit(ClientEvent.SyncUnexpectedError, e);
|
|
746
|
+
}
|
|
787
747
|
|
|
788
|
-
|
|
789
|
-
|
|
748
|
+
// Persist after processing as `unsigned` may get mutated
|
|
749
|
+
// with an `org.matrix.msc4023.thread_id`
|
|
750
|
+
await this.client.store.setSyncData(data);
|
|
790
751
|
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
_this7.updateSyncState(SyncState.Prepared, syncEventData);
|
|
794
|
-
syncOptions.hasSyncedBefore = true;
|
|
795
|
-
}
|
|
752
|
+
// update this as it may have changed
|
|
753
|
+
syncEventData.catchingUp = this.catchingUp;
|
|
796
754
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
755
|
+
// emit synced events
|
|
756
|
+
if (!syncOptions.hasSyncedBefore) {
|
|
757
|
+
this.updateSyncState(SyncState.Prepared, syncEventData);
|
|
758
|
+
syncOptions.hasSyncedBefore = true;
|
|
759
|
+
}
|
|
802
760
|
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
yield _this7.client.store.save();
|
|
808
|
-
}
|
|
761
|
+
// tell the crypto module to do its processing. It may block (to do a
|
|
762
|
+
// /keys/changes request).
|
|
763
|
+
if (this.syncOpts.cryptoCallbacks) {
|
|
764
|
+
this.syncOpts.cryptoCallbacks.onSyncCompleted(syncEventData);
|
|
809
765
|
}
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
766
|
+
|
|
767
|
+
// keep emitting SYNCING -> SYNCING for clients who want to do bulk updates
|
|
768
|
+
this.updateSyncState(SyncState.Syncing, syncEventData);
|
|
769
|
+
if (this.client.store.wantsSave()) {
|
|
770
|
+
// tell databases that everything is now in a consistent state and can be saved.
|
|
771
|
+
await this.client.store.save();
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
if (!this.running) {
|
|
775
|
+
this.syncOpts.logger.debug("Sync no longer running: exiting.");
|
|
776
|
+
if (this.connectionReturnedResolvers) {
|
|
777
|
+
this.connectionReturnedResolvers.reject();
|
|
778
|
+
this.connectionReturnedResolvers = undefined;
|
|
817
779
|
}
|
|
818
|
-
|
|
780
|
+
this.updateSyncState(SyncState.Stopped);
|
|
781
|
+
}
|
|
819
782
|
}
|
|
820
783
|
doSyncRequest(syncOptions, syncToken) {
|
|
821
|
-
|
|
822
|
-
var qps = this.getSyncParams(syncOptions, syncToken);
|
|
784
|
+
const qps = this.getSyncParams(syncOptions, syncToken);
|
|
823
785
|
return this.client.http.authedRequest(Method.Get, "/sync", qps, undefined, {
|
|
824
786
|
localTimeoutMs: qps.timeout + BUFFER_PERIOD_MS,
|
|
825
|
-
abortSignal:
|
|
787
|
+
abortSignal: this.abortController?.signal
|
|
826
788
|
});
|
|
827
789
|
}
|
|
828
790
|
getSyncParams(syncOptions, syncToken) {
|
|
829
|
-
|
|
791
|
+
let timeout = this.opts.pollTimeout;
|
|
830
792
|
if (this.getSyncState() !== SyncState.Syncing || this.catchingUp) {
|
|
831
793
|
// unless we are happily syncing already, we want the server to return
|
|
832
794
|
// as quickly as possible, even if there are no events queued. This
|
|
@@ -842,11 +804,11 @@ export class SyncApi {
|
|
|
842
804
|
this.catchingUp = true;
|
|
843
805
|
timeout = 0;
|
|
844
806
|
}
|
|
845
|
-
|
|
807
|
+
let filter = syncOptions.filter;
|
|
846
808
|
if (this.client.isGuest() && !filter) {
|
|
847
809
|
filter = this.getGuestFilter();
|
|
848
810
|
}
|
|
849
|
-
|
|
811
|
+
const qps = {
|
|
850
812
|
filter,
|
|
851
813
|
timeout,
|
|
852
814
|
"org.matrix.msc4222.use_state_after": true
|
|
@@ -881,51 +843,48 @@ export class SyncApi {
|
|
|
881
843
|
setPresence(presence) {
|
|
882
844
|
this.presence = presence;
|
|
883
845
|
}
|
|
884
|
-
onSyncError(err) {
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
if (
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
_this8.connectionReturnedResolvers.reject();
|
|
891
|
-
_this8.connectionReturnedResolvers = undefined;
|
|
892
|
-
}
|
|
893
|
-
_this8.updateSyncState(SyncState.Stopped);
|
|
894
|
-
return true; // abort
|
|
895
|
-
}
|
|
896
|
-
_this8.syncOpts.logger.error("/sync error %s", err);
|
|
897
|
-
if (_this8.shouldAbortSync(err)) {
|
|
898
|
-
return true; // abort
|
|
846
|
+
async onSyncError(err) {
|
|
847
|
+
if (!this.running) {
|
|
848
|
+
this.syncOpts.logger.debug("Sync no longer running: exiting");
|
|
849
|
+
if (this.connectionReturnedResolvers) {
|
|
850
|
+
this.connectionReturnedResolvers.reject();
|
|
851
|
+
this.connectionReturnedResolvers = undefined;
|
|
899
852
|
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
853
|
+
this.updateSyncState(SyncState.Stopped);
|
|
854
|
+
return true; // abort
|
|
855
|
+
}
|
|
856
|
+
this.syncOpts.logger.error("/sync error %s", err);
|
|
857
|
+
if (this.shouldAbortSync(err)) {
|
|
858
|
+
return true; // abort
|
|
859
|
+
}
|
|
860
|
+
this.failedSyncCount++;
|
|
861
|
+
this.syncOpts.logger.debug("Number of consecutive failed sync requests:", this.failedSyncCount);
|
|
862
|
+
this.syncOpts.logger.debug("Starting keep-alive");
|
|
863
|
+
// Note that we do *not* mark the sync connection as
|
|
864
|
+
// lost yet: we only do this if a keepalive poke
|
|
865
|
+
// fails, since long lived HTTP connections will
|
|
866
|
+
// go away sometimes and we shouldn't treat this as
|
|
867
|
+
// erroneous. We set the state to 'reconnecting'
|
|
868
|
+
// instead, so that clients can observe this state
|
|
869
|
+
// if they wish.
|
|
870
|
+
const keepAlivePromise = this.startKeepAlives();
|
|
871
|
+
this.currentSyncRequest = undefined;
|
|
872
|
+
// Transition from RECONNECTING to ERROR after a given number of failed syncs
|
|
873
|
+
this.updateSyncState(this.failedSyncCount >= FAILED_SYNC_ERROR_THRESHOLD ? SyncState.Error : SyncState.Reconnecting, {
|
|
874
|
+
error: err
|
|
875
|
+
});
|
|
876
|
+
const connDidFail = await keepAlivePromise;
|
|
877
|
+
|
|
878
|
+
// Only emit CATCHUP if we detected a connectivity error: if we didn't,
|
|
879
|
+
// it's quite likely the sync will fail again for the same reason and we
|
|
880
|
+
// want to stay in ERROR rather than keep flip-flopping between ERROR
|
|
881
|
+
// and CATCHUP.
|
|
882
|
+
if (connDidFail && this.getSyncState() === SyncState.Error) {
|
|
883
|
+
this.updateSyncState(SyncState.Catchup, {
|
|
884
|
+
catchingUp: true
|
|
915
885
|
});
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
// Only emit CATCHUP if we detected a connectivity error: if we didn't,
|
|
919
|
-
// it's quite likely the sync will fail again for the same reason and we
|
|
920
|
-
// want to stay in ERROR rather than keep flip-flopping between ERROR
|
|
921
|
-
// and CATCHUP.
|
|
922
|
-
if (connDidFail && _this8.getSyncState() === SyncState.Error) {
|
|
923
|
-
_this8.updateSyncState(SyncState.Catchup, {
|
|
924
|
-
catchingUp: true
|
|
925
|
-
});
|
|
926
|
-
}
|
|
927
|
-
return false;
|
|
928
|
-
})();
|
|
886
|
+
}
|
|
887
|
+
return false;
|
|
929
888
|
}
|
|
930
889
|
|
|
931
890
|
/**
|
|
@@ -935,491 +894,450 @@ export class SyncApi {
|
|
|
935
894
|
* @param syncEventData - Object containing sync tokens associated with this sync
|
|
936
895
|
* @param data - The response from /sync
|
|
937
896
|
*/
|
|
938
|
-
processSyncResponse(syncEventData, data) {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
897
|
+
async processSyncResponse(syncEventData, data) {
|
|
898
|
+
const client = this.client;
|
|
899
|
+
|
|
900
|
+
// data looks like:
|
|
901
|
+
// {
|
|
902
|
+
// next_batch: $token,
|
|
903
|
+
// presence: { events: [] },
|
|
904
|
+
// account_data: { events: [] },
|
|
905
|
+
// device_lists: { changed: ["@user:server", ... ]},
|
|
906
|
+
// to_device: { events: [] },
|
|
907
|
+
// device_one_time_keys_count: { signed_curve25519: 42 },
|
|
908
|
+
// rooms: {
|
|
909
|
+
// invite: {
|
|
910
|
+
// $roomid: {
|
|
911
|
+
// invite_state: { events: [] }
|
|
912
|
+
// }
|
|
913
|
+
// },
|
|
914
|
+
// join: {
|
|
915
|
+
// $roomid: {
|
|
916
|
+
// state: { events: [] },
|
|
917
|
+
// timeline: { events: [], prev_batch: $token, limited: true },
|
|
918
|
+
// ephemeral: { events: [] },
|
|
919
|
+
// summary: {
|
|
920
|
+
// m.heroes: [ $user_id ],
|
|
921
|
+
// m.joined_member_count: $count,
|
|
922
|
+
// m.invited_member_count: $count
|
|
923
|
+
// },
|
|
924
|
+
// account_data: { events: [] },
|
|
925
|
+
// unread_notifications: {
|
|
926
|
+
// highlight_count: 0,
|
|
927
|
+
// notification_count: 0,
|
|
928
|
+
// }
|
|
929
|
+
// "org.matrix.msc4222.state_after": { events: [] }, // only if "org.matrix.msc4222.use_state_after" is true
|
|
930
|
+
// msc4354_sticky: { events: [] }, // only if "org.matrix.msc4354.sticky" is true
|
|
931
|
+
// }
|
|
932
|
+
// },
|
|
933
|
+
// leave: {
|
|
934
|
+
// $roomid: {
|
|
935
|
+
// state: { events: [] },
|
|
936
|
+
// timeline: { events: [], prev_batch: $token }
|
|
937
|
+
// }
|
|
938
|
+
// }
|
|
939
|
+
// }
|
|
940
|
+
// }
|
|
941
|
+
|
|
942
|
+
// TODO-arch:
|
|
943
|
+
// - Each event we pass through needs to be emitted via 'event', can we
|
|
944
|
+
// do this in one place?
|
|
945
|
+
// - The isBrandNewRoom boilerplate is boilerplatey.
|
|
946
|
+
|
|
947
|
+
// handle presence events (User objects)
|
|
948
|
+
if (Array.isArray(data.presence?.events)) {
|
|
949
|
+
data.presence.events.filter(noUnsafeEventProps).map(client.getEventMapper()).forEach(function (presenceEvent) {
|
|
950
|
+
let user = client.store.getUser(presenceEvent.getSender());
|
|
951
|
+
if (user) {
|
|
952
|
+
user.setPresenceEvent(presenceEvent);
|
|
953
|
+
} else {
|
|
954
|
+
user = User.createUser(presenceEvent.getSender(), client);
|
|
955
|
+
user.setPresenceEvent(presenceEvent);
|
|
956
|
+
client.store.storeUser(user);
|
|
957
|
+
}
|
|
958
|
+
client.emit(ClientEvent.Event, presenceEvent);
|
|
959
|
+
});
|
|
960
|
+
}
|
|
990
961
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
962
|
+
// handle non-room account_data
|
|
963
|
+
if (Array.isArray(data.account_data?.events)) {
|
|
964
|
+
const events = data.account_data.events.filter(noUnsafeEventProps).map(client.getEventMapper());
|
|
965
|
+
const prevEventsMap = events.reduce((m, c) => {
|
|
966
|
+
m[c.getType()] = client.store.getAccountData(c.getType());
|
|
967
|
+
return m;
|
|
968
|
+
}, {});
|
|
969
|
+
client.store.storeAccountDataEvents(events);
|
|
970
|
+
events.forEach(function (accountDataEvent) {
|
|
971
|
+
// Honour push rules that come down the sync stream but also
|
|
972
|
+
// honour push rules that were previously cached. Base rules
|
|
973
|
+
// will be updated when we receive push rules via getPushRules
|
|
974
|
+
// (see sync) before syncing over the network.
|
|
975
|
+
if (accountDataEvent.getType() === EventType.PushRules) {
|
|
976
|
+
const rules = accountDataEvent.getContent();
|
|
977
|
+
client.setPushRules(rules);
|
|
978
|
+
}
|
|
979
|
+
const prevEvent = prevEventsMap[accountDataEvent.getType()];
|
|
980
|
+
client.emit(ClientEvent.AccountData, accountDataEvent, prevEvent);
|
|
981
|
+
return accountDataEvent;
|
|
982
|
+
});
|
|
983
|
+
}
|
|
1005
984
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
return accountDataEvent;
|
|
1026
|
-
});
|
|
985
|
+
// handle user profile updates (MSC4429)
|
|
986
|
+
const userUpdate = data["users"] ?? data["org.matrix.msc4429.users"];
|
|
987
|
+
if (typeof userUpdate === "object" && userUpdate !== null) {
|
|
988
|
+
const usersToRemove = [];
|
|
989
|
+
const profilesToAmend = new Map();
|
|
990
|
+
for (const [userId, userData] of Object.entries(userUpdate)) {
|
|
991
|
+
logger.info(`Storing user profile ${userId}`, userData);
|
|
992
|
+
if (userData.profile_updates) {
|
|
993
|
+
const existingProfile = await client.store.getUserProfile(userId);
|
|
994
|
+
profilesToAmend.set(userId, _objectSpread(_objectSpread({}, existingProfile), userData.profile_updates));
|
|
995
|
+
} else if (userData.profile_updates === null) {
|
|
996
|
+
usersToRemove.push(userId);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
if (usersToRemove.length) {
|
|
1000
|
+
await client.store.removeUserProfiles(usersToRemove);
|
|
1001
|
+
}
|
|
1002
|
+
if (profilesToAmend.size) {
|
|
1003
|
+
await client.store.storeUserProfiles(profilesToAmend);
|
|
1027
1004
|
}
|
|
1028
1005
|
|
|
1029
|
-
//
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
for (var _ref0 of Object.entries(userUpdate)) {
|
|
1035
|
-
var _ref9 = _slicedToArray(_ref0, 2);
|
|
1036
|
-
var userId = _ref9[0];
|
|
1037
|
-
var userData = _ref9[1];
|
|
1038
|
-
logger.info("Storing user profile ".concat(userId), userData);
|
|
1039
|
-
if (userData.profile_updates) {
|
|
1040
|
-
var existingProfile = yield client.store.getUserProfile(userId);
|
|
1041
|
-
profilesToAmend.set(userId, _objectSpread(_objectSpread({}, existingProfile), userData.profile_updates));
|
|
1042
|
-
} else if (userData.profile_updates === null) {
|
|
1043
|
-
usersToRemove.push(userId);
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
if (usersToRemove.length) {
|
|
1047
|
-
yield client.store.removeUserProfiles(usersToRemove);
|
|
1048
|
-
}
|
|
1049
|
-
if (profilesToAmend.size) {
|
|
1050
|
-
yield client.store.storeUserProfiles(profilesToAmend);
|
|
1051
|
-
}
|
|
1006
|
+
// emit after we've update the store so that clients can get the updated profile if they want to
|
|
1007
|
+
for (const [userId, userData] of Object.entries(userUpdate)) {
|
|
1008
|
+
client.emit(ClientEvent.UserProfileUpdate, userId, userData.profile_updates ?? null);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1052
1011
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1012
|
+
// handle to-device events
|
|
1013
|
+
if (data.to_device && Array.isArray(data.to_device.events) && data.to_device.events.length > 0) {
|
|
1014
|
+
const toDeviceMessages = data.to_device.events.filter(noUnsafeEventProps);
|
|
1015
|
+
let receivedToDeviceMessages;
|
|
1016
|
+
if (this.syncOpts.cryptoCallbacks) {
|
|
1017
|
+
receivedToDeviceMessages = await this.syncOpts.cryptoCallbacks.preprocessToDeviceMessages(toDeviceMessages);
|
|
1018
|
+
} else {
|
|
1019
|
+
// Crypto is not enabled, so we just return the events.
|
|
1020
|
+
receivedToDeviceMessages = toDeviceMessages.map(rawEvent => ({
|
|
1021
|
+
message: rawEvent,
|
|
1022
|
+
encryptionInfo: null
|
|
1023
|
+
}));
|
|
1061
1024
|
}
|
|
1025
|
+
processToDeviceMessages(receivedToDeviceMessages, client);
|
|
1026
|
+
} else {
|
|
1027
|
+
// no more to-device events: we can stop polling with a short timeout.
|
|
1028
|
+
this.catchingUp = false;
|
|
1029
|
+
}
|
|
1062
1030
|
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1031
|
+
// the returned json structure is a bit crap, so make it into a
|
|
1032
|
+
// nicer form (array) after applying sanity to make sure we don't fail
|
|
1033
|
+
// on missing keys (on the off chance)
|
|
1034
|
+
let inviteRooms = [];
|
|
1035
|
+
let joinRooms = [];
|
|
1036
|
+
let leaveRooms = [];
|
|
1037
|
+
let knockRooms = [];
|
|
1038
|
+
if (data.rooms) {
|
|
1039
|
+
if (data.rooms.invite) {
|
|
1040
|
+
inviteRooms = this.mapSyncResponseToRoomArray(data.rooms.invite);
|
|
1041
|
+
}
|
|
1042
|
+
if (data.rooms.join) {
|
|
1043
|
+
joinRooms = this.mapSyncResponseToRoomArray(data.rooms.join);
|
|
1044
|
+
}
|
|
1045
|
+
if (data.rooms.leave) {
|
|
1046
|
+
leaveRooms = this.mapSyncResponseToRoomArray(data.rooms.leave);
|
|
1047
|
+
}
|
|
1048
|
+
if (data.rooms.knock) {
|
|
1049
|
+
knockRooms = this.mapSyncResponseToRoomArray(data.rooms.knock);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
this.notifEvents = [];
|
|
1053
|
+
|
|
1054
|
+
// Handle invites
|
|
1055
|
+
await Promise.all(inviteRooms.map(async inviteObj => {
|
|
1056
|
+
const room = inviteObj.room;
|
|
1057
|
+
const stateEvents = this.mapSyncEventsFormat(inviteObj.invite_state, room);
|
|
1058
|
+
await this.injectRoomEvents(room, stateEvents, undefined);
|
|
1059
|
+
if (inviteObj.isBrandNewRoom) {
|
|
1060
|
+
room.recalculate();
|
|
1061
|
+
client.store.storeRoom(room);
|
|
1062
|
+
client.emit(ClientEvent.Room, room);
|
|
1078
1063
|
} else {
|
|
1079
|
-
//
|
|
1080
|
-
|
|
1064
|
+
// Update room state for invite->reject->invite cycles
|
|
1065
|
+
room.recalculate();
|
|
1081
1066
|
}
|
|
1067
|
+
stateEvents.forEach(function (e) {
|
|
1068
|
+
client.emit(ClientEvent.Event, e);
|
|
1069
|
+
});
|
|
1070
|
+
}));
|
|
1082
1071
|
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1072
|
+
// Handle joins
|
|
1073
|
+
await Promise.all(joinRooms.map(async joinObj => {
|
|
1074
|
+
const room = joinObj.room;
|
|
1075
|
+
const stateEvents = this.mapSyncEventsFormat(joinObj.state, room);
|
|
1076
|
+
const stateAfterEvents = this.mapSyncEventsFormat(joinObj["org.matrix.msc4222.state_after"], room);
|
|
1077
|
+
// Prevent events from being decrypted ahead of time
|
|
1078
|
+
// this helps large account to speed up faster
|
|
1079
|
+
// room::decryptCriticalEvent is in charge of decrypting all the events
|
|
1080
|
+
// required for a client to function properly
|
|
1081
|
+
const timelineEvents = this.mapSyncEventsFormat(joinObj.timeline, room, false);
|
|
1082
|
+
const ephemeralEvents = this.mapSyncEventsFormat(joinObj.ephemeral);
|
|
1083
|
+
const accountDataEvents = this.mapSyncEventsFormat(joinObj.account_data);
|
|
1084
|
+
const stickyEvents = this.mapSyncEventsFormat(joinObj.msc4354_sticky);
|
|
1085
|
+
|
|
1086
|
+
// If state_after is present, this is the events that form the state at the end of the timeline block and
|
|
1087
|
+
// regular timeline events do *not* count towards state. If it's not present, then the state is formed by
|
|
1088
|
+
// the state events plus the timeline events. Note mapSyncEventsFormat returns an empty array if the field
|
|
1089
|
+
// is absent so we explicitly check the field on the original object.
|
|
1090
|
+
const eventsFormingFinalState = joinObj["org.matrix.msc4222.state_after"] ? stateAfterEvents : stateEvents.concat(timelineEvents);
|
|
1091
|
+
const encrypted = this.isRoomEncrypted(room, eventsFormingFinalState);
|
|
1092
|
+
// We store the server-provided value first so it's correct when any of the events fire.
|
|
1093
|
+
if (joinObj.unread_notifications) {
|
|
1094
|
+
/**
|
|
1095
|
+
* We track unread notifications ourselves in encrypted rooms, so don't
|
|
1096
|
+
* bother setting it here. We trust our calculations better than the
|
|
1097
|
+
* server's for this case, and therefore will assume that our non-zero
|
|
1098
|
+
* count is accurate.
|
|
1099
|
+
* XXX: this is known faulty as the push rule for `.m.room.encrypted` may be disabled so server
|
|
1100
|
+
* may issue notification counts of 0 which we wrongly trust.
|
|
1101
|
+
* https://github.com/matrix-org/matrix-spec-proposals/pull/2654 would fix this
|
|
1102
|
+
*
|
|
1103
|
+
* @see import("./client").fixNotificationCountOnDecryption
|
|
1104
|
+
*/
|
|
1105
|
+
if (!encrypted || joinObj.unread_notifications.notification_count === 0) {
|
|
1106
|
+
// In an encrypted room, if the room has notifications enabled then it's typical for
|
|
1107
|
+
// the server to flag all new messages as notifying. However, some push rules calculate
|
|
1108
|
+
// events as ignored based on their event contents (e.g. ignoring msgtype=m.notice messages)
|
|
1109
|
+
// so we want to calculate this figure on the client in all cases.
|
|
1110
|
+
room.setUnreadNotificationCount(NotificationCountType.Total, joinObj.unread_notifications.notification_count ?? 0);
|
|
1096
1111
|
}
|
|
1097
|
-
if (
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
if (data.rooms.knock) {
|
|
1101
|
-
knockRooms = _this9.mapSyncResponseToRoomArray(data.rooms.knock);
|
|
1112
|
+
if (!encrypted || room.getUnreadNotificationCount(NotificationCountType.Highlight) <= 0) {
|
|
1113
|
+
// If the locally stored highlight count is zero, use the server provided value.
|
|
1114
|
+
room.setUnreadNotificationCount(NotificationCountType.Highlight, joinObj.unread_notifications.highlight_count ?? 0);
|
|
1102
1115
|
}
|
|
1103
1116
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
if (
|
|
1113
|
-
room.
|
|
1114
|
-
client.store.storeRoom(room);
|
|
1115
|
-
client.emit(ClientEvent.Room, room);
|
|
1116
|
-
} else {
|
|
1117
|
-
// Update room state for invite->reject->invite cycles
|
|
1118
|
-
room.recalculate();
|
|
1119
|
-
}
|
|
1120
|
-
stateEvents.forEach(function (e) {
|
|
1121
|
-
client.emit(ClientEvent.Event, e);
|
|
1122
|
-
});
|
|
1123
|
-
});
|
|
1124
|
-
return function (_x3) {
|
|
1125
|
-
return _ref12.apply(this, arguments);
|
|
1126
|
-
};
|
|
1127
|
-
}()));
|
|
1128
|
-
|
|
1129
|
-
// Handle joins
|
|
1130
|
-
yield Promise.all(joinRooms.map(/*#__PURE__*/function () {
|
|
1131
|
-
var _ref13 = _asyncToGenerator(function* (joinObj) {
|
|
1132
|
-
var _joinObj$UNREAD_THREA;
|
|
1133
|
-
var room = joinObj.room;
|
|
1134
|
-
var stateEvents = _this9.mapSyncEventsFormat(joinObj.state, room);
|
|
1135
|
-
var stateAfterEvents = _this9.mapSyncEventsFormat(joinObj["org.matrix.msc4222.state_after"], room);
|
|
1136
|
-
// Prevent events from being decrypted ahead of time
|
|
1137
|
-
// this helps large account to speed up faster
|
|
1138
|
-
// room::decryptCriticalEvent is in charge of decrypting all the events
|
|
1139
|
-
// required for a client to function properly
|
|
1140
|
-
var timelineEvents = _this9.mapSyncEventsFormat(joinObj.timeline, room, false);
|
|
1141
|
-
var ephemeralEvents = _this9.mapSyncEventsFormat(joinObj.ephemeral);
|
|
1142
|
-
var accountDataEvents = _this9.mapSyncEventsFormat(joinObj.account_data);
|
|
1143
|
-
var stickyEvents = _this9.mapSyncEventsFormat(joinObj.msc4354_sticky);
|
|
1144
|
-
|
|
1145
|
-
// If state_after is present, this is the events that form the state at the end of the timeline block and
|
|
1146
|
-
// regular timeline events do *not* count towards state. If it's not present, then the state is formed by
|
|
1147
|
-
// the state events plus the timeline events. Note mapSyncEventsFormat returns an empty array if the field
|
|
1148
|
-
// is absent so we explicitly check the field on the original object.
|
|
1149
|
-
var eventsFormingFinalState = joinObj["org.matrix.msc4222.state_after"] ? stateAfterEvents : stateEvents.concat(timelineEvents);
|
|
1150
|
-
var encrypted = _this9.isRoomEncrypted(room, eventsFormingFinalState);
|
|
1151
|
-
// We store the server-provided value first so it's correct when any of the events fire.
|
|
1152
|
-
if (joinObj.unread_notifications) {
|
|
1153
|
-
/**
|
|
1154
|
-
* We track unread notifications ourselves in encrypted rooms, so don't
|
|
1155
|
-
* bother setting it here. We trust our calculations better than the
|
|
1156
|
-
* server's for this case, and therefore will assume that our non-zero
|
|
1157
|
-
* count is accurate.
|
|
1158
|
-
* XXX: this is known faulty as the push rule for `.m.room.encrypted` may be disabled so server
|
|
1159
|
-
* may issue notification counts of 0 which we wrongly trust.
|
|
1160
|
-
* https://github.com/matrix-org/matrix-spec-proposals/pull/2654 would fix this
|
|
1161
|
-
*
|
|
1162
|
-
* @see import("./client").fixNotificationCountOnDecryption
|
|
1163
|
-
*/
|
|
1164
|
-
if (!encrypted || joinObj.unread_notifications.notification_count === 0) {
|
|
1165
|
-
var _joinObj$unread_notif;
|
|
1166
|
-
// In an encrypted room, if the room has notifications enabled then it's typical for
|
|
1167
|
-
// the server to flag all new messages as notifying. However, some push rules calculate
|
|
1168
|
-
// events as ignored based on their event contents (e.g. ignoring msgtype=m.notice messages)
|
|
1169
|
-
// so we want to calculate this figure on the client in all cases.
|
|
1170
|
-
room.setUnreadNotificationCount(NotificationCountType.Total, (_joinObj$unread_notif = joinObj.unread_notifications.notification_count) !== null && _joinObj$unread_notif !== void 0 ? _joinObj$unread_notif : 0);
|
|
1171
|
-
}
|
|
1172
|
-
if (!encrypted || room.getUnreadNotificationCount(NotificationCountType.Highlight) <= 0) {
|
|
1173
|
-
var _joinObj$unread_notif2;
|
|
1174
|
-
// If the locally stored highlight count is zero, use the server provided value.
|
|
1175
|
-
room.setUnreadNotificationCount(NotificationCountType.Highlight, (_joinObj$unread_notif2 = joinObj.unread_notifications.highlight_count) !== null && _joinObj$unread_notif2 !== void 0 ? _joinObj$unread_notif2 : 0);
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
var unreadThreadNotifications = (_joinObj$UNREAD_THREA = joinObj[UNREAD_THREAD_NOTIFICATIONS.name]) !== null && _joinObj$UNREAD_THREA !== void 0 ? _joinObj$UNREAD_THREA : joinObj[UNREAD_THREAD_NOTIFICATIONS.altName];
|
|
1179
|
-
if (unreadThreadNotifications) {
|
|
1180
|
-
// This mirrors the logic above for rooms: take the *total* notification count from
|
|
1181
|
-
// the server for unencrypted rooms or is it's zero. Any threads not present in this
|
|
1182
|
-
// object implicitly have zero notifications, so start by clearing the total counts
|
|
1183
|
-
// for all such threads.
|
|
1184
|
-
room.resetThreadUnreadNotificationCountFromSync(Object.keys(unreadThreadNotifications));
|
|
1185
|
-
for (var _ref16 of Object.entries(unreadThreadNotifications)) {
|
|
1186
|
-
var _ref15 = _slicedToArray(_ref16, 2);
|
|
1187
|
-
var threadId = _ref15[0];
|
|
1188
|
-
var unreadNotification = _ref15[1];
|
|
1189
|
-
if (!encrypted || unreadNotification.notification_count === 0) {
|
|
1190
|
-
var _unreadNotification$n;
|
|
1191
|
-
room.setThreadUnreadNotificationCount(threadId, NotificationCountType.Total, (_unreadNotification$n = unreadNotification.notification_count) !== null && _unreadNotification$n !== void 0 ? _unreadNotification$n : 0);
|
|
1192
|
-
}
|
|
1193
|
-
var hasNoNotifications = room.getThreadUnreadNotificationCount(threadId, NotificationCountType.Highlight) <= 0;
|
|
1194
|
-
if (!encrypted || encrypted && hasNoNotifications) {
|
|
1195
|
-
var _unreadNotification$h;
|
|
1196
|
-
room.setThreadUnreadNotificationCount(threadId, NotificationCountType.Highlight, (_unreadNotification$h = unreadNotification.highlight_count) !== null && _unreadNotification$h !== void 0 ? _unreadNotification$h : 0);
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
} else {
|
|
1200
|
-
room.resetThreadUnreadNotificationCountFromSync();
|
|
1117
|
+
const unreadThreadNotifications = joinObj[UNREAD_THREAD_NOTIFICATIONS.name] ?? joinObj[UNREAD_THREAD_NOTIFICATIONS.altName];
|
|
1118
|
+
if (unreadThreadNotifications) {
|
|
1119
|
+
// This mirrors the logic above for rooms: take the *total* notification count from
|
|
1120
|
+
// the server for unencrypted rooms or is it's zero. Any threads not present in this
|
|
1121
|
+
// object implicitly have zero notifications, so start by clearing the total counts
|
|
1122
|
+
// for all such threads.
|
|
1123
|
+
room.resetThreadUnreadNotificationCountFromSync(Object.keys(unreadThreadNotifications));
|
|
1124
|
+
for (const [threadId, unreadNotification] of Object.entries(unreadThreadNotifications)) {
|
|
1125
|
+
if (!encrypted || unreadNotification.notification_count === 0) {
|
|
1126
|
+
room.setThreadUnreadNotificationCount(threadId, NotificationCountType.Total, unreadNotification.notification_count ?? 0);
|
|
1201
1127
|
}
|
|
1202
|
-
|
|
1203
|
-
if (
|
|
1204
|
-
|
|
1205
|
-
// events so that clients can start back-paginating.
|
|
1206
|
-
if (joinObj.timeline.prev_batch !== null) {
|
|
1207
|
-
room.getLiveTimeline().setPaginationToken(joinObj.timeline.prev_batch, EventTimeline.BACKWARDS);
|
|
1208
|
-
}
|
|
1209
|
-
} else if (joinObj.timeline.limited) {
|
|
1210
|
-
var limited = true;
|
|
1211
|
-
|
|
1212
|
-
// we've got a limited sync, so we *probably* have a gap in the
|
|
1213
|
-
// timeline, so should reset. But we might have been peeking or
|
|
1214
|
-
// paginating and already have some of the events, in which
|
|
1215
|
-
// case we just want to append any subsequent events to the end
|
|
1216
|
-
// of the existing timeline.
|
|
1217
|
-
//
|
|
1218
|
-
// This is particularly important in the case that we already have
|
|
1219
|
-
// *all* of the events in the timeline - in that case, if we reset
|
|
1220
|
-
// the timeline, we'll end up with an entirely empty timeline,
|
|
1221
|
-
// which we'll try to paginate but not get any new events (which
|
|
1222
|
-
// will stop us linking the empty timeline into the chain).
|
|
1223
|
-
//
|
|
1224
|
-
for (var i = timelineEvents.length - 1; i >= 0; i--) {
|
|
1225
|
-
var eventId = timelineEvents[i].getId();
|
|
1226
|
-
if (room.getTimelineForEvent(eventId)) {
|
|
1227
|
-
_this9.syncOpts.logger.debug("Already have event ".concat(eventId, " in limited sync - not resetting"));
|
|
1228
|
-
limited = false;
|
|
1229
|
-
|
|
1230
|
-
// we might still be missing some of the events before i;
|
|
1231
|
-
// we don't want to be adding them to the end of the
|
|
1232
|
-
// timeline because that would put them out of order.
|
|
1233
|
-
timelineEvents.splice(0, i);
|
|
1234
|
-
|
|
1235
|
-
// XXX: there's a problem here if the skipped part of the
|
|
1236
|
-
// timeline modifies the state set in stateEvents, because
|
|
1237
|
-
// we'll end up using the state from stateEvents rather
|
|
1238
|
-
// than the later state from timelineEvents. We probably
|
|
1239
|
-
// need to wind stateEvents forward over the events we're
|
|
1240
|
-
// skipping.
|
|
1241
|
-
|
|
1242
|
-
break;
|
|
1243
|
-
}
|
|
1244
|
-
}
|
|
1245
|
-
if (limited) {
|
|
1246
|
-
var _syncEventData$oldSyn;
|
|
1247
|
-
room.resetLiveTimeline(joinObj.timeline.prev_batch, _this9.syncOpts.canResetEntireTimeline(room.roomId) ? null : (_syncEventData$oldSyn = syncEventData.oldSyncToken) !== null && _syncEventData$oldSyn !== void 0 ? _syncEventData$oldSyn : null);
|
|
1248
|
-
|
|
1249
|
-
// We have to assume any gap in any timeline is
|
|
1250
|
-
// reason to stop incrementally tracking notifications and
|
|
1251
|
-
// reset the timeline.
|
|
1252
|
-
client.resetNotifTimelineSet();
|
|
1253
|
-
}
|
|
1128
|
+
const hasNoNotifications = room.getThreadUnreadNotificationCount(threadId, NotificationCountType.Highlight) <= 0;
|
|
1129
|
+
if (!encrypted || encrypted && hasNoNotifications) {
|
|
1130
|
+
room.setThreadUnreadNotificationCount(threadId, NotificationCountType.Highlight, unreadNotification.highlight_count ?? 0);
|
|
1254
1131
|
}
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1132
|
+
}
|
|
1133
|
+
} else {
|
|
1134
|
+
room.resetThreadUnreadNotificationCountFromSync();
|
|
1135
|
+
}
|
|
1136
|
+
joinObj.timeline = joinObj.timeline || {};
|
|
1137
|
+
if (joinObj.isBrandNewRoom) {
|
|
1138
|
+
// set the back-pagination token. Do this *before* adding any
|
|
1139
|
+
// events so that clients can start back-paginating.
|
|
1140
|
+
if (joinObj.timeline.prev_batch !== null) {
|
|
1141
|
+
room.getLiveTimeline().setPaginationToken(joinObj.timeline.prev_batch, EventTimeline.BACKWARDS);
|
|
1142
|
+
}
|
|
1143
|
+
} else if (joinObj.timeline.limited) {
|
|
1144
|
+
let limited = true;
|
|
1145
|
+
|
|
1146
|
+
// we've got a limited sync, so we *probably* have a gap in the
|
|
1147
|
+
// timeline, so should reset. But we might have been peeking or
|
|
1148
|
+
// paginating and already have some of the events, in which
|
|
1149
|
+
// case we just want to append any subsequent events to the end
|
|
1150
|
+
// of the existing timeline.
|
|
1151
|
+
//
|
|
1152
|
+
// This is particularly important in the case that we already have
|
|
1153
|
+
// *all* of the events in the timeline - in that case, if we reset
|
|
1154
|
+
// the timeline, we'll end up with an entirely empty timeline,
|
|
1155
|
+
// which we'll try to paginate but not get any new events (which
|
|
1156
|
+
// will stop us linking the empty timeline into the chain).
|
|
1157
|
+
//
|
|
1158
|
+
for (let i = timelineEvents.length - 1; i >= 0; i--) {
|
|
1159
|
+
const eventId = timelineEvents[i].getId();
|
|
1160
|
+
if (room.getTimelineForEvent(eventId)) {
|
|
1161
|
+
this.syncOpts.logger.debug(`Already have event ${eventId} in limited sync - not resetting`);
|
|
1162
|
+
limited = false;
|
|
1163
|
+
|
|
1164
|
+
// we might still be missing some of the events before i;
|
|
1165
|
+
// we don't want to be adding them to the end of the
|
|
1166
|
+
// timeline because that would put them out of order.
|
|
1167
|
+
timelineEvents.splice(0, i);
|
|
1168
|
+
|
|
1169
|
+
// XXX: there's a problem here if the skipped part of the
|
|
1170
|
+
// timeline modifies the state set in stateEvents, because
|
|
1171
|
+
// we'll end up using the state from stateEvents rather
|
|
1172
|
+
// than the later state from timelineEvents. We probably
|
|
1173
|
+
// need to wind stateEvents forward over the events we're
|
|
1174
|
+
// skipping.
|
|
1175
|
+
|
|
1176
|
+
break;
|
|
1267
1177
|
}
|
|
1178
|
+
}
|
|
1179
|
+
if (limited) {
|
|
1180
|
+
room.resetLiveTimeline(joinObj.timeline.prev_batch, this.syncOpts.canResetEntireTimeline(room.roomId) ? null : syncEventData.oldSyncToken ?? null);
|
|
1268
1181
|
|
|
1269
|
-
//
|
|
1270
|
-
//
|
|
1271
|
-
//
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
try {
|
|
1276
|
-
if ("org.matrix.msc4222.state_after" in joinObj) {
|
|
1277
|
-
yield _this9.injectRoomEvents(room, undefined, stateAfterEvents, timelineEvents, syncEventData.fromCache);
|
|
1278
|
-
} else {
|
|
1279
|
-
yield _this9.injectRoomEvents(room, stateEvents, undefined, timelineEvents, syncEventData.fromCache);
|
|
1280
|
-
}
|
|
1281
|
-
} catch (e) {
|
|
1282
|
-
_this9.syncOpts.logger.error("Failed to process events on room ".concat(room.roomId, ":"), e);
|
|
1283
|
-
}
|
|
1182
|
+
// We have to assume any gap in any timeline is
|
|
1183
|
+
// reason to stop incrementally tracking notifications and
|
|
1184
|
+
// reset the timeline.
|
|
1185
|
+
client.resetNotifTimelineSet();
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1284
1188
|
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
room.setSummary(joinObj.summary);
|
|
1290
|
-
}
|
|
1189
|
+
// process any crypto events *before* emitting the RoomStateEvent events. This
|
|
1190
|
+
// avoids a race condition if the application tries to send a message after the
|
|
1191
|
+
// state event is processed, but before crypto is enabled, which then causes the
|
|
1192
|
+
// crypto layer to complain.
|
|
1291
1193
|
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
room.addAccountData(accountDataEvents);
|
|
1297
|
-
|
|
1298
|
-
// Sticky events primarily come via the `timeline` field, with the
|
|
1299
|
-
// sticky info field marking them as sticky.
|
|
1300
|
-
// If the sync is "gappy" (meaning it is skipping events to catch up) then
|
|
1301
|
-
// sticky events will instead come down the sticky section.
|
|
1302
|
-
// This ensures we collect sticky events from both places.
|
|
1303
|
-
var stickyEventsAndStickyEventsFromTheTimeline = stickyEvents.concat(timelineEvents.filter(e => e.unstableStickyInfo !== undefined));
|
|
1304
|
-
// Note: We calculate sticky events before emitting `.Room` as it's nice to have
|
|
1305
|
-
// sticky events calculated and ready to go.
|
|
1306
|
-
room._unstable_addStickyEvents(stickyEventsAndStickyEventsFromTheTimeline);
|
|
1307
|
-
room.recalculate();
|
|
1308
|
-
if (joinObj.isBrandNewRoom) {
|
|
1309
|
-
client.store.storeRoom(room);
|
|
1310
|
-
client.emit(ClientEvent.Room, room);
|
|
1311
|
-
}
|
|
1312
|
-
_this9.processEventsForNotifs(room, timelineEvents);
|
|
1313
|
-
var emitEvent = e => client.emit(ClientEvent.Event, e);
|
|
1314
|
-
// this fires a couple of times for some events. (eg state events are in the timeline and the state)
|
|
1315
|
-
// should this get a sync section as an additional event emission param (e, syncSection))?
|
|
1316
|
-
stateEvents.forEach(emitEvent);
|
|
1317
|
-
timelineEvents.forEach(emitEvent);
|
|
1318
|
-
ephemeralEvents.forEach(emitEvent);
|
|
1319
|
-
accountDataEvents.forEach(emitEvent);
|
|
1320
|
-
stickyEvents.filter(stickyEvent =>
|
|
1321
|
-
// This is highly unlikey, but in the case where a sticky event
|
|
1322
|
-
// has appeared in the timeline AND the sticky section, we only
|
|
1323
|
-
// want to emit the event once.
|
|
1324
|
-
!timelineEvents.some(timelineEvent => timelineEvent.getId() === stickyEvent.getId())).forEach(emitEvent);
|
|
1325
|
-
// Decrypt only the last message in all rooms to make sure we can generate a preview
|
|
1326
|
-
// And decrypt all events after the recorded read receipt to ensure an accurate
|
|
1327
|
-
// notification count
|
|
1328
|
-
room.decryptCriticalEvents();
|
|
1329
|
-
});
|
|
1330
|
-
return function (_x4) {
|
|
1331
|
-
return _ref13.apply(this, arguments);
|
|
1332
|
-
};
|
|
1333
|
-
}()));
|
|
1334
|
-
|
|
1335
|
-
// Handle leaves (e.g. kicked rooms)
|
|
1336
|
-
yield Promise.all(leaveRooms.map(/*#__PURE__*/function () {
|
|
1337
|
-
var _ref17 = _asyncToGenerator(function* (leaveObj) {
|
|
1338
|
-
var room = leaveObj.room;
|
|
1339
|
-
var _yield$_this9$mapAndI = yield _this9.mapAndInjectRoomEvents(leaveObj),
|
|
1340
|
-
timelineEvents = _yield$_this9$mapAndI.timelineEvents,
|
|
1341
|
-
stateEvents = _yield$_this9$mapAndI.stateEvents,
|
|
1342
|
-
stateAfterEvents = _yield$_this9$mapAndI.stateAfterEvents;
|
|
1343
|
-
var accountDataEvents = _this9.mapSyncEventsFormat(leaveObj.account_data);
|
|
1344
|
-
room.addAccountData(accountDataEvents);
|
|
1345
|
-
room.recalculate();
|
|
1346
|
-
if (leaveObj.isBrandNewRoom) {
|
|
1347
|
-
client.store.storeRoom(room);
|
|
1348
|
-
client.emit(ClientEvent.Room, room);
|
|
1194
|
+
if (this.syncOpts.cryptoCallbacks) {
|
|
1195
|
+
for (const e of eventsFormingFinalState) {
|
|
1196
|
+
if (e.isState() && e.getType() === EventType.RoomEncryption && e.getStateKey() === "") {
|
|
1197
|
+
await this.syncOpts.cryptoCallbacks.onCryptoEvent(room, e);
|
|
1349
1198
|
}
|
|
1350
|
-
|
|
1351
|
-
stateEvents === null || stateEvents === void 0 || stateEvents.forEach(function (e) {
|
|
1352
|
-
client.emit(ClientEvent.Event, e);
|
|
1353
|
-
});
|
|
1354
|
-
stateAfterEvents === null || stateAfterEvents === void 0 || stateAfterEvents.forEach(function (e) {
|
|
1355
|
-
client.emit(ClientEvent.Event, e);
|
|
1356
|
-
});
|
|
1357
|
-
timelineEvents.forEach(function (e) {
|
|
1358
|
-
client.emit(ClientEvent.Event, e);
|
|
1359
|
-
});
|
|
1360
|
-
accountDataEvents.forEach(function (e) {
|
|
1361
|
-
client.emit(ClientEvent.Event, e);
|
|
1362
|
-
});
|
|
1363
|
-
});
|
|
1364
|
-
return function (_x5) {
|
|
1365
|
-
return _ref17.apply(this, arguments);
|
|
1366
|
-
};
|
|
1367
|
-
}()));
|
|
1368
|
-
|
|
1369
|
-
// Handle knocks
|
|
1370
|
-
yield Promise.all(knockRooms.map(/*#__PURE__*/function () {
|
|
1371
|
-
var _ref18 = _asyncToGenerator(function* (knockObj) {
|
|
1372
|
-
var room = knockObj.room;
|
|
1373
|
-
var stateEvents = _this9.mapSyncEventsFormat(knockObj.knock_state, room);
|
|
1374
|
-
yield _this9.injectRoomEvents(room, stateEvents, undefined);
|
|
1375
|
-
if (knockObj.isBrandNewRoom) {
|
|
1376
|
-
room.recalculate();
|
|
1377
|
-
client.store.storeRoom(room);
|
|
1378
|
-
client.emit(ClientEvent.Room, room);
|
|
1379
|
-
} else {
|
|
1380
|
-
// Update room state for knock->leave->knock cycles
|
|
1381
|
-
room.recalculate();
|
|
1382
|
-
}
|
|
1383
|
-
stateEvents.forEach(function (e) {
|
|
1384
|
-
client.emit(ClientEvent.Event, e);
|
|
1385
|
-
});
|
|
1386
|
-
});
|
|
1387
|
-
return function (_x6) {
|
|
1388
|
-
return _ref18.apply(this, arguments);
|
|
1389
|
-
};
|
|
1390
|
-
}()));
|
|
1391
|
-
|
|
1392
|
-
// update the notification timeline, if appropriate.
|
|
1393
|
-
// we only do this for live events, as otherwise we can't order them sanely
|
|
1394
|
-
// in the timeline relative to ones paginated in by /notifications.
|
|
1395
|
-
// XXX: we could fix this by making EventTimeline support chronological
|
|
1396
|
-
// ordering... but it doesn't, right now.
|
|
1397
|
-
if (syncEventData.oldSyncToken && _this9.notifEvents.length) {
|
|
1398
|
-
_this9.notifEvents.sort(function (a, b) {
|
|
1399
|
-
return a.getTs() - b.getTs();
|
|
1400
|
-
});
|
|
1401
|
-
_this9.notifEvents.forEach(function (event) {
|
|
1402
|
-
var _client$getNotifTimel;
|
|
1403
|
-
(_client$getNotifTimel = client.getNotifTimelineSet()) === null || _client$getNotifTimel === void 0 || _client$getNotifTimel.addLiveEvent(event, {
|
|
1404
|
-
addToState: true
|
|
1405
|
-
});
|
|
1406
|
-
});
|
|
1199
|
+
}
|
|
1407
1200
|
}
|
|
1408
1201
|
|
|
1409
|
-
//
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1202
|
+
// Proactively decrypt state events: normally we decrypt on demand, but for state
|
|
1203
|
+
// events we need them immediately, so we handle them here. Specifically, consumers
|
|
1204
|
+
// (e.g. Element Web) expect state events to be unencrypted upon receipt.
|
|
1205
|
+
for (const ev of timelineEvents.filter(ev => ev.isState())) {
|
|
1206
|
+
await this.client.decryptEventIfNeeded(ev);
|
|
1207
|
+
}
|
|
1208
|
+
try {
|
|
1209
|
+
if ("org.matrix.msc4222.state_after" in joinObj) {
|
|
1210
|
+
await this.injectRoomEvents(room, undefined, stateAfterEvents, timelineEvents, syncEventData.fromCache);
|
|
1413
1211
|
} else {
|
|
1414
|
-
|
|
1415
|
-
// invalidate the device lists. But that would require a
|
|
1416
|
-
// substantial bit of rework :/.
|
|
1212
|
+
await this.injectRoomEvents(room, stateEvents, undefined, timelineEvents, syncEventData.fromCache);
|
|
1417
1213
|
}
|
|
1214
|
+
} catch (e) {
|
|
1215
|
+
this.syncOpts.logger.error(`Failed to process events on room ${room.roomId}:`, e);
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
// set summary after processing events,
|
|
1219
|
+
// because it will trigger a name calculation
|
|
1220
|
+
// which needs the room state to be up to date
|
|
1221
|
+
if (joinObj.summary) {
|
|
1222
|
+
room.setSummary(joinObj.summary);
|
|
1223
|
+
}
|
|
1224
|
+
|
|
1225
|
+
// we deliberately don't add ephemeral events to the timeline
|
|
1226
|
+
room.addEphemeralEvents(ephemeralEvents);
|
|
1227
|
+
|
|
1228
|
+
// we deliberately don't add accountData to the timeline
|
|
1229
|
+
room.addAccountData(accountDataEvents);
|
|
1230
|
+
|
|
1231
|
+
// Sticky events primarily come via the `timeline` field, with the
|
|
1232
|
+
// sticky info field marking them as sticky.
|
|
1233
|
+
// If the sync is "gappy" (meaning it is skipping events to catch up) then
|
|
1234
|
+
// sticky events will instead come down the sticky section.
|
|
1235
|
+
// This ensures we collect sticky events from both places.
|
|
1236
|
+
const stickyEventsAndStickyEventsFromTheTimeline = stickyEvents.concat(timelineEvents.filter(e => e.unstableStickyInfo !== undefined));
|
|
1237
|
+
// Note: We calculate sticky events before emitting `.Room` as it's nice to have
|
|
1238
|
+
// sticky events calculated and ready to go.
|
|
1239
|
+
room._unstable_addStickyEvents(stickyEventsAndStickyEventsFromTheTimeline);
|
|
1240
|
+
room.recalculate();
|
|
1241
|
+
if (joinObj.isBrandNewRoom) {
|
|
1242
|
+
client.store.storeRoom(room);
|
|
1243
|
+
client.emit(ClientEvent.Room, room);
|
|
1244
|
+
}
|
|
1245
|
+
this.processEventsForNotifs(room, timelineEvents);
|
|
1246
|
+
const emitEvent = e => client.emit(ClientEvent.Event, e);
|
|
1247
|
+
// this fires a couple of times for some events. (eg state events are in the timeline and the state)
|
|
1248
|
+
// should this get a sync section as an additional event emission param (e, syncSection))?
|
|
1249
|
+
stateEvents.forEach(emitEvent);
|
|
1250
|
+
timelineEvents.forEach(emitEvent);
|
|
1251
|
+
ephemeralEvents.forEach(emitEvent);
|
|
1252
|
+
accountDataEvents.forEach(emitEvent);
|
|
1253
|
+
stickyEvents.filter(stickyEvent =>
|
|
1254
|
+
// This is highly unlikey, but in the case where a sticky event
|
|
1255
|
+
// has appeared in the timeline AND the sticky section, we only
|
|
1256
|
+
// want to emit the event once.
|
|
1257
|
+
!timelineEvents.some(timelineEvent => timelineEvent.getId() === stickyEvent.getId())).forEach(emitEvent);
|
|
1258
|
+
// Decrypt only the last message in all rooms to make sure we can generate a preview
|
|
1259
|
+
// And decrypt all events after the recorded read receipt to ensure an accurate
|
|
1260
|
+
// notification count
|
|
1261
|
+
room.decryptCriticalEvents();
|
|
1262
|
+
}));
|
|
1263
|
+
|
|
1264
|
+
// Handle leaves (e.g. kicked rooms)
|
|
1265
|
+
await Promise.all(leaveRooms.map(async leaveObj => {
|
|
1266
|
+
const room = leaveObj.room;
|
|
1267
|
+
const {
|
|
1268
|
+
timelineEvents,
|
|
1269
|
+
stateEvents,
|
|
1270
|
+
stateAfterEvents
|
|
1271
|
+
} = await this.mapAndInjectRoomEvents(leaveObj);
|
|
1272
|
+
const accountDataEvents = this.mapSyncEventsFormat(leaveObj.account_data);
|
|
1273
|
+
room.addAccountData(accountDataEvents);
|
|
1274
|
+
room.recalculate();
|
|
1275
|
+
if (leaveObj.isBrandNewRoom) {
|
|
1276
|
+
client.store.storeRoom(room);
|
|
1277
|
+
client.emit(ClientEvent.Room, room);
|
|
1278
|
+
}
|
|
1279
|
+
this.processEventsForNotifs(room, timelineEvents);
|
|
1280
|
+
stateEvents?.forEach(function (e) {
|
|
1281
|
+
client.emit(ClientEvent.Event, e);
|
|
1282
|
+
});
|
|
1283
|
+
stateAfterEvents?.forEach(function (e) {
|
|
1284
|
+
client.emit(ClientEvent.Event, e);
|
|
1285
|
+
});
|
|
1286
|
+
timelineEvents.forEach(function (e) {
|
|
1287
|
+
client.emit(ClientEvent.Event, e);
|
|
1288
|
+
});
|
|
1289
|
+
accountDataEvents.forEach(function (e) {
|
|
1290
|
+
client.emit(ClientEvent.Event, e);
|
|
1291
|
+
});
|
|
1292
|
+
}));
|
|
1293
|
+
|
|
1294
|
+
// Handle knocks
|
|
1295
|
+
await Promise.all(knockRooms.map(async knockObj => {
|
|
1296
|
+
const room = knockObj.room;
|
|
1297
|
+
const stateEvents = this.mapSyncEventsFormat(knockObj.knock_state, room);
|
|
1298
|
+
await this.injectRoomEvents(room, stateEvents, undefined);
|
|
1299
|
+
if (knockObj.isBrandNewRoom) {
|
|
1300
|
+
room.recalculate();
|
|
1301
|
+
client.store.storeRoom(room);
|
|
1302
|
+
client.emit(ClientEvent.Room, room);
|
|
1303
|
+
} else {
|
|
1304
|
+
// Update room state for knock->leave->knock cycles
|
|
1305
|
+
room.recalculate();
|
|
1306
|
+
}
|
|
1307
|
+
stateEvents.forEach(function (e) {
|
|
1308
|
+
client.emit(ClientEvent.Event, e);
|
|
1309
|
+
});
|
|
1310
|
+
}));
|
|
1311
|
+
|
|
1312
|
+
// update the notification timeline, if appropriate.
|
|
1313
|
+
// we only do this for live events, as otherwise we can't order them sanely
|
|
1314
|
+
// in the timeline relative to ones paginated in by /notifications.
|
|
1315
|
+
// XXX: we could fix this by making EventTimeline support chronological
|
|
1316
|
+
// ordering... but it doesn't, right now.
|
|
1317
|
+
if (syncEventData.oldSyncToken && this.notifEvents.length) {
|
|
1318
|
+
this.notifEvents.sort(function (a, b) {
|
|
1319
|
+
return a.getTs() - b.getTs();
|
|
1320
|
+
});
|
|
1321
|
+
this.notifEvents.forEach(function (event) {
|
|
1322
|
+
client.getNotifTimelineSet()?.addLiveEvent(event, {
|
|
1323
|
+
addToState: true
|
|
1324
|
+
});
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
// Handle device list updates
|
|
1329
|
+
if (data.device_lists) {
|
|
1330
|
+
if (this.syncOpts.cryptoCallbacks) {
|
|
1331
|
+
await this.syncOpts.cryptoCallbacks.processDeviceLists(data.device_lists);
|
|
1332
|
+
} else {
|
|
1333
|
+
// FIXME if we *don't* have a crypto module, we still need to
|
|
1334
|
+
// invalidate the device lists. But that would require a
|
|
1335
|
+
// substantial bit of rework :/.
|
|
1418
1336
|
}
|
|
1337
|
+
}
|
|
1419
1338
|
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
})();
|
|
1339
|
+
// Handle one_time_keys_count and unused fallback keys
|
|
1340
|
+
await this.syncOpts.cryptoCallbacks?.processKeyCounts(data.device_one_time_keys_count, data.device_unused_fallback_key_types ?? data["org.matrix.msc2732.device_unused_fallback_key_types"]);
|
|
1423
1341
|
}
|
|
1424
1342
|
|
|
1425
1343
|
/**
|
|
@@ -1456,9 +1374,7 @@ export class SyncApi {
|
|
|
1456
1374
|
*
|
|
1457
1375
|
* @param connDidFail - True if a connectivity failure has been detected. Optional.
|
|
1458
1376
|
*/
|
|
1459
|
-
pokeKeepAlive() {
|
|
1460
|
-
var _this$abortController4;
|
|
1461
|
-
var connDidFail = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
1377
|
+
pokeKeepAlive(connDidFail = false) {
|
|
1462
1378
|
if (!this.running) {
|
|
1463
1379
|
// we are in a keepAlive, retrying to connect, but the syncronization
|
|
1464
1380
|
// was stopped, so we are stopping the retry.
|
|
@@ -1469,7 +1385,7 @@ export class SyncApi {
|
|
|
1469
1385
|
}
|
|
1470
1386
|
return;
|
|
1471
1387
|
}
|
|
1472
|
-
|
|
1388
|
+
const success = () => {
|
|
1473
1389
|
clearTimeout(this.keepAliveTimer);
|
|
1474
1390
|
if (this.connectionReturnedResolvers) {
|
|
1475
1391
|
this.connectionReturnedResolvers.resolve(connDidFail);
|
|
@@ -1483,7 +1399,7 @@ export class SyncApi {
|
|
|
1483
1399
|
{
|
|
1484
1400
|
prefix: "",
|
|
1485
1401
|
localTimeoutMs: 15 * 1000,
|
|
1486
|
-
abortSignal:
|
|
1402
|
+
abortSignal: this.abortController?.signal
|
|
1487
1403
|
}).then(() => {
|
|
1488
1404
|
success();
|
|
1489
1405
|
}, err => {
|
|
@@ -1513,10 +1429,10 @@ export class SyncApi {
|
|
|
1513
1429
|
// Maps { roomid: {stuff}, roomid: {stuff} }
|
|
1514
1430
|
// to
|
|
1515
1431
|
// [{stuff+Room+isBrandNewRoom}, {stuff+Room+isBrandNewRoom}]
|
|
1516
|
-
|
|
1432
|
+
const client = this.client;
|
|
1517
1433
|
return Object.keys(obj).filter(k => !unsafeProp(k)).map(roomId => {
|
|
1518
|
-
|
|
1519
|
-
|
|
1434
|
+
let room = client.store.getRoom(roomId);
|
|
1435
|
+
let isBrandNewRoom = false;
|
|
1520
1436
|
if (!room) {
|
|
1521
1437
|
room = this.createRoom(roomId);
|
|
1522
1438
|
isBrandNewRoom = true;
|
|
@@ -1527,12 +1443,11 @@ export class SyncApi {
|
|
|
1527
1443
|
});
|
|
1528
1444
|
});
|
|
1529
1445
|
}
|
|
1530
|
-
mapSyncEventsFormat(obj, room) {
|
|
1531
|
-
var decrypt = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
|
|
1446
|
+
mapSyncEventsFormat(obj, room, decrypt = true) {
|
|
1532
1447
|
if (!obj || !Array.isArray(obj.events)) {
|
|
1533
1448
|
return [];
|
|
1534
1449
|
}
|
|
1535
|
-
|
|
1450
|
+
const mapper = this.client.getEventMapper({
|
|
1536
1451
|
decrypt
|
|
1537
1452
|
});
|
|
1538
1453
|
return obj.events.filter(noUnsafeEventProps).map(function (e) {
|
|
@@ -1549,15 +1464,15 @@ export class SyncApi {
|
|
|
1549
1464
|
if (!room || !this.opts.resolveInvitesToProfiles) {
|
|
1550
1465
|
return;
|
|
1551
1466
|
}
|
|
1552
|
-
|
|
1467
|
+
const client = this.client;
|
|
1553
1468
|
// For each invited room member we want to give them a displayname/avatar url
|
|
1554
1469
|
// if they have one (the m.room.member invites don't contain this).
|
|
1555
1470
|
room.getMembersWithMembership(KnownMembership.Invite).forEach(function (member) {
|
|
1556
1471
|
if (member.requestedProfileInfo) return;
|
|
1557
1472
|
member.requestedProfileInfo = true;
|
|
1558
1473
|
// try to get a cached copy first.
|
|
1559
|
-
|
|
1560
|
-
|
|
1474
|
+
const user = client.getUser(member.userId);
|
|
1475
|
+
let promise;
|
|
1561
1476
|
if (user) {
|
|
1562
1477
|
promise = Promise.resolve({
|
|
1563
1478
|
avatar_url: user.avatarUrl,
|
|
@@ -1570,8 +1485,8 @@ export class SyncApi {
|
|
|
1570
1485
|
// slightly naughty by doctoring the invite event but this means all
|
|
1571
1486
|
// the code paths remain the same between invite/join display name stuff
|
|
1572
1487
|
// which is a worthy trade-off for some minor pollution.
|
|
1573
|
-
|
|
1574
|
-
if (
|
|
1488
|
+
const inviteEvent = member.events.member;
|
|
1489
|
+
if (inviteEvent?.getContent().membership !== KnownMembership.Invite) {
|
|
1575
1490
|
// between resolving and now they have since joined, so don't clobber
|
|
1576
1491
|
return;
|
|
1577
1492
|
}
|
|
@@ -1585,7 +1500,7 @@ export class SyncApi {
|
|
|
1585
1500
|
});
|
|
1586
1501
|
}
|
|
1587
1502
|
findEncryptionEvent(events) {
|
|
1588
|
-
return events
|
|
1503
|
+
return events?.find(e => e.getType() === EventType.RoomEncryption && e.getStateKey() === "");
|
|
1589
1504
|
}
|
|
1590
1505
|
|
|
1591
1506
|
// When processing the sync response we cannot rely on Room.hasEncryptionStateEvent we actually
|
|
@@ -1593,23 +1508,20 @@ export class SyncApi {
|
|
|
1593
1508
|
isRoomEncrypted(room, eventsFormingFinalState) {
|
|
1594
1509
|
return room.hasEncryptionStateEvent() || !!this.findEncryptionEvent(eventsFormingFinalState);
|
|
1595
1510
|
}
|
|
1596
|
-
mapAndInjectRoomEvents(wrappedRoom) {
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
stateAfterEvents
|
|
1611
|
-
};
|
|
1612
|
-
})();
|
|
1511
|
+
async mapAndInjectRoomEvents(wrappedRoom) {
|
|
1512
|
+
const stateEvents = this.mapSyncEventsFormat(wrappedRoom.state, wrappedRoom.room);
|
|
1513
|
+
const stateAfterEvents = this.mapSyncEventsFormat(wrappedRoom["org.matrix.msc4222.state_after"], wrappedRoom.room);
|
|
1514
|
+
const timelineEvents = this.mapSyncEventsFormat(wrappedRoom.timeline, wrappedRoom.room);
|
|
1515
|
+
if ("org.matrix.msc4222.state_after" in wrappedRoom) {
|
|
1516
|
+
await this.injectRoomEvents(wrappedRoom.room, undefined, stateAfterEvents, timelineEvents);
|
|
1517
|
+
} else {
|
|
1518
|
+
await this.injectRoomEvents(wrappedRoom.room, stateEvents, undefined, timelineEvents);
|
|
1519
|
+
}
|
|
1520
|
+
return {
|
|
1521
|
+
timelineEvents,
|
|
1522
|
+
stateEvents,
|
|
1523
|
+
stateAfterEvents
|
|
1524
|
+
};
|
|
1613
1525
|
}
|
|
1614
1526
|
|
|
1615
1527
|
/**
|
|
@@ -1628,76 +1540,71 @@ export class SyncApi {
|
|
|
1628
1540
|
* are not added to the state.
|
|
1629
1541
|
*/
|
|
1630
1542
|
|
|
1631
|
-
injectRoomEvents(room, stateEventList, stateAfterEventList, timelineEventList) {
|
|
1632
|
-
|
|
1633
|
-
_this1 = this;
|
|
1634
|
-
return _asyncToGenerator(function* () {
|
|
1635
|
-
var fromCache = _arguments.length > 4 && _arguments[4] !== undefined ? _arguments[4] : false;
|
|
1636
|
-
var eitherStateEventList = stateAfterEventList !== null && stateAfterEventList !== void 0 ? stateAfterEventList : stateEventList;
|
|
1637
|
-
|
|
1638
|
-
// If there are no events in the timeline yet, initialise it with
|
|
1639
|
-
// the given state events
|
|
1640
|
-
var liveTimeline = room.getLiveTimeline();
|
|
1641
|
-
var timelineWasEmpty = liveTimeline.getEvents().length == 0;
|
|
1642
|
-
if (timelineWasEmpty) {
|
|
1643
|
-
// Passing these events into initialiseState will freeze them, so we need
|
|
1644
|
-
// to compute and cache the push actions for them now, otherwise sync dies
|
|
1645
|
-
// with an attempt to assign to read only property.
|
|
1646
|
-
// XXX: This is pretty horrible and is assuming all sorts of behaviour from
|
|
1647
|
-
// these functions that it shouldn't be. We should probably either store the
|
|
1648
|
-
// push actions cache elsewhere so we can freeze MatrixEvents, or otherwise
|
|
1649
|
-
// find some solution where MatrixEvents are immutable but allow for a cache
|
|
1650
|
-
// field.
|
|
1651
|
-
|
|
1652
|
-
for (var ev of eitherStateEventList) {
|
|
1653
|
-
_this1.client.getPushActionsForEvent(ev);
|
|
1654
|
-
}
|
|
1655
|
-
liveTimeline.initialiseState(eitherStateEventList, {
|
|
1656
|
-
timelineWasEmpty
|
|
1657
|
-
});
|
|
1658
|
-
}
|
|
1659
|
-
_this1.resolveInvites(room);
|
|
1660
|
-
|
|
1661
|
-
// recalculate the room name at this point as adding events to the timeline
|
|
1662
|
-
// may make notifications appear which should have the right name.
|
|
1663
|
-
// XXX: This looks suspect: we'll end up recalculating the room once here
|
|
1664
|
-
// and then again after adding events (processSyncResponse calls it after
|
|
1665
|
-
// calling us) even if no state events were added. It also means that if
|
|
1666
|
-
// one of the room events in timelineEventList is something that needs
|
|
1667
|
-
// a recalculation (like m.room.name) we won't recalculate until we've
|
|
1668
|
-
// finished adding all the events, which will cause the notification to have
|
|
1669
|
-
// the old room name rather than the new one.
|
|
1670
|
-
room.recalculate();
|
|
1543
|
+
async injectRoomEvents(room, stateEventList, stateAfterEventList, timelineEventList, fromCache = false) {
|
|
1544
|
+
const eitherStateEventList = stateAfterEventList ?? stateEventList;
|
|
1671
1545
|
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
//
|
|
1678
|
-
//
|
|
1679
|
-
//
|
|
1680
|
-
//
|
|
1681
|
-
//
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1546
|
+
// If there are no events in the timeline yet, initialise it with
|
|
1547
|
+
// the given state events
|
|
1548
|
+
const liveTimeline = room.getLiveTimeline();
|
|
1549
|
+
const timelineWasEmpty = liveTimeline.getEvents().length == 0;
|
|
1550
|
+
if (timelineWasEmpty) {
|
|
1551
|
+
// Passing these events into initialiseState will freeze them, so we need
|
|
1552
|
+
// to compute and cache the push actions for them now, otherwise sync dies
|
|
1553
|
+
// with an attempt to assign to read only property.
|
|
1554
|
+
// XXX: This is pretty horrible and is assuming all sorts of behaviour from
|
|
1555
|
+
// these functions that it shouldn't be. We should probably either store the
|
|
1556
|
+
// push actions cache elsewhere so we can freeze MatrixEvents, or otherwise
|
|
1557
|
+
// find some solution where MatrixEvents are immutable but allow for a cache
|
|
1558
|
+
// field.
|
|
1559
|
+
|
|
1560
|
+
for (const ev of eitherStateEventList) {
|
|
1561
|
+
this.client.getPushActionsForEvent(ev);
|
|
1688
1562
|
}
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
// events in it, this will continue to diverge the current state.
|
|
1692
|
-
// This also needs to be done before running push rules on the events as they need
|
|
1693
|
-
// to be decorated with sender etc.
|
|
1694
|
-
yield room.addLiveEvents(timelineEventList || [], {
|
|
1695
|
-
fromCache,
|
|
1696
|
-
timelineWasEmpty,
|
|
1697
|
-
addToState: stateAfterEventList === undefined
|
|
1563
|
+
liveTimeline.initialiseState(eitherStateEventList, {
|
|
1564
|
+
timelineWasEmpty
|
|
1698
1565
|
});
|
|
1699
|
-
|
|
1700
|
-
|
|
1566
|
+
}
|
|
1567
|
+
this.resolveInvites(room);
|
|
1568
|
+
|
|
1569
|
+
// recalculate the room name at this point as adding events to the timeline
|
|
1570
|
+
// may make notifications appear which should have the right name.
|
|
1571
|
+
// XXX: This looks suspect: we'll end up recalculating the room once here
|
|
1572
|
+
// and then again after adding events (processSyncResponse calls it after
|
|
1573
|
+
// calling us) even if no state events were added. It also means that if
|
|
1574
|
+
// one of the room events in timelineEventList is something that needs
|
|
1575
|
+
// a recalculation (like m.room.name) we won't recalculate until we've
|
|
1576
|
+
// finished adding all the events, which will cause the notification to have
|
|
1577
|
+
// the old room name rather than the new one.
|
|
1578
|
+
room.recalculate();
|
|
1579
|
+
|
|
1580
|
+
// If the timeline wasn't empty, we process the state events here: they're
|
|
1581
|
+
// defined as updates to the state before the start of the timeline, so this
|
|
1582
|
+
// starts to roll the state forward.
|
|
1583
|
+
// XXX: That's what we *should* do, but this can happen if we were previously
|
|
1584
|
+
// peeking in a room, in which case we obviously do *not* want to add the
|
|
1585
|
+
// state events here onto the end of the timeline. Historically, the js-sdk
|
|
1586
|
+
// has just set these new state events on the old and new state. This seems
|
|
1587
|
+
// very wrong because there could be events in the timeline that diverge the
|
|
1588
|
+
// state, in which case this is going to leave things out of sync. However,
|
|
1589
|
+
// for now I think it;s best to behave the same as the code has done previously.
|
|
1590
|
+
if (!timelineWasEmpty) {
|
|
1591
|
+
// XXX: As above, don't do this...
|
|
1592
|
+
//room.addLiveEvents(stateEventList || []);
|
|
1593
|
+
// Do this instead...
|
|
1594
|
+
room.oldState.setStateEvents(eitherStateEventList);
|
|
1595
|
+
room.currentState.setStateEvents(eitherStateEventList);
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
// Execute the timeline events. If addToState is true the timeline has any state
|
|
1599
|
+
// events in it, this will continue to diverge the current state.
|
|
1600
|
+
// This also needs to be done before running push rules on the events as they need
|
|
1601
|
+
// to be decorated with sender etc.
|
|
1602
|
+
await room.addLiveEvents(timelineEventList || [], {
|
|
1603
|
+
fromCache,
|
|
1604
|
+
timelineWasEmpty,
|
|
1605
|
+
addToState: stateAfterEventList === undefined
|
|
1606
|
+
});
|
|
1607
|
+
this.client.processBeaconEvents(room, timelineEventList);
|
|
1701
1608
|
}
|
|
1702
1609
|
|
|
1703
1610
|
/**
|
|
@@ -1711,10 +1618,9 @@ export class SyncApi {
|
|
|
1711
1618
|
processEventsForNotifs(room, timelineEventList) {
|
|
1712
1619
|
// gather our notifications into this.notifEvents
|
|
1713
1620
|
if (this.client.getNotifTimelineSet()) {
|
|
1714
|
-
for (
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
if (pushActions !== null && pushActions !== void 0 && pushActions.notify && (_pushActions$tweaks = pushActions.tweaks) !== null && _pushActions$tweaks !== void 0 && _pushActions$tweaks.highlight) {
|
|
1621
|
+
for (const event of timelineEventList) {
|
|
1622
|
+
const pushActions = this.client.getPushActionsForEvent(event);
|
|
1623
|
+
if (pushActions?.notify && pushActions.tweaks?.highlight) {
|
|
1718
1624
|
this.notifEvents.push(event);
|
|
1719
1625
|
}
|
|
1720
1626
|
}
|
|
@@ -1732,7 +1638,7 @@ export class SyncApi {
|
|
|
1732
1638
|
* @param data - Object of additional data to emit in the event
|
|
1733
1639
|
*/
|
|
1734
1640
|
updateSyncState(newState, data) {
|
|
1735
|
-
|
|
1641
|
+
const old = this.syncState;
|
|
1736
1642
|
this.syncState = newState;
|
|
1737
1643
|
this.syncStateData = data;
|
|
1738
1644
|
this.client.emit(ClientEvent.Sync, this.syncState, old, data);
|
|
@@ -1742,8 +1648,10 @@ export class SyncApi {
|
|
|
1742
1648
|
// /!\ This function is not intended for public use! It's only exported from
|
|
1743
1649
|
// here in order to share some common logic with sliding-sync-sdk.ts.
|
|
1744
1650
|
export function _createAndReEmitRoom(client, roomId, opts) {
|
|
1745
|
-
|
|
1746
|
-
|
|
1651
|
+
const {
|
|
1652
|
+
timelineSupport
|
|
1653
|
+
} = client;
|
|
1654
|
+
const room = new Room(roomId, client, client.getUserId(), {
|
|
1747
1655
|
lazyLoadMembers: opts.lazyLoadMembers,
|
|
1748
1656
|
pendingEventOrdering: opts.pendingEventOrdering,
|
|
1749
1657
|
timelineSupport
|
|
@@ -1753,8 +1661,7 @@ export function _createAndReEmitRoom(client, roomId, opts) {
|
|
|
1753
1661
|
// We need to add a listener for RoomState.members in order to hook them
|
|
1754
1662
|
// correctly.
|
|
1755
1663
|
room.on(RoomStateEvent.NewMember, (event, state, member) => {
|
|
1756
|
-
|
|
1757
|
-
member.user = (_client$getUser = client.getUser(member.userId)) !== null && _client$getUser !== void 0 ? _client$getUser : undefined;
|
|
1664
|
+
member.user = client.getUser(member.userId) ?? undefined;
|
|
1758
1665
|
client.reEmitter.reEmit(member, [RoomMemberEvent.Name, RoomMemberEvent.Typing, RoomMemberEvent.PowerLevel, RoomMemberEvent.Membership]);
|
|
1759
1666
|
});
|
|
1760
1667
|
return room;
|
|
@@ -1767,7 +1674,7 @@ export function _createAndReEmitRoom(client, roomId, opts) {
|
|
|
1767
1674
|
* Also converts the events into `MatrixEvent`s, and emits the now deprecated {@link ClientEvent.ToDeviceEvent} events for compatibility.
|
|
1768
1675
|
* */
|
|
1769
1676
|
export function processToDeviceMessages(toDeviceMessages, client) {
|
|
1770
|
-
|
|
1677
|
+
const cancelledKeyVerificationTxns = [];
|
|
1771
1678
|
toDeviceMessages.map(processedMessage => {
|
|
1772
1679
|
// map is a cheap inline forEach
|
|
1773
1680
|
// We want to flag m.key.verification.start events as cancelled
|
|
@@ -1776,7 +1683,7 @@ export function processToDeviceMessages(toDeviceMessages, client) {
|
|
|
1776
1683
|
// so we can flag the verification events as cancelled in the loop
|
|
1777
1684
|
// below.
|
|
1778
1685
|
if (processedMessage.message.type === "m.key.verification.cancel") {
|
|
1779
|
-
|
|
1686
|
+
const txnId = processedMessage.message.content["transaction_id"];
|
|
1780
1687
|
if (txnId) {
|
|
1781
1688
|
cancelledKeyVerificationTxns.push(txnId);
|
|
1782
1689
|
}
|
|
@@ -1788,14 +1695,14 @@ export function processToDeviceMessages(toDeviceMessages, client) {
|
|
|
1788
1695
|
}).forEach(function (processedEvent) {
|
|
1789
1696
|
// For backwards compatibility, we also emit the event as a `MatrixEvent` using `ClientEvent.ToDeviceEvent`.
|
|
1790
1697
|
{
|
|
1791
|
-
|
|
1792
|
-
|
|
1698
|
+
const toDeviceEvent = processedEvent.message;
|
|
1699
|
+
const content = toDeviceEvent.content;
|
|
1793
1700
|
// The message is cloned before being passed to the MatrixEvent constructor, because
|
|
1794
1701
|
// the `makeEncrypted` method will mutate the type and content properties of the original message and will interfere
|
|
1795
1702
|
// with the emitted event for `ReceivedToDeviceMessage`.
|
|
1796
|
-
|
|
1703
|
+
const deprecatedCompatibilityEvent = new MatrixEvent(Object.assign({}, toDeviceEvent));
|
|
1797
1704
|
if (toDeviceEvent.type === "m.key.verification.start" || toDeviceEvent.type === "m.key.verification.request") {
|
|
1798
|
-
|
|
1705
|
+
const txnId = content["transaction_id"];
|
|
1799
1706
|
if (cancelledKeyVerificationTxns.includes(txnId)) {
|
|
1800
1707
|
deprecatedCompatibilityEvent.flagCancelled();
|
|
1801
1708
|
}
|