*Initial version

This commit is contained in:
Derrick Hammer 2022-07-21 13:03:18 -04:00
parent bb0c5fe92e
commit 05f3916b4a
6 changed files with 262 additions and 0 deletions

13
build.js Normal file
View File

@ -0,0 +1,13 @@
import esbuild from "esbuild";
esbuild.buildSync({
entryPoints: ["src/index.ts"],
outfile: "dist/index.js",
format: "esm",
bundle: true,
legalComments: "external",
// minify: true
define: {
global: "self",
},
});

42
package.json Normal file
View File

@ -0,0 +1,42 @@
{
"name": "@lumeweb/kernel-dht",
"author": {
"name": "Hammer Technologies LLC",
"email": "contact@lumeweb.com"
},
"scripts": {
"test": "jest",
"build-script": "tsc --project tsconfig.build.json && mv dist-build/build.js dist-build/build.mjs",
"compile": "npm run build-script && node build.js",
"build": "npm run compile && node ./dist-build/build.mjs dev"
},
"type": "module",
"dependencies": {
"@lumeweb/dht-web": "https://github.com/LumeWeb/dht-web.git",
"hyperswarm": "^4.0.2",
"libkmodule": "^0.2.12",
"libskynet": "^0.0.62"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^22.0.1",
"@rollup/plugin-node-resolve": "^13.3.0",
"@rollup/plugin-typescript": "^8.3.3",
"@types/jest": "^28.1.3",
"@types/read": "^0.0.29",
"buffer": "^6.0.3",
"esbuild": "^0.14.48",
"inspectpack": "^4.7.1",
"jest": "^28.1.1",
"jest-puppeteer": "^6.1.0",
"libskynetnode": "^0.1.3",
"prettier": "^2.7.1",
"puppeteer": "^15.2.0",
"read": "^1.0.7",
"rollup": "^2.75.7",
"rollup-plugin-polyfill-node": "^0.9.0",
"ts-loader": "^9.3.1",
"typescript": "^4.7.4",
"webpack": "^5.73.0",
"webpack-cli": "^4.10.0"
}
}

12
src/id.ts Normal file
View File

@ -0,0 +1,12 @@
function idFactory(start = 1, step = 1, limit = 2 ** 32) {
let id = start;
return function nextId() {
const nextId = id;
id += step;
if (id >= limit) id = start;
return nextId;
};
}
export const nextId = idFactory(1);

169
src/index.ts Normal file
View File

@ -0,0 +1,169 @@
// @ts-ignore
import DHT from "@lumeweb/dht-web";
import { addHandler, handleMessage } from "libkmodule";
import type { ActiveQuery } from "libkmodule";
import { nextId } from "./id";
import { Buffer } from "buffer";
let dht: DHT;
const connections = new Map();
onmessage = handleMessage;
addHandler("presentSeed", handlePresentSeed);
addHandler("connect", handleConnect);
addHandler("listenSocketEvent", handleListenSocketEvent, {
receiveUpdates: true,
});
addHandler("close", handleCloseSocketEvent);
addHandler("write", handleWriteSocketEvent);
addHandler("addRelay", handleAddRelay);
addHandler("removeRelay", handleRemoveRelay);
addHandler("clearRelays", handleClearRelays);
addHandler("ready", handleReady);
function handlePresentSeed(aq: ActiveQuery) {
const keyPair = aq.callerInput.myskyRootKeypair;
if (!dht) {
dht = new DHT({ keyPair });
}
}
async function handleConnect(aq: ActiveQuery) {
const { pubkey, options = {} } = aq.callerInput;
let socket: any;
try {
// @ts-ignore
socket = await dht.connect(
typeof pubkey === "string" ? Buffer.from(pubkey, "hex") : pubkey,
options
);
} catch (e: any) {
aq.reject(e);
return;
}
const id = nextId();
socket.on("open", () => {
connections.set(id, socket);
aq.respond({ id });
});
socket.on("error", (e: any) => {
connections.set(id, socket);
aq.reject(e);
});
}
function handleListenSocketEvent(aq: ActiveQuery) {
const { event = null } = aq.callerInput;
const id = validateConnection(aq);
if (!id) {
return;
}
if (!event) {
aq.reject("Invalid event");
return;
}
const socket = connections.get(id);
const cb = (data: Buffer) => {
aq.sendUpdate(data);
};
socket.on(event, cb);
socket.on("close", () => {
socket.off(socket, cb);
aq.respond();
});
aq.setReceiveUpdate?.((data: any) => {
switch (data?.action) {
case "off":
socket.off(socket, cb);
aq.respond();
break;
}
});
}
function handleCloseSocketEvent(aq: ActiveQuery) {
const id = validateConnection(aq);
if (!id) {
return;
}
connections.get(id).end();
aq.respond();
}
function handleWriteSocketEvent(aq: ActiveQuery) {
const id = validateConnection(aq);
if (!id) {
return;
}
const { message = null } = aq.callerInput;
if (!message) {
aq.reject("empty message");
return false;
}
connections.get(id).write(message);
aq.respond();
}
function validateConnection(aq: ActiveQuery): number | boolean {
const { id = null } = aq.callerInput;
if (!id || !connections.has(id)) {
aq.reject("Invalid connection id");
return false;
}
return id;
}
async function handleAddRelay(aq: ActiveQuery) {
const { pubkey = null } = aq.callerInput;
if (!pubkey) {
aq.reject("invalid pubkey");
return;
}
aq.respond(await dht.addRelay(pubkey));
}
function handleRemoveRelay(aq: ActiveQuery) {
const { pubkey = null } = aq.callerInput;
if (!pubkey) {
aq.reject("invalid pubkey");
return;
}
aq.respond(dht.removeRelay(pubkey));
}
function handleClearRelays(aq: ActiveQuery) {
dht.clearRelays();
aq.respond();
}
async function handleReady(aq: ActiveQuery) {
// @ts-ignore
await dht.ready();
aq.respond();
}

14
tsconfig.build.json Normal file
View File

@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"declaration": true,
"outDir": "./dist-build",
"strict": true,
"esModuleInterop": true
},
"include": ["src-build"],
"exclude": ["node_modules", "**/__tests__/*"]
}

12
tsconfig.json Normal file
View File

@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "esnext",
"declaration": true,
"moduleResolution": "node",
"outDir": "./build",
"strict": true,
"allowSyntheticDefaultImports": true
},
"include": ["src"],
"exclude": ["node_modules", "**/__tests__/*"]
}