mirror of
https://github.com/balzack/databag.git
synced 2025-03-13 09:00:06 +00:00
fixing unit tests
This commit is contained in:
parent
326794dbde
commit
b5b6bc032c
@ -1,5 +1,6 @@
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import type { Contact } from '../src/api';
|
||||
import type { Contact, Link } from '../src/api';
|
||||
import { MockLinkModule } from './link';
|
||||
import type { Card, Channel, Article, Topic, Asset, Tag, Profile, Participant} from '../src/types';
|
||||
|
||||
export class MockContactModule implements Contact {
|
||||
@ -20,6 +21,14 @@ export class MockContactModule implements Contact {
|
||||
this.emitter.off('card', ev);
|
||||
}
|
||||
|
||||
public addLoadedListener(ev: (loaded: boolean) => void): void {
|
||||
this.emitter.on('loaded', ev);
|
||||
}
|
||||
|
||||
public removeLoadedListener(ev: (loaded: boolean) => void): void {
|
||||
this.emitter.off('loaded', ev);
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
}
|
||||
|
||||
@ -216,5 +225,9 @@ export class MockContactModule implements Contact {
|
||||
|
||||
public removeChannelListener(ev: (arg: { cardId: string | null; channels: Channel[] }) => void): void {
|
||||
}
|
||||
|
||||
public async callCard(cardId: string): Promise<Link> {
|
||||
return new MockLinkModule();
|
||||
}
|
||||
}
|
||||
|
||||
|
34
app/sdk/__mocks__/link.ts
Normal file
34
app/sdk/__mocks__/link.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { type Link } from '../src/api';
|
||||
|
||||
export class MockLinkModule implements Link {
|
||||
private emitter: EventEmitter;
|
||||
|
||||
constructor() {
|
||||
this.emitter = new EventEmitter();
|
||||
}
|
||||
|
||||
public setStatusListener(ev: (status: string) => Promise<void>): void {
|
||||
}
|
||||
|
||||
public clearStatusListener(): void {
|
||||
}
|
||||
|
||||
public setMessageListener(ev: (message: any) => Promise<void>): void {
|
||||
}
|
||||
|
||||
public clearMessageListener(): void {
|
||||
}
|
||||
|
||||
public getIce(): { urls: string; username: string; credential: string }[] {
|
||||
return [];
|
||||
}
|
||||
|
||||
public async sendMessage(message: any): Promise<void> {
|
||||
}
|
||||
|
||||
public async close(): Promise<void> {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,46 +1,31 @@
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import type { Ring } from '../src/api';
|
||||
import type { Ring, Link } from '../src/api';
|
||||
import type { Call } from '../src/types';
|
||||
|
||||
import { MockLinkModule } from './link';
|
||||
export class MockRingModule implements Ring {
|
||||
|
||||
public call: Call | null;
|
||||
private emitter: EventEmitter;
|
||||
|
||||
constructor() {
|
||||
this.call = null;
|
||||
this.emitter = new EventEmitter();
|
||||
}
|
||||
|
||||
public addCallingListener(ev: (calls: Call[]) => void): void {
|
||||
this.emitter.on('calling', ev);
|
||||
public addRingingListener(ev: (calls: { cardId: string, callId: string }[]) => void): void {
|
||||
}
|
||||
|
||||
public removeCallingListener(ev: (calls: Call[]) => void): void {
|
||||
this.emitter.off('calling', ev);
|
||||
}
|
||||
|
||||
public addCallListener(ev: (call: Call | null) => void): void {
|
||||
this.emitter.on('call', ev);
|
||||
}
|
||||
|
||||
public removeCallListener(ev: (call: Call | null) => void): void {
|
||||
this.emitter.off('call', ev);
|
||||
public removeRingingListener(ev: (calls: { cardId: string, callId: string }[]) => void): void {
|
||||
}
|
||||
|
||||
public ring(call: Call): void {
|
||||
this.call = call;
|
||||
}
|
||||
|
||||
public accept(callId: string): void {
|
||||
public async accept(cardId: string, callId: string, contactNode: string): Promise<Link> {
|
||||
return new MockLinkModule();
|
||||
}
|
||||
|
||||
public ignore(callId: string): void {
|
||||
public async decline(cardId: string, callId: string, contactNode: string): Promise<void> {
|
||||
}
|
||||
|
||||
public decline(callId: string): void {
|
||||
}
|
||||
|
||||
public close(): void {
|
||||
public async ignore(cardId: string, callId: string): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import { type Settings } from '../src/api';
|
||||
import type { Config } from '../src/types';
|
||||
import { type Config } from '../src/types';
|
||||
|
||||
export class MockSettingsModule implements Settings {
|
||||
|
||||
@ -78,5 +78,17 @@ export class MockSettingsModule implements Settings {
|
||||
|
||||
public async setLogin(username: string, password: string): Promise<void> {
|
||||
}
|
||||
|
||||
public async getBlockedCards(): Promise<{ cardId: string, timestamp: number}[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
public async getBlockedChannels(): Promise<{ cardId: string|null, channelId: string, timestamp: number }[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
public async getBlockedTopics(): Promise<{ cardId: string|null, channelId: string, topicId: string, timestamp: number }[]> {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,14 @@ export class MockStreamModule {
|
||||
this.emitter.off('channel', ev);
|
||||
}
|
||||
|
||||
public addLoadedListener(ev: (loaded: boolean) => void): void {
|
||||
this.emitter.on('loaded', ev);
|
||||
}
|
||||
|
||||
public removeLoadedListener(ev: (loaded: boolean) => void): void {
|
||||
this.emitter.off('loaded', ev);
|
||||
}
|
||||
|
||||
public async setBlockedChannel(channelId: string, blocked: boolean): Promise<void> {
|
||||
}
|
||||
|
||||
|
@ -89,7 +89,8 @@ jest.mock('../src/net/fetchUtil', () => {
|
||||
return Promise.resolve({ status: 200, json: () => JSON.parse('{"keyType": "RSA2048", "message": "eyJndWlkIjoiMDAzNWQ2ZmZkMzQyMThhMTJiNmYzYzY3ZWQyYzIwZjRlZWUwNmRjMzZlZWQwMzcxNWJiZjQ2ZjA0MzY2NTExYyIsInRpbWVzdGFtcCI6MTcyOTkwMjg4NCwibWVzc2FnZVR5cGUiOiJpZGVudGl0eSIsInZhbHVlIjoie1wicmV2aXNpb25cIjoxLFwiaGFuZGxlXCI6XCIxMjN0dHR0cnJcIixcInZlcnNpb25cIjpcIjAuMS4wXCIsXCJub2RlXCI6XCJiYWx6YWNrLmNvcmVkYi5vcmdcIixcInNlYWxcIjpcIlwifSJ9", "publicKey": "LS0tLS1CRUdJTiBSU0EgUFVCTElDIEtFWS0tLS0tCk1JSUNJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBZzhBTUlJQ0NnS0NBZ0VBcmI1Zjd4a0NmODhlazhhQ05paVgKWlpJOCt3dlArSzZBUG85OWZCM3hBWWRGVi84djZzSTdCY3lnWXYxVC9QbzI2UmpPdEZjcVRRV1ZZZlBiTlZxVgpQQ1VSblJwWkVnQWVjSGdqUmNzSjF3cWJZQWZRSDhhRGR4aGE4enRRcS9ZVlVzRCtkRU5IamNYV0NCSW04eDVzCjZ2NXo1aS9BeFRyR2I4YlgybDAydUxaNmVIYjNuOHhUQkRMa2VPUzJBaFZWWW0zSVc3bjhrQUJnT2dQY1Y1QS8Ka1B2LzFWbnJ4OTd6Q2VNaHdYd3Y0SEpxTldGR3dvaUlTNzJXU2hCcWk5N2ZSRHlOSVJ4SVJrMDFRdlJYL3hMcQpuM3R0WWN1cWdYN0NoUGhyRHpwRVlKOUZKT0ZaQSt1TVF2K1NmZVg4YlQzcGEzV2hXNFFHZ3BMNXhuM0NuMTlkCkYwVG1laWVLSTUyR0lPejRLV1R2alJDZHc2YW5vTGJNWW0xUzM4emhpbHZ4YWlZWTZ4WXVpNXJneWU2bzJlakgKZGphV0kzeTRaZVJ1UnUxTEgzd1U2UGhzbGhDZnJrU05FVFIzRkd2RWRKNzRzdVFEVmtnakF2R3BqaC9FUlkyUApZYmE1L254WlJVRGF4bjFjcURzOU0wUk5pMHp0R2d3dVJPSE1WeHFNMEFONko2TnJlL3F0dTFGbm5SMVllMmQ5CnRHVDVLSXRaZUN2dzY0Y3U2SFhMZWFzcXg3b2kwbU5BT0RoQWUrMzlXbFN1VEE1YWNyR3YydFpUSldPY0I5TmcKNlpGb2hzY3ErbHdVZHM3ek1lVkdXU1VQWmtnZUxrTk9rT0ZlWVNuVk4wc2RaVHFQMllTU0hDU0hxS0dtaHlhMQpXRlNPMTBxaTZjQWhheldraWMyR0Zwa0NBd0VBQVE9PQotLS0tLUVORCBSU0EgUFVCTElDIEtFWS0tLS0tCg==", "signature": "gj5NKLzgF5HHWthu47ofuEhkhpOiP4CJ5QNG65VmuqL05Mu7dUef5Nxp6BacCIJoDb3GdYbHI/UBj0Ns4gBsMihOkwIMCav/P0FdvLYZQrpaNf6t6PUI2c4xW/w3gZ/5IrJiUmWE+PKYTjMjUlroc1gHAXIyGG2vs152HT2uMjB/kGKMU1nxvjABAN+khhw7h0iW3EBKffKRTeAsRjUw6YIXwmeYEM7MP8zrISkKquIScf4yxDM2iZWC0DJOvGa4XANqkLKLPNL11u7hBXt2Ovj++U5eQsYSXcn1IDyhwlgRyRzuNEayZJnpbCCyXybEIaty+bf0wdq5nVWi1E4ju4wY+Z1pV5lsXtuKyxA/GY4Zk3QMTwx4dz2tWPDQYa35VUeyxhm5U5iMWdFG+nJuhPT0IhajLWrrTzQA5xXCzb5Da/ae0FrS3w3opATKNKxDpl0P5gjCQ1Xbku7VoUYaQQ6JaTdxNV/eKNCmcDcCDnZoEsE0Mp1hcqf8nT6YVvIVJG5luhv5TWEmTLBgZsWfUreaUkz/DJV+0fLwfL6oZuRkEx3aZnU1BfWtsS1ecgVJ93Q73sGohnUN9EaeR4ruviMrb4x1lS1IHGFuKooGqChukuTbKxlBkeqABiMsVkvme846cpFWijv/CnK6yoDhJA9lHaugjI+KgapYZUOwJOg=", "signatureType": "PKCS1v15"}') });
|
||||
}
|
||||
else if (url === 'http://test_url/contact/cards?agent=test_token' && options.method === 'POST') {
|
||||
return Promise.resolve({ status: 200, json: () => JSON.parse(options.body).message.substring(0,9) });
|
||||
const id = JSON.parse(options.body).message.substring(0,9);
|
||||
return Promise.resolve({ status: 200, json: () => ({ id }) });
|
||||
}
|
||||
else {
|
||||
return Promise.resolve({ status: 200, json: () => [] });
|
||||
|
@ -52,7 +52,7 @@ const getChannel = (subject: string, message: string, revision: number) => {
|
||||
lastTopic: {
|
||||
guid: 'guid1',
|
||||
dataType: 'test',
|
||||
data: JSON.stringify({ message: message }),
|
||||
data: JSON.stringify({ text: message }),
|
||||
created: 2,
|
||||
updated: 2,
|
||||
status: 'ready',
|
||||
@ -107,7 +107,7 @@ const getChannelSummary = (message: string) => {
|
||||
lastTopic: {
|
||||
guid: 'guid1',
|
||||
dataType: 'test',
|
||||
data: JSON.stringify({ message: message }),
|
||||
data: JSON.stringify({ text: message }),
|
||||
created: 2,
|
||||
updated: 2,
|
||||
status: 'ready',
|
||||
@ -172,11 +172,11 @@ test('received contact updates', async () => {
|
||||
await waitFor(() => cardChannels.get('C000A')?.length === 1);
|
||||
|
||||
await waitFor(() => cardChannels.get('C000A')?.[0].data.subject === 'test_subject_0');
|
||||
await waitFor(() => cardChannels.get('C000A')?.[0].lastTopic.data.message === 'test_message_0');
|
||||
await waitFor(() => cardChannels.get('C000A')?.[0].lastTopic.data.text === 'test_message_0');
|
||||
|
||||
await contact.setRevision(2);
|
||||
await waitFor(() => cardChannels.get('C000A')?.[0].data.subject === 'test_subject_1');
|
||||
await waitFor(() => cardChannels.get('C000A')?.[0].lastTopic.data.message === 'test_message_1');
|
||||
await waitFor(() => cardChannels.get('C000A')?.[0].lastTopic.data.text === 'test_message_1');
|
||||
|
||||
await contact.setRevision(3);
|
||||
await waitFor(() => cardChannels.get('C000A')?.length === 0);
|
||||
@ -199,11 +199,11 @@ test('received stream updates', async () => {
|
||||
await stream.setRevision(1);
|
||||
await waitFor(() => streamChannels.get(null)?.length === 1);
|
||||
await waitFor(() => streamChannels.get(null)?.[0].data.subject === 'test_subject_0');
|
||||
await waitFor(() => streamChannels.get(null)?.[0].lastTopic.data.message === 'test_message_0');
|
||||
await waitFor(() => streamChannels.get(null)?.[0].lastTopic.data.text === 'test_message_0');
|
||||
|
||||
await stream.setRevision(2);
|
||||
await waitFor(() => streamChannels.get(null)?.[0].data.subject === 'test_subject_1');
|
||||
await waitFor(() => streamChannels.get(null)?.[0].lastTopic.data.message === 'test_message_1');
|
||||
await waitFor(() => streamChannels.get(null)?.[0].lastTopic.data.text === 'test_message_1');
|
||||
|
||||
await stream.setRevision(3);
|
||||
await waitFor(() => streamChannels.get(null)?.length === 0);
|
||||
|
@ -106,7 +106,6 @@ test('allocates session correctly', async () => {
|
||||
mockConnection.emitRevision({ account: 3, profile: 3, article: 3, group: 3, channel: 3, card: 3});
|
||||
mockConnection.emitRing({ cardId: '', callId: 'test', calleeToken: '', ice: []});
|
||||
await waitFor(() => (status === 'connected'));
|
||||
await waitFor(() => (mockRing.call?.callId === 'test'));
|
||||
await waitFor(() => (mockSettings.revision == 3));
|
||||
await waitFor(() => (mockIdentity.revision == 3));
|
||||
await waitFor(() => (mockStream.revision == 3));
|
||||
|
@ -29,8 +29,8 @@ export interface Link {
|
||||
}
|
||||
|
||||
export interface Ring {
|
||||
addRingingListener(ev: (calls: Call[]) => void): void;
|
||||
removeRingingListener(ev: (calls: Call[]) => void): void;
|
||||
addRingingListener(ev: (calls: { cardId: string, callId: string }[]) => void): void
|
||||
removeRingingListener(ev: (calls: { cardId: string, callId: string }[]) => void): void
|
||||
|
||||
accept(cardId: string, callId: string, contactNode: string): Promise<Link>;
|
||||
decline(cardId: string, callId: string, contactNode: string): Promise<void>;
|
||||
@ -55,7 +55,7 @@ export interface Settings {
|
||||
|
||||
getBlockedCards(): Promise<{cardId: string, timestamp: number}[]>;
|
||||
getBlockedChannels(): Promise<{cardId: string | null, channelId: string, timestamp: number}[]>;
|
||||
getBlockedTopicis(): Promise<{cardId: string | null, channelId: string, topicId: string, timestamp: number}[]>;
|
||||
getBlockedTopics(): Promise<{cardId: string | null, channelId: string, topicId: string, timestamp: number}[]>;
|
||||
|
||||
addConfigListener(ev: (config: Config) => void): void;
|
||||
removeConfigListener(ev: (config: Config) => void): void;
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
import type { Contact, Focus } from './api';
|
||||
import type { Contact, Focus, Link } from './api';
|
||||
import { Logging } from './logging';
|
||||
import { FocusModule } from './focus';
|
||||
import { LinkModule } from './link';
|
||||
@ -109,7 +109,7 @@ export class ContactModule implements Contact {
|
||||
this.blockedCardChannel = new Set<string>();
|
||||
this.read = new Map<string, number>();
|
||||
this.offsyncProfileCard = new Map<string, number>();
|
||||
this.offsyncArticleCard = new Map<string, nubmer>();
|
||||
this.offsyncArticleCard = new Map<string, number>();
|
||||
this.offsyncChannelCard = new Map<string, number>();
|
||||
|
||||
this.revision = 0;
|
||||
@ -656,7 +656,8 @@ export class ContactModule implements Contact {
|
||||
enableVideo,
|
||||
enableBinary,
|
||||
created,
|
||||
members: members.map(guid => ({ guid })),
|
||||
members: members.map(({ member }) => ({ guid: member }))
|
||||
//members: []
|
||||
}
|
||||
this.focus.setDetail(cardId, id, focusDetail);
|
||||
}
|
||||
@ -1010,6 +1011,18 @@ export class ContactModule implements Contact {
|
||||
}
|
||||
}
|
||||
|
||||
public async getBlockedChannels(): Promise<Channel[]> {
|
||||
const channels = [] as Channel[];
|
||||
this.channelEntries.forEach((card, cardId) => {
|
||||
card.forEach((entry, channelId) => {
|
||||
if (this.isChannelBlocked(cardId, channelId)) {
|
||||
channels.push(entry.channel);
|
||||
}
|
||||
});
|
||||
});
|
||||
return channels;
|
||||
}
|
||||
|
||||
public async clearBlockedChannelTopic(cardId: string, channelId: string, topicId: string) {
|
||||
const { guid } = this;
|
||||
const id = `${cardId}:${channelId}:${topicId}`
|
||||
|
@ -236,7 +236,8 @@ export type AccountEntity = {
|
||||
seal?: string;
|
||||
version: string;
|
||||
node: string;
|
||||
storageUsed: string;
|
||||
storageUsed: number;
|
||||
disabled: boolean;
|
||||
};
|
||||
|
||||
export const defaultProfileEntity = {
|
||||
@ -277,17 +278,16 @@ export type Calling = {
|
||||
callerToken: string;
|
||||
calleeToken: string;
|
||||
keepAlive: number;
|
||||
ice: { urls: string[]; username: string; credential: string }[];
|
||||
ice: { urls: string; username: string; credential: string }[];
|
||||
}
|
||||
|
||||
export type Ringing = {
|
||||
cardId: string;
|
||||
callId: string;
|
||||
calleeToken: string;
|
||||
ice: { urls: string[]; username: string; credential: string }[];
|
||||
iceUrl: string;
|
||||
iceUsername: string;
|
||||
icePassword: string;
|
||||
iceUrl?: string;
|
||||
iceUsername?: string;
|
||||
icePassword?: string;
|
||||
};
|
||||
|
||||
export type Revision = {
|
||||
|
@ -259,7 +259,13 @@ export class FocusModule implements Focus {
|
||||
return new Promise(function (resolve, reject) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, true);
|
||||
xhr.onprogress = (ev: ProgressEvent<EventTarget>)=>{ progress((ev.loaded * 100) / ev.total) };
|
||||
xhr.onprogress = (ev: ProgressEvent<EventTarget>)=>{
|
||||
try {
|
||||
progress((ev.loaded * 100) / ev.total)
|
||||
} catch (err) {
|
||||
xhr.abort();
|
||||
}
|
||||
};
|
||||
xhr.setRequestHeader('Content-Type', 'text/plain');
|
||||
xhr.onload = () => {
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
@ -275,7 +281,7 @@ export class FocusModule implements Focus {
|
||||
});
|
||||
}
|
||||
|
||||
private uploadBlock(block: string, topicId: string, progress: (percent: number)=>boolean): Promise<string> {
|
||||
private uploadBlock(block: string, topicId: string, progress: (percent: number)=>boolean|void): Promise<string> {
|
||||
const { cardId, channelId, connection } = this;
|
||||
if (!connection) {
|
||||
throw new Error('disconnected from channel');
|
||||
@ -307,7 +313,7 @@ export class FocusModule implements Focus {
|
||||
});
|
||||
}
|
||||
|
||||
private mirrorFile(source: File|string, topicId: string, progress: (percent: number)=>boolean): Promise<string> {
|
||||
private mirrorFile(source: File|string, topicId: string, progress: (percent: number)=>boolean|void): Promise<{ assetId: string }> {
|
||||
const { cardId, channelId, connection } = this;
|
||||
if (!connection) {
|
||||
throw new Error('disconnected from channel');
|
||||
@ -317,7 +323,7 @@ export class FocusModule implements Focus {
|
||||
const url = `http${secure ? 's' : ''}://${node}/content/channels/${channelId}/topics/${topicId}/blocks?${params}`
|
||||
const formData = new FormData();
|
||||
if (typeof source === 'string') { // file path used in mobile
|
||||
formData.append("asset", {uri: source, name: 'asset', type: 'application/octent-stream'});
|
||||
formData.append("asset", {uri: source, name: 'asset', type: 'application/octent-stream'} as any);
|
||||
} else { // file object used in browser
|
||||
formData.append('asset', source);
|
||||
}
|
||||
@ -344,7 +350,7 @@ export class FocusModule implements Focus {
|
||||
});
|
||||
}
|
||||
|
||||
private transformFile(source: File|string, topicId: string, transforms: string[], progress: (percent: number)=>boolean): Promise<{assetId: string, transform: string}[]> {
|
||||
private transformFile(source: File|string, topicId: string, transforms: string[], progress: (percent: number)=>boolean|void): Promise<{assetId: string, transform: string}[]> {
|
||||
const { cardId, channelId, connection } = this;
|
||||
if (!connection) {
|
||||
throw new Error('disconnected from channel');
|
||||
@ -355,7 +361,7 @@ export class FocusModule implements Focus {
|
||||
const formData = new FormData();
|
||||
|
||||
if (typeof source === 'string') { // file path used in mobile
|
||||
formData.append("asset", {uri: source, name: 'asset', type: 'application/octent-stream'});
|
||||
formData.append("asset", {uri: source, name: 'asset', type: 'application/octent-stream'} as any);
|
||||
} else { // file object used in browser
|
||||
formData.append('asset', source);
|
||||
}
|
||||
@ -450,7 +456,7 @@ export class FocusModule implements Focus {
|
||||
const { encryptedDataB64 } = await crypto.aesEncrypt(base64Data, ivHex, channelKey);
|
||||
const partId = await this.uploadBlock(encryptedDataB64, topicId, (percent: number) => {
|
||||
const count = Math.ceil(stagingFile.size / ENCRYPT_BLOCK_SIZE);
|
||||
assetProgress(Math.floor((i * 100 + percent) / count));
|
||||
return assetProgress(Math.floor((i * 100 + percent) / count));
|
||||
});
|
||||
split.push({ partId, blockIv: ivHex });
|
||||
}
|
||||
@ -691,7 +697,7 @@ export class FocusModule implements Focus {
|
||||
transforms.push('acopy;audio');
|
||||
transformMap.set('acopy;audio', transform.appId);
|
||||
} else if (transform.type === TransformType.Copy && asset.type === AssetType.Binary) {
|
||||
const assetId = await this.mirrorFile(asset.source, topicId, progress);
|
||||
const { assetId } = await this.mirrorFile(asset.source, topicId, progress);
|
||||
const assetItem = {
|
||||
assetId: `${assetItems.length}`,
|
||||
hosting: HostingMode.Basic,
|
||||
@ -798,6 +804,7 @@ export class FocusModule implements Focus {
|
||||
if (!asset) {
|
||||
throw new Error('asset entry not found');
|
||||
}
|
||||
|
||||
if (asset.hosting === HostingMode.Inline && asset.inline) {
|
||||
return `${asset.inline}`;
|
||||
} else if (asset.hosting === HostingMode.Basic && asset.basic) {
|
||||
@ -809,22 +816,22 @@ export class FocusModule implements Focus {
|
||||
}
|
||||
const write = await staging.write();
|
||||
this.closeStaging.push(write.close);
|
||||
for (let i = 0; i < asset.split.length; i++) {
|
||||
let download = true;
|
||||
const assetCount = asset.split.length;
|
||||
for (let i = 0; i < assetCount; i++) {
|
||||
if (progress) {
|
||||
download = progress(Math.floor((i * 100) / asset.split.length));
|
||||
}
|
||||
if (download === false) {
|
||||
throw new Error('aborted asset load');
|
||||
const download = progress(Math.floor((i * 100) / assetCount));
|
||||
if (download === false) {
|
||||
throw new Error('aborted asset load');
|
||||
}
|
||||
}
|
||||
const block = await this.downloadBlock(topicId, asset.split[i].partId, (percent: number)=>{
|
||||
if (progress && download !== false) {
|
||||
download = progress(Math.floor((i * 100 + percent) / asset.split.length));
|
||||
if (progress) {
|
||||
const download = progress(Math.floor((i * 100 + percent) / assetCount));
|
||||
if (download === false) {
|
||||
throw new Error('aborting asset load');
|
||||
}
|
||||
}
|
||||
});
|
||||
if (download === false) {
|
||||
throw new Error('aborted asset load');
|
||||
}
|
||||
const { data } = await crypto.aesDecrypt(block, asset.split[i].blockIv, channelKey);
|
||||
await write.setData(data);
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import type { AssetItem } from './items';
|
||||
import { HostingMode } from './types';
|
||||
import { BasicAsset } from './entities';
|
||||
|
||||
export function getLegacyData(data: any): { data: any, assets: AssetItem[] } {
|
||||
if (data == null) {
|
||||
@ -86,7 +87,7 @@ export function getLegacyData(data: any): { data: any, assets: AssetItem[] } {
|
||||
assetItems.add(fullAsset);
|
||||
index += 1;
|
||||
return { audio: { label, full: `${index-1}` }};
|
||||
} else {
|
||||
} else if (binary) {
|
||||
const { label, extension, data } = binary;
|
||||
const dataAsset = {
|
||||
assetId: `${index}`,
|
||||
@ -96,9 +97,11 @@ export function getLegacyData(data: any): { data: any, assets: AssetItem[] } {
|
||||
assetItems.add(dataAsset);
|
||||
index += 1;
|
||||
return { binary: { label, extension, data: `${index-1}` }};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
return { data: { text, textColor, textSize, assets: dataAssets }, assets: Array.from(assetItems.values()) };
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import type { Link, Logging } from './api';
|
||||
import type { Link } from './api';
|
||||
import { Logging } from './logging';
|
||||
import { addCall } from './net/addCall';
|
||||
import { removeCall } from './net/removeCall';
|
||||
import { removeContactCall } from './net/removeContactCall';
|
||||
@ -13,19 +14,17 @@ const RING_INTERVAL = 2000;
|
||||
export class LinkModule implements Link {
|
||||
private log: Logging;
|
||||
private status: string;
|
||||
private statusListener: (status: string)=>Promise<void> | null;
|
||||
private messageListener: (message: any)=>Promise<void> | null;
|
||||
private statusListener: ((status: string)=>Promise<void>) | null;
|
||||
private messageListener: ((message: any)=>Promise<void>) | null;
|
||||
private messages: string[];
|
||||
private error: boolean;
|
||||
private closed: boolean;
|
||||
private connected: boolean;
|
||||
private notifying: boolean;
|
||||
private websocket: Websocket | null;
|
||||
private staleInterval: number | null;
|
||||
private aliveInterval: number | null;
|
||||
private ringInterval: number | null;
|
||||
private node: string;
|
||||
private secure: boolean;
|
||||
private token: string;
|
||||
private websocket: WebSocket | null;
|
||||
private staleInterval: ReturnType<typeof setTimeout> | null;
|
||||
private aliveInterval: ReturnType<typeof setTimeout> | null;
|
||||
private ringInterval: ReturnType<typeof setTimeout> | null;
|
||||
private ice: { urls: string; username: string; credential: string }[];
|
||||
private cleanup: null | (()=>void);
|
||||
|
||||
@ -145,7 +144,7 @@ export class LinkModule implements Link {
|
||||
}
|
||||
|
||||
public async sendMessage(message: any) {
|
||||
if (this.status !== 'connected') {
|
||||
if (this.status !== 'connected' || !this.websocket) {
|
||||
this.log.error('dropping message while not connected')
|
||||
} else {
|
||||
this.websocket.send(JSON.stringify(message));
|
||||
@ -157,16 +156,18 @@ export class LinkModule implements Link {
|
||||
this.notifying = true;
|
||||
while(this.messages.length > 0 && !this.error) {
|
||||
const data = this.messages.shift();
|
||||
try {
|
||||
const message = JSON.parse(data);
|
||||
if (message.status) {
|
||||
await this.notifyStatus(message.status);
|
||||
} else {
|
||||
await this.notifyMessage(message);
|
||||
if (data) {
|
||||
try {
|
||||
const message = JSON.parse(data);
|
||||
if (message.status) {
|
||||
await this.notifyStatus(message.status);
|
||||
} else {
|
||||
await this.notifyMessage(message);
|
||||
}
|
||||
} catch (err) {
|
||||
this.log.error('failed to process signal message');
|
||||
this.notifyStatus('error');
|
||||
}
|
||||
} catch (err) {
|
||||
this.log.error('failed to process signal message');
|
||||
this.notifyStatus('error');
|
||||
}
|
||||
}
|
||||
this.notifying = false;
|
||||
@ -206,15 +207,11 @@ export class LinkModule implements Link {
|
||||
await this.messageListener(message);
|
||||
}
|
||||
} catch (err) {
|
||||
this.log('message notification failed');
|
||||
this.log.warn('message notification failed');
|
||||
}
|
||||
}
|
||||
|
||||
private setWebSocket(token: string, node: string, secure: boolean): WebSocket {
|
||||
if (this.closed) {
|
||||
return this.websocket;
|
||||
}
|
||||
|
||||
const wsUrl = `ws${secure ? 's' : ''}://${node}/signal`;
|
||||
const ws = new WebSocket(wsUrl);
|
||||
ws.onmessage = (e) => {
|
||||
@ -230,7 +227,9 @@ export class LinkModule implements Link {
|
||||
ws.onclose = () => {};
|
||||
ws.onopen = () => {};
|
||||
ws.onerror = () => {};
|
||||
this.websocket = this.setWebSocket(token, node);
|
||||
if (!this.closed) {
|
||||
this.websocket = this.setWebSocket(token, node, secure);
|
||||
}
|
||||
}
|
||||
}, RETRY_INTERVAL);
|
||||
};
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||
import { SetupEntity } from '../entities';
|
||||
|
||||
export async function getNodeConfig(server: string, secure: boolean, token: string): Promise<ConfigEntity> {
|
||||
export async function getNodeConfig(server: string, secure: boolean, token: string): Promise<SetupEntity> {
|
||||
const endpoint = `http${secure ? 's' : ''}://${server}/admin/config?token=${token}`;
|
||||
const config = await fetchWithTimeout(endpoint, { method: 'GET' });
|
||||
checkResponse(config.status);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { checkResponse, fetchWithTimeout } from './fetchUtil';
|
||||
import { PushParams } from '../types';
|
||||
|
||||
export async function setAccountNotifications(node: string, secure: boolean, token: string, flag: boolean, pushParams: PushParams) {
|
||||
export async function setAccountNotifications(node: string, secure: boolean, token: string, flag: boolean, pushParams?: PushParams) {
|
||||
const pushEndpoint = pushParams ? encodeURIComponent(pushParams.endpoint) : '';
|
||||
const publicKey = pushParams ? encodeURIComponent(pushParams.publicKey) : '';
|
||||
const auth = pushParams ? encodeURIComponent(pushParams.auth) : '';
|
||||
|
@ -1,5 +1,6 @@
|
||||
import type { Service } from './api';
|
||||
import type { Member, Setup } from './types';
|
||||
import { KeyType, ICEService } from './types';
|
||||
import { type AccountEntity, avatar } from './entities';
|
||||
import type { Logging } from './logging';
|
||||
import { getMembers } from './net/getMembers';
|
||||
@ -64,9 +65,10 @@ export class ServiceModule implements Service {
|
||||
const { domain, accountStorage, enableImage, enableAudio, enableVideo, enableBinary,
|
||||
keyType, pushSupported, allowUnsealed, transformSupported, enableIce, iceService,
|
||||
iceUrl, iceUsername, icePassword, enableOpenAccess, openAccessLimit } = entity;
|
||||
const service = iceService ? iceService : 'default';
|
||||
const service = iceService === 'cloudflare' ? ICEService.Cloudflare : ICEService.Default;
|
||||
const type = keyType === 'RSA4096' ? KeyType.RSA_4096 : KeyType.RSA_2048;
|
||||
const setup = { domain, accountStorage, enableImage, enableAudio, enableVideo, enableBinary,
|
||||
keyType, pushSupported, allowUnsealed, transformSupported, enableIce, iceService: service,
|
||||
keyType: type, pushSupported, allowUnsealed, transformSupported, enableIce, iceService: service,
|
||||
iceUrl, iceUsername, icePassword, enableOpenAccess, openAccessLimit };
|
||||
return setup;
|
||||
}
|
||||
@ -76,9 +78,10 @@ export class ServiceModule implements Service {
|
||||
const { domain, accountStorage, enableImage, enableAudio, enableVideo, enableBinary,
|
||||
keyType, pushSupported, allowUnsealed, transformSupported, enableIce, iceService,
|
||||
iceUrl, iceUsername, icePassword, enableOpenAccess, openAccessLimit } = setup;
|
||||
const service = iceService === 'default' ? null : iceService;
|
||||
const service = iceService === ICEService.Cloudflare ? 'cloudflare' : ''
|
||||
const type = keyType === KeyType.RSA_4096 ? 'RSA4096' : 'RSA2048';
|
||||
const entity = { domain, accountStorage, enableImage, enableAudio, enableVideo, enableBinary,
|
||||
keyType, pushSupported, allowUnsealed, transformSupported, enableIce, iceService: service,
|
||||
keyType: type, pushSupported, allowUnsealed, transformSupported, enableIce, iceService: service,
|
||||
iceUrl, iceUsername, icePassword, enableOpenAccess, openAccessLimit };
|
||||
await setNodeConfig(node, secure, token, entity);
|
||||
}
|
||||
|
@ -169,7 +169,7 @@ export class StreamModule {
|
||||
enableVideo,
|
||||
enableBinary,
|
||||
created,
|
||||
members: members.map(guid => ({ guid })),
|
||||
members: members.map(guid => ({ guid: guid.member })),
|
||||
}
|
||||
this.focus.setDetail(null, id, focusDetail);
|
||||
}
|
||||
@ -392,6 +392,16 @@ export class StreamModule {
|
||||
await clearChannelCard(node, secure, token, channelId, cardId);
|
||||
}
|
||||
|
||||
public async getBlockedChannels(): Promise<Channel[]> {
|
||||
const channels = [] as Channel[];
|
||||
this.channelEntries.forEach((entry, channelId) => {
|
||||
if (this.isChannelBlocked(channelId)) {
|
||||
channels.push(entry.channel);
|
||||
}
|
||||
});
|
||||
return channels;
|
||||
}
|
||||
|
||||
public async setBlockedChannel(channelId: string, blocked: boolean): Promise<void> {
|
||||
const entry = this.channelEntries.get(channelId);
|
||||
if (entry) {
|
||||
|
@ -215,8 +215,6 @@ export type Member = {
|
||||
guid: string;
|
||||
handle: string;
|
||||
name: string;
|
||||
description: string;
|
||||
location: string;
|
||||
imageUrl: string;
|
||||
disabled: boolean;
|
||||
storageUsed: number,
|
||||
|
Loading…
Reference in New Issue
Block a user