Compare commits
153 Commits
v0.0.1
...
v0.0.2-dev
Author | SHA1 | Date |
---|---|---|
semantic-release-bot | 11034dc7a8 | |
Derrick Hammer | 009dc4e003 | |
Derrick Hammer | d22b636889 | |
Derrick Hammer | 2ebe64b33a | |
Derrick Hammer | 00f37b829b | |
Derrick Hammer | 8daf4b4e7d | |
Derrick Hammer | 060faf45ac | |
Derrick Hammer | f7a5628a91 | |
Derrick Hammer | 4829b48058 | |
Derrick Hammer | 79bbf5c144 | |
Derrick Hammer | 9740402e82 | |
Derrick Hammer | bb657e5af0 | |
Derrick Hammer | 20e9a6e0e5 | |
Derrick Hammer | fdda2befa8 | |
Derrick Hammer | cf27a6518f | |
Derrick Hammer | 952b3a0d1a | |
Derrick Hammer | 0d7090206c | |
Derrick Hammer | 3a207c107c | |
Derrick Hammer | 92bc8e5ce8 | |
Derrick Hammer | 7c8763c530 | |
Derrick Hammer | d10aad49f4 | |
Derrick Hammer | 1d0718af05 | |
Derrick Hammer | b274b82d3c | |
Derrick Hammer | 9ae392e1ab | |
Derrick Hammer | 62058d31fd | |
Derrick Hammer | c0acff3955 | |
Derrick Hammer | caec48d0a6 | |
Derrick Hammer | eec453ba91 | |
Derrick Hammer | c2ebdc00b9 | |
Derrick Hammer | 0596a132f3 | |
Derrick Hammer | f5127bd809 | |
Derrick Hammer | aefd401d22 | |
Derrick Hammer | 650998c810 | |
Derrick Hammer | 382ce99ada | |
Derrick Hammer | 4cd89acb12 | |
Derrick Hammer | 794ab2f792 | |
Derrick Hammer | 9c1bedc83e | |
Derrick Hammer | a9bc1e3a73 | |
Derrick Hammer | 4541386514 | |
Derrick Hammer | a59de99e56 | |
Derrick Hammer | bce1bca13e | |
Derrick Hammer | 7a6a740484 | |
Derrick Hammer | 301f751ad4 | |
Derrick Hammer | 55159d89ce | |
Derrick Hammer | 3bdaedd939 | |
Derrick Hammer | be450ecbce | |
Derrick Hammer | 7486904592 | |
Derrick Hammer | 275c08efe7 | |
Derrick Hammer | d61df5d4e8 | |
Derrick Hammer | 990d77d86e | |
Derrick Hammer | 6c41fbc114 | |
Derrick Hammer | 8d74bf96af | |
Derrick Hammer | 049a629e47 | |
Derrick Hammer | c7a7fa9194 | |
Derrick Hammer | 1aa1be90d4 | |
Derrick Hammer | e47a1f26d7 | |
Derrick Hammer | 1c167aad2a | |
Derrick Hammer | bdf0cb705c | |
Derrick Hammer | 1a4f33c697 | |
Derrick Hammer | 290ca18c4b | |
Derrick Hammer | 14a71cffd9 | |
Derrick Hammer | ce24ca1bd9 | |
Derrick Hammer | 0ee94ca1e5 | |
Derrick Hammer | c869488951 | |
Derrick Hammer | ab78add294 | |
Derrick Hammer | 4e504124b2 | |
Derrick Hammer | 30c08327b4 | |
Derrick Hammer | 44b9842ea9 | |
Derrick Hammer | 46b0911d57 | |
Derrick Hammer | acc2ed4db3 | |
Derrick Hammer | 1d61d00881 | |
Derrick Hammer | 36dd596aab | |
Derrick Hammer | ee3e71351c | |
Derrick Hammer | 7028609da4 | |
Derrick Hammer | bbbe813360 | |
Derrick Hammer | 4977f88d55 | |
Derrick Hammer | 1ba371fb1c | |
Derrick Hammer | 232f82d828 | |
Derrick Hammer | 8061477c0b | |
Derrick Hammer | df63f8be30 | |
Derrick Hammer | ae487a27e5 | |
Derrick Hammer | b98db98b6a | |
Derrick Hammer | c52e437f50 | |
Derrick Hammer | 6f30bb7faa | |
Derrick Hammer | 1970763114 | |
Derrick Hammer | ff7266f05e | |
Derrick Hammer | acbc5408c9 | |
Derrick Hammer | b76aa38f76 | |
Derrick Hammer | 7d031231a3 | |
Derrick Hammer | d3460ae956 | |
Derrick Hammer | 54a817742c | |
Derrick Hammer | a7384cf688 | |
Derrick Hammer | 72324beb68 | |
Derrick Hammer | ba0832588d | |
Derrick Hammer | 3ede7224aa | |
Derrick Hammer | db894376eb | |
Derrick Hammer | 524d647f21 | |
Derrick Hammer | 1786e56380 | |
Derrick Hammer | e69e7a67b6 | |
Derrick Hammer | 1f76aef53a | |
Derrick Hammer | e84b009244 | |
Derrick Hammer | e211fa3b48 | |
Derrick Hammer | d4df7d45c3 | |
Derrick Hammer | 875ba862f0 | |
Derrick Hammer | fe04cbe10d | |
Derrick Hammer | 2bcd37e271 | |
Derrick Hammer | 176a95f026 | |
Derrick Hammer | acdbfb7a9a | |
Derrick Hammer | 994cab10bc | |
Derrick Hammer | 9e8665338b | |
Derrick Hammer | 7fa2a83141 | |
Derrick Hammer | 8ec7444770 | |
Derrick Hammer | b252b331ad | |
Derrick Hammer | 0bcec3e3e1 | |
Derrick Hammer | a0279262b1 | |
Derrick Hammer | 1af9931725 | |
Derrick Hammer | 9354fbebbd | |
Derrick Hammer | b250c30327 | |
Derrick Hammer | c6b595380a | |
Derrick Hammer | 4359c590ba | |
Derrick Hammer | ebe2a18d91 | |
Derrick Hammer | 5974956e48 | |
Derrick Hammer | b567d70dda | |
Derrick Hammer | b5a81d51ab | |
Derrick Hammer | 3ebfe51a83 | |
Derrick Hammer | 2773b1f38b | |
Derrick Hammer | 14d6888baf | |
Derrick Hammer | 4799cf4a98 | |
Derrick Hammer | 557fb887d2 | |
Derrick Hammer | 2e20565e54 | |
Derrick Hammer | f404dff8eb | |
Derrick Hammer | 77141c3003 | |
Derrick Hammer | 4f21ab970d | |
Derrick Hammer | 43041160be | |
Derrick Hammer | 395edfe75a | |
Derrick Hammer | cc2def1901 | |
Derrick Hammer | bf70a54b31 | |
Derrick Hammer | ddf79c2efd | |
Derrick Hammer | 85fb05b854 | |
Derrick Hammer | cc3b188d5d | |
Derrick Hammer | 20c55f94ad | |
Derrick Hammer | f76391d46e | |
Derrick Hammer | 9071ed0592 | |
Derrick Hammer | 188fa6433b | |
Derrick Hammer | 018c9f0387 | |
Derrick Hammer | a321cf0859 | |
Derrick Hammer | 179bef1f9f | |
Derrick Hammer | 2c41826632 | |
Derrick Hammer | 200221e742 | |
Derrick Hammer | 648951208c | |
Derrick Hammer | 2437037a14 | |
Derrick Hammer | 1fabdc7e4d | |
Derrick Hammer | afc332b75e |
|
@ -0,0 +1,13 @@
|
|||
name: Build/Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- develop-*
|
||||
|
||||
jobs:
|
||||
main:
|
||||
uses: lumeweb/github-node-deploy-workflow/.github/workflows/main.yml@master
|
||||
secrets: inherit
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"preset": [
|
||||
"@lumeweb/node-library-preset"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
## [0.0.2-develop.1](https://git.lumeweb.com/LumeWeb/kernel-swarm-client/compare/v0.0.1...v0.0.2-develop.1) (2023-07-01)
|
||||
|
||||
|
||||
### Reverts
|
||||
|
||||
* Revert "*Change end to close" ([b5a81d5](https://git.lumeweb.com/LumeWeb/kernel-swarm-client/commit/b5a81d51ab490e5e8f405a18a5859f624d7b0b93))
|
File diff suppressed because it is too large
Load Diff
36
package.json
36
package.json
|
@ -1,16 +1,32 @@
|
|||
{
|
||||
"name": "@lumeweb/kernel-dht-client",
|
||||
"version": "0.1.0",
|
||||
"name": "@lumeweb/kernel-swarm-client",
|
||||
"version": "0.0.2-develop.1",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"dependencies": {
|
||||
"buffer": "^6.0.3",
|
||||
"libkernel": "^0.1.43",
|
||||
"libkmodule": "^0.2.44",
|
||||
"libskynet": "^0.0.62"
|
||||
"main": "lib/index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "gitea@git.lumeweb.com:LumeWeb/kernel-swarm-client.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.0.6",
|
||||
"prettier": "^2.7.1"
|
||||
"@lumeweb/node-library-preset": "^0.2.7",
|
||||
"@types/b4a": "^1.6.0",
|
||||
"presetter": "*"
|
||||
},
|
||||
"readme": "ERROR: No README data found!",
|
||||
"scripts": {
|
||||
"prepare": "presetter bootstrap",
|
||||
"build": "run build",
|
||||
"semantic-release": "semantic-release"
|
||||
},
|
||||
"dependencies": {
|
||||
"@lumeweb/libkernel": "^0.1.0-develop.9",
|
||||
"async-mutex": "^0.4.0",
|
||||
"b4a": "^1.6.4"
|
||||
},
|
||||
"files": [
|
||||
"lib/**"
|
||||
],
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
}
|
||||
}
|
||||
|
|
320
src/index.ts
320
src/index.ts
|
@ -1,94 +1,260 @@
|
|||
import {
|
||||
callModule as callModuleKernel,
|
||||
connectModule as connectModuleKernel,
|
||||
} from "libkernel";
|
||||
import {
|
||||
callModule as callModuleModule,
|
||||
connectModule as connectModuleModule,
|
||||
} from "libkmodule";
|
||||
import { EventEmitter } from "events";
|
||||
import { DataFn, ErrTuple } from "libskynet";
|
||||
import { Buffer } from "buffer";
|
||||
import { Client, factory } from "@lumeweb/libkernel/module";
|
||||
import { DataFn, ErrTuple, hexToBuf, logErr } from "@lumeweb/libkernel";
|
||||
import { blake2b } from "@noble/hashes/blake2b";
|
||||
import b4a from "b4a";
|
||||
|
||||
const DHT_MODULE = "AQD1IgE4lTZkq1fqdoYGojKRNrSk0YQ_wrHbRtIiHDrnow";
|
||||
// @ts-ignore
|
||||
import Backoff from "backoff.js";
|
||||
import { Mutex } from "async-mutex";
|
||||
// @ts-ignore
|
||||
import Protomux from "protomux";
|
||||
import type { UnsubscribeFn } from "emittery";
|
||||
|
||||
let callModule: typeof callModuleModule,
|
||||
connectModule: typeof connectModuleModule;
|
||||
export class SwarmClient extends Client {
|
||||
private useDefaultSwarm: boolean;
|
||||
private id: number = 0;
|
||||
private _autoReconnect: boolean;
|
||||
private _connectBackoff: any;
|
||||
|
||||
if (window.document) {
|
||||
callModule = callModuleKernel;
|
||||
connectModule = connectModuleKernel;
|
||||
} else {
|
||||
callModule = callModuleModule;
|
||||
connectModule = connectModuleModule;
|
||||
private _ready?: Promise<void>;
|
||||
private _connectionListener?: [
|
||||
sendUpdate: DataFn,
|
||||
response: Promise<ErrTuple>,
|
||||
];
|
||||
|
||||
private _topics: Set<Uint8Array> = new Set<Uint8Array>();
|
||||
private _sockets: Map<number, Socket> = new Map<number, Socket>();
|
||||
|
||||
get dht() {
|
||||
const self = this;
|
||||
return {
|
||||
async ready() {
|
||||
return self.ready();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
constructor(module: string, useDefaultDht = true, autoReconnect = false) {
|
||||
super(module);
|
||||
this.useDefaultSwarm = useDefaultDht;
|
||||
this._autoReconnect = autoReconnect;
|
||||
this._connectBackoff = new Backoff({
|
||||
strategy: "fibo",
|
||||
maxAttempts: Number.MAX_SAFE_INTEGER,
|
||||
});
|
||||
|
||||
this._connectBackoff.on("retry", (error: any) => {
|
||||
logErr(error);
|
||||
});
|
||||
}
|
||||
|
||||
get swarm(): number | undefined {
|
||||
return this.useDefaultSwarm ? undefined : this.id;
|
||||
}
|
||||
|
||||
public async connect(pubkey: string | Uint8Array): Promise<Socket> {
|
||||
if (typeof pubkey === "string") {
|
||||
const buf = hexToBuf(pubkey);
|
||||
pubkey = this.handleErrorOrReturn(buf);
|
||||
}
|
||||
|
||||
let existing = Array.from(this._sockets.values()).filter((socket) => {
|
||||
return b4a.equals(socket.remotePublicKey, pubkey as Uint8Array);
|
||||
});
|
||||
|
||||
if (existing.length) {
|
||||
return existing[0] as Socket;
|
||||
}
|
||||
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
async init(): Promise<ErrTuple> {
|
||||
return await this.callModuleReturn("init", { swarm: this.swarm });
|
||||
}
|
||||
|
||||
async ready(): Promise<void> {
|
||||
if (this._ready) {
|
||||
return this._ready;
|
||||
}
|
||||
|
||||
this._listen();
|
||||
|
||||
this._ready = this.callModuleReturn("ready", { swarm: this.swarm });
|
||||
|
||||
await this._ready;
|
||||
|
||||
this._ready = undefined;
|
||||
|
||||
for (const topic of this._topics) {
|
||||
await this.join(topic);
|
||||
}
|
||||
}
|
||||
|
||||
async start(): Promise<void> {
|
||||
await this._connectBackoff.run(() => this.init());
|
||||
|
||||
await this.ready();
|
||||
}
|
||||
|
||||
private async _listen() {
|
||||
if (!this._connectionListener) {
|
||||
this._connectionListener = this.connectModule(
|
||||
"listenConnections",
|
||||
{ swarm: this.swarm },
|
||||
async (socketId: any) => {
|
||||
const socket =
|
||||
this._sockets.get(socketId) ?? (await createSocket(socketId, this));
|
||||
|
||||
socket.on("close", () => {
|
||||
this._sockets.delete(socketId);
|
||||
});
|
||||
|
||||
if (!this._sockets.has(socketId)) {
|
||||
this._sockets.set(socketId, socket);
|
||||
}
|
||||
|
||||
this.emit("connection", socket);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
await this._connectionListener[1];
|
||||
this._connectionListener = undefined;
|
||||
this.start();
|
||||
}
|
||||
|
||||
public async addRelay(pubkey: string): Promise<void> {
|
||||
return this.callModuleReturn("addRelay", { pubkey, swarm: this.swarm });
|
||||
}
|
||||
|
||||
public async removeRelay(pubkey: string): Promise<void> {
|
||||
return this.callModuleReturn("removeRelay", { pubkey, swarm: this.swarm });
|
||||
}
|
||||
|
||||
public async clearRelays(): Promise<void> {
|
||||
return this.callModuleReturn("clearRelays", { swarm: this.swarm });
|
||||
}
|
||||
|
||||
public async getRelays(): Promise<string[]> {
|
||||
return this.callModuleReturn("getRelays", { swarm: this.swarm });
|
||||
}
|
||||
|
||||
public async join(topic: Buffer | Uint8Array | string): Promise<void> {
|
||||
if (typeof topic === "string") {
|
||||
topic = blake2b(topic, { dkLen: 32 });
|
||||
}
|
||||
|
||||
this._topics.add(topic);
|
||||
this.callModule("join", { id: this.id, topic });
|
||||
}
|
||||
}
|
||||
|
||||
export class DHT {
|
||||
public async connect(pubkey: string): Promise<Socket> {
|
||||
const [resp, err] = await callModule(DHT_MODULE, "connect", { pubkey });
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
return new Socket(resp.id);
|
||||
}
|
||||
|
||||
async ready(): Promise<ErrTuple> {
|
||||
return callModule(DHT_MODULE, "ready");
|
||||
}
|
||||
interface SocketRawStream {
|
||||
remoteHost: string;
|
||||
remotePort: number;
|
||||
remoteFamily: string;
|
||||
}
|
||||
|
||||
export class Socket extends EventEmitter {
|
||||
private id: number;
|
||||
private eventUpdates: { [event: string]: DataFn[] } = {};
|
||||
export class Socket extends Client {
|
||||
private id: number;
|
||||
private eventUpdates: { [event: string]: DataFn[] } = {};
|
||||
|
||||
constructor(id: number) {
|
||||
super();
|
||||
this.id = id;
|
||||
private syncMutex = new Mutex();
|
||||
|
||||
private swarm: SwarmClient;
|
||||
private userData?: any = null;
|
||||
|
||||
constructor(module: string, id: number, swarm: SwarmClient) {
|
||||
super(module);
|
||||
this.id = id;
|
||||
this.swarm = swarm;
|
||||
}
|
||||
|
||||
private _remotePublicKey?: Uint8Array;
|
||||
|
||||
get remotePublicKey(): Uint8Array {
|
||||
return this._remotePublicKey as Uint8Array;
|
||||
}
|
||||
|
||||
private _rawStream?: Uint8Array;
|
||||
|
||||
get rawStream(): Uint8Array {
|
||||
return this._rawStream as Uint8Array;
|
||||
}
|
||||
|
||||
async setup() {
|
||||
let info = await this.callModuleReturn("socketGetInfo", { id: this.id });
|
||||
|
||||
this._remotePublicKey = info.remotePublicKey;
|
||||
this._rawStream = info.rawStream;
|
||||
await this.swarm.emit("setup", this);
|
||||
}
|
||||
|
||||
on(event: any, listener: any): UnsubscribeFn {
|
||||
const [update, promise] = this.connectModule(
|
||||
"socketListenEvent",
|
||||
{ id: this.id, event: event },
|
||||
(data: any) => {
|
||||
this.emit(event, data);
|
||||
},
|
||||
);
|
||||
this.trackEvent(event as string, update);
|
||||
|
||||
promise.then(() => {
|
||||
this.off(event as string, listener);
|
||||
});
|
||||
|
||||
return super.on(event, listener);
|
||||
}
|
||||
|
||||
off(event: any, listener: any): this {
|
||||
const updates = [...this.eventUpdates[event as string]];
|
||||
this.eventUpdates[event as string] = [];
|
||||
for (const func of updates) {
|
||||
func();
|
||||
}
|
||||
super.off(event, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
on(eventName: string, listener: (...args: any[]) => void): this {
|
||||
const [update, promise] = connectModule(
|
||||
DHT_MODULE,
|
||||
"listenSocketEvent",
|
||||
{ id: this.id, event: eventName },
|
||||
(data: any) => {
|
||||
this.emit(eventName, data);
|
||||
}
|
||||
);
|
||||
this.trackEvent(eventName, update);
|
||||
write(message: string | Buffer): void {
|
||||
this.callModule("socketWrite", { id: this.id, message });
|
||||
}
|
||||
|
||||
promise.then(() => {
|
||||
this.off(eventName, listener);
|
||||
});
|
||||
|
||||
return super.on(eventName, listener);
|
||||
}
|
||||
|
||||
off(type: string, listener: any): this {
|
||||
const updates = [...this.eventUpdates[type]];
|
||||
this.eventUpdates[type] = [];
|
||||
for (const func of updates) {
|
||||
func({ action: "off" });
|
||||
end(): void {
|
||||
this.callModule("socketExists", { id: this.id }).then(
|
||||
([exists]: ErrTuple) => {
|
||||
if (exists) {
|
||||
this.callModule("socketClose", { id: this.id });
|
||||
}
|
||||
return super.off(type, listener);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
write(message: string | Buffer): void {
|
||||
callModule(DHT_MODULE, "write", { id: this.id, message });
|
||||
private ensureEvent(event: string): void {
|
||||
if (!(event in this.eventUpdates)) {
|
||||
this.eventUpdates[event] = [];
|
||||
}
|
||||
}
|
||||
|
||||
end(): void {
|
||||
callModule(DHT_MODULE, "close", { id: this.id });
|
||||
}
|
||||
|
||||
private ensureEvent(event: string): void {
|
||||
if (!(event in this.eventUpdates)) {
|
||||
this.eventUpdates[event] = [];
|
||||
}
|
||||
}
|
||||
|
||||
private trackEvent(event: string, update: DataFn): void {
|
||||
this.ensureEvent(event as string);
|
||||
this.eventUpdates[event].push(update);
|
||||
}
|
||||
private trackEvent(event: string, update: DataFn): void {
|
||||
this.ensureEvent(event as string);
|
||||
this.eventUpdates[event].push(update);
|
||||
}
|
||||
}
|
||||
|
||||
export const MODULE =
|
||||
"zduSB7gEXpcHo4F1esrpHRaB9nYh6KtTn3bktnpJRxWnpvqPhaLNmPwAp7";
|
||||
|
||||
export const createClient = factory<SwarmClient>(SwarmClient, MODULE);
|
||||
|
||||
const socketFactory = factory<Socket>(Socket, MODULE);
|
||||
const createSocket = async (...args: any): Promise<Socket> => {
|
||||
const socket = socketFactory(...args);
|
||||
|
||||
await socket.setup();
|
||||
|
||||
return socket;
|
||||
};
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"module": "esnext",
|
||||
"target": "esnext",
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": false,
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"typeRoots": [
|
||||
"node_modules/@types",
|
||||
],
|
||||
"moduleResolution": "node",
|
||||
"declarationMap": true,
|
||||
"declarationDir": "dist",
|
||||
"emitDeclarationOnly": false,
|
||||
"allowJs": true
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue