Skip to content

Commit

Permalink
build(packaging): ci build
Browse files Browse the repository at this point in the history
  • Loading branch information
Rinse12 authored and github-actions[bot] committed May 8, 2024
1 parent 334a1fb commit 11e7c35
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 41 deletions.
4 changes: 3 additions & 1 deletion dist/cli/commands/daemon.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ export default class Daemon extends Command {
ipfsGatewayPort: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<number, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
};
static examples: string[];
private _generateRpcAuthKeyIfNotExisting;
private _setupLogger;
private _getNewLogfileByEvacuatingOldLogsIfNeeded;
private _pipeDebugLogsToLogFile;
run(): Promise<void>;
}
108 changes: 71 additions & 37 deletions dist/cli/commands/daemon.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,15 @@
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
// import { seedSubplebbits } from "../../seeder";
const defaults_js_1 = tslib_1.__importDefault(require("../../common-utils/defaults.js"));
const startIpfs_js_1 = require("../../ipfs/startIpfs.js");
const path_1 = tslib_1.__importDefault(require("path"));
const crypto_1 = require("crypto");
const promises_1 = tslib_1.__importDefault(require("fs/promises"));
const tcp_port_used_1 = tslib_1.__importDefault(require("tcp-port-used"));
const util_js_1 = require("../../util.js");
const daemon_server_js_1 = require("../../webui/daemon-server.js");
const fs_1 = tslib_1.__importDefault(require("fs"));
const promises_1 = tslib_1.__importDefault(require("fs/promises"));
const node_os_1 = require("node:os");
class Daemon extends core_1.Command {
static description = "Run a network-connected Plebbit node. Once the daemon is running you can create and start your subplebbits and receive publications from users";
static flags = {
Expand All @@ -34,28 +35,70 @@ class Daemon extends core_1.Command {
default: defaults_js_1.default.IPFS_GATEWAY_PORT
})
};
static examples = [
"plebbit daemon",
"plebbit daemon --plebbitRpcPort 80"
// "plebbit daemon --seed",
// "plebbit daemon --seed --seedSubs mysub.eth, myothersub.eth, 12D3KooWEKA6Fhp6qtyttMvNKcNCtqH2N7ZKpPy5rfCeM1otr5qU"
];
async _generateRpcAuthKeyIfNotExisting(plebbitDataPath) {
// generate plebbit rpc auth key if doesn't exist
const plebbitRpcAuthKeyPath = path_1.default.join(plebbitDataPath, "auth-key");
let plebbitRpcAuthKey;
static examples = ["plebbit daemon", "plebbit daemon --plebbitRpcPort 80"];
_setupLogger(Logger) {
const envDebug = process.env["DEBUG"];
const debugNamespace = envDebug === "0" || envDebug === "" ? undefined : envDebug || "plebbit*, -plebbit*trace";
if (debugNamespace) {
console.log("Debug logs is on with namespace", `"${debugNamespace}"`);
Logger.enable(debugNamespace);
}
else {
console.log("Debug logs are disabled");
Logger.disable();
}
}
async _getNewLogfileByEvacuatingOldLogsIfNeeded() {
try {
plebbitRpcAuthKey = await promises_1.default.readFile(plebbitRpcAuthKeyPath, "utf-8");
await promises_1.default.mkdir(defaults_js_1.default.PLEBBIT_LOG_PATH, { recursive: true });
}
catch (e) {
plebbitRpcAuthKey = (0, crypto_1.randomBytes)(32).toString("base64").replace(/[/+=]/g, "").substring(0, 40);
await promises_1.default.writeFile(plebbitRpcAuthKeyPath, plebbitRpcAuthKey, { flag: "wx" });
//@ts-expect-error
if (e.code !== "EEXIST")
throw e;
}
const logFiles = (await promises_1.default.readdir(defaults_js_1.default.PLEBBIT_LOG_PATH, { withFileTypes: true })).filter((file) => file.name.startsWith("plebbit_cli_daemon"));
const logfilesCapacity = 5; // we only store 5 log files
if (logFiles.length >= logfilesCapacity) {
// we need to pick the oldest log to delete
const logFileToDelete = logFiles.map((logFile) => logFile.name).sort()[0]; // TODO need to test this, not sure if it works
console.log(`Will remove log (${logFileToDelete}) because we reached capacity (${logfilesCapacity})`);
await promises_1.default.rm(path_1.default.join(defaults_js_1.default.PLEBBIT_LOG_PATH, logFileToDelete));
}
return plebbitRpcAuthKey;
return path_1.default.join(defaults_js_1.default.PLEBBIT_LOG_PATH, `plebbit_cli_daemon_${new Date().toISOString()}.log`);
}
async _pipeDebugLogsToLogFile() {
const logFilePath = await this._getNewLogfileByEvacuatingOldLogsIfNeeded();
const logFile = fs_1.default.createWriteStream(logFilePath, { flags: "a" });
const stdoutWrite = process.stdout.write.bind(process.stdout);
const stderrWrite = process.stderr.write.bind(process.stderr);
const removeColor = (data) => {
const parsedData = data instanceof Uint8Array ? Buffer.from(data).toString() : data;
return parsedData.replaceAll(/\u001b\[.*?m/g, "");
};
process.stdout.write = (...args) => {
//@ts-expect-error
const res = stdoutWrite(...args);
logFile.write(removeColor(args[0]) + node_os_1.EOL);
return res;
};
process.stderr.write = (...args) => {
//@ts-expect-error
const res = stderrWrite(...args);
logFile.write(removeColor(args[0]).trimStart() + node_os_1.EOL);
return res;
};
console.log("Will store stderr + stdout log to", logFilePath);
// errors aren't console logged
process.on("uncaughtException", console.error);
process.on("unhandledRejection", console.error);
}
async run() {
const { flags } = await this.parse(Daemon);
const log = (await (0, util_js_1.getPlebbitLogger)())("plebbit-cli:daemon");
const Logger = await (0, util_js_1.getPlebbitLogger)();
this._setupLogger(Logger);
await this._pipeDebugLogsToLogFile();
const log = Logger("plebbit-cli:daemon");
log(`flags: `, flags);
const ipfsApiEndpoint = `http://localhost:${flags.ipfsApiPort}/api/v0`;
const ipfsGatewayEndpoint = `http://localhost:${flags.ipfsGatewayPort}`;
Expand Down Expand Up @@ -105,28 +148,19 @@ class Daemon extends core_1.Command {
usingDifferentProcessRpc = true;
return;
}
const rpcAuthKey = await this._generateRpcAuthKeyIfNotExisting(flags.plebbitDataPath);
const PlebbitWsServer = await import("@plebbit/plebbit-js/dist/node/rpc/src/index.js");
const rpcServer = await PlebbitWsServer.default.PlebbitWsServer({
port: flags.plebbitRpcPort,
plebbitOptions: {
ipfsHttpClientsOptions: [ipfsApiEndpoint],
dataPath: flags.plebbitDataPath
},
authKey: rpcAuthKey
});
const daemonServer = await (0, daemon_server_js_1.startDaemonServer)(flags.plebbitRpcPort, flags.ipfsGatewayPort, ipfsApiEndpoint, flags.plebbitDataPath);
usingDifferentProcessRpc = false;
startedOwnRpc = true;
console.log(`plebbit rpc: listening on ws://localhost:${flags.plebbitRpcPort} (local connections only)`);
console.log(`plebbit rpc: listening on ws://localhost:${flags.plebbitRpcPort}/${rpcAuthKey} (secret auth key for remote connections)`);
console.log(`Plebbit data path: ${path_1.default.resolve(rpcServer.plebbit.dataPath)}`);
console.log(`Subplebbits in data path: `, await rpcServer.plebbit.listSubplebbits());
const handlRpcExit = async (signal) => {
log(`in handle exit (${signal})`);
await rpcServer.destroy();
process.exit();
};
["SIGINT", "SIGTERM", "SIGHUP", "beforeExit"].forEach((exitSignal) => process.on(exitSignal, handlRpcExit));
console.log(`plebbit rpc: listening on ws://localhost:${flags.plebbitRpcPort}/${daemonServer.rpcAuthKey} (secret auth key for remote connections)`);
console.log(`Plebbit data path: ${path_1.default.resolve(flags.plebbitDataPath)}`);
console.log(`Subplebbits in data path: `, daemonServer.listedSub);
const localIpAddress = "localhost";
const remoteIpAddress = (0, util_js_1.getLanIpV4Address)() || localIpAddress;
for (const webui of daemonServer.webuis) {
console.log(`WebUI (${webui.name}): http://${localIpAddress}:${flags.plebbitRpcPort}${webui.endpointLocal} (local connections only)`);
console.log(`WebUI (${webui.name}): http://${remoteIpAddress}:${flags.plebbitRpcPort}${webui.endpointRemote} (secret auth key for remote connections)`);
}
};
await keepIpfsUp();
await createOrConnectRpc();
Expand Down
9 changes: 9 additions & 0 deletions dist/cli/commands/subplebbit/get.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { BaseCommand } from "../../base-command.js";
export default class Get extends BaseCommand {
static description: string;
static examples: string[];
static args: {
address: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
};
run(): Promise<void>;
}
28 changes: 28 additions & 0 deletions dist/cli/commands/subplebbit/get.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const core_1 = require("@oclif/core");
const base_command_js_1 = require("../../base-command.js");
const lodash_1 = tslib_1.__importDefault(require("lodash"));
class Get extends base_command_js_1.BaseCommand {
static description = "Fetch a local or remote subplebbit, and print its json in the terminal";
static examples = [
"plebbit subplebbit get plebmusic.eth",
"plebbit subplebbit get 12D3KooWG3XbzoVyAE6Y9vHZKF64Yuuu4TjdgQKedk14iYmTEPWu"
];
static args = {
address: core_1.Args.string({
name: "address",
required: true,
description: "Address of the subplebbit address to fetch"
})
};
async run() {
const { args, flags } = await this.parse(Get);
const plebbit = await this._connectToPlebbitRpc(flags.plebbitRpcApiUrl.toString());
const sub = await plebbit.getSubplebbit(args.address);
await plebbit.destroy();
this.logJson({ posts: sub.toJSON().posts, ...lodash_1.default.omit(sub.toJSON(), "posts") }); // make sure posts is printed first, because most users won't look at it
}
}
exports.default = Get;
1 change: 1 addition & 0 deletions dist/common-utils/defaults.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ declare const _default: {
PLEBBIT_RPC_API_PORT: number;
IPFS_API_PORT: number;
IPFS_GATEWAY_PORT: number;
PLEBBIT_LOG_PATH: string;
};
export default _default;
3 changes: 2 additions & 1 deletion dist/common-utils/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ exports.default = {
PLEBBIT_DATA_PATH: (0, env_paths_1.default)("plebbit", { suffix: "" }).data,
PLEBBIT_RPC_API_PORT: 9138,
IPFS_API_PORT: 5001,
IPFS_GATEWAY_PORT: 6473
IPFS_GATEWAY_PORT: 6473,
PLEBBIT_LOG_PATH: (0, env_paths_1.default)("plebbit", { suffix: "" }).log
};
4 changes: 4 additions & 0 deletions dist/ipfs/startIpfs.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ async function startIpfsNode(apiPortNumber, gatewayPortNumber) {
env,
hideWindows: true
});
await _spawnAsync(log, ipfsExePath, ["config", "profile", "apply", `server`], {
env,
hideWindows: true
});
log("Called ipfs config Addresses.Gateway successfully");
await _spawnAsync(log, ipfsExePath, ["config", "Addresses.API", `/ip4/127.0.0.1/tcp/${apiPortNumber}`], { env, hideWindows: true });
log("Called ipfs config Addresses.API successfully");
Expand Down
2 changes: 1 addition & 1 deletion dist/tsconfig.tsbuildinfo

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions dist/util.d.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export declare function getPlebbitLogger(): Promise<typeof import("@plebbit/plebbit-logger", { with: { "resolution-mode": "import" } }).default>;
export declare function getLanIpV4Address(): string | undefined;
18 changes: 17 additions & 1 deletion dist/util.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPlebbitLogger = void 0;
exports.getLanIpV4Address = exports.getPlebbitLogger = void 0;
const tslib_1 = require("tslib");
const os_1 = tslib_1.__importDefault(require("os"));
async function getPlebbitLogger() {
const Logger = await import("@plebbit/plebbit-logger");
return Logger.default;
}
exports.getPlebbitLogger = getPlebbitLogger;
function getLanIpV4Address() {
const allInterfaces = os_1.default.networkInterfaces();
for (const k in allInterfaces) {
const specificInterfaceInfos = allInterfaces[k];
if (!specificInterfaceInfos)
continue;
const lanAddress = specificInterfaceInfos.filter((info) => info.family === "IPv4" && !info.internal)[0]
?.address;
if (lanAddress)
return lanAddress;
}
return undefined;
}
exports.getLanIpV4Address = getLanIpV4Address;
9 changes: 9 additions & 0 deletions dist/webui/daemon-server.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export declare function startDaemonServer(daemonPort: number, ipfsGatewayPort: number, ipfsApiEndpoint: string, plebbitDataPath: string): Promise<{
rpcAuthKey: string;
listedSub: string[];
webuis: {
name: string;
endpointLocal: string;
endpointRemote: string;
}[];
}>;
91 changes: 91 additions & 0 deletions dist/webui/daemon-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.startDaemonServer = void 0;
const tslib_1 = require("tslib");
const path_1 = tslib_1.__importDefault(require("path"));
const promises_1 = tslib_1.__importDefault(require("fs/promises"));
const util_1 = require("../util");
const crypto_1 = require("crypto");
const express_1 = tslib_1.__importDefault(require("express"));
async function _writeModifiedIndexHtmlWithDefaultSettings(webuiPath, webuiName, ipfsGatewayPort) {
const indexHtmlString = (await promises_1.default.readFile(path_1.default.join(webuiPath, "index.html"))).toString();
const defaultRpcOptionString = `[window.location.origin.replace("https", "wss").replace("http", "ws") + window.location.pathname.split('/' + '${webuiName}')[0]]`;
// Ipfs media only locally because ipfs gateway doesn't allow remote connections
const defaultIpfsMedia = `if (window.location.hostname === "localhost" || window.location.hostname === "127.0.0.1")window.defaultMediaIpfsGatewayUrl = 'http://' + window.location.hostname + ':' + ${ipfsGatewayPort}`;
const defaultOptionsString = `<script>window.defaultPlebbitOptions = {plebbitRpcClientsOptions: ${defaultRpcOptionString}};${defaultIpfsMedia};console.log(window.defaultPlebbitOptions, window.defaultMediaIpfsGatewayUrl)</script>`;
const modifiedIndexHtmlFileName = `index_with_rpc_settings.html`;
const modifiedIndexHtmlContent = "<!DOCTYPE html>" + defaultOptionsString + indexHtmlString.replace("<!DOCTYPE html>", "");
await promises_1.default.writeFile(path_1.default.join(webuiPath, modifiedIndexHtmlFileName), modifiedIndexHtmlContent);
return modifiedIndexHtmlFileName;
}
async function _generateRpcAuthKeyIfNotExisting(plebbitDataPath) {
// generate plebbit rpc auth key if doesn't exist
const plebbitRpcAuthKeyPath = path_1.default.join(plebbitDataPath, "auth-key");
let plebbitRpcAuthKey;
try {
plebbitRpcAuthKey = await promises_1.default.readFile(plebbitRpcAuthKeyPath, "utf-8");
}
catch (e) {
plebbitRpcAuthKey = (0, crypto_1.randomBytes)(32).toString("base64").replace(/[/+=]/g, "").substring(0, 40);
await promises_1.default.writeFile(plebbitRpcAuthKeyPath, plebbitRpcAuthKey, { flag: "wx" });
}
return plebbitRpcAuthKey;
}
// The daemon server will host both RPC and webui on the same port
async function startDaemonServer(daemonPort, ipfsGatewayPort, ipfsApiEndpoint, plebbitDataPath) {
// Start plebbit-js RPC
const log = (await (0, util_1.getPlebbitLogger)())("plebbit-cli:daemon:startDaemonServer");
const webuiExpressApp = (0, express_1.default)();
const httpServer = webuiExpressApp.listen(daemonPort);
const rpcAuthKey = await _generateRpcAuthKeyIfNotExisting(plebbitDataPath);
const PlebbitWsServer = await import("@plebbit/plebbit-js/dist/node/rpc/src/index.js");
const rpcServer = await PlebbitWsServer.default.PlebbitWsServer({
server: httpServer,
plebbitOptions: {
ipfsHttpClientsOptions: [ipfsApiEndpoint],
dataPath: plebbitDataPath
},
authKey: rpcAuthKey
});
const webuisDir = path_1.default.join(process.cwd(), "dist", "webuis");
const webUiNames = (await promises_1.default.readdir(webuisDir, { withFileTypes: true })).filter((file) => file.isDirectory()).map((file) => file.name);
const webuis = [];
log("Discovered webuis", webUiNames);
for (const webuiNameWithVersion of webUiNames) {
const webuiDirPath = path_1.default.join(webuisDir, webuiNameWithVersion);
const webuiName = webuiNameWithVersion.split("-")[0]; // should be "seedit", "plebchan", "plebones"
const modifiedIndexHtmlFileName = await _writeModifiedIndexHtmlWithDefaultSettings(webuiDirPath, webuiName, ipfsGatewayPort);
const endpointLocal = `/${webuiName}`;
webuiExpressApp.get(endpointLocal, (req, res, next) => {
const isLocal = req.socket.localAddress && req.socket.localAddress === req.socket.remoteAddress;
if (!isLocal)
res.status(403).send("This endpoint does not exist for remote connections");
else
next();
});
webuiExpressApp.use(endpointLocal, express_1.default.static(webuiDirPath, { index: modifiedIndexHtmlFileName, cacheControl: false }));
const endpointRemote = `/${rpcAuthKey}/${webuiName}`;
webuiExpressApp.get(endpointRemote, (req, res, next) => {
const isLocal = req.socket.localAddress && req.socket.localAddress === req.socket.remoteAddress;
if (isLocal)
res.redirect(`http://localhost:${daemonPort}${endpointLocal}`);
else
next();
});
webuiExpressApp.use(endpointRemote, express_1.default.static(webuiDirPath, { index: modifiedIndexHtmlFileName, cacheControl: false }));
webuis.push({ name: webuiName, endpointLocal, endpointRemote });
}
process.on("exit", async () => {
await rpcServer.destroy();
httpServer.close();
});
const handlRpcExit = async (signal) => {
log(`Detecting exit signal ${signal}, shutting down rpc server and webui`);
await rpcServer.destroy();
httpServer.close();
process.exit();
};
["SIGINT", "SIGTERM", "SIGHUP", "beforeExit"].forEach((exitSignal) => process.on(exitSignal, handlRpcExit));
return { rpcAuthKey, listedSub: await rpcServer.plebbit.listSubplebbits(), webuis };
}
exports.startDaemonServer = startDaemonServer;

0 comments on commit 11e7c35

Please sign in to comment.