@peers-app/peers-sdk 0.7.5 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/context/user-context.d.ts +2 -1
- package/dist/context/user-context.js +7 -5
- package/dist/data/data-locks.test.js +4 -1
- package/dist/device/connection.d.ts +3 -1
- package/dist/device/connection.js +19 -2
- package/dist/device/device-election.js +6 -4
- package/dist/device/socket.type.d.ts +2 -2
- package/dist/device/streamed-socket.d.ts +1 -1
- package/dist/device/streamed-socket.js +2 -2
- package/dist/types/peer-device.d.ts +5 -0
- package/dist/utils.js +6 -0
- package/package.json +1 -1
|
@@ -6,6 +6,7 @@ import { Observable } from "../observable";
|
|
|
6
6
|
export declare class UserContext {
|
|
7
7
|
readonly userId: string;
|
|
8
8
|
readonly dataSourceFactory: DataSourceFactory;
|
|
9
|
+
readonly ephemeral?: boolean | undefined;
|
|
9
10
|
readonly deviceId: Observable<string>;
|
|
10
11
|
readonly currentlyActiveGroupId: Observable<string | undefined>;
|
|
11
12
|
readonly reloadPackagesOnPageRefresh: Observable<boolean>;
|
|
@@ -14,7 +15,7 @@ export declare class UserContext {
|
|
|
14
15
|
readonly groupDataContexts: Map<string, DataContext>;
|
|
15
16
|
readonly defaultDataContext: Observable<DataContext>;
|
|
16
17
|
readonly loadingPromise: Promise<UserContext>;
|
|
17
|
-
constructor(userId: string, dataSourceFactory: DataSourceFactory);
|
|
18
|
+
constructor(userId: string, dataSourceFactory: DataSourceFactory, ephemeral?: boolean | undefined);
|
|
18
19
|
private init;
|
|
19
20
|
/**
|
|
20
21
|
* We want to load all packages as part of user context initialization
|
|
@@ -11,6 +11,7 @@ const utils_1 = require("../utils");
|
|
|
11
11
|
class UserContext {
|
|
12
12
|
userId;
|
|
13
13
|
dataSourceFactory;
|
|
14
|
+
ephemeral;
|
|
14
15
|
deviceId = (0, observable_1.observable)('');
|
|
15
16
|
currentlyActiveGroupId = (0, observable_1.observable)();
|
|
16
17
|
reloadPackagesOnPageRefresh = (0, observable_1.observable)(false);
|
|
@@ -19,19 +20,20 @@ class UserContext {
|
|
|
19
20
|
groupDataContexts = new Map();
|
|
20
21
|
defaultDataContext;
|
|
21
22
|
loadingPromise;
|
|
22
|
-
constructor(userId, dataSourceFactory) {
|
|
23
|
+
constructor(userId, dataSourceFactory, ephemeral) {
|
|
23
24
|
this.userId = userId;
|
|
24
25
|
this.dataSourceFactory = dataSourceFactory;
|
|
26
|
+
this.ephemeral = ephemeral;
|
|
27
|
+
if (ephemeral === undefined && typeof process !== 'undefined' && process.env.NODE_ENV === 'test') {
|
|
28
|
+
this.ephemeral = true;
|
|
29
|
+
}
|
|
25
30
|
this.userDataContext = new data_context_1.DataContext(this);
|
|
26
31
|
this.defaultDataContext = (0, observable_1.observable)(this.userDataContext);
|
|
27
32
|
this.defaultDataContext(this.userDataContext);
|
|
28
33
|
this.loadingPromise = this.init();
|
|
29
34
|
}
|
|
30
35
|
async init() {
|
|
31
|
-
if (
|
|
32
|
-
console.log(`not setting up user-context pvars during tests because they will interfere with other UserContext instances`);
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
36
|
+
if (!this.ephemeral) {
|
|
35
37
|
await this.loadUserContextObservablesFromDB();
|
|
36
38
|
}
|
|
37
39
|
await this.loadGroupContexts();
|
|
@@ -49,7 +49,10 @@ class MockPeerDevice {
|
|
|
49
49
|
deviceId: this.deviceId,
|
|
50
50
|
timestampLastApplied: Date.now(),
|
|
51
51
|
connections: this.connections,
|
|
52
|
-
preferredDeviceIds: []
|
|
52
|
+
preferredDeviceIds: [],
|
|
53
|
+
cpuPercent: 10,
|
|
54
|
+
memPercent: 10,
|
|
55
|
+
connectionSlotsAvailable: 10,
|
|
53
56
|
};
|
|
54
57
|
}
|
|
55
58
|
async listChanges(query) {
|
|
@@ -32,10 +32,12 @@ export declare class Connection {
|
|
|
32
32
|
exposeRPC<T extends Function>(fn: T): void;
|
|
33
33
|
emit<T = any>(eventName: string, ...args: any): Promise<T>;
|
|
34
34
|
on(eventName: string, handler: Function): void;
|
|
35
|
-
removeAllListeners(eventName
|
|
35
|
+
removeAllListeners(eventName?: string): void;
|
|
36
36
|
reset(): void;
|
|
37
37
|
initiateHandshake(serverAddress: string, remoteDeviceInfo?: IDeviceInfo): IDataBox;
|
|
38
38
|
completeHandshake(boxedHandshake: IDataBox): Promise<IDeviceHandshake>;
|
|
39
39
|
doHandshake(remoteAddress: string): Promise<IDeviceHandshake>;
|
|
40
|
+
private closeLocal;
|
|
41
|
+
close(): Promise<void>;
|
|
40
42
|
}
|
|
41
43
|
export declare function normalizeAddress(address: string): string;
|
|
@@ -42,6 +42,11 @@ class Connection {
|
|
|
42
42
|
socket.id = (0, utils_1.newid)();
|
|
43
43
|
}
|
|
44
44
|
// Only the server side of a connection should expose these methods
|
|
45
|
+
this.exposeRPC('close', () => {
|
|
46
|
+
(0, utils_1.sleep)(100).then(() => {
|
|
47
|
+
this.closeLocal();
|
|
48
|
+
});
|
|
49
|
+
});
|
|
45
50
|
if (localDeviceServerAddresses) {
|
|
46
51
|
this.exposeRPC('reset', this.reset.bind(this));
|
|
47
52
|
this.exposeRPC('getTrustLevel', async (deviceInfo) => {
|
|
@@ -127,9 +132,9 @@ class Connection {
|
|
|
127
132
|
});
|
|
128
133
|
}
|
|
129
134
|
on(eventName, handler) {
|
|
130
|
-
const
|
|
135
|
+
const safeEvents = ['requestDeviceInfo', 'completeHandshake', 'reset', 'getTrustLevel', 'close'];
|
|
131
136
|
this.socket.on(eventName, async (args, callback) => {
|
|
132
|
-
if (!this.verified && !
|
|
137
|
+
if (!this.verified && !safeEvents.includes(eventName)) {
|
|
133
138
|
console.error(`Ignoring event from unverified connection: ${eventName}`);
|
|
134
139
|
return callback(`Connection not verified. Handshake must be completed successfully before calling ${eventName}`);
|
|
135
140
|
}
|
|
@@ -242,6 +247,18 @@ class Connection {
|
|
|
242
247
|
console.log(`Connection ${this.connectionId} (${remoteAddress}) verified on client side with trust level ${this.trustLevel}`);
|
|
243
248
|
return handshakeResponse;
|
|
244
249
|
}
|
|
250
|
+
closeLocal() {
|
|
251
|
+
this.reset();
|
|
252
|
+
this.removeAllListeners();
|
|
253
|
+
this.socket.disconnect(true);
|
|
254
|
+
}
|
|
255
|
+
async close() {
|
|
256
|
+
await Promise.race([
|
|
257
|
+
this.emit('close'),
|
|
258
|
+
(0, utils_1.sleep)(100),
|
|
259
|
+
]);
|
|
260
|
+
this.closeLocal();
|
|
261
|
+
}
|
|
245
262
|
}
|
|
246
263
|
exports.Connection = Connection;
|
|
247
264
|
function normalizeAddress(address) {
|
|
@@ -81,10 +81,12 @@ function sortConnections({ myDeviceId, connections, unconnectedDeviceIds }) {
|
|
|
81
81
|
const MAX_CONNECTIONS = peer_device_1.PeerDeviceConsts.MAX_CONNECTIONS;
|
|
82
82
|
// deprioritize devices that are close to max connections
|
|
83
83
|
connections.sort((a, b) => {
|
|
84
|
-
const aConnCnt = a.preferredByDeviceIds.length + a.preferredDeviceIds.length;
|
|
85
|
-
const bConnCnt = b.preferredByDeviceIds.length + b.preferredDeviceIds.length;
|
|
86
|
-
const nearingMaxA = aConnCnt >= MAX_CONNECTIONS * 0.9;
|
|
87
|
-
const nearingMaxB = bConnCnt >= MAX_CONNECTIONS * 0.9;
|
|
84
|
+
// const aConnCnt = a.preferredByDeviceIds.length + a.preferredDeviceIds.length;
|
|
85
|
+
// const bConnCnt = b.preferredByDeviceIds.length + b.preferredDeviceIds.length;
|
|
86
|
+
// const nearingMaxA = aConnCnt >= MAX_CONNECTIONS * 0.9;
|
|
87
|
+
// const nearingMaxB = bConnCnt >= MAX_CONNECTIONS * 0.9;
|
|
88
|
+
const nearingMaxA = a.connectionSlotsAvailable <= 3;
|
|
89
|
+
const nearingMaxB = b.connectionSlotsAvailable <= 3;
|
|
88
90
|
if (nearingMaxA && !nearingMaxB)
|
|
89
91
|
return 1;
|
|
90
92
|
if (!nearingMaxA && nearingMaxB)
|
|
@@ -5,8 +5,8 @@ export interface ISocket {
|
|
|
5
5
|
connected?: boolean;
|
|
6
6
|
emit(eventName: string, args: any, callback: RPCCallback): void;
|
|
7
7
|
on(eventName: string, handler: ((...args: any[]) => void)): void;
|
|
8
|
-
removeAllListeners(eventName
|
|
9
|
-
disconnect(): void;
|
|
8
|
+
removeAllListeners(eventName?: string): void;
|
|
9
|
+
disconnect(close?: boolean): void;
|
|
10
10
|
}
|
|
11
11
|
export declare enum TrustLevel {
|
|
12
12
|
Malicious = -20,
|
|
@@ -14,7 +14,7 @@ export declare class StreamedSocket implements ISocket {
|
|
|
14
14
|
constructor(socket: ISocket, maxChunkSize?: number);
|
|
15
15
|
get id(): string | undefined;
|
|
16
16
|
get connected(): boolean | undefined;
|
|
17
|
-
disconnect(): void;
|
|
17
|
+
disconnect(close?: boolean): void;
|
|
18
18
|
private readonly callbacks;
|
|
19
19
|
emit(eventName: string, args: any, callback: RPCCallback): void;
|
|
20
20
|
private handlers;
|
|
@@ -17,12 +17,16 @@ export interface IDeviceMessage {
|
|
|
17
17
|
ttl: number;
|
|
18
18
|
payload: any;
|
|
19
19
|
signature: string;
|
|
20
|
+
hops?: string[];
|
|
20
21
|
}
|
|
21
22
|
export interface INetworkInfo {
|
|
22
23
|
deviceId: string;
|
|
23
24
|
timestampLastApplied: number;
|
|
24
25
|
connections: IDeviceConnection[];
|
|
25
26
|
preferredDeviceIds: string[];
|
|
27
|
+
cpuPercent: number;
|
|
28
|
+
memPercent: number;
|
|
29
|
+
connectionSlotsAvailable: number;
|
|
26
30
|
}
|
|
27
31
|
export interface IDeviceConnection {
|
|
28
32
|
deviceId: string;
|
|
@@ -30,6 +34,7 @@ export interface IDeviceConnection {
|
|
|
30
34
|
errorRate: number;
|
|
31
35
|
timestampLastApplied: number;
|
|
32
36
|
onClose?(): Promise<void>;
|
|
37
|
+
closed?: boolean;
|
|
33
38
|
}
|
|
34
39
|
export declare const PeerDeviceConsts: Readonly<{
|
|
35
40
|
MAX_CONNECTIONS: 30;
|
package/dist/utils.js
CHANGED
|
@@ -216,11 +216,17 @@ async function retryOnErrorOrTimeout({ fn, connection, opts = {}, }) {
|
|
|
216
216
|
// timeout *= 2; // double the timeout for the next attempt
|
|
217
217
|
timeoutCount++;
|
|
218
218
|
finalError = undefined;
|
|
219
|
+
if (connection.closed) {
|
|
220
|
+
throw new Error(`connection has been closed`);
|
|
221
|
+
}
|
|
219
222
|
}
|
|
220
223
|
catch (error) {
|
|
221
224
|
finalError = error;
|
|
222
225
|
connection.errorRate = (connection.errorRate * 0.9) + 0.1;
|
|
223
226
|
errorCount++;
|
|
227
|
+
if (connection.closed) {
|
|
228
|
+
throw new Error(`connection has been closed`);
|
|
229
|
+
}
|
|
224
230
|
}
|
|
225
231
|
console.warn(`Call failed, retrying: timeout is ${timeout}ms, errorCount: ${errorCount} of ${retriesOnError}, timeoutCount: ${timeoutCount} of ${retriesOnTimeout + 1}. Last error:`, finalError);
|
|
226
232
|
}
|