mirror of
https://github.com/balzack/databag.git
synced 2025-05-04 15:35:16 +00:00
renamed account interface
This commit is contained in:
parent
5de105ed89
commit
5c3b491f82
@ -1,5 +1,5 @@
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import type { Alias, Account } from '../src/api';
|
import type { Alias } from '../src/api';
|
||||||
import type { Group } from '../src/types';
|
import type { Group } from '../src/types';
|
||||||
|
|
||||||
export class MockAliasModule implements Alias {
|
export class MockAliasModule implements Alias {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import type { Attribute, Account } from '../src/api';
|
import type { Attribute } from '../src/api';
|
||||||
import type { Article } from '../src/types';
|
import type { Article } from '../src/types';
|
||||||
|
|
||||||
export class MockAttributeModule implements Attribute {
|
export class MockAttributeModule implements Attribute {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import type { Content, Account } from '../src/api';
|
import type { Content } from '../src/api';
|
||||||
import type { Channel, Topic, Asset, Tag, Repeater } from '../src/types';
|
import type { Channel, Topic, Asset, Tag, Repeater } from '../src/types';
|
||||||
|
|
||||||
export class MockContentModule implements Content {
|
export class MockContentModule implements Content {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import { type Account } from '../src/api';
|
import { type Settings } from '../src/api';
|
||||||
import type { AccountStatus } from '../src/types';
|
import type { Config } from '../src/types';
|
||||||
|
|
||||||
export class MockAccountModule implements Account {
|
export class MockSettingsModule implements Settings {
|
||||||
|
|
||||||
public revision: number;
|
public revision: number;
|
||||||
private emitter: EventEmitter;
|
private emitter: EventEmitter;
|
||||||
@ -12,11 +12,11 @@ export class MockAccountModule implements Account {
|
|||||||
this.emitter = new EventEmitter();
|
this.emitter = new EventEmitter();
|
||||||
}
|
}
|
||||||
|
|
||||||
public addStatusListener(ev: (status: AccountStatus) => void): void {
|
public addStatusListener(ev: (status: Config) => void): void {
|
||||||
this.emitter.on('status', ev);
|
this.emitter.on('status', ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeStatusListener(ev: (status: AccountStatus) => void): void {
|
public removeStatusListener(ev: (status: Config) => void): void {
|
||||||
this.emitter.off('status', ev);
|
this.emitter.off('status', ev);
|
||||||
}
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ import { DatabagSDK } from '../src/index';
|
|||||||
import { type SessionParams } from '../src/types';
|
import { type SessionParams } from '../src/types';
|
||||||
|
|
||||||
import { MockConnection } from '../__mocks__/connection';
|
import { MockConnection } from '../__mocks__/connection';
|
||||||
import { MockAccountModule } from '../__mocks__/account';
|
import { MockSettingsModule } from '../__mocks__/settings';
|
||||||
import { MockIdentityModule } from '../__mocks__/identity';
|
import { MockIdentityModule } from '../__mocks__/identity';
|
||||||
import { MockAliasModule } from '../__mocks__/alias';
|
import { MockAliasModule } from '../__mocks__/alias';
|
||||||
import { MockContentModule } from '../__mocks__/content';
|
import { MockContentModule } from '../__mocks__/content';
|
||||||
@ -29,11 +29,11 @@ jest.mock('../src/connection', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const mockAccount = new MockAccountModule();
|
const mockSettings = new MockSettingsModule();
|
||||||
jest.mock('../src/account', () => {
|
jest.mock('../src/settings', () => {
|
||||||
return {
|
return {
|
||||||
AccountModule: jest.fn().mockImplementation(() => {
|
SettingsModule: jest.fn().mockImplementation(() => {
|
||||||
return mockAccount;
|
return mockSettings;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -99,14 +99,14 @@ test('allocates session correctly', async () => {
|
|||||||
const params: SessionParams = { topicBatch: 0, tagBatch: 0, channelTypes: [], pushType: '', deviceToken: '', notifications: [], deviceId: '', version: '', appName: '' };
|
const params: SessionParams = { topicBatch: 0, tagBatch: 0, channelTypes: [], pushType: '', deviceToken: '', notifications: [], deviceId: '', version: '', appName: '' };
|
||||||
const session = await sdk.login('handle', 'password', 'jest.test', true, null, params);
|
const session = await sdk.login('handle', 'password', 'jest.test', true, null, params);
|
||||||
session.addStatusListener((ev: string) => { status = ev; });
|
session.addStatusListener((ev: string) => { status = ev; });
|
||||||
const account = session.getAccount();
|
const settings = session.getSettings();
|
||||||
account.enableNotifications();
|
settings.enableNotifications();
|
||||||
mockConnection.emitStatus('connected');
|
mockConnection.emitStatus('connected');
|
||||||
mockConnection.emitRevision({ account: 3, profile: 3, article: 3, group: 3, channel: 3, card: 3});
|
mockConnection.emitRevision({ account: 3, profile: 3, article: 3, group: 3, channel: 3, card: 3});
|
||||||
mockConnection.emitRing({ cardId: '', callId: 'test', calleeToken: '', ice: []});
|
mockConnection.emitRing({ cardId: '', callId: 'test', calleeToken: '', ice: []});
|
||||||
await waitFor(() => (status === 'connected'));
|
await waitFor(() => (status === 'connected'));
|
||||||
await waitFor(() => (mockRing.call?.callId === 'test'));
|
await waitFor(() => (mockRing.call?.callId === 'test'));
|
||||||
await waitFor(() => (mockAccount.revision == 3));
|
await waitFor(() => (mockSettings.revision == 3));
|
||||||
await waitFor(() => (mockIdentity.revision == 3));
|
await waitFor(() => (mockIdentity.revision == 3));
|
||||||
await waitFor(() => (mockContent.revision == 3));
|
await waitFor(() => (mockContent.revision == 3));
|
||||||
await waitFor(() => (mockContact.revision == 3));
|
await waitFor(() => (mockContact.revision == 3));
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
import { AccountModule } from '../src/account';
|
import { SettingsModule } from '../src/settings';
|
||||||
import { NoStore } from '../src/store';
|
import { NoStore } from '../src/store';
|
||||||
import { Crypto } from '../src/crypto';
|
import { Crypto } from '../src/crypto';
|
||||||
import { ConsoleLogging } from '../src/logging';
|
import { ConsoleLogging } from '../src/logging';
|
||||||
import { defaultAccountEntity } from '../src/entities';
|
import { defaultConfigEntity } from '../src/entities';
|
||||||
import { AccountStatus } from '../src/types';
|
import { Config } from '../src/types';
|
||||||
import { waitFor } from '../__mocks__/waitFor';
|
import { waitFor } from '../__mocks__/waitFor';
|
||||||
import axios from 'redaxios';
|
import axios from 'redaxios';
|
||||||
|
|
||||||
const testStatus = JSON.parse(JSON.stringify(defaultAccountEntity));
|
const testStatus = JSON.parse(JSON.stringify(defaultConfigEntity));
|
||||||
|
|
||||||
jest.mock('redaxios', () => {
|
jest.mock('redaxios', () => {
|
||||||
return {
|
return {
|
||||||
@ -76,29 +76,29 @@ class TestStore extends NoStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test('allocates session correctly', async () => {
|
test('allocates session correctly', async () => {
|
||||||
let status: AccountStatus | null = null;
|
let status: Config | null = null;
|
||||||
const log = new ConsoleLogging();
|
const log = new ConsoleLogging();
|
||||||
const store = new TestStore();
|
const store = new TestStore();
|
||||||
const crypto = new TestCrypto();
|
const crypto = new TestCrypto();
|
||||||
const account = new AccountModule(log, store, crypto, 'test_guid', 'test_token', 'test_url', false);
|
const settings = new SettingsModule(log, store, crypto, 'test_guid', 'test_token', 'test_url', false);
|
||||||
account.addStatusListener((ev: AccountStatus) => { status = ev });
|
settings.addStatusListener((ev: Config) => { status = ev });
|
||||||
account.setRevision(5);
|
settings.setRevision(5);
|
||||||
await waitFor(() => (status?.storageUsed == 2));
|
await waitFor(() => (status?.storageUsed == 2));
|
||||||
account.enableRegistry();
|
settings.enableRegistry();
|
||||||
account.setRevision(6);
|
settings.setRevision(6);
|
||||||
await waitFor(() => Boolean(status?.searchable));
|
await waitFor(() => Boolean(status?.searchable));
|
||||||
account.disableRegistry();
|
settings.disableRegistry();
|
||||||
account.setRevision(7);
|
settings.setRevision(7);
|
||||||
await waitFor(() => !Boolean(status?.searchable));
|
await waitFor(() => !Boolean(status?.searchable));
|
||||||
|
|
||||||
account.enableNotifications();
|
settings.enableNotifications();
|
||||||
account.setRevision(8);
|
settings.setRevision(8);
|
||||||
await waitFor(() => Boolean(status?.pushEnabled));
|
await waitFor(() => Boolean(status?.pushEnabled));
|
||||||
account.disableNotifications();
|
settings.disableNotifications();
|
||||||
account.setRevision(9);
|
settings.setRevision(9);
|
||||||
await waitFor(() => !Boolean(status?.pushEnabled));
|
await waitFor(() => !Boolean(status?.pushEnabled));
|
||||||
|
|
||||||
account.setSeal('password');
|
settings.setSeal('password');
|
||||||
account.setRevision(10);
|
settings.setRevision(10);
|
||||||
await waitFor(() => Boolean(status?.sealSet));
|
await waitFor(() => Boolean(status?.sealSet));
|
||||||
});
|
});
|
@ -1,5 +1,5 @@
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import type { Alias, Account, Logging } from './api';
|
import type { Alias, Settings, Logging } from './api';
|
||||||
import type { Group } from './types';
|
import type { Group } from './types';
|
||||||
import { Store } from './store';
|
import { Store } from './store';
|
||||||
|
|
||||||
@ -10,16 +10,16 @@ export class AliasModule implements Alias {
|
|||||||
private token: string;
|
private token: string;
|
||||||
private node: string;
|
private node: string;
|
||||||
private secure: boolean;
|
private secure: boolean;
|
||||||
private account: Account;
|
private settings: Settings;
|
||||||
private emitter: EventEmitter;
|
private emitter: EventEmitter;
|
||||||
|
|
||||||
constructor(log: Logging, account: Account, store: Store, guid: string, token: string, node: string, secure: boolean) {
|
constructor(log: Logging, settings: Settings, store: Store, guid: string, token: string, node: string, secure: boolean) {
|
||||||
this.guid = guid;
|
this.guid = guid;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.secure = secure;
|
this.secure = secure;
|
||||||
this.log = log;
|
this.log = log;
|
||||||
this.account = account;
|
this.settings = settings;
|
||||||
this.emitter = new EventEmitter();
|
this.emitter = new EventEmitter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,54 +4,10 @@
|
|||||||
// formaize delete vs block remote channel
|
// formaize delete vs block remote channel
|
||||||
// articles share by cards now
|
// articles share by cards now
|
||||||
|
|
||||||
import type { Channel, Topic, Asset, Tag, Article, Group, Card, Profile, Call, AccountStatus, NodeConfig, NodeAccount, Repeater } from './types';
|
import type { Channel, Topic, Asset, Tag, Article, Group, Card, Profile, Call, Config, NodeConfig, NodeAccount, Repeater } from './types';
|
||||||
|
|
||||||
export interface SqlStore {
|
|
||||||
set(stmt: string, params?: (string | number | null)[]): Promise<void>;
|
|
||||||
get(stmt: string, params?: (string | number | null)[]): Promise<any[]>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface WebStore {
|
|
||||||
getValue(key: string): Promise<string>;
|
|
||||||
setValue(key: string, value: string): Promise<void>;
|
|
||||||
clearValue(key: string): Promise<void>;
|
|
||||||
clearAll(): Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Crypto {
|
|
||||||
|
|
||||||
// generate salt for pbk function
|
|
||||||
pkdkfSalt(): { saltHex: string };
|
|
||||||
|
|
||||||
// generate aes key with pbkdf2
|
|
||||||
pbkdfKey(saltHex: string, password: string): { aesKeyHex: string };
|
|
||||||
|
|
||||||
// generate random aes key
|
|
||||||
aesKey(): { aesKeyHex: string };
|
|
||||||
|
|
||||||
// generate iv to use to aes function
|
|
||||||
aesIv(): { ivHex: string };
|
|
||||||
|
|
||||||
// encrypt data with aes key and iv
|
|
||||||
aesEncrypt(data: string, ivHex: string, aesKeyHex: string): { encryptedDataB64: string };
|
|
||||||
|
|
||||||
// decrypt data with aes key and iv
|
|
||||||
aesDecrypt(encryptedDataB64: string, ivHex: string, aesKeyHex: string): { data: string };
|
|
||||||
|
|
||||||
// generate rsa key
|
|
||||||
rsaKey(): { publicKeyB64: string, privateKeyB64: string };
|
|
||||||
|
|
||||||
// encrypt data with public rsa key
|
|
||||||
rsaEncrypt(data: string, publicKeyB64: string): { encryptedDataB64: string }
|
|
||||||
|
|
||||||
// decrypt data with private rsa key
|
|
||||||
rsaDecrypt(encryptedDataB64: string, privateKeyB64: string): { data: string }
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Session {
|
export interface Session {
|
||||||
close(): Promise<{ node: string, secure: boolean, token: string }>;
|
getSettings(): Settings;
|
||||||
|
|
||||||
getAccount(): Account;
|
|
||||||
getIdentity(): Identity;
|
getIdentity(): Identity;
|
||||||
getContact(): Contact;
|
getContact(): Contact;
|
||||||
getAlias(): Alias;
|
getAlias(): Alias;
|
||||||
@ -63,8 +19,6 @@ export interface Session {
|
|||||||
addFocus(cardId: string | null, channelId: string): Focus;
|
addFocus(cardId: string | null, channelId: string): Focus;
|
||||||
removeFocus(focus: Focus): void;
|
removeFocus(focus: Focus): void;
|
||||||
|
|
||||||
resync(): void;
|
|
||||||
|
|
||||||
addStatusListener(ev: (status: string) => void): void;
|
addStatusListener(ev: (status: string) => void): void;
|
||||||
removeStatusListener(ev: (status: string) => void): void;
|
removeStatusListener(ev: (status: string) => void): void;
|
||||||
}
|
}
|
||||||
@ -82,7 +36,7 @@ export interface Ring {
|
|||||||
decline(callId: string): void;
|
decline(callId: string): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Account {
|
export interface Settings {
|
||||||
setLogin(username: string, password: string): Promise<void>;
|
setLogin(username: string, password: string): Promise<void>;
|
||||||
enableNotifications(): Promise<void>;
|
enableNotifications(): Promise<void>;
|
||||||
disableNotifications(): Promise<void>;
|
disableNotifications(): Promise<void>;
|
||||||
@ -96,8 +50,8 @@ export interface Account {
|
|||||||
unlockSeal(password: string): Promise<void>;
|
unlockSeal(password: string): Promise<void>;
|
||||||
forgetSeal(): Promise<void>;
|
forgetSeal(): Promise<void>;
|
||||||
|
|
||||||
addStatusListener(ev: (status: AccountStatus) => void): void;
|
addStatusListener(ev: (config: Config) => void): void;
|
||||||
removeStatusListener(ev: (status: AccountStatus) => void): void;
|
removeStatusListener(ev: (config: Config) => void): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Identity {
|
export interface Identity {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import type { Attribute, Account, Logging } from './api';
|
import type { Attribute, Settings, Logging } from './api';
|
||||||
import type { Article } from './types';
|
import type { Article } from './types';
|
||||||
import { Store } from './store';
|
import { Store } from './store';
|
||||||
|
|
||||||
@ -10,16 +10,16 @@ export class AttributeModule implements Attribute {
|
|||||||
private token: string;
|
private token: string;
|
||||||
private node: string;
|
private node: string;
|
||||||
private secure: boolean;
|
private secure: boolean;
|
||||||
private account: Account;
|
private settings: Settings;
|
||||||
private emitter: EventEmitter;
|
private emitter: EventEmitter;
|
||||||
|
|
||||||
constructor(log: Logging, account: Account, store: Store, guid: string, token: string, node: string, secure: boolean) {
|
constructor(log: Logging, settings: Settings, store: Store, guid: string, token: string, node: string, secure: boolean) {
|
||||||
this.guid = guid;
|
this.guid = guid;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.secure = secure;
|
this.secure = secure;
|
||||||
this.log = log;
|
this.log = log;
|
||||||
this.account = account;
|
this.settings = settings;
|
||||||
this.emitter = new EventEmitter();
|
this.emitter = new EventEmitter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import type { Content, Account, Logging } from './api';
|
import type { Content, Settings, Logging } from './api';
|
||||||
import type { Channel, Topic, Asset, Tag, Repeater } from './types';
|
import type { Channel, Topic, Asset, Tag, Repeater } from './types';
|
||||||
import { Store } from './store';
|
import { Store } from './store';
|
||||||
|
|
||||||
@ -10,16 +10,16 @@ export class ContentModule implements Content {
|
|||||||
private token: string;
|
private token: string;
|
||||||
private node: string;
|
private node: string;
|
||||||
private secure: boolean;
|
private secure: boolean;
|
||||||
private account: Account;
|
private settings: Settings;
|
||||||
private emitter: EventEmitter;
|
private emitter: EventEmitter;
|
||||||
|
|
||||||
constructor(log: Logging, account: Account, store: Store, guid: string, token: string, node: string, secure: boolean) {
|
constructor(log: Logging, settings: Settings, store: Store, guid: string, token: string, node: string, secure: boolean) {
|
||||||
this.guid = guid;
|
this.guid = guid;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.node = node;
|
this.node = node;
|
||||||
this.secure = secure;
|
this.secure = secure;
|
||||||
this.log = log;
|
this.log = log;
|
||||||
this.account = account;
|
this.settings = settings;
|
||||||
this.emitter = new EventEmitter();
|
this.emitter = new EventEmitter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ export type SealEntity = {
|
|||||||
publicKey: string,
|
publicKey: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AccountEntity = {
|
export type ConfigEntity = {
|
||||||
disabled: boolean,
|
disabled: boolean,
|
||||||
storageUsed: number,
|
storageUsed: number,
|
||||||
storageAvailable: number,
|
storageAvailable: number,
|
||||||
@ -164,7 +164,7 @@ export type AccountEntity = {
|
|||||||
webPushKey: string,
|
webPushKey: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultAccountEntity = {
|
export const defaultConfigEntity = {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
storageUsed: 0,
|
storageUsed: 0,
|
||||||
storageAvailable: 0,
|
storageAvailable: 0,
|
||||||
|
@ -10,13 +10,16 @@ import { addAccount } from './net/addAccount';
|
|||||||
import { setAdmin } from './net/setAdmin';
|
import { setAdmin } from './net/setAdmin';
|
||||||
import { getAvailable } from './net/getAvailable';
|
import { getAvailable } from './net/getAvailable';
|
||||||
import { getUsername } from './net/getUsername';
|
import { getUsername } from './net/getUsername';
|
||||||
import type { Session, Node, Bot, SqlStore, WebStore } from './api';
|
import type { Session, Node, Bot } from './api';
|
||||||
import type { SessionParams } from './types';
|
import type { SessionParams } from './types';
|
||||||
import type { Login } from './entities';
|
import type { Login } from './entities';
|
||||||
import type { Crypto } from './crypto';
|
import type { Crypto } from './crypto';
|
||||||
|
import type { WebStore, SqlStore } from './store';
|
||||||
|
|
||||||
export * from './api';
|
export * from './api';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
export { WebStore, SqlStore } from './store';
|
||||||
|
export { Crypto } from './crypto';
|
||||||
|
|
||||||
export class DatabagSDK {
|
export class DatabagSDK {
|
||||||
|
|
||||||
@ -77,7 +80,8 @@ export class DatabagSDK {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async logout(session: Session, all: boolean): Promise<void> {
|
public async logout(session: Session, all: boolean): Promise<void> {
|
||||||
const params = await session.close();
|
const sessionModule = session as SessionModule;
|
||||||
|
const params = await sessionModule.close();
|
||||||
try {
|
try {
|
||||||
const { node, secure, token } = params;
|
const { node, secure, token } = params;
|
||||||
await clearLogin(node, secure, token, all);
|
await clearLogin(node, secure, token, all);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import axios from 'redaxios';
|
import axios from 'redaxios';
|
||||||
import { AccountEntity } from '../entities';
|
import { ConfigEntity } from '../entities';
|
||||||
|
|
||||||
export async function getAccountStatus(node: string, secure: boolean, token: string): Promise<AccountEntity> {
|
export async function getAccountStatus(node: string, secure: boolean, token: string): Promise<ConfigEntity> {
|
||||||
const endpoint = `http${secure ? 's' : ''}://${node}/account/status?agent=${token}`;
|
const endpoint = `http${secure ? 's' : ''}://${node}/account/status?agent=${token}`;
|
||||||
const response = await axios.get(endpoint);
|
const response = await axios.get(endpoint);
|
||||||
if (response.status >= 400 && response.status < 600) {
|
if (response.status >= 400 && response.status < 600) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
|
|
||||||
import { AccountModule } from './account';
|
import { SettingsModule } from './settings';
|
||||||
import { IdentityModule } from './identity';
|
import { IdentityModule } from './identity';
|
||||||
import { ContactModule } from './contact';
|
import { ContactModule } from './contact';
|
||||||
import { AliasModule } from './alias';
|
import { AliasModule } from './alias';
|
||||||
@ -12,7 +12,7 @@ import { RingModule } from './ring';
|
|||||||
|
|
||||||
import { Connection } from './connection';
|
import { Connection } from './connection';
|
||||||
|
|
||||||
import type { Session, Account, Identity, Contact, Ring, Alias, Attribute, Content, Stream, Focus } from './api';
|
import type { Session, Settings, Identity, Contact, Ring, Alias, Attribute, Content, Stream, Focus } from './api';
|
||||||
import { Revision } from './entities';
|
import { Revision } from './entities';
|
||||||
import { Call } from './types';
|
import { Call } from './types';
|
||||||
import { Store } from './store';
|
import { Store } from './store';
|
||||||
@ -30,9 +30,8 @@ export class SessionModule implements Session {
|
|||||||
private node: string;
|
private node: string;
|
||||||
private secure: boolean;
|
private secure: boolean;
|
||||||
private loginTimestamp: number;
|
private loginTimestamp: number;
|
||||||
private syncRevision: Revision | null;
|
|
||||||
private status: string;
|
private status: string;
|
||||||
private account: AccountModule;
|
private settings: SettingsModule;
|
||||||
private identity: IdentityModule;
|
private identity: IdentityModule;
|
||||||
private contact: ContactModule;
|
private contact: ContactModule;
|
||||||
private alias: AliasModule;
|
private alias: AliasModule;
|
||||||
@ -54,16 +53,15 @@ export class SessionModule implements Session {
|
|||||||
this.node = node;
|
this.node = node;
|
||||||
this.secure = secure;
|
this.secure = secure;
|
||||||
this.loginTimestamp = loginTimestamp;
|
this.loginTimestamp = loginTimestamp;
|
||||||
this.syncRevision = null;
|
|
||||||
this.status = 'connecting'
|
this.status = 'connecting'
|
||||||
this.emitter = new EventEmitter();
|
this.emitter = new EventEmitter();
|
||||||
|
|
||||||
this.identity = new IdentityModule(log, this.store, guid, token, node, secure);
|
this.identity = new IdentityModule(log, this.store, guid, token, node, secure);
|
||||||
this.account = new AccountModule(log, this.store, this.crypto, guid, token, node, secure);
|
this.settings = new SettingsModule(log, this.store, this.crypto, guid, token, node, secure);
|
||||||
this.contact = new ContactModule(log, this.store, guid, token, node, secure);
|
this.contact = new ContactModule(log, this.store, guid, token, node, secure);
|
||||||
this.alias = new AliasModule(log, this.account, this.store, guid, token, node, secure);
|
this.alias = new AliasModule(log, this.settings, this.store, guid, token, node, secure);
|
||||||
this.attribute = new AttributeModule(log, this.account, 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.account, this.store, guid, token, node, secure);
|
this.content = new ContentModule(log, this.settings, this.store, guid, token, node, secure);
|
||||||
this.stream = new StreamModule(log, this.contact, this.content, this.store, guid);
|
this.stream = new StreamModule(log, this.contact, this.content, this.store, guid);
|
||||||
this.ring = new RingModule(log);
|
this.ring = new RingModule(log);
|
||||||
this.connection = new Connection(log, token, node, secure);
|
this.connection = new Connection(log, token, node, secure);
|
||||||
@ -74,23 +72,12 @@ export class SessionModule implements Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onRevision = async (ev: Revision) => {
|
const onRevision = async (ev: Revision) => {
|
||||||
try {
|
await this.identity.setRevision(ev.profile);
|
||||||
await this.identity.setRevision(ev.profile);
|
await this.settings.setRevision(ev.account);
|
||||||
await this.account.setRevision(ev.account);
|
await this.contact.setRevision(ev.card);
|
||||||
await this.contact.setRevision(ev.card);
|
await this.attribute.setRevision(ev.article);
|
||||||
await this.attribute.setRevision(ev.article);
|
await this.alias.setRevision(ev.group);
|
||||||
await this.alias.setRevision(ev.group);
|
await this.content.setRevision(ev.channel);
|
||||||
await this.content.setRevision(ev.channel);
|
|
||||||
if (this.syncRevision) {
|
|
||||||
this.syncRevision = null
|
|
||||||
this.emitter.emit('status', this.getStatus());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
this.log.warn(err);
|
|
||||||
this.syncRevision = ev;
|
|
||||||
this.emitter.emit('status', this.getStatus());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const onRing = (ev: Call) => {
|
const onRing = (ev: Call) => {
|
||||||
@ -111,45 +98,24 @@ export class SessionModule implements Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getStatus(): string {
|
private getStatus(): string {
|
||||||
if (this.status === 'connected' && this.syncRevision) {
|
|
||||||
return 'offsync';
|
|
||||||
}
|
|
||||||
return this.status;
|
return this.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async resync() {
|
|
||||||
if (this.syncRevision) {
|
|
||||||
try {
|
|
||||||
await this.identity.setRevision(this.syncRevision.profile);
|
|
||||||
await this.account.setRevision(this.syncRevision.account);
|
|
||||||
await this.contact.setRevision(this.syncRevision.card);
|
|
||||||
await this.attribute.setRevision(this.syncRevision.article);
|
|
||||||
await this.alias.setRevision(this.syncRevision.group);
|
|
||||||
await this.content.setRevision(this.syncRevision.channel);
|
|
||||||
this.syncRevision = null
|
|
||||||
this.emitter.emit('status', this.getStatus());
|
|
||||||
}
|
|
||||||
catch(err) {
|
|
||||||
this.log.warn(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async close(): Promise<{ node: string, secure: boolean, token: string }> {
|
public async close(): Promise<{ node: string, secure: boolean, token: string }> {
|
||||||
await this.content.close();
|
await this.content.close();
|
||||||
await this.attribute.close();
|
await this.attribute.close();
|
||||||
await this.alias.close();
|
await this.alias.close();
|
||||||
await this.contact.close();
|
await this.contact.close();
|
||||||
await this.identity.close();
|
await this.identity.close();
|
||||||
await this.account.close();
|
await this.settings.close();
|
||||||
await this.stream.close();
|
await this.stream.close();
|
||||||
this.connection.close();
|
this.connection.close();
|
||||||
const { node, secure, token } = this;
|
const { node, secure, token } = this;
|
||||||
return { node: node, secure: secure, token: token };
|
return { node: node, secure: secure, token: token };
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAccount(): Account {
|
public getSettings(): Settings {
|
||||||
return this.account;
|
return this.settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getIdentity(): Identity {
|
public getIdentity(): Identity {
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
import type { Account } from './api';
|
import type { Settings } from './api';
|
||||||
import type { AccountStatus } from './types';
|
import type { Config } from './types';
|
||||||
import { Store } from './store';
|
import { Store } from './store';
|
||||||
import { Crypto } from './crypto';
|
import { Crypto } from './crypto';
|
||||||
import { Logging } from './logging';
|
import { Logging } from './logging';
|
||||||
import { defaultAccountEntity, AccountEntity } from './entities';
|
import { defaultConfigEntity, ConfigEntity } from './entities';
|
||||||
import { getAccountStatus } from './net/getAccountStatus';
|
import { getAccountStatus } from './net/getAccountStatus';
|
||||||
import { addAccountMFAuth } from './net/addAccountMFAuth';
|
import { addAccountMFAuth } from './net/addAccountMFAuth';
|
||||||
import { setAccountMFAuth } from './net/setAccountMFAuth';
|
import { setAccountMFAuth } from './net/setAccountMFAuth';
|
||||||
@ -18,7 +18,7 @@ import { clearAccountSeal } from './net/clearAccountSeal';
|
|||||||
const CLOSE_POLL_MS = 100;
|
const CLOSE_POLL_MS = 100;
|
||||||
const RETRY_POLL_MS = 2000;
|
const RETRY_POLL_MS = 2000;
|
||||||
|
|
||||||
export class AccountModule implements Account {
|
export class SettingsModule implements Settings {
|
||||||
|
|
||||||
private emitter: EventEmitter;
|
private emitter: EventEmitter;
|
||||||
private guid: string;
|
private guid: string;
|
||||||
@ -32,7 +32,7 @@ export class AccountModule implements Account {
|
|||||||
private closing: boolean;
|
private closing: boolean;
|
||||||
private revision: number;
|
private revision: number;
|
||||||
private nextRevision: number | null;
|
private nextRevision: number | null;
|
||||||
private entity: AccountEntity;
|
private entity: ConfigEntity;
|
||||||
private sealKey: { privateKey: string, publicKey: string } | null;
|
private sealKey: { privateKey: string, publicKey: string } | null;
|
||||||
|
|
||||||
constructor(log: Logging, store: Store, crypto: Crypto | null, guid: string, token: string, node: string, secure: boolean) {
|
constructor(log: Logging, store: Store, crypto: Crypto | null, guid: string, token: string, node: string, secure: boolean) {
|
||||||
@ -46,7 +46,7 @@ export class AccountModule implements Account {
|
|||||||
this.sealKey = null;
|
this.sealKey = null;
|
||||||
this.secure = secure;
|
this.secure = secure;
|
||||||
this.revision = 0;
|
this.revision = 0;
|
||||||
this.entity = defaultAccountEntity;
|
this.entity = defaultConfigEntity;
|
||||||
this.syncing = true;
|
this.syncing = true;
|
||||||
this.closing = false;
|
this.closing = false;
|
||||||
this.nextRevision = null;
|
this.nextRevision = null;
|
||||||
@ -54,8 +54,8 @@ export class AccountModule implements Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async init() {
|
private async init() {
|
||||||
this.revision = await this.store.getAccountRevision(this.guid);
|
this.revision = await this.store.getSettingsRevision(this.guid);
|
||||||
this.entity = await this.store.getAccountData(this.guid);
|
this.entity = await this.store.getSettingsData(this.guid);
|
||||||
this.sealKey = await this.store.getSeal(this.guid);
|
this.sealKey = await this.store.getSeal(this.guid);
|
||||||
this.syncing = false;
|
this.syncing = false;
|
||||||
await this.sync();
|
await this.sync();
|
||||||
@ -73,8 +73,8 @@ export class AccountModule implements Account {
|
|||||||
try {
|
try {
|
||||||
const { guid, node, secure, token } = this;
|
const { guid, node, secure, token } = this;
|
||||||
const status = await getAccountStatus(node, secure, token);
|
const status = await getAccountStatus(node, secure, token);
|
||||||
await this.store.setAccountData(guid, status);
|
await this.store.setSettingsData(guid, status);
|
||||||
await this.store.setAccountRevision(guid, nextRev);
|
await this.store.setSettingsRevision(guid, nextRev);
|
||||||
this.entity = status;
|
this.entity = status;
|
||||||
this.emitter.emit('status', this.getStatus());
|
this.emitter.emit('status', this.getStatus());
|
||||||
this.revision = nextRev;
|
this.revision = nextRev;
|
||||||
@ -101,12 +101,12 @@ export class AccountModule implements Account {
|
|||||||
return { storageUsed, storageAvailable, forwardingAddress, searchable, allowUnsealed, pushEnabled, sealable, sealSet, sealUnlocked, enableIce, multiFactorAuth, webPushKey };
|
return { storageUsed, storageAvailable, forwardingAddress, searchable, allowUnsealed, pushEnabled, sealable, sealSet, sealUnlocked, enableIce, multiFactorAuth, webPushKey };
|
||||||
}
|
}
|
||||||
|
|
||||||
public addStatusListener(ev: (status: AccountStatus) => void): void {
|
public addStatusListener(ev: (status: Config) => void): void {
|
||||||
this.emitter.on('status', ev);
|
this.emitter.on('status', ev);
|
||||||
this.emitter.emit('status', this.getStatus());
|
this.emitter.emit('status', this.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeStatusListener(ev: (status: AccountStatus) => void): void {
|
public removeStatusListener(ev: (status: Config) => void): void {
|
||||||
this.emitter.off('status', ev);
|
this.emitter.off('status', ev);
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,4 @@
|
|||||||
import { WebStore, SqlStore } from './api';
|
import { Login, ProfileEntity, defaultProfileEntity, ConfigEntity, defaultConfigEntity } from './entities';
|
||||||
import { Login, ProfileEntity, defaultProfileEntity, AccountEntity, defaultAccountEntity } from './entities';
|
|
||||||
import type { Logging } from './logging';
|
import type { Logging } from './logging';
|
||||||
|
|
||||||
export interface Store {
|
export interface Store {
|
||||||
@ -15,10 +14,22 @@ export interface Store {
|
|||||||
getProfileData(guid: string): Promise<ProfileEntity>;
|
getProfileData(guid: string): Promise<ProfileEntity>;
|
||||||
setProfileData(guid: string, data: ProfileEntity): Promise<void>;
|
setProfileData(guid: string, data: ProfileEntity): Promise<void>;
|
||||||
|
|
||||||
getAccountRevision(guid: string): Promise<number>;
|
getSettingsRevision(guid: string): Promise<number>;
|
||||||
setAccountRevision(guid: string, revision: number): Promise<void>;
|
setSettingsRevision(guid: string, revision: number): Promise<void>;
|
||||||
getAccountData(guid: string): Promise<AccountEntity>;
|
getSettingsData(guid: string): Promise<ConfigEntity>;
|
||||||
setAccountData(guid: string, data: AccountEntity): Promise<void>;
|
setSettingsData(guid: string, data: ConfigEntity): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SqlStore {
|
||||||
|
set(stmt: string, params?: (string | number | null)[]): Promise<void>;
|
||||||
|
get(stmt: string, params?: (string | number | null)[]): Promise<any[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WebStore {
|
||||||
|
getValue(key: string): Promise<string>;
|
||||||
|
setValue(key: string, value: string): Promise<void>;
|
||||||
|
clearValue(key: string): Promise<void>;
|
||||||
|
clearAll(): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class OfflineStore implements Store {
|
export class OfflineStore implements Store {
|
||||||
@ -102,19 +113,19 @@ export class OfflineStore implements Store {
|
|||||||
await this.setAppValue(guid, 'profile_data', JSON.stringify(data));
|
await this.setAppValue(guid, 'profile_data', JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAccountRevision(guid: string): Promise<number> {
|
public async getSettingsRevision(guid: string): Promise<number> {
|
||||||
return await this.getAppValue(guid, 'account_revision', 0) as number;
|
return await this.getAppValue(guid, 'account_revision', 0) as number;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setAccountRevision(guid: string, revision: number): Promise<void> {
|
public async setSettingsRevision(guid: string, revision: number): Promise<void> {
|
||||||
await this.setAppValue(guid, 'account_revision', revision.toString());
|
await this.setAppValue(guid, 'account_revision', revision.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAccountData(guid: string): Promise<AccountEntity> {
|
public async getSettingsData(guid: string): Promise<ConfigEntity> {
|
||||||
return await this.getAppValue(guid, 'account_data', defaultAccountEntity) as AccountEntity;
|
return await this.getAppValue(guid, 'account_data', defaultConfigEntity) as ConfigEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setAccountData(guid: string, data: AccountEntity): Promise<void> {
|
public async setSettingsData(guid: string, data: ConfigEntity): Promise<void> {
|
||||||
await this.setAppValue(guid, 'account_data', JSON.stringify(data));
|
await this.setAppValue(guid, 'account_data', JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,18 +195,18 @@ export class OnlineStore implements Store {
|
|||||||
public async setProfileData(guid: string, data: ProfileEntity): Promise<void> {
|
public async setProfileData(guid: string, data: ProfileEntity): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAccountRevision(guid: string): Promise<number> {
|
public async getSettingsRevision(guid: string): Promise<number> {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setAccountRevision(guid: string, revision: number): Promise<void> {
|
public async setSettingsRevision(guid: string, revision: number): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAccountData(guid: string): Promise<AccountEntity> {
|
public async getSettingsData(guid: string): Promise<ConfigEntity> {
|
||||||
return defaultAccountEntity;
|
return defaultConfigEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setAccountData(guid: string, data: AccountEntity): Promise<void> {
|
public async setSettingsData(guid: string, data: ConfigEntity): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -238,18 +249,18 @@ export class NoStore implements Store {
|
|||||||
public async setProfileData(guid: string, data: ProfileEntity): Promise<void> {
|
public async setProfileData(guid: string, data: ProfileEntity): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAccountRevision(guid: string): Promise<number> {
|
public async getSettingsRevision(guid: string): Promise<number> {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setAccountRevision(guid: string, revision: number): Promise<void> {
|
public async setSettingsRevision(guid: string, revision: number): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getAccountData(guid: string): Promise<AccountEntity> {
|
public async getSettingsData(guid: string): Promise<ConfigEntity> {
|
||||||
return defaultAccountEntity;
|
return defaultConfigEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async setAccountData(guid: string, data: AccountEntity): Promise<void> {
|
public async setSettingsData(guid: string, data: ConfigEntity): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ export type Repeater = {
|
|||||||
server: string,
|
server: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AccountStatus = {
|
export type Config = {
|
||||||
disabled: boolean,
|
disabled: boolean,
|
||||||
storageUsed: number,
|
storageUsed: number,
|
||||||
storageAvailable: number,
|
storageAvailable: number,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user