diff --git a/app/client/mobile/src/context/useAppContext.hook.ts b/app/client/mobile/src/context/useAppContext.hook.ts index a414ee5d..6574172a 100644 --- a/app/client/mobile/src/context/useAppContext.hook.ts +++ b/app/client/mobile/src/context/useAppContext.hook.ts @@ -3,7 +3,7 @@ import {DatabagSDK, Session} from 'databag-client-sdk'; import {SessionStore} from '../SessionStore'; import {NativeCrypto} from '../NativeCrypto'; import {LocalStore} from '../LocalStore'; -const DATABAG_DB = 'db_v214.db'; +const DATABAG_DB = 'db_v215.db'; const SETTINGS_DB = 'ls_v001.db'; const databag = new DatabagSDK( diff --git a/app/sdk/README.md b/app/sdk/README.md index 3b4434b9..93475a69 100644 --- a/app/sdk/README.md +++ b/app/sdk/README.md @@ -122,14 +122,10 @@ Automate allocates the Bot interface for ia specific communication channel ```Session::getAttribute(): Attribute``` - Account content channels are managed through the Content Interface + Account and Contact channels are managed through the Content Interface ```Session::getContent(): Content``` - An aggregation of content channels provided by contacts is managed through the Stream Interface - - ```Session::getStream(): Stream``` - WebRTC calling is managed through the Ring Interface ```Session::getRing(): Ring``` diff --git a/app/sdk/__mocks__/content.ts b/app/sdk/__mocks__/stream.ts similarity index 95% rename from app/sdk/__mocks__/content.ts rename to app/sdk/__mocks__/stream.ts index cf072942..270e5e32 100644 --- a/app/sdk/__mocks__/content.ts +++ b/app/sdk/__mocks__/stream.ts @@ -1,8 +1,7 @@ import { EventEmitter } from 'eventemitter3'; -import type { Content } from '../src/api'; import type { Channel, Topic, Asset, Tag, Participant } from '../src/types'; -export class MockContentModule implements Content { +export class MockStreamModule { public revision: number; private emitter: EventEmitter; diff --git a/app/sdk/__tests__/session.tests.ts b/app/sdk/__tests__/session.tests.ts index ed5f9cf2..9abeabaa 100644 --- a/app/sdk/__tests__/session.tests.ts +++ b/app/sdk/__tests__/session.tests.ts @@ -5,7 +5,7 @@ import { MockConnection } from '../__mocks__/connection'; import { MockSettingsModule } from '../__mocks__/settings'; import { MockIdentityModule } from '../__mocks__/identity'; import { MockAliasModule } from '../__mocks__/alias'; -import { MockContentModule } from '../__mocks__/content'; +import { MockStreamModule } from '../__mocks__/stream'; import { MockContactModule } from '../__mocks__/contact'; import { MockAttributeModule } from '../__mocks__/attribute'; import { MockRingModule } from '../__mocks__/ring'; @@ -49,11 +49,11 @@ jest.mock('../src/identity', () => { } }) -const mockContent = new MockContentModule(); -jest.mock('../src/content', () => { +const mockStream = new MockStreamModule(); +jest.mock('../src/stream', () => { return { - ContentModule: jest.fn().mockImplementation(() => { - return mockContent; + StreamModule: jest.fn().mockImplementation(() => { + return mockStream; }) } }) @@ -109,7 +109,7 @@ test('allocates session correctly', async () => { await waitFor(() => (mockRing.call?.callId === 'test')); await waitFor(() => (mockSettings.revision == 3)); await waitFor(() => (mockIdentity.revision == 3)); - await waitFor(() => (mockContent.revision == 3)); + await waitFor(() => (mockStream.revision == 3)); await waitFor(() => (mockContact.revision == 3)); await waitFor(() => (mockAttribute.revision == 3)); await waitFor(() => (mockAlias.revision == 3)); diff --git a/app/sdk/src/api.ts b/app/sdk/src/api.ts index 6132f54d..32b4af7a 100644 --- a/app/sdk/src/api.ts +++ b/app/sdk/src/api.ts @@ -6,7 +6,7 @@ export interface Session { getContact(): Contact; getAlias(): Alias; getAttribute(): Attribute; - getStream(): Stream; + getContent(): Content; getRing(): Ring; setFocus(cardId: string | null, channelId: string): Promise; @@ -93,23 +93,6 @@ export interface Content { setChannelSubject(channelId: string, subject: string): Promise; setChannelCard(channelId: string, cardId: string): Promise; clearChannelCard(channelId: string, cardId: string): Promise; - setBlockedChannel(channelId: string, blocked: boolean): Promise; - getBlockedChannels(): Promise; - flagChannel(channelId: string): Promise; - getChannelNotifications(channelId: string): Promise; - setChannelNotifications(channelId: string, enabled: boolean): Promise; - setUnreadChannel(channelId: string, unread: boolean): Promise; - - addChannelListener(ev: (arg: { channels: Channel[], cardId: string | null }) => void): void; - removeChannelListener(ev: (arg: { channels: Channel[], cardId: string | null }) => void): void; -} - -export interface Stream { - addChannel(sealed: boolean, type: string, subject: string, cardIds: string[]): Promise; - removeChannel(channelId: string): Promise; - setChannelSubject(channelId: string, subject: string): Promise; - setChannelCard(channelId: string, cardId: string): Promise; - clearChannelCard(channelId: string, cardId: string): Promise; leaveChannel(cardId: string, channelId: string): Promise; diff --git a/app/sdk/src/content.ts b/app/sdk/src/content.ts index 7f553f84..205a1b37 100644 --- a/app/sdk/src/content.ts +++ b/app/sdk/src/content.ts @@ -1,121 +1,92 @@ -import { EventEmitter } from 'eventemitter3'; -import type { Content, Logging, Focus } from './api'; -import { FocusModule } from './focus'; -import type { ChannelItem } from './items'; -import type { Channel, Topic, Asset, Tag, Participant } from './types'; -import { Store } from './store'; -import { Crypto } from './crypto'; +import type { Content } from './api'; +import type { Channel } from './types'; +import { ContactModule } from './contact'; +import { StreamModule } from './stream'; +import { Logging } from './logging'; export class ContentModule implements Content { private log: Logging; - private store: Store; - private crypto: Crypto | null; - private guid: string; - private token: string; - private node: string; - private secure: boolean; - private emitter: EventEmitter; - private focus: Focus | null; - private revision: number; - private syncing: boolean; - private closing: boolean; - private nextRevision: number | null; + private contact: ContactModule; + private stream: StreamModule; - // view of channels - private channelEntries: Map; - - constructor(log: Logging, store: Store, crypto: Crypto | null, guid: string, token: string, node: string, secure: boolean) { - this.guid = guid; - this.token = token; - this.node = node; - this.secure = secure; + constructor(log: Logging, contact: ContactModule, stream: StreamModule) { + this.contact = contact; + this.stream = stream; this.log = log; - this.store = store; - this.crypto = crypto; - this.focus = null; - this.emitter = new EventEmitter(); - - this.channelEntries = new Map(); - - this.revision = 0; - this.syncing = true; - this.closing = false; - this.nextRevision = null; - this.init(); - } - - private async init() { } - - private async sync() { } - - public addChannelListener(ev: (arg: { channels: Channel[], cardId: string | null }) => void): void { - this.emitter.on('channel', ev); - const channels = Array.from(this.channelEntries, ([channelId, entry]) => entry.channel); - ev({ channels, cardId: null }); - } - - public removeChannelListener(ev: (arg: { channels: Channel[], cardId: string | null }) => void): void { - this.emitter.off('channel', ev); - } - - private emitChannels() { - const channels = Array.from(this.channelEntries, ([channelId, entry]) => entry.channel); - this.emitter.emit('channel', { channels, cardId: null }); - } - - public async close(): void {} - - public async setRevision(rev: number): Promise { - console.log('set content revision:', rev); } public async addChannel(sealed: boolean, type: string, subject: string, cardIds: string[]): Promise { - return ''; + return await this.stream.addChannel(sealed, type, subject, cardIds); } - public async removeChannel(channelId: string): Promise { } - - setChannelSubject(channelId: string, subject: string): Promise { } - - setChannelCard(channelId: string, cardId: string): Promise { } - - clearChannelCard(channelId: string, cardId: string): Promise { } - - setBlockedChannel(channelId: string, blocked: boolean): Promise { } - - getBlockedChannels(): Promise { - return []; + public async removeChannel(channelId: string): Promise { + return await this.stream.removeChannel(channelId); } - flagChannel(channelId: string): Promise { } - - getChannelNotifications(channelId: string): Promise { - return false; + public async setChannelSubject(channelId: string, subject: string): Promise { + return await this.stream.setChannelSubject(channelId, subject); } - setChannelNotifications(channelId: string, enabled: boolean): Promise { } + public async setChannelCard(channelId: string, cardId: string): Promise { + return await this.stream.setChannelCard(channelId, cardId); + } - setUnreadChannel(channelId: string, unread: boolean): Promise { } + public async clearChannelCard(channelId: string, cardId: string): Promise { + return await this.stream.clearChannelCard(channelId, cardId); + } - public async setFocus(chanenlId: string): Promise { - const { node, secure, token, focus } = this; - if (focus) { - await focus.close(); + public async leaveChannel(cardId: string, channelId: string): Promise { + return await this.contact.leaveChannel(cardId, channelId) + } + + public async getChannelNotifications(cardId: string | null, channelId: string): Promise { + if (cardId) { + return await this.contact.getChannelNotifications(cardId, channelId); } - this.focus = new FocusModule(this.log, this.store, this.crypto, null, channelId, { node, secure, token }); - return this.focus; + return await this.stream.getChannelNotifications(channelId) } - - public async clearFocus() { - if (this.focus) { - await this.focus.close(); + + public async setChannelNotifications(cardId: string | null, channelId: string, enabled: boolean): Promise { + if (cardId) { + return await this.contact.setChannelNotifications(cardId, channelId, enabled) } - this.focus = null; + return await this.stream.setChannelNotifications(channelId, enabled); } - public async setSeal(seal: { privateKey: string; publicKey: string } | null) { - this.seal = seal; - this.unsealAll = true; - await this.sync(); + public async setUnreadChannel(cardId: string | null, channelId: string, unread: boolean): Promise { + if (cardId) { + return await this.contact.setUnreadChannel(cardId, channelId, unread); + } + return await this.stream.setUnreadChannel(channelId, unread); + } + + public async flagChannel(cardId: string, channelId: string): Promise { + if (cardId) { + return await this.contact.flagChannel(cardId, channelId); + } + return await this.stream.flagChannel(channelId); + } + + public async setBlockedChannel(cardId: string | null, channelId: string, blocked: boolean): Promise { + if (cardId) { + return await this.contact.setBlockedChannel(cardId, channelId, blocked); + } + return await this.stream.setBlockedChannel(channelId, blocked); + } + + public async getBlockedChannels(): Promise { + const channels = await this.stream.getBlockedChannels(); + const cardChannels = await this.contact.getBlockedChannels(); + return channels.concat(cardChannels); + } + + public addChannelListener(ev: (arg: { channels: Channel[], cardId: string | null }) => void): void { + this.stream.addChannelListener(ev); + this.contact.addChannelListener(ev); + } + + public removeChannelListener(ev: (arg: { channels: Channel[], cardId: string | null }) => void): void { + this.stream.removeChannelListener(ev); + this.contact.removeChannelListener(ev); } } diff --git a/app/sdk/src/session.ts b/app/sdk/src/session.ts index 5c905f6b..5c0e3ecd 100644 --- a/app/sdk/src/session.ts +++ b/app/sdk/src/session.ts @@ -12,7 +12,7 @@ import { RingModule } from './ring'; import { Connection } from './connection'; -import type { Session, Settings, Identity, Contact, Ring, Alias, Attribute, Content, Stream, Focus } from './api'; +import type { Session, Settings, Identity, Contact, Ring, Alias, Attribute, Content, Focus } from './api'; import { Revision } from './entities'; import { Call } from './types'; import { Store } from './store'; @@ -63,8 +63,8 @@ export class SessionModule implements Session { this.contact = new ContactModule(log, this.store, this.crypto, guid, token, node, secure, channelTypes, articleTypes); this.alias = new AliasModule(log, this.settings, this.store, guid, token, node, secure); this.attribute = new AttributeModule(log, this.settings, this.store, guid, token, node, secure); - this.content = new ContentModule(log, this.store, this.crypto, guid, token, node, secure); - this.stream = new StreamModule(log, this.contact, this.content); + this.stream = new StreamModule(log, this.store, this.crypto, guid, token, node, secure); + this.content = new ContentModule(log, this.contact, this.stream); this.ring = new RingModule(log); this.connection = new Connection(log, token, node, secure); @@ -75,7 +75,7 @@ export class SessionModule implements Session { const onSeal = (seal: { privateKey: string; publicKey: string } | null) => { this.contact.setSeal(seal); - this.content.setSeal(seal); + this.stream.setSeal(seal); }; const onRevision = async (ev: Revision) => { @@ -84,7 +84,7 @@ export class SessionModule implements Session { await this.contact.setRevision(ev.card); await this.attribute.setRevision(ev.article); await this.alias.setRevision(ev.group); - await this.content.setRevision(ev.channel); + await this.stream.setRevision(ev.channel); }; const onRing = (ev: Call) => { @@ -115,7 +115,7 @@ export class SessionModule implements Session { } public async close(): Promise { - await this.content.close(); + await this.stream.close(); await this.attribute.close(); await this.alias.close(); await this.contact.close(); @@ -144,8 +144,8 @@ export class SessionModule implements Session { return this.attribute; } - public getStream(): Stream { - return this.stream; + public getContent(): Content { + return this.content; } public getRing(): Ring { @@ -156,11 +156,11 @@ export class SessionModule implements Session { if (cardId) { return await this.contact.setFocus(cardId, channelId); } - return await this.content.setFocus(channelId); + return await this.stream.setFocus(channelId); } public async clearFocus(): Promise { await this.contact.clearFocus(); - await this.content.clearFocus(); + await this.stream.clearFocus(); } } diff --git a/app/sdk/src/stream.ts b/app/sdk/src/stream.ts index 49b25923..1f21fe91 100644 --- a/app/sdk/src/stream.ts +++ b/app/sdk/src/stream.ts @@ -1,90 +1,126 @@ -import type { Contact, Content, Stream } from './api'; -import type { Channel } from './types'; +import { EventEmitter } from 'eventemitter3'; +import type { Content, Focus } from './api'; import { Logging } from './logging'; +import { FocusModule } from './focus'; +import type { ChannelItem } from './items'; +import type { Channel, Topic, Asset, Tag, Participant } from './types'; +import { Store } from './store'; +import { Crypto } from './crypto'; -export class StreamModule implements Stream { +export class StreamModule { private log: Logging; - private contact: Contact; - private content: Content; + private store: Store; + private crypto: Crypto | null; + private guid: string; + private token: string; + private node: string; + private secure: boolean; + private emitter: EventEmitter; + private focus: FocusModule | null; + private revision: number; + private syncing: boolean; + private closing: boolean; + private nextRevision: number | null; + private seal: { privateKey: string; publicKey: string } | null; + private unsealAll: boolean; - constructor(log: Logging, contact: Contact, content: Content) { - this.contact = contact; - this.content = content; + // view of channels + private channelEntries: Map; + + constructor(log: Logging, store: Store, crypto: Crypto | null, guid: string, token: string, node: string, secure: boolean) { + this.guid = guid; + this.token = token; + this.node = node; + this.secure = secure; this.log = log; + this.store = store; + this.crypto = crypto; + this.focus = null; + this.seal = null; + this.unsealAll = false; + this.emitter = new EventEmitter(); + + this.channelEntries = new Map(); + + this.revision = 0; + this.syncing = true; + this.closing = false; + this.nextRevision = null; + this.init(); } - public async addChannel(sealed: boolean, type: string, subject: string, cardIds: string[]): Promise { - return await this.content.addChannel(sealed, type, subject, cardIds); - } + private async init() { } - public async removeChannel(channelId: string): Promise { - return await this.content.removeChannel(channelId); - } - - public async setChannelSubject(channelId: string, subject: string): Promise { - return await this.content.setChannelSubject(channelId, subject); - } - - public async setChannelCard(channelId: string, cardId: string): Promise { - return await this.content.setChannelCard(channelId, cardId); - } - - public async clearChannelCard(channelId: string, cardId: string): Promise { - return await this.content.clearChannelCard(channelId, cardId); - } - - public async leaveChannel(cardId: string, channelId: string): Promise { - return await this.contact.leaveChannel(cardId, channelId) - } - - public async getChannelNotifications(cardId: string | null, channelId: string): Promise { - if (cardId) { - return await this.contact.getChannelNotifications(cardId, channelId); - } - return await this.content.getChannelNotifications(channelId) - } - - public async setChannelNotifications(cardId: string | null, channelId: string, enabled: boolean): Promise { - if (cardId) { - return await this.contact.setChannelNotifications(cardId, channelId, enabled) - } - return await this.content.setChannelNotifications(channelId, enabled); - } - - public async setUnreadChannel(cardId: string | null, channelId: string, unread: boolean): Promise { - if (cardId) { - return await this.contact.setUnreadChannel(cardId, channelId, unread); - } - return await this.content.setUnreadChannel(channelId, unread); - } - - public async flagChannel(cardId: string, channelId: string): Promise { - if (cardId) { - return await this.contact.flagChannel(cardId, channelId); - } - return await this.content.flagChannel(channelId); - } - - public async setBlockedChannel(cardId: string | null, channelId: string, blocked: boolean): Promise { - if (cardId) { - return await this.contact.setBlockedChannel(cardId, channelId, blocked); - } - return await this.content.setBlockedChannel(channelId, blocked); - } - - public async getBlockedChannels(): Promise { - const channels = await this.content.getBlockedChannels(); - const cardChannels = await this.contact.getBlockedChannels(); - return channels.concat(cardChannels); - } + private async sync() { } public addChannelListener(ev: (arg: { channels: Channel[], cardId: string | null }) => void): void { - this.content.addChannelListener(ev); - this.contact.addChannelListener(ev); + this.emitter.on('channel', ev); + const channels = Array.from(this.channelEntries, ([channelId, entry]) => entry.channel); + ev({ channels, cardId: null }); } public removeChannelListener(ev: (arg: { channels: Channel[], cardId: string | null }) => void): void { - this.content.removeChannelListener(ev); - this.contact.removeChannelListener(ev); + this.emitter.off('channel', ev); + } + + private emitChannels() { + const channels = Array.from(this.channelEntries, ([channelId, entry]) => entry.channel); + this.emitter.emit('channel', { channels, cardId: null }); + } + + public async close(): Promise {} + + public async setRevision(rev: number): Promise { + console.log('set content revision:', rev); + } + + public async addChannel(sealed: boolean, type: string, subject: string, cardIds: string[]): Promise { + return ''; + } + + public async removeChannel(channelId: string): Promise { } + + public async setChannelSubject(channelId: string, subject: string): Promise { } + + public async setChannelCard(channelId: string, cardId: string): Promise { } + + public async clearChannelCard(channelId: string, cardId: string): Promise { } + + public async setBlockedChannel(channelId: string, blocked: boolean): Promise { } + + public async getBlockedChannels(): Promise { + return []; + } + + public async flagChannel(channelId: string): Promise { } + + public async getChannelNotifications(channelId: string): Promise { + return false; + } + + public async setChannelNotifications(channelId: string, enabled: boolean): Promise { } + + public async setUnreadChannel(channelId: string, unread: boolean): Promise { } + + public async setFocus(channelId: string): Promise { + const { node, secure, token, focus } = this; + if (focus) { + await focus.close(); + } + this.focus = new FocusModule(this.log, this.store, this.crypto, null, channelId, this.guid, { node, secure, token }); + return this.focus; + } + + public async clearFocus() { + if (this.focus) { + await this.focus.close(); + } + this.focus = null; + } + + public async setSeal(seal: { privateKey: string; publicKey: string } | null) { + this.seal = seal; + this.unsealAll = true; + await this.sync(); } }