From c4aca28ed516b8a7f8d2e4cea64d09826a3cb3e1 Mon Sep 17 00:00:00 2001 From: balzack Date: Wed, 1 Jan 2025 09:20:23 -0800 Subject: [PATCH] rename media files to staging files as more descriptive --- app/client/mobile/src/MediaFiles.ts | 44 --------------- .../mobile/src/context/useAppContext.hook.ts | 4 +- app/client/web/src/MediaFiles.ts | 2 + app/sdk/src/contact.ts | 12 ++--- app/sdk/src/focus.ts | 54 +++++++++---------- app/sdk/src/index.ts | 21 ++++---- app/sdk/src/session.ts | 12 ++--- app/sdk/src/{media.ts => staging.ts} | 3 +- app/sdk/src/stream.ts | 10 ++-- 9 files changed, 61 insertions(+), 101 deletions(-) delete mode 100644 app/client/mobile/src/MediaFiles.ts rename app/sdk/src/{media.ts => staging.ts} (82%) diff --git a/app/client/mobile/src/MediaFiles.ts b/app/client/mobile/src/MediaFiles.ts deleted file mode 100644 index ced7df29..00000000 --- a/app/client/mobile/src/MediaFiles.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Media } from 'databag-client-sdk' -import RNFS from 'react-native-fs'; -import fileType from 'react-native-file-type' - -export class MediaFiles implements Media { - - public async read(source: any): Promise<{ size: number, getData: (position: number, length: number)=>Promise, close: ()=>Promise }> { - const path = source; - const stat = await RNFS.stat(path); - const size = state.size; - const getData = async (position: number, length: number) => { - return await RNFS.read(path, length, position, 'base64'); - } - const close = async ()=>{} - return { size, getData, close }; - } - - public async write(): Promise<{ setData: (data: string)=>Promise, getUrl: ()=>Promise, close: ()=>Promise }> { - let extension = ''; - const path = RNFS.DocumentDirectoryPath + `/${Date.now()}` - const setData = async (data: string) => { - await RNFS.appendFile(path, data, 'base64'); - } - const getUrl = async () => { - if (!extension) { - try { - const type = await fileType(path); - await RNFS.moveFile(path, `${path}.${type.ext}`); - extension = `.${type.ext}`; - } catch (err) { - console.log(err); - await RNFS.moveFile(path, `${path}.dat`); - extension = '.dat'; - } - } - return `file://${path}${extension}` - } - const close = async () => { - await RNFS.unlink(`${path}${extension}`); - } - return { setData, getUrl, close }; - } -} - diff --git a/app/client/mobile/src/context/useAppContext.hook.ts b/app/client/mobile/src/context/useAppContext.hook.ts index f9048bb2..c98a3e17 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, Focus} from 'databag-client-sdk'; import {SessionStore} from '../SessionStore'; import {NativeCrypto} from '../NativeCrypto'; import {LocalStore} from '../LocalStore'; -import { MediaFiles } from '../MediaFiles' +import { StagingFiles } from '../StagingFiles' const DATABAG_DB = 'db_v239.db'; const SETTINGS_DB = 'ls_v001.db'; @@ -15,7 +15,7 @@ const databag = new DatabagSDK( channelTypes: ['sealed', 'superbasic'], }, new NativeCrypto(), - new MediaFiles(), + new StagingFiles(), ); export function useAppContext() { diff --git a/app/client/web/src/MediaFiles.ts b/app/client/web/src/MediaFiles.ts index 70264947..83fc91fd 100644 --- a/app/client/web/src/MediaFiles.ts +++ b/app/client/web/src/MediaFiles.ts @@ -2,6 +2,8 @@ import { Media } from 'databag-client-sdk' export class MediaFiles implements Media { + public clear(): Promise {} + private base64ToUint8Array(base64: string): Uint8Array { var binaryString = atob(base64); var bytes = new Uint8Array(binaryString.length); diff --git a/app/sdk/src/contact.ts b/app/sdk/src/contact.ts index 6bf6b9ad..e796c13c 100644 --- a/app/sdk/src/contact.ts +++ b/app/sdk/src/contact.ts @@ -8,7 +8,7 @@ import type { ArticleDetail, ChannelSummary, ChannelDetail, CardProfile, CardDet import { defaultCardItem, defaultChannelItem } from './items'; import { Store } from './store'; import { Crypto } from './crypto'; -import { Media } from './media'; +import { Staging } from './staging'; import { getCards } from './net/getCards'; import { getCardProfile } from './net/getCardProfile'; import { getCardDetail } from './net/getCardDetail'; @@ -53,7 +53,7 @@ export class ContactModule implements Contact { private focus: FocusModule | null; private crypto: Crypto | null; - private media: Media | null; + private staging: Staging | null; private store: Store; private revision: number; private nextRevision: number | null; @@ -78,7 +78,7 @@ export class ContactModule implements Contact { // view of channels private channelEntries: Map>; - constructor(log: Logging, store: Store, crypto: Crypto | null, media: Media | null, guid: string, token: string, node: string, secure: boolean, articleTypes: string[], channelTypes: string[]) { + constructor(log: Logging, store: Store, crypto: Crypto | null, staging: Staging | null, guid: string, token: string, node: string, secure: boolean, articleTypes: string[], channelTypes: string[]) { this.guid = guid; this.token = token; this.node = node; @@ -86,7 +86,7 @@ export class ContactModule implements Contact { this.log = log; this.store = store; this.crypto = crypto; - this.media = media; + this.staging = staging; this.emitter = new EventEmitter(); this.articleTypes = articleTypes; this.channelTypes = channelTypes; @@ -716,7 +716,7 @@ export class ContactModule implements Contact { const channelKey = await this.setChannelKey(channelEntry.item); const sealEnabled = Boolean(this.seal); const insecure = /^(?!0)(?!.*\.$)((1?\d?\d|25[0-5]|2[0-4]\d)(\.|:\d+$|$)){4}$/.test(node); - this.focus = new FocusModule(this.log, this.store, this.crypto, this.media, cardId, channelId, this.guid, { node, secure: !insecure, token: `${guid}.${token}` }, channelKey, sealEnabled, revision, markRead, flagTopic); + this.focus = new FocusModule(this.log, this.store, this.crypto, this.staging, cardId, channelId, this.guid, { node, secure: !insecure, token: `${guid}.${token}` }, channelKey, sealEnabled, revision, markRead, flagTopic); // set current detail const { dataType, data, enableImage, enableAudio, enableVideo, enableBinary, members, created } = channelEntry.item.detail; @@ -736,7 +736,7 @@ export class ContactModule implements Contact { } this.focus.setDetail(cardId, channelId, focusDetail); } else { - this.focus = new FocusModule(this.log, this.store, this.crypto, this.media, cardId, channelId, this.guid, null, null, false, 0, markRead, flagTopic); + this.focus = new FocusModule(this.log, this.store, this.crypto, this.staging, cardId, channelId, this.guid, null, null, false, 0, markRead, flagTopic); } return this.focus; } diff --git a/app/sdk/src/focus.ts b/app/sdk/src/focus.ts index 340e4acd..b5f33082 100644 --- a/app/sdk/src/focus.ts +++ b/app/sdk/src/focus.ts @@ -6,7 +6,7 @@ import { TransformType, HostingMode, AssetType, FocusDetail } from './types'; import type { Logging } from './logging'; import { Store } from './store'; import { Crypto } from './crypto'; -import { Media } from './media'; +import { Staging } from './staging'; import { BasicEntity, BasicAsset, SealedBasicEntity, TopicDetailEntity } from './entities'; import { defaultTopicItem } from './items'; import { getChannelTopics } from './net/getChannelTopics'; @@ -33,7 +33,7 @@ export class FocusModule implements Focus { private log: Logging; private emitter: EventEmitter; private crypto: Crypto | null; - private media: Media | null; + private staging: Staging | null; private store: Store; private guid: string; private connection: { node: string; secure: boolean; token: string } | null; @@ -47,7 +47,7 @@ export class FocusModule implements Focus { private sealEnabled: boolean; private channelKey: string | null; private loadMore: boolean; - private closeMedia: (()=>Promise)[]; + private closeStaging: (()=>Promise)[]; private unsealAll: boolean; private markRead: ()=>Promise; private flagChannelTopic: (id: string)=>Promise; @@ -59,14 +59,14 @@ export class FocusModule implements Focus { // view of topics private topicEntries: Map; - constructor(log: Logging, store: Store, crypto: Crypto | null, media: Media | null, cardId: string | null, channelId: string, guid: string, connection: { node: string; secure: boolean; token: string } | null, channelKey: string | null, sealEnabled: boolean, revision: number, markRead: ()=>Promise, flagChannelTopic: (id: string)=>Promise) { + constructor(log: Logging, store: Store, crypto: Crypto | null, staging: Staging | null, cardId: string | null, channelId: string, guid: string, connection: { node: string; secure: boolean; token: string } | null, channelKey: string | null, sealEnabled: boolean, revision: number, markRead: ()=>Promise, flagChannelTopic: (id: string)=>Promise) { this.cardId = cardId; this.channelId = channelId; this.log = log; this.emitter = new EventEmitter(); this.store = store; this.crypto = crypto; - this.media = media; + this.staging = staging; this.guid = guid; this.connection = connection; this.channelKey = channelKey; @@ -81,7 +81,7 @@ export class FocusModule implements Focus { this.storeView = { revision: null, marker: null }; this.syncing = true; this.closing = false; - this.closeMedia = []; + this.closeStaging = []; this.nextRevision = null; this.focusDetail = null; this.loadMore = false; @@ -414,22 +414,22 @@ export class FocusModule implements Focus { appAsset.push({appId: transform.appId, assetId: assetItem.assetId}); assetItems.push(assetItem); } else if (transform.type === TransformType.Copy) { - const { media } = this; - if (!media) { - throw new Error('media file processing support not enabled'); + const { staging } = this; + if (!staging) { + throw new Error('staging file processing support not enabled'); } if (!crypto || !channelKey) { throw new Error('duplicate throw for build warning'); } - const mediaFile = await media.read(asset.source); + const stagingFile = await staging.read(asset.source); const split = [] as { partId: string, blockIv: string }[]; - for (let i = 0; i * ENCRYPT_BLOCK_SIZE < mediaFile.size; i++) { - const length = mediaFile.size - (i * ENCRYPT_BLOCK_SIZE) > ENCRYPT_BLOCK_SIZE ? ENCRYPT_BLOCK_SIZE : mediaFile.size - (i * ENCRYPT_BLOCK_SIZE); - const base64Data = await mediaFile.getData(i * ENCRYPT_BLOCK_SIZE, length); + for (let i = 0; i * ENCRYPT_BLOCK_SIZE < stagingFile.size; i++) { + const length = stagingFile.size - (i * ENCRYPT_BLOCK_SIZE) > ENCRYPT_BLOCK_SIZE ? ENCRYPT_BLOCK_SIZE : stagingFile.size - (i * ENCRYPT_BLOCK_SIZE); + const base64Data = await stagingFile.getData(i * ENCRYPT_BLOCK_SIZE, length); const { ivHex } = await crypto.aesIv(); const { encryptedDataB64 } = await crypto.aesEncrypt(base64Data, ivHex, channelKey); const partId = await this.uploadBlock(encryptedDataB64, topicId, (percent: number) => { - const count = Math.ceil(mediaFile.size / ENCRYPT_BLOCK_SIZE); + const count = Math.ceil(stagingFile.size / ENCRYPT_BLOCK_SIZE); assetProgress(Math.floor((i * 100 + percent) / count)); }); split.push({ partId, blockIv: ivHex }); @@ -616,18 +616,18 @@ export class FocusModule implements Focus { appAsset.push({appId: transform.appId, assetId: assetItem.assetId}); assetItems.push(assetItem); } else if (transform.type === TransformType.Copy) { - const { media } = this; - if (!media) { - throw new Error('media file processing support not enabled'); + const { staging } = this; + if (!staging) { + throw new Error('staging file processing support not enabled'); } if (!crypto || !channelKey) { throw new Error('duplicate throw for build warning'); } - const mediaFile = await media.read(asset.source); + const stagingFile = await staging.read(asset.source); const split = [] as { partId: string, blockIv: string }[]; - for (let i = 0; i * ENCRYPT_BLOCK_SIZE < mediaFile.size; i++) { - const length = mediaFile.size - (i * ENCRYPT_BLOCK_SIZE) > ENCRYPT_BLOCK_SIZE ? ENCRYPT_BLOCK_SIZE : mediaFile.size - (i * ENCRYPT_BLOCK_SIZE); - const base64Data = await mediaFile.getData(i * ENCRYPT_BLOCK_SIZE, length); + for (let i = 0; i * ENCRYPT_BLOCK_SIZE < stagingFile.size; i++) { + const length = stagingFile.size - (i * ENCRYPT_BLOCK_SIZE) > ENCRYPT_BLOCK_SIZE ? ENCRYPT_BLOCK_SIZE : stagingFile.size - (i * ENCRYPT_BLOCK_SIZE); + const base64Data = await stagingFile.getData(i * ENCRYPT_BLOCK_SIZE, length); const { ivHex } = await crypto.aesIv(); const { encryptedDataB64 } = await crypto.aesEncrypt(base64Data, ivHex, channelKey); const partId = await this.uploadBlock(encryptedDataB64, topicId, progress); @@ -781,12 +781,12 @@ export class FocusModule implements Focus { } else if (asset.hosting === HostingMode.Basic && asset.basic) { return this.getRemoteChannelTopicAssetUrl(topicId, asset.basic); } else if (asset.hosting === HostingMode.Split && asset.split) { - const { sealEnabled, channelKey, crypto, media } = this; - if (!sealEnabled || !channelKey || !crypto || !media) { - throw new Error('media file decryption not set'); + const { sealEnabled, channelKey, crypto, staging } = this; + if (!sealEnabled || !channelKey || !crypto || !staging) { + throw new Error('staging file decryption not set'); } - const write = await media.write(); - this.closeMedia.push(write.close); + const write = await staging.write(); + this.closeStaging.push(write.close); for (let i = 0; i < asset.split.length; i++) { let download = true; if (progress) { @@ -954,7 +954,7 @@ export class FocusModule implements Focus { while (this.syncing) { await new Promise((r) => setTimeout(r, CLOSE_POLL_MS)); } - this.closeMedia.forEach(item => { + this.closeStaging.forEach(item => { item(); }); } diff --git a/app/sdk/src/index.ts b/app/sdk/src/index.ts index 5bbe513f..c5cea31d 100644 --- a/app/sdk/src/index.ts +++ b/app/sdk/src/index.ts @@ -15,27 +15,27 @@ import type { Session, Node, Contributor } from './api'; import type { Params, SessionParams } from './types'; import type { Login } from './entities'; import type { Crypto } from './crypto'; -import type { Media } from './media'; +import type { Staging } from './staging'; import type { WebStore, SqlStore } from './store'; export * from './api'; export * from './types'; export { WebStore, SqlStore } from './store'; export { Crypto } from './crypto'; -export { Media } from './media'; +export { Staging } from './staging'; export class DatabagSDK { private log: Logging; private crypto: Crypto | null; - private media: Media | null; + private staging: Staging | null; private store: Store; private params: Params; - constructor(params: Params, crypto?: Crypto, media?: Media, log?: Logging) { + constructor(params: Params, crypto?: Crypto, staging?: Staging, log?: Logging) { this.store = new NoStore(); this.params = params; this.crypto = crypto ? crypto : null; - this.media = media ? media : null; + this.staging = staging ? staging : null; this.log = log ? log : new ConsoleLogging(); this.log.info('databag sdk'); } @@ -43,15 +43,16 @@ export class DatabagSDK { public async initOfflineStore(sql: SqlStore): Promise { const { articleTypes, channelTypes } = this.params; this.store = new OfflineStore(this.log, sql); + await this.staging?.clear(); const login = await this.store.init(); - return login ? new SessionModule(this.store, this.crypto, this.log, this.media, login.guid, login.token, login.node, login.secure, login.timestamp, articleTypes, channelTypes) : null; + return login ? new SessionModule(this.store, this.crypto, this.log, this.staging, login.guid, login.token, login.node, login.secure, login.timestamp, articleTypes, channelTypes) : null; } public async initOnlineStore(web: WebStore): Promise { const { articleTypes, channelTypes } = this.params; this.store = new OnlineStore(this.log, web); const login = await this.store.init(); - return login ? new SessionModule(this.store, this.crypto, this.log, this.media, login.guid, login.token, login.node, login.secure, login.timestamp, articleTypes, channelTypes) : null; + return login ? new SessionModule(this.store, this.crypto, this.log, this.staging, login.guid, login.token, login.node, login.secure, login.timestamp, articleTypes, channelTypes) : null; } public async available(node: string, secure: boolean): Promise { @@ -75,7 +76,7 @@ export class DatabagSDK { pushSupported, }; await this.store.setLogin(login); - return new SessionModule(this.store, this.crypto, this.log, this.media, guid, appToken, node, secure, created, articleTypes, channelTypes); + return new SessionModule(this.store, this.crypto, this.log, this.staging, guid, appToken, node, secure, created, articleTypes, channelTypes); } public async access(node: string, secure: boolean, token: string, params: SessionParams): Promise { @@ -91,7 +92,7 @@ export class DatabagSDK { pushSupported, }; await this.store.setLogin(login); - return new SessionModule(this.store, this.crypto, this.log, this.media, guid, appToken, node, secure, created, articleTypes, channelTypes); + return new SessionModule(this.store, this.crypto, this.log, this.staging, guid, appToken, node, secure, created, articleTypes, channelTypes); } public async create(handle: string, password: string, node: string, secure: boolean, token: string | null, params: SessionParams): Promise { @@ -108,7 +109,7 @@ export class DatabagSDK { pushSupported, }; await this.store.setLogin(login); - return new SessionModule(this.store, this.crypto, this.log, this.media, guid, appToken, node, secure, created, articleTypes, channelTypes); + return new SessionModule(this.store, this.crypto, this.log, this.staging, guid, appToken, node, secure, created, articleTypes, channelTypes); } public async remove(session: Session): Promise { diff --git a/app/sdk/src/session.ts b/app/sdk/src/session.ts index e627c311..c1973c7b 100644 --- a/app/sdk/src/session.ts +++ b/app/sdk/src/session.ts @@ -18,13 +18,13 @@ import { Call } from './types'; import { Store } from './store'; import type { Logging } from './logging'; import type { Crypto } from './crypto'; -import type { Media } from './media'; +import type { Staging } from './staging'; export class SessionModule implements Session { private emitter: EventEmitter; private store: Store; private crypto: Crypto | null; - private media: Media | null; + private staging: Staging | null; private log: Logging; private guid: string; private token: string; @@ -44,12 +44,12 @@ export class SessionModule implements Session { private channelTypes: string[]; private articleTypes: string[]; - constructor(store: Store, crypto: Crypto | null, log: Logging, media: Media | null, guid: string, token: string, node: string, secure: boolean, loginTimestamp: number, articleTypes: string[], channelTypes: string[]) { + constructor(store: Store, crypto: Crypto | null, log: Logging, staging: Staging | null, guid: string, token: string, node: string, secure: boolean, loginTimestamp: number, articleTypes: string[], channelTypes: string[]) { log.info('new databag session'); this.store = store; this.crypto = crypto; - this.media = media; + this.staging = staging; this.log = log; this.guid = guid; this.token = token; @@ -63,10 +63,10 @@ export class SessionModule implements Session { this.identity = new IdentityModule(log, this.store, guid, token, node, secure); this.settings = new SettingsModule(log, this.store, this.crypto, guid, token, node, secure); - this.contact = new ContactModule(log, this.store, this.crypto, this.media, guid, token, node, secure, articleTypes, channelTypes); + this.contact = new ContactModule(log, this.store, this.crypto, this.staging, guid, token, node, secure, articleTypes, channelTypes); 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.stream = new StreamModule(log, this.store, this.crypto, this.media, guid, token, node, secure, channelTypes); + this.stream = new StreamModule(log, this.store, this.crypto, this.staging, guid, token, node, secure, channelTypes); this.content = new ContentModule(log, this.crypto, this.contact, this.stream); this.ring = new RingModule(log); this.connection = new Connection(log, token, node, secure); diff --git a/app/sdk/src/media.ts b/app/sdk/src/staging.ts similarity index 82% rename from app/sdk/src/media.ts rename to app/sdk/src/staging.ts index 8aa91eec..501f318c 100644 --- a/app/sdk/src/media.ts +++ b/app/sdk/src/staging.ts @@ -1,4 +1,5 @@ -export interface Media { +export interface Staging { + clear(): Promise; read(source: any): Promise<{ size: number, getData: (position: number, length: number)=>Promise, close: ()=>Promise }>; write(): Promise<{ setData: (data: string)=>Promise, getUrl: ()=>Promise, close: ()=>Promise }>; } diff --git a/app/sdk/src/stream.ts b/app/sdk/src/stream.ts index 646bc428..a89cc015 100644 --- a/app/sdk/src/stream.ts +++ b/app/sdk/src/stream.ts @@ -6,7 +6,7 @@ import type { ChannelItem } from './items'; import type { Channel, Topic, Asset, Tag, Participant } from './types'; import { Store } from './store'; import { Crypto } from './crypto'; -import { Media } from './media'; +import { Staging } from './staging'; import { addChannel } from './net/addChannel'; import { removeChannel } from './net/removeChannel'; import { getChannels } from './net/getChannels'; @@ -28,7 +28,7 @@ export class StreamModule { private log: Logging; private store: Store; private crypto: Crypto | null; - private media: Media | null; + private staging: Staging | null; private guid: string; private token: string; private node: string; @@ -49,7 +49,7 @@ export class StreamModule { // view of channels private channelEntries: Map; - constructor(log: Logging, store: Store, crypto: Crypto | null, media: Media | null, guid: string, token: string, node: string, secure: boolean, channelTypes: string[]) { + constructor(log: Logging, store: Store, crypto: Crypto | null, staging: Staging | null, guid: string, token: string, node: string, secure: boolean, channelTypes: string[]) { this.guid = guid; this.token = token; this.node = node; @@ -57,7 +57,7 @@ export class StreamModule { this.log = log; this.store = store; this.crypto = crypto; - this.media = media; + this.staging = staging; this.focus = null; this.seal = null; this.unsealAll = false; @@ -449,7 +449,7 @@ export class StreamModule { const channelKey = entry ? await this.setChannelKey(entry.item) : null; const revision = entry ? entry.item.summary.revision : 0; const sealEnabled = Boolean(this.seal); - this.focus = new FocusModule(this.log, this.store, this.crypto, this.media, null, channelId, this.guid, { node, secure, token }, channelKey, sealEnabled, revision, markRead, flagTopic); + this.focus = new FocusModule(this.log, this.store, this.crypto, this.staging, null, channelId, this.guid, { node, secure, token }, channelKey, sealEnabled, revision, markRead, flagTopic); if (entry) { const { dataType, data, enableImage, enableAudio, enableVideo, enableBinary, members, created } = entry.item.detail;