From b582d994754036cf41787f1fd21db3734deeac44 Mon Sep 17 00:00:00 2001 From: balzack Date: Mon, 30 Sep 2024 23:53:19 -0700 Subject: [PATCH] implementing contact module --- app/sdk/src/contact.ts | 137 +++++++++++++++++++++++++++++++++-------- app/sdk/src/items.ts | 11 ++-- app/sdk/src/store.ts | 24 ++++---- app/sdk/src/types.ts | 32 +++++----- 4 files changed, 145 insertions(+), 59 deletions(-) diff --git a/app/sdk/src/contact.ts b/app/sdk/src/contact.ts index 25f87934..be31d71e 100644 --- a/app/sdk/src/contact.ts +++ b/app/sdk/src/contact.ts @@ -21,13 +21,13 @@ export class ContactModule implements Contact { private closing: boolean; // view of cards - private cardEntries: Map + private cardEntries: Map // view of articles - private articleEntries: Map> + private articleEntries: Map> // view of channels - private channelEntries: Map>; + private channelEntries: Map>; constructor(log: Logging, store: Store, guid: string, token: string, node: string, secure: boolean) { this.guid = guid; @@ -37,6 +37,11 @@ export class ContactModule implements Contact { this.log = log; this.emitter = new EventEmitter(); + this.cardGuid = new Map(); + this.cardEntries = new Map(); + this.articleEntries = new Map>; + this.channelEntries = new Map>; + this.revision = 0; this.sycning = true; this.closing = false; @@ -44,7 +49,90 @@ export class ContactModule implements Contact { this.init(); } + private setCard(cardId: string, item: CardItem): Card { + const { offsync, blocked, profile, detail } = item; + const { guid, handle, name, description, location, imageSet, node } = profile; + const { status, statusUpdated } = detail; + return { cardId, offsync, blocked, status, statusUpdated, guid, handle, name, description, location, imageSet, node }; + } + + private setArticle(cardId: string, articleId: string, item: ArticleItem): Article { + const { unread, blocked, detail, unsealedData } = item; + const { dataType, sealed, data, created, updated } = detail; + const articleData = sealed ? unsealedData : data; + return { cardId, articleId, dataType, articleData, created, updated, status }; + } + + private setChannel(cardId: string, channelId: string, item: ChannelItem): Channel { + const { blocked, summary, detail, unsealedChannelData, unsealedTopicData } = item; + const { enableImage, enableAudio, enableVideo, enableBinary, members } = detail; + const channelData = detail.sealed ? unsealedChannelData : detail.data; + const { guid, status, transform } = summary; + const topicData = summary.sealed ? unsealedTopicData : summary.data; + + const { pushEnabled } = members.find(({ member }) => (member === this.guid)) | {} + const contacts = members.filter(({ member }) => (member != this.guid)).map(({ member, pushEnabled }) => { guid: member, pushEnabled }); + + return { + channelId, + cardId, + lastTopic: { + guid, + sealed: summary.sealed, + dataType: summary.dataType, + data: topicData, + created: summary.created, + updated: summary.updated, + status, + transform, + }, + unread, + sealed: channelSealed, + dataType: detail.dataType, + data: channelData, + created: detail.created, + updated: detail.updated, + enableImage, + enableAudio, + enableVideo, + enableBinary, + membership: { pushEnabled }, + members: contacts, + }; + } + private async init() { + this.revision = await this.store.getContactRevision(this.guid); + + // load map of cards + const cards = await this.store.getContacts(this.guid); + cards.forEach(({ cardId, item }) => { + const card = setCard(cardId, item); + this.cardEntries.set(cardId, { item, card }); + }) + + // load map of articles + const articles = await this.store.getContactCardArticles(this.guid); + articles.forEach(({ cardId, articleId, item }) => { + if (!this.articleEntries.has(cardId)) { + this.articleEntries.set(cardId, new Map>); + } + const article = setArticle(cardId, articleId, item); + this.articleEntries.set(cardId).set(articleId, { item, article }); + }); + + // load map of channels + const channels = await this.store.getContactCardChannles(this.guid); + channels.forEach(({ cardId, channelId, item }) => { + if (!this.channelEntries.has(cardId)) { + this.channelEntries.set(cardId, new Map>); + } + const channel = setChannel(cardId, channelId, item); + this.channelEntries.set(cardId).set(channelId, { item, channel }); + }); + + this.syncing = false; + await this.sync(); } private async sync(): Promise { @@ -52,7 +140,7 @@ export class ContactModule implements Contact { public addCardListener(ev: (cards: Card[]) => void): void { this.emitter.on('card', ev); - const cards = Array.from(cardEntries, ([cardId, entry]) => (entry.card)); + const cards = Array.from(this.cardEntries, ([cardId, entry]) => (entry.card)); ev(cards); } @@ -60,7 +148,8 @@ export class ContactModule implements Contact { this.emitter.off('card', ev); } - private emitCards(cards: Card[]) { + private emitCards() { + const cards = Array.from(this.cardEntries, ([cardId, entry]) => (entry.card)); this.emitter.emit('card', cards); } @@ -69,10 +158,8 @@ export class ContactModule implements Contact { const cardId = id as string; this.emitter.on(`article::${cardId}`, ev); const entries = this.articleEntries.get(cardId); - if (entries) { - const articles = Array.from(entries, ([articleId, entry]) => (entry.article)); - ev({ cardId, articles }); - } + const articles = entries ? Array.from(entries, ([articleId, entry]) => (entry.article)) : []; + ev({ cardId, articles }); } else { this.emitter.on('article', ev); this.articleEntries.forEach((entries, cardId) => { @@ -91,21 +178,20 @@ export class ContactModule implements Contact { } } - private emitArticles(cardId: string, articles: Article[]) { + private emitArticles(cardId: string) { + const entries = this.articleEntries.get(cardId); + const articles = entries ? Array.from(entries, ([articleId, entry]) => (entry.article)) : []; this.emitter.emit('article', { cardId, articles }); this.emitter.emit(`article::${cardId}`, { cardId, articles }); } public addChannelListener(id: string | null, ev: (arg: { cardId: string, channels: Channel[] }) => void): void { - if (id) { const cardId = id as string; this.emitter.on(`channel::${cardId}`, ev); const entries = this.channelEntries.get(cardId); - if (entries) { - const channels = Array.from(entries, ([channelId, entry]) => (entry.channel)); - ev({ cardId, channels }); - } + const channels = entries ? Array.from(entries, ([channelId, entry]) => (entry.channel)) : []; + ev({ cardId, channels }); } else { this.emitter.on('channel', ev); this.channelEntries.forEach((entries, cardId) => { @@ -124,28 +210,29 @@ export class ContactModule implements Contact { } } - private emitChannels(cardId: string, channels: Channel[]) { + private emitChannels(cardId: string) { + const entries = this.channelEntries.get(cardId); + const channels = entries ? Array.from(entries, ([channelId, entry]) => (entry.channel)) : []; this.emitter.emit('channel', { cardId, channels }); this.emitter.emit(`channel::${cardId}`, { cardId, channels }); } public addTopicRevisionListener(cardId: string, channelId: string, ev: (arg: { cardId: string, channelId: string, revision: number }) => void): void { this.emitter.on(`revision::${cardId}::${channelId}`, ev); - const card = this.channelEntries.get(cardId); - if (card) { - const channel = card.get(channelId); - if (channel) { - const revision = channel.revision.topic; - ev({ cardId, channelId, revision }); - } - } + const entries = this.channelEntries.get(cardId); + const entry = entries ? entries.get(channelId) : null; + const revision = entry ? entry.revision.topic : 0; + ev({ cardId, channelId, revision }); } public removeTopicRevisionListener(cardId: string, channelId: string, ev: (arg: { cardId: string, channelId: string, revision: number }) => void): void { this.emitter.off(`revision::${cardId}::${channelId}`, ev); } - public emitTopicRevision(cardId: string, channelId: string, revision: number) { + public emitTopicRevision(cardId: string, channelId: string) { + const entries = this.channelEntries.get(cardId); + const entry = entries ? entries.get(channelId) : null; + const revision = entry ? entry.revision.topic : 0; this.emitter.emit(`revision::${cardId}::${channelId}`, revision); } diff --git a/app/sdk/src/items.ts b/app/sdk/src/items.ts index 3a987de5..e26ad6b2 100644 --- a/app/sdk/src/items.ts +++ b/app/sdk/src/items.ts @@ -43,6 +43,7 @@ export type ChannelSummary = { export type ChannelDetail = { revision: number, + sealed: boolean, dataType: string, data: string, created: number, @@ -66,6 +67,7 @@ export type ArticleRevision = { } export type ArticleDetail = { + sealed: boolean, dataType: string, data: string, created: number, @@ -78,7 +80,6 @@ export type ArticleDetail = { } export type CardItem = { - cardId: string, offsync: boolean, blocked: boolean, revision: CardRevision, @@ -89,8 +90,6 @@ export type CardItem = { } export type ArticleItem = { - cardId: string | null, - articleId: string, blocked: boolean, detail: ArticleDetail, unsealedData: any, @@ -98,11 +97,11 @@ export type ArticleItem = { } export type ChannelItem = { - cardId: string | null, - channelId: string, + unread: boolean, blocked: boolean, summary: ChannelSummary, detail: ChannelDetail, - unsealedData: any, + unsealedChannelData: any, + unsealedTopicData: any, revision: ChannelRevision, } diff --git a/app/sdk/src/store.ts b/app/sdk/src/store.ts index 0d801b82..1260047a 100644 --- a/app/sdk/src/store.ts +++ b/app/sdk/src/store.ts @@ -24,7 +24,7 @@ export interface Store { getContactRevision(guid: string): Promise; setContactRevision(guid: string, revision: number): Promise; - getContacts(guid: string): Promise; + getContacts(guid: string): Promise<{ cardId: string, item: CardItem }[]>; setContactCardRevision(guid: string, cardId: string, revision: CardRevision): Promise; setContactCardProfile(guid: string, cardId: string, profile: CardProfile): Promise; setContactCardDetail(guid: string, cardId: string, detail: CardDetail): Promise; @@ -34,12 +34,12 @@ export interface Store { setContactCardSyncRevision(guid: string, cardId: string, notification: CardNotification): Promise; setContactCardOffsync(guid: string, cardId: string, offsync: boolean): Promise; - getContactCardArticles(guid: string): Promise; + getContactCardArticles(guid: string): Promise<{ cardId: string, articleId: string, item: ArticleItem }[]>; setContactCardArticleRevision(guid: string, cardId: string, articleId: string, revision: ArticleRevision): Promise; setContactCardArticleDetail(guid: string, cardId: string, articleId: string, detail: ChannelDetail, unsealedData: any): Promise; setContactCardArticleUnsealed(guid: string, cardId: string, articleId: string, unsealedData: any): Promise; - getContactCardChannels(guid: string): Promise; + getContactCardChannels(guid: string): Promise<{ cardId: string, channelId: string, item: ChannelItem }[]>; setContactCardChannelBlocked(guid: string, cardId: string, channelId: string, blocked: boolean): Promise; setContactCardChannelRevision(guid: string, cardId: string, channelId: string, revision: ChannelRevision): Promise; setContactCardChannelSummary(guid: string, cardId: string, channelId: string, summary: ChannelSummary): Promise; @@ -166,7 +166,7 @@ export class OfflineStore implements Store { public async setContactRevision(guid: string, revision: number): Promise { } - public async getContacts(guid: string): Promise { + public async getContacts(guid: string): Promise<{ cardId: string, item: CardItem }[]> { return []; } @@ -191,7 +191,7 @@ export class OfflineStore implements Store { public async setContactCardOffsync(guid: string, cardId: string, offsync: boolean): Promise { } - public async getContactCardArticles(guid: string): Promise { + public async getContactCardArticles(guid: string): Promise<{ cardId: string, articleId: string, item: ArticleItem }[]> { return []; } @@ -204,7 +204,7 @@ export class OfflineStore implements Store { public async setContactCardArticleUnsealed(guid: string, cardId: string, articleId: string, unsealedData: any): Promise { } - public async getContactCardChannels(guid: string): Promise { + public async getContactCardChannels(guid: string): Promise<{ cardId: string, channelId: string, item: ChannelItem }[]> { return []; } @@ -315,7 +315,7 @@ export class OnlineStore implements Store { public async setContactRevision(guid: string, revision: number): Promise { } - public async getContacts(guid: string): Promise { + public async getContacts(guid: string): Promise<{ cardId: string, item: CardItem }[]> { return []; } @@ -340,7 +340,7 @@ export class OnlineStore implements Store { public async setContactCardOffsync(guid: string, cardId: string, offsync: boolean): Promise { } - public async getContactCardArticles(guid: string): Promise { + public async getContactCardArticles(guid: string): Promise<{ cardId: string, articleId: string, item: ArticleItem }[]> { return []; } @@ -353,7 +353,7 @@ export class OnlineStore implements Store { public async setContactCardArticleUnsealed(guid: string, cardId: string, articleId: string, unsealedData: any): Promise { } - public async getContactCardChannels(guid: string): Promise { + public async getContactCardChannels(guid: string): Promise<{ cardId: string, channelId: string, item: ChannelItem }[]> { return []; } @@ -438,7 +438,7 @@ export class NoStore implements Store { public async setContactRevision(guid: string, revision: number): Promise { } - public async getContacts(guid: string): Promise { + public async getContacts(guid: string): Promise<{ cardId: string, item: CardItem }[]> { return []; } @@ -463,7 +463,7 @@ export class NoStore implements Store { public async setContactCardOffsync(guid: string, cardId: string, offsync: boolean): Promise { } - public async getContactCardArticles(guid: string): Promise { + public async getContactCardArticles(guid: string): Promise<{ cardId: string, articleId: string, item: ArticleItem }[]> { return []; } @@ -476,7 +476,7 @@ export class NoStore implements Store { public async setContactCardArticleUnsealed(guid: string, cardId: string, articleId: string, unsealedData: any): Promise { } - public async getContactCardChannels(guid: string): Promise { + public async getContactCardChannels(guid: string): Promise<{ cardId: string, channelId: string, item: ChannelItem }[]> { return []; } diff --git a/app/sdk/src/types.ts b/app/sdk/src/types.ts index e40fabe5..19675f1c 100644 --- a/app/sdk/src/types.ts +++ b/app/sdk/src/types.ts @@ -1,5 +1,7 @@ export type Card = { - id: string, + cardId: string, + offsync: boolean, + blocked: boolean, status: string, statusUpdated: number, guid: string, @@ -34,10 +36,11 @@ export type Activity = { } export type Channel = { - id: string, + channelId: string, cardId: string | null, lastTopic: { guid: string, + sealed: boolean, dataType: string, data: string, created: number, @@ -47,9 +50,8 @@ export type Channel = { } unread: boolean, sealed: boolean, - unsealed: boolean; dataType: string, - data: any, + data: string, created: number, updated: number, enableImage: boolean, @@ -61,16 +63,15 @@ export type Channel = { } export type Member = { - id: string, - guid: string, + guid?: string, pushEnabled: boolean, - canAddTopic: boolean, - canAddTag: boolean, - canAddAsset: boolean, - canAddParticipant: boolean, - canSortTopic: boolean, - canSortTag: boolean, - participants: Participant[]; + //canAddTopic: boolean, + //canAddTag: boolean, + //canAddAsset: boolean, + //canAddParticipant: boolean, + //canSortTopic: boolean, + //canSortTag: boolean, + //participants: Participant[]; } export type Participant = { @@ -127,11 +128,10 @@ export type Group = { } export type Article = { - id: string, + articleId: string, sealed: boolean, - unsealed: boolean, dataType: string, - data: string, + data?: string, created: number, updated: number, contacts?: {