defining store object

This commit is contained in:
balzack 2024-07-11 08:25:01 -07:00
parent f0124247db
commit 11e32e21cf
16 changed files with 152 additions and 43 deletions

View File

@ -1,6 +1,6 @@
{
"name": "databag-client-sdk",
"version": "0.0.18",
"version": "0.0.20",
"description": "an SDK for developing Databag applications",
"main": "./dist/index.js",
"module": "./dist/index.mjs",

View File

@ -1,6 +1,7 @@
import { EventEmitter } from 'eventemitter3';
import type { Account, Logging } from './api';
import type { AccountStatus } from './types';
import { Store } from './store';
export class AccountModule implements Account {
@ -9,7 +10,7 @@ export class AccountModule implements Account {
private url: string;
private log: Logging;
constructor(log: Logging, token: string, url: string) {
constructor(log: Logging, token: string, url: string, store: Store) {
this.log = log;
this.emitter = new EventEmitter();
this.token = token;

View File

@ -1,6 +1,7 @@
import { EventEmitter } from 'eventemitter3';
import type { Alias, Account, Logging } from './api';
import type { Group } from './types';
import { Store } from './store';
export class AliasModule implements Alias {
@ -10,7 +11,7 @@ export class AliasModule implements Alias {
private account: Account;
private emitter: EventEmitter;
constructor(log: Logging, token: string, url: string, account: Account) {
constructor(log: Logging, token: string, url: string, account: Account, store: Store) {
this.token = token;
this.url = url;
this.log = log;

View File

@ -7,8 +7,8 @@
import type { Channel, Topic, Asset, Tag, Article, Group, Card, Profile, Call, AccountStatus, NodeConfig, NodeAccount, Repeater } from './types';
export interface SqlStore {
set(stmt: string, params: (string | number)[]): Promise<void>;
get(stmt: string, params: (string | number)[]): Promise<any[]>;
set(stmt: string, params?: (string | number)[]): Promise<void>;
get(stmt: string, params?: (string | number)[]): Promise<any[]>;
}
export interface WebStore {
@ -263,9 +263,9 @@ export interface Node {
}
export interface Bot {
addTopic(server: string, token: string, type: string, message: string, assets: Asset[]): Promise<string>;
removeTopic(server: string, token: string, topicId: string): Promise<void>;
addTag(server: string, token: string, topicId: string, type: string, value: string): Promise<string>;
removeTag(server: string, token: string, topicId: string, tagId: string): Promise<void>;
addTopic(type: string, message: string, assets: Asset[]): Promise<string>;
removeTopic(topicId: string): Promise<void>;
addTag(topicId: string, type: string, value: string): Promise<string>;
removeTag(topicId: string, tagId: string): Promise<void>;
}

View File

@ -1,6 +1,7 @@
import { EventEmitter } from 'eventemitter3';
import type { Attribute, Account, Logging } from './api';
import type { Article } from './types';
import { Store } from './store';
export class AttributeModule implements Attribute {
@ -10,7 +11,7 @@ export class AttributeModule implements Attribute {
private account: Account;
private emitter: EventEmitter;
constructor(log: Logging, token: string, url: string, account: Account) {
constructor(log: Logging, token: string, url: string, account: Account, store: Store) {
this.token = token;
this.url = url;
this.log = log;

View File

@ -4,22 +4,26 @@ import type { Asset } from './types';
export class BotModule implements Bot {
private log: Logging;
private server: string;
private token: string;
constructor(log: Logging) {
constructor(log: Logging, server: string, token: string) {
this.log = log;
this.server = server;
this.token = token;
}
public async addTopic(server: string, token: string, type: string, message: string, assets: Asset[]): Promise<string> {
public async addTopic(type: string, message: string, assets: Asset[]): Promise<string> {
return '';
}
public async removeTopic(server: string, token: string, topicId: string): Promise<void> {
public async removeTopic(topicId: string): Promise<void> {
}
public async addTag(server: string, token: string, topicId: string, type: string, value: string): Promise<string> {
public async addTag(topicId: string, type: string, value: string): Promise<string> {
return '';
}
public async removeTag(server: string, token: string, topicId: string, tagId: string): Promise<void> {
public async removeTag(topicId: string, tagId: string): Promise<void> {
}
}

View File

@ -1,6 +1,7 @@
import { EventEmitter } from 'eventemitter3';
import type { Contact, Logging } from './api';
import type { Card, Topic, Asset, Tag, Profile, Repeater} from './types';
import { Store } from './store';
export class ContactModule implements Contact {
@ -9,7 +10,7 @@ export class ContactModule implements Contact {
private url: string;
private emitter: EventEmitter;
constructor(log: Logging, token: string, url: string) {
constructor(log: Logging, token: string, url: string, store: Store) {
this.token = token;
this.url = url;
this.log = log;

View File

@ -1,6 +1,7 @@
import { EventEmitter } from 'eventemitter3';
import type { Content, Account, Logging } from './api';
import type { Channel, Topic, Asset, Tag, Repeater } from './types';
import { Store } from './store';
export class ContentModule implements Content {
@ -10,7 +11,7 @@ export class ContentModule implements Content {
private account: Account;
private emitter: EventEmitter;
constructor(log: Logging, token: string, url: string, account: Account) {
constructor(log: Logging, token: string, url: string, account: Account, store: Store) {
this.token = token;
this.url = url;
this.log = log;

View File

@ -186,3 +186,9 @@ export type Revision = {
card: number
}
export type Login = {
url: string,
token: string,
timestamp: number,
}

View File

@ -1,6 +1,7 @@
import { EventEmitter } from 'eventemitter3';
import type { Identity, Contact, Content, Focus, Logging } from './api';
import type { Topic, Asset, Repeater } from './types';
import { Store } from './store';
export class FocusModule implements Focus {
@ -12,7 +13,7 @@ export class FocusModule implements Focus {
private log: Logging;
private emitter: EventEmitter;
constructor(log: Logging, identity: Identity, contact: Contact, content: Content, cardId: string | null, channelId: string) {
constructor(log: Logging, identity: Identity, contact: Contact, content: Content, store: Store, cardId: string | null, channelId: string) {
this.identity = identity;
this.contact = contact;
this.content = content;

View File

@ -1,6 +1,7 @@
import { EventEmitter } from 'eventemitter3';
import type { Identity, Logging } from './api';
import type { Profile } from './types';
import { Store } from './store';
export class IdentityModule implements Identity {
@ -9,7 +10,7 @@ export class IdentityModule implements Identity {
private log: Logging;
private emitter: EventEmitter;
constructor(log: Logging, token: string, url: string) {
constructor(log: Logging, token: string, url: string, store: Store) {
this.token = token;
this.url = url;
this.log = log;

View File

@ -2,6 +2,7 @@ import { SessionModule } from './session';
import { NodeModule } from './node';
import { BotModule } from './bot';
import { ConsoleLogging } from './logging';
import { type Store, OfflineStore, OnlineStore, NoStore } from './store';
import type { Session, Node, Bot, SqlStore, WebStore, Crypto, Logging } from './api';
import type { SessionParams } from './types';
@ -13,36 +14,43 @@ export class DatabagSDK {
private log: Logging;
private crypto: Crypto | null;
private store: SqlStore | WebStore | null = null;
private store: Store;
constructor(crypto: Crypto | null, log: Logging | null) {
this.crypto = crypto;
this.store = new NoStore();
this.log = log ? log : new ConsoleLogging();
this.log.info("databag sdk");
}
public async initOfflineStore(sql: SqlStore): Promise<Session | null> {
this.store = sql;
// initialize
return new SessionModule(this.store, this.crypto, this.log, '', '');
this.store = new OfflineStore(this.log, sql);
const login = await this.store.init();
if (!login) {
return null;
}
return new SessionModule(this.store, this.crypto, this.log, login.token, login.url, login.timestamp);
}
public async initOnlineStore(web: WebStore): Promise<Session | null> {
this.store = web;
// initialize
return new SessionModule(this.store, this.crypto, this.log, '', '');
this.store = new OnlineStore(this.log, web);
const login = await this.store.init();
if (!login) {
return null;
}
return new SessionModule(this.store, this.crypto, this.log, login.token, login.url, login.timestamp);
}
public async login(handle: string, password: string, url: string, mfaCode: string | null, params: SessionParams): Promise<Session> {
return new SessionModule(this.store, this.crypto, this.log, '', '');
return new SessionModule(this.store, this.crypto, this.log, '', '', 0);
}
public async access(url: string, token: string, params: SessionParams): Promise<Session> {
return new SessionModule(this.store, this.crypto, this.log, '', '');
return new SessionModule(this.store, this.crypto, this.log, '', '', 0);
}
public async create(handle: string, password: string, url: string, token: string | null, params: SessionParams): Promise<Session> {
return new SessionModule(this.store, this.crypto, this.log, '', '');
return new SessionModule(this.store, this.crypto, this.log, '', '', 0);
}
public async logout(session: Session): Promise<void> {
@ -53,7 +61,7 @@ export class DatabagSDK {
return new NodeModule(this.log, '', '');
}
public async automate() {
return new BotModule(this.log);
public async automate(token: string, url: string) {
return new BotModule(this.log, token, url);
}
}

14
app/sdk/src/logging.ts Normal file
View File

@ -0,0 +1,14 @@
import { Logging } from './api';
export class ConsoleLogging implements Logging {
public error(m: any): void {
console.log('error:', m);
}
public warn(m: any): void {
console.log('warn:', m);
}
public info(m: any): void {
console.log('info:', m);
}
}

View File

@ -12,18 +12,20 @@ import { RingModule } from './ring';
import { Connection } from './connection';
import type { Session, SqlStore, WebStore, Account, Identity, Contact, Ring, Alias, Attribute, Content, Stream, Focus, Crypto, Logging } from './api';
import type { Session, Account, Identity, Contact, Ring, Alias, Attribute, Content, Stream, Focus, Crypto, Logging } from './api';
import { Revision } from './entities';
import { Call } from './types';
import { Store } from './store';
export class SessionModule implements Session {
private emitter: EventEmitter;
private store: SqlStore | WebStore | null;
private store: Store;
private crypto: Crypto | null;
private log: Logging;
private token: string;
private url: string;
private loginTimestamp: number;
private syncRevision: Revision | null;
private status: string;
private account: AccountModule;
@ -36,24 +38,27 @@ export class SessionModule implements Session {
private ring: RingModule;
private connection: Connection;
constructor(store: SqlStore | WebStore | null, crypto: Crypto | null, log: Logging, token: string, url: string) {
constructor(store: Store, crypto: Crypto | null, log: Logging, token: string, url: string, loginTimestamp: number) {
log.info('new databag session');
this.store = store;
this.crypto = crypto;
this.log = log;
this.token = token;
this.url = url;
this.loginTimestamp = loginTimestamp;
this.syncRevision = null;
this.status = 'connecting'
this.emitter = new EventEmitter();
this.account = new AccountModule(log, token, url);
this.identity = new IdentityModule(log, token, url);
this.contact = new ContactModule(log, token, url);
this.alias = new AliasModule(log, token, url, this.account);
this.attribute = new AttributeModule(log, token, url, this.account);
this.content = new ContentModule(log, token, url, this.account);
this.stream = new StreamModule(log, this.contact, this.content);
this.account = new AccountModule(log, token, url, this.store);
this.identity = new IdentityModule(log, token, url, this.store);
this.contact = new ContactModule(log, token, url, this.store);
this.alias = new AliasModule(log, token, url, this.account, this.store);
this.attribute = new AttributeModule(log, token, url, this.account, this.store);
this.content = new ContentModule(log, token, url, this.account, this.store);
this.stream = new StreamModule(log, this.contact, this.content, this.store);
this.ring = new RingModule(log);
this.connection = new Connection(log, token, url);
@ -168,7 +173,7 @@ export class SessionModule implements Session {
}
public addFocus(cardId: string | null, channelId: string): Focus {
return new FocusModule(this.log, this.identity, this.contact, this.content, cardId, channelId);
return new FocusModule(this.log, this.identity, this.contact, this.content, this.store, cardId, channelId);
}
public removeFocus(focus: Focus): void {

64
app/sdk/src/store.ts Normal file
View File

@ -0,0 +1,64 @@
import { WebStore, SqlStore, Logging } from './api';
import { Login } from './entities';
export interface Store {
init(): Promise<Login | null>;
}
export class OfflineStore implements Store {
private sql: SqlStore;
private log: Logging;
constructor(log: Logging, sql: SqlStore) {
this.sql = sql;
this.log = log;
}
private async getAppValue(id: string, unset: any): Promise<any> {
const rows = await this.sql.get(`SELECT * FROM app WHERE key='${id}';`);
if (rows.length == 1 && rows[0].value != null) {
return JSON.parse(rows[0].value);
}
return unset;
}
public async init(): Promise<Login | null> {
await this.sql.set("CREATE TABLE IF NOT EXISTS app (key text, value text, unique(key));");
await this.sql.set("INSERT OR IGNORE INTO app (key, value) values ('session', null);");
return await this.getAppValue('login', null);
}
}
export class OnlineStore implements Store {
private web: WebStore;
private log: Logging;
constructor(log: Logging, web: WebStore) {
this.web = web;
this.log = log;
}
private async getAppValue(id: string, unset: any): Promise<any> {
const value = await this.web.getValue(id);
if (value != null) {
return JSON.parse(value);
}
return unset;
}
public async init(): Promise<Login | null> {
return await this.getAppValue('login', null);
}
}
export class NoStore implements Store {
constructor() {
}
public async init(): Promise<Login | null> {
return null;
}
}

View File

@ -1,6 +1,7 @@
import { EventEmitter } from 'eventemitter3';
import type { Contact, Content, Stream, Logging } from './api';
import type { Channel } from './types';
import { Store } from './store';
export class StreamModule implements Stream {
@ -9,7 +10,7 @@ export class StreamModule implements Stream {
private content: Content;
private emitter: EventEmitter;
constructor(log: Logging, contact: Contact, content: Content) {
constructor(log: Logging, contact: Contact, content: Content, store: Store) {
this.contact = contact;
this.content = content;
this.log = log;