OverviewFilesCommitsIssuesDocsReleasesPeers

holepunchto-deps / @holepunchto / keet-core / lib / core / sync / loader.js

1 lines · javascript ref:
const t=require("ready-resource"),e=require("safety-catch"),i=require("b4a"),{KeetContractError:a}=require("../contract/errors"),{contract:{hyperschema:{getEnum:s}}}=require("../../../schema/spec"),o=s("@keet/room-type"),{restoreAvatar:n,restoreFile:l}=require("../contract/avatars"),{getMemberForDeviceKey:r}=require("../contract/query"),{getCall:h}=require("../../api/v1/helpers"),d=require("hypercore-id-encoding");function g(t,e){return t.clock-e.clock}module.exports=class extends t{constructor(t,i,a,{latestMessagesLimit:s=16,latestRoomsLimit:o=3}={}){super(),this.local=t,this.view=i,this.engine=a,this.latestMessagesLimit=s,this.latestRoomsLimit=o,this.syncTime=null,this.head=null,this.systemHead=null,this.output=null,this.input=null,this.system=null,this.core=null,this.legacyBlobs=null,this._loadingLocalPrivateProfileInfo=null,this._loadingLocalIdentityInfo=null,this._loadingLocalRoomInfo=null,this._loadingRoomUpdate=null,this._loadingLatestMessages=null,this._loadingLatestRooms=null,this._loadingLatestMembers=null,this._loadingLatestMessageDetails=null,this._loadingDigest=null,this._loadingConfig=null,this._loadingCapabilities=null,this._loadingIdentity=null,this._loadingPrimaryThread=null,this._loadingLastMessage=null,this._loadingDMMembers=null,this._loadingReadLengths=null,this._loadingWriterInfo=null,this._loadingChatChanges=null,this._loadingContactChanges=null,this._loadingSharedRoomChanges=null,this._loadingPendingInvitations=null,this.ready().catch(e)}_close(){return Promise.all([this.input.close(),this.output.close(),this.system.close()])}async _open(){await this.engine.loadMigratedViews(),this.view.db.update(),this.head=this.view.bee.head(),this.systemHead=this.engine.system.bee.head(),this.output=this.local.snapshot(),this.input=this.view.db.snapshot(),this.system=this.engine.system.snapshot(),this.legacyBlobs=this.engine.blobs,this.core=this.input.engine.db.core,this.syncTime=Date.now()}async _runLoadConfig(){const[t,e,a,s]=await Promise.all([this.loadLocalRoomInfo(),this.loadDigest(),this.loadSelfMember(),this.input.get("@keet/room-config")]);let l=s?.title||null,r=s?.avatar||null;if(a&&e?.settings.roomType===o.DirectMessage){const t=await this.input.find("@keet/members").toArray();for(const e of t)if(!i.equals(a.key,e.key)){l=e.profile.displayName,r=e.profile.avatar;break}}if(r){const e=t?.config?.avatar?.small?.hash,a=r?.small?.hash;e&&a&&i.equals(e,a)?s.avatar=t.config.avatar:await n(this.input,this.legacyBlobs,r)}return{...s,title:l,avatar:r}}async _runLoadSelfMember(){const t=await r(this.input,this.engine.local.key);if(!t)return null;const e=await this.input.get("@keet/member-proofs",{key:t.key}),i={...t,proofs:e};return i?.profile.avatar?(await n(this.input,this.legacyBlobs,i.profile.avatar),i):i}async _runLoadLastMessage(){const t=await this.loadPrimaryThread();if(!t||0===t.count)return null;const e={thread:0,index:t.count-1};return this.loadMessage(e)}async _runLoadDMMembers(){const[t,e]=await Promise.all([this.loadDigest(),this.loadSelfMember()]);if(!t||!e||t.settings.roomType!==o.DirectMessage)return[];const a=await this.input.find("@keet/members").toArray(),s=[];for(const t of a)i.equals(t.key,e.key)||s.push(t.key);return s}async _runLoadChatChanges(){const[t,e]=await Promise.all([this.loadLocalRoomInfo(),this.loadLastMessage()]),a=t?.lastMessage?.oplog.key,s=t?.lastMessage?.oplog.seq,o=e?.oplog.key,n=e?.oplog.seq;let l=!1;return l=!a||!(i.equals(a,o)&&s===n),{lastMessage:e,changed:l}}async _runLoadLatestMessages(){const t=await this.loadLocalIdentityInfo();return t&&i.equals(this.engine.key,t.privateProfileKey)?[]:this.input.find("@keet/chat",{gte:{id:{thread:0}},lte:{id:{thread:0}},limit:this.latestMessagesLimit,reverse:!0}).toArray()}_runLoadLatestRooms(){return this.input.find("@keet-private-id/rooms-by-clock",{limit:this.latestRoomsLimit,reverse:!0}).toArray()}async _runLoadLatestMessageDetails(){const[t,e]=await Promise.all([this.loadLatestMessages(),this.loadSelfMember()]);return this.closing||!t.length?[]:Promise.all(t.map(t=>this._loadMessageRecord(t,e)))}async _runLoadLatestMembers(){const t=await this.loadLatestMessages();if(this.closing||!t.length)return[];const e=[],i=[],a=new Set,s=new Set;for(const o of t){const t=d.encode(o.oplog.key);a.has(t)||(a.add(t),i.push(this._loadMemberForDeviceKey(s,e,o.oplog.key)))}return await Promise.all(i),e}async _loadMemberForDeviceKey(t,e,i){const a=await r(this.input,i);if(!a)return null;const s=d.encode(a.key);t.has(s)||(t.add(s),a.avatar&&await n(this.input,this.legacyBlobs,a.avatar),e.push(a))}async _loadFiles(t){const e=await Promise.all(t.map(t=>this.input.get("@keet/files",{id:t})));return await Promise.all(e.map(async t=>(await l(this.input,this.legacyBlobs,t.file.preview),t.file)))}async _loadMessageAnnotations(t,e){const[i,a,s]=await Promise.all([this.input.get("@keet/reaction-digests",{id:t}),this.input.get("@keet/chat-label-digests",{id:t}),e?this.input.find("@keet/chat-labels",{gte:{id:t,sender:e.key},lte:{id:t,sender:e.key}}).toArray():[]]);return{reactions:i,labels:a&&{digest:a,mine:s}}}async _loadMessageRefs(t){const e=t.message?.files,i=!!e&&e.length>0,[a,s,o]=await Promise.all([this.input.get("@keet/devices",{key:t.oplog.key}),r(this.input,t.oplog.key),i?this._loadFiles(e):null]),l=[];return await Promise.all([s?.profile.avatar?n(this.input,this.legacyBlobs,s.profile.avatar):null,this._loadRemovedMember(t,l)]),o&&(t.message.files=o),{device:a,member:s,otherMembers:l}}async _loadRemovedMember(t,e){if(!t.event?.memberRemoved?.memberKey)return;const i=await this.input.get("@keet/members",{key:t.event.memberRemoved.memberKey});i&&(i.profile.avatar&&await n(this.input,this.legacyBlobs,i.profile.avatar),e.push(i))}async _loadMessageRecord(t,e){const[i,a]=await Promise.all([this._loadMessageAnnotations(t.id,e),this._loadMessageRefs(t)]);return{message:t,...i,...a}}async _runLoadSharedRoomChanges(t){const e=[];for await(const{right:i}of this.input.diff("@keet-private-id/rooms",{from:t}))i&&e.push(i);return e.sort(g)}async _runLoadContactChanges(t){const e=[];for await(const{right:i}of this.input.diff("@keet-private-id/contacts",{from:t}))i&&(i.contactInfo?.profile.avatar&&await n(this.input,this.legacyBlobs,i.contactInfo.profile.avatar),e.push(i));return e.sort(g)}_runLoadPendingInvitations(){return this.input.find("@keet-private-id/pending-invitations").toArray()}async _runLoadLocalPrivateProfileInfo(){const t=await this.loadLocalIdentityInfo();return this.closing||!t?null:this.output.get("@local/rooms",{roomKey:t.privateProfileKey})}_runLoadReadLengths(){return this.input.find("@keet/read-lengths").toArray()}_runLoadActiveCall(){return h(this.input,"@keet/active-calls-by-timestamp")}_runLoadActiveCallDevice(t,e){return this.input.get("@keet/call-devices",{callKey:t,deviceKey:e})}loadRoomUpdate(){return this._loadingRoomUpdate||(this._loadingRoomUpdate=this.output.get("@local/room-updates",{roomKey:this.engine.key}),this._loadingRoomUpdate.catch(e)),this._loadingRoomUpdate}loadLocalRoomInfo(){return this._loadingLocalRoomInfo||(this._loadingLocalRoomInfo=this.output.get("@local/rooms",{roomKey:this.engine.key}),this._loadingLocalRoomInfo.catch(e)),this._loadingLocalRoomInfo}loadLocalPrivateProfileInfo(){return this._loadingLocalPrivateProfileInfo||(this._loadingLocalPrivateProfileInfo=this._runLoadLocalPrivateProfileInfo(),this._loadingLocalPrivateProfileInfo.catch(e)),this._loadingLocalPrivateProfileInfo}loadLocalIdentityInfo(){return this._loadingLocalIdentityInfo||(this._loadingLocalIdentityInfo=this.output.get("@local/identity"),this._loadingLocalIdentityInfo.catch(e)),this._loadingLocalIdentityInfo}loadDigest(){return this._loadingDigest||(this._loadingDigest=this.input.get("@keet/system-digest"),this._loadingDigest.catch(e)),this._loadingDigest}loadConfig(){return this._loadingConfig||(this._loadingConfig=this._runLoadConfig(),this._loadingConfig.catch(e)),this._loadingConfig}loadCapabilities(){return this._loadingCapabilities||(this._loadingCapabilities=this.input.get("@keet/room-capabilities"),this._loadingCapabilities.catch(e)),this._loadingCapabilities}loadPrimaryThread(){return this._loadingPrimaryThread||(this._loadingPrimaryThread=this.input.get("@keet/threads",{id:0}),this._loadingPrimaryThread.catch(e)),this._loadingPrimaryThread}loadSelfDevice(){return this._loadingSelfDevice||(this._loadingSelfDevice=this.input.get("@keet/devices",{key:this.engine.local.key}),this._loadingSelfDevice.catch(e)),this._loadingSelfDevice}loadWriterInfo(){return this._loadingWriterInfo||(this._loadingWriterInfo=this.system.get(this.engine.local.key),this._loadingWriterInfo.catch(e)),this._loadingWriterInfo}loadSelfMember(){return this._loadingSelfMember||(this._loadingSelfMember=this._runLoadSelfMember(),this._loadingSelfMember.catch(e)),this._loadingSelfMember}loadLastMessage(){return this._loadingLastMessage||(this._loadingLastMessage=this._runLoadLastMessage(),this._loadingLastMessage.catch(e)),this._loadingLastMessage}loadDMMembers(){return this._loadingDMMembers||(this._loadingDMMembers=this._runLoadDMMembers(),this._loadingDMMembers.catch(e)),this._loadingDMMembers}loadIdentity(){return this._loadingIdentity||(this._loadingIdentity=this.input.get("@keet-private-id/identity"),this._loadingIdentity.catch(e)),this._loadingIdentity}loadSettings(){return this._loadSettings||(this._loadSettings=this.input.get("@keet-private-id/settings"),this._loadSettings.catch(e)),this._loadSettings}loadChatChanges(){return this._loadingChatChanges||(this._loadingChatChanges=this._runLoadChatChanges(),this._loadingChatChanges.catch(e)),this._loadingChatChanges}loadContactChanges(t){return this._loadingContactChanges||(this._loadingContactChanges=this._runLoadContactChanges(t),this._loadingContactChanges.catch(e)),this._loadingContactChanges}loadSharedRoomChanges(t){return this._loadingSharedRoomChanges||(this._loadingSharedRoomChanges=this._runLoadSharedRoomChanges(t),this._loadingSharedRoomChanges.catch(e)),this._loadingSharedRoomChanges}loadPendingInvitations(){return this._loadingPendingInvitations||(this._loadingPendingInvitations=this._runLoadPendingInvitations(),this._loadingPendingInvitations.catch(e)),this._loadingPendingInvitations}loadLatestMessages(){return this._loadingLatestMessages||(this._loadingLatestMessages=this._runLoadLatestMessages(),this._loadingLatestMessages.catch(e)),this._loadingLatestMessages}loadLatestRooms(){return this._loadingLatestRooms||(this._loadingLatestRooms=this._runLoadLatestRooms(),this._loadingLatestRooms.catch(e)),this._loadingLatestRooms}loadLatestMessageDetails(){return this._loadingLatestMessageDetails||(this._loadingLatestMessageDetails=this._runLoadLatestMessageDetails(),this._loadingLatestMessageDetails.catch(e)),this._loadingLatestMessageDetails}loadLatestMembers(){return this._loadingLatestMembers||(this._loadingLatestMembers=this._runLoadLatestMembers(),this._loadingLatestMembers.catch(e)),this._loadingLatestMembers}loadReadLengths(){return this._loadingReadLengths||(this._loadingReadLengths=this._runLoadReadLengths(),this._loadingReadLengths.catch(e)),this._loadingReadLengths}loadActiveCall(){return this._loadingActiveCall||(this._loadingActiveCall=this._runLoadActiveCall(),this._loadingActiveCall.catch(e)),this._loadingActiveCall}loadActiveCallDevice(t,i){return this._loadingActiveCallDevice||(this._loadingActiveCallDevice=this._runLoadActiveCallDevice(t,i),this._loadingActiveCallDevice.catch(e)),this._loadingActiveCallDevice}loadPreferences(){return this._loadingPreferences||(this._loadingPreferences=this.local.get("@local/room-preferences",{roomKey:this.engine.key}),this._loadingPreferences.catch(e)),this._loadingPreferences}async loadLabels(t){const e=await this.loadSelfMember(),{labels:i}=await this._loadMessageAnnotations(t,e);return i}async loadMessage(t){const e=await this.loadSelfMember(),[i,s]=await Promise.all([this.input.get("@keet/chat",{id:t}),this._loadMessageAnnotations(t,e)]);if(!i)return null;const o=await this._loadMessageRefs(i);if(!o.member)throw a.CORRUPT("Last chat message does not have a member");return{message:i,...s,...o}}};