pinggy 0.1.3 → 0.1.4
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/cli/buildConfig.js +1 -1
- package/dist/cli/extendedOptions.js +16 -1
- package/dist/cli/options.js +3 -1
- package/dist/cli/starCli.js +77 -104
- package/dist/index.js +11 -11
- package/dist/logger.js +12 -2
- package/dist/remote_management/handler.js +97 -138
- package/dist/tunnel_manager/TunnelManager.js +135 -64
- package/package.json +2 -2
- package/src/cli/buildConfig.ts +1 -1
- package/src/cli/extendedOptions.ts +20 -1
- package/src/cli/options.ts +3 -1
- package/src/cli/starCli.tsx +92 -125
- package/src/index.ts +13 -12
- package/src/logger.ts +13 -2
- package/src/remote_management/handler.ts +116 -152
- package/src/remote_management/remote_schema.ts +1 -1
- package/src/tunnel_manager/TunnelManager.ts +95 -31
- package/src/utils/parseArgs.ts +0 -2
- package/src/utils/printer.ts +1 -1
- package/dist/workers/worker.js +0 -76
- package/src/workers/worker.ts +0 -87
package/dist/cli/buildConfig.js
CHANGED
|
@@ -88,7 +88,7 @@ function parseUsers(positionalArgs, explicitToken) {
|
|
|
88
88
|
}
|
|
89
89
|
function parseType(finalConfig, values, inferredType) {
|
|
90
90
|
const t = inferredType || values.type || finalConfig.tunnelType;
|
|
91
|
-
if (t === "http" /* TunnelType.Http */ || t === "tcp" /* TunnelType.Tcp */ || t === "tls" /* TunnelType.Tls */ || t === "udp" /* TunnelType.Udp */) {
|
|
91
|
+
if (t === "http" /* TunnelType.Http */ || t === "tcp" /* TunnelType.Tcp */ || t === "tls" /* TunnelType.Tls */ || t === "udp" /* TunnelType.Udp */ || t === "tlstcp" /* TunnelType.TlsTcp */) {
|
|
92
92
|
finalConfig.tunnelType = [t];
|
|
93
93
|
}
|
|
94
94
|
}
|
|
@@ -37,7 +37,7 @@ export function parseExtendedOptions(options, config) {
|
|
|
37
37
|
// Whitelist IPs
|
|
38
38
|
if (value) {
|
|
39
39
|
const ips = value.split(",").map(ip => ip.trim()).filter(Boolean);
|
|
40
|
-
const invalidIps = ips.filter(ip => !isValidIpV4Cidr(ip));
|
|
40
|
+
const invalidIps = ips.filter(ip => !(isValidIpV4Cidr(ip) || isValidIpV6Cidr(ip)));
|
|
41
41
|
if (invalidIps.length > 0) {
|
|
42
42
|
CLIPrinter.warn(`Invalid IP/CIDR(s) in whitelist: ${invalidIps.join(", ")}`);
|
|
43
43
|
logger.warn(`Warning: Invalid IP/CIDR(s) in whitelist: ${invalidIps.join(", ")}`);
|
|
@@ -132,3 +132,18 @@ function isValidIpV4Cidr(input) {
|
|
|
132
132
|
}
|
|
133
133
|
return false;
|
|
134
134
|
}
|
|
135
|
+
function isValidIpV6Cidr(input) {
|
|
136
|
+
// Check for CIDR notation
|
|
137
|
+
if (input.includes('/')) {
|
|
138
|
+
const [rawIp, mask] = input.split('/');
|
|
139
|
+
if (!rawIp || !mask)
|
|
140
|
+
return false;
|
|
141
|
+
// Strip zone index (e.g. %eth0) and surrounding brackets if present
|
|
142
|
+
const ip = rawIp.split('%')[0].replace(/^\[|\]$/g, '');
|
|
143
|
+
const isIp6 = isIP(ip) === 6;
|
|
144
|
+
const maskNum = parseInt(mask, 10);
|
|
145
|
+
const isMaskValid = !isNaN(maskNum) && maskNum >= 0 && maskNum <= 128;
|
|
146
|
+
return isIp6 && isMaskValid;
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
package/dist/cli/options.js
CHANGED
|
@@ -19,7 +19,9 @@ export const cliOptions = {
|
|
|
19
19
|
// Logging options (CLI overrides env)
|
|
20
20
|
loglevel: { type: 'string', description: 'Logging level: ERROR, INFO, DEBUG. Overrides PINGGY_LOG_LEVEL environment variable' },
|
|
21
21
|
logfile: { type: 'string', description: 'Path to log file. Overrides PINGGY_LOG_FILE environment variable' },
|
|
22
|
-
|
|
22
|
+
v: { type: 'boolean', description: 'Print logs to stdout for Cli. Overrides PINGGY_LOG_STDOUT environment variable' },
|
|
23
|
+
vv: { type: 'boolean', description: 'Enable detailed logging for the Node.js SDK and Libpinggy, including both info and debug level logs.' },
|
|
24
|
+
vvv: { type: 'boolean', description: 'Enable all logs from Cli, SDK and internal components.' },
|
|
23
25
|
// Save and load config
|
|
24
26
|
saveconf: { type: 'string', description: 'Create the configuration file based on the options provided here' },
|
|
25
27
|
conf: { type: 'string', description: 'Use the configuration file as base. Other options will be used to override this file' },
|
package/dist/cli/starCli.js
CHANGED
|
@@ -9,13 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
};
|
|
10
10
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
11
|
import CLIPrinter from "../utils/printer.js";
|
|
12
|
+
import { TunnelManager } from "../tunnel_manager/TunnelManager.js";
|
|
12
13
|
import chalk from "chalk";
|
|
13
14
|
import TunnelTui from "../tui/index.js";
|
|
14
15
|
import { withFullScreen } from "fullscreen-ink";
|
|
15
|
-
import path from "node:path";
|
|
16
|
-
import { Worker } from "node:worker_threads";
|
|
17
16
|
import { getFreePort } from "../utils/getFreePort.js";
|
|
18
|
-
import { fileURLToPath } from "url";
|
|
19
17
|
import { logger } from "../logger.js";
|
|
20
18
|
import React, { useState } from "react";
|
|
21
19
|
const TunnelData = {
|
|
@@ -26,8 +24,6 @@ const TunnelData = {
|
|
|
26
24
|
let activeTui = null;
|
|
27
25
|
let disconnectState = null;
|
|
28
26
|
let updateDisconnectState = null;
|
|
29
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
30
|
-
const __dirname = path.dirname(__filename);
|
|
31
27
|
const TunnelTuiWrapper = ({ finalConfig, urls, greet }) => {
|
|
32
28
|
const [disconnectInfo, setDisconnectInfo] = useState(null);
|
|
33
29
|
React.useEffect(() => {
|
|
@@ -40,118 +36,95 @@ const TunnelTuiWrapper = ({ finalConfig, urls, greet }) => {
|
|
|
40
36
|
};
|
|
41
37
|
export function startCli(finalConfig, manager) {
|
|
42
38
|
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
var _a, _b, _c;
|
|
43
40
|
if (!finalConfig.NoTUI && finalConfig.webDebugger === "") {
|
|
44
41
|
// Need a webdebugger port
|
|
45
42
|
const freePort = yield getFreePort(finalConfig.webDebugger || "");
|
|
46
43
|
finalConfig.webDebugger = `localhost:${freePort}`;
|
|
47
44
|
}
|
|
48
|
-
const workerPath = path.resolve(__dirname, "../workers/worker.js");
|
|
49
45
|
try {
|
|
50
|
-
const
|
|
51
|
-
|
|
46
|
+
const manager = TunnelManager.getInstance();
|
|
47
|
+
const tunnel = manager.createTunnel(finalConfig);
|
|
48
|
+
CLIPrinter.startSpinner("Connecting to Pinggy...");
|
|
49
|
+
if (!finalConfig.NoTUI) {
|
|
50
|
+
manager.registerStatsListener(tunnel.tunnelid, (tunnelId, stats) => {
|
|
51
|
+
var _a;
|
|
52
|
+
(_a = globalThis.__PINGGY_TUNNEL_STATS__) === null || _a === void 0 ? void 0 : _a.call(globalThis, stats);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
manager.registerWorkerErrorListner(tunnel.tunnelid, (_tunnelid, error) => {
|
|
56
|
+
// The CLI terminates in this callback because these errors occur only when the tunnel worker
|
|
57
|
+
// exits, crashes, or encounters critical problems (e.g., authentication failure or primary forwarding failure).
|
|
58
|
+
CLIPrinter.error(`${error.message}`);
|
|
52
59
|
});
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const tui = withFullScreen(_jsx(TunnelTuiWrapper, { finalConfig: finalConfig, urls: TunnelData.urls, greet: TunnelData.greet }));
|
|
97
|
-
activeTui = tui;
|
|
98
|
-
try {
|
|
99
|
-
yield tui.start();
|
|
100
|
-
yield tui.waitUntilExit();
|
|
101
|
-
}
|
|
102
|
-
catch (e) {
|
|
103
|
-
logger.warn("TUI error", e);
|
|
104
|
-
}
|
|
105
|
-
finally {
|
|
106
|
-
activeTui = null;
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
break;
|
|
110
|
-
case "warnings":
|
|
111
|
-
CLIPrinter.warn(msg.message);
|
|
112
|
-
break;
|
|
113
|
-
case "disconnected":
|
|
114
|
-
if (activeTui && updateDisconnectState) {
|
|
115
|
-
disconnectState = {
|
|
116
|
-
disconnected: true,
|
|
117
|
-
error: msg.error,
|
|
118
|
-
messages: msg.messages
|
|
119
|
-
};
|
|
120
|
-
updateDisconnectState(disconnectState);
|
|
121
|
-
try {
|
|
122
|
-
// Wait for Ink to fully exit
|
|
123
|
-
yield activeTui.waitUntilExit();
|
|
124
|
-
}
|
|
125
|
-
catch (e) {
|
|
126
|
-
logger.warn("Failed to wait for TUI exit", e);
|
|
127
|
-
}
|
|
128
|
-
finally {
|
|
129
|
-
activeTui = null;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
if ((_e = msg.messages) === null || _e === void 0 ? void 0 : _e.length) {
|
|
133
|
-
msg.messages.forEach((m) => CLIPrinter.print(m));
|
|
134
|
-
}
|
|
60
|
+
yield manager.startTunnel(tunnel.tunnelid);
|
|
61
|
+
CLIPrinter.stopSpinnerSuccess("Connected to Pinggy");
|
|
62
|
+
CLIPrinter.success(chalk.bold("Tunnel established!"));
|
|
63
|
+
CLIPrinter.print(chalk.gray("───────────────────────────────"));
|
|
64
|
+
TunnelData.urls = yield manager.getTunnelUrls(tunnel.tunnelid);
|
|
65
|
+
TunnelData.greet = yield manager.getTunnelGreetMessage(tunnel.tunnelid);
|
|
66
|
+
CLIPrinter.info(chalk.cyanBright("Remote URLs:"));
|
|
67
|
+
((_a = TunnelData.urls) !== null && _a !== void 0 ? _a : []).forEach((url) => CLIPrinter.print(" " + chalk.magentaBright(url)));
|
|
68
|
+
CLIPrinter.print(chalk.gray("───────────────────────────────"));
|
|
69
|
+
if ((_b = TunnelData.greet) === null || _b === void 0 ? void 0 : _b.includes("not authenticated")) {
|
|
70
|
+
// show unauthenticated warning
|
|
71
|
+
CLIPrinter.warn(chalk.yellowBright(TunnelData.greet));
|
|
72
|
+
}
|
|
73
|
+
else if ((_c = TunnelData.greet) === null || _c === void 0 ? void 0 : _c.includes("authenticated as")) {
|
|
74
|
+
// extract email
|
|
75
|
+
const emailMatch = /authenticated as (.+)/.exec(TunnelData.greet);
|
|
76
|
+
if (emailMatch) {
|
|
77
|
+
const email = emailMatch[1];
|
|
78
|
+
CLIPrinter.info(chalk.cyanBright("Authenticated as: " + email));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
CLIPrinter.print(chalk.gray("───────────────────────────────"));
|
|
82
|
+
CLIPrinter.print(chalk.gray("\nPress Ctrl+C to stop the tunnel.\n"));
|
|
83
|
+
manager.registerDisconnectListener(tunnel.tunnelid, (tunnelId, error, messages) => __awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
if (activeTui && updateDisconnectState) {
|
|
85
|
+
disconnectState = {
|
|
86
|
+
disconnected: true,
|
|
87
|
+
error: error,
|
|
88
|
+
messages: messages
|
|
89
|
+
};
|
|
90
|
+
updateDisconnectState(disconnectState);
|
|
91
|
+
try {
|
|
92
|
+
// Wait for Ink to fully exit
|
|
93
|
+
yield activeTui.waitUntilExit();
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
logger.warn("Failed to wait for TUI exit", e);
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
activeTui = null;
|
|
100
|
+
messages.forEach(function (m) {
|
|
101
|
+
CLIPrinter.warn(m);
|
|
102
|
+
});
|
|
135
103
|
// Exit ONLY after fullscreen ink has restored the terminal
|
|
136
104
|
process.exit(0);
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
messages.forEach(function (m) {
|
|
109
|
+
CLIPrinter.warn(m);
|
|
110
|
+
});
|
|
111
|
+
process.exit(0);
|
|
141
112
|
}
|
|
142
113
|
}));
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
CLIPrinter.error(`Worker stopped with exit code ${code}`);
|
|
114
|
+
if (!finalConfig.NoTUI) {
|
|
115
|
+
const tui = withFullScreen(_jsx(TunnelTuiWrapper, { finalConfig: finalConfig, urls: TunnelData.urls, greet: TunnelData.greet }));
|
|
116
|
+
activeTui = tui;
|
|
117
|
+
try {
|
|
118
|
+
yield tui.start();
|
|
119
|
+
yield tui.waitUntilExit();
|
|
150
120
|
}
|
|
151
|
-
|
|
152
|
-
|
|
121
|
+
catch (e) {
|
|
122
|
+
logger.warn("TUI error", e);
|
|
153
123
|
}
|
|
154
|
-
|
|
124
|
+
finally {
|
|
125
|
+
activeTui = null;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
155
128
|
}
|
|
156
129
|
catch (err) {
|
|
157
130
|
CLIPrinter.stopSpinnerFail("Failed to connect");
|
package/dist/index.js
CHANGED
|
@@ -25,6 +25,16 @@ function main() {
|
|
|
25
25
|
const { values, positionals, hasAnyArgs } = parseCliArgs(cliOptions);
|
|
26
26
|
// Configure logger from CLI args
|
|
27
27
|
configureLogger(values);
|
|
28
|
+
// Use the TunnelManager to start the tunnel
|
|
29
|
+
const manager = TunnelManager.getInstance();
|
|
30
|
+
// Keep the process alive and handle graceful shutdown
|
|
31
|
+
process.on('SIGINT', () => {
|
|
32
|
+
logger.info("SIGINT received: stopping tunnels and exiting");
|
|
33
|
+
console.log("\nStopping all tunnels...");
|
|
34
|
+
manager.stopAllTunnels();
|
|
35
|
+
console.log("Tunnels stopped. Exiting.");
|
|
36
|
+
process.exit(0);
|
|
37
|
+
});
|
|
28
38
|
if (!hasAnyArgs || values.help) {
|
|
29
39
|
printHelpMessage();
|
|
30
40
|
return;
|
|
@@ -44,17 +54,7 @@ function main() {
|
|
|
44
54
|
logger.debug("Building final config from CLI values and positionals", { values, positionals });
|
|
45
55
|
const finalConfig = buildFinalConfig(values, positionals);
|
|
46
56
|
logger.debug("Final configuration built", finalConfig);
|
|
47
|
-
|
|
48
|
-
const manager = TunnelManager.getInstance();
|
|
49
|
-
const tunnel = yield startCli(finalConfig, manager);
|
|
50
|
-
// Keep the process alive and handle graceful shutdown
|
|
51
|
-
process.on('SIGINT', () => {
|
|
52
|
-
logger.info("SIGINT received: stopping tunnels and exiting");
|
|
53
|
-
console.log("\nStopping all tunnels...");
|
|
54
|
-
manager.stopAllTunnels();
|
|
55
|
-
console.log("Tunnels stopped. Exiting.");
|
|
56
|
-
process.exit(0);
|
|
57
|
-
});
|
|
57
|
+
yield startCli(finalConfig, manager);
|
|
58
58
|
}
|
|
59
59
|
catch (error) {
|
|
60
60
|
logger.error("Unhandled error in CLI:", error);
|
package/dist/logger.js
CHANGED
|
@@ -12,6 +12,7 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
12
12
|
import winston from "winston";
|
|
13
13
|
import fs from "fs";
|
|
14
14
|
import path from "path";
|
|
15
|
+
import { pinggy } from "@pinggy/pinggy";
|
|
15
16
|
// Singleton logger instance
|
|
16
17
|
let _logger = null;
|
|
17
18
|
function getLogger() {
|
|
@@ -22,10 +23,15 @@ function getLogger() {
|
|
|
22
23
|
}
|
|
23
24
|
export const logger = getLogger();
|
|
24
25
|
export function configureLogger(values, silent = false) {
|
|
26
|
+
var _a;
|
|
25
27
|
// Parse values from CLI args
|
|
26
28
|
const levelStr = values.loglevel || undefined;
|
|
27
29
|
const filePath = values.logfile || process.env.PINGGY_LOG_FILE || undefined;
|
|
28
|
-
const printlog = values.
|
|
30
|
+
const printlog = values.v || values.vvv || undefined;
|
|
31
|
+
const source = (_a = values.vvv) !== null && _a !== void 0 ? _a : false;
|
|
32
|
+
if (values.vv || values.vvv) {
|
|
33
|
+
enableLoggingByLogLevel();
|
|
34
|
+
}
|
|
29
35
|
// Ensure log directory exists if file logging is enabled
|
|
30
36
|
if (filePath) {
|
|
31
37
|
const dir = path.dirname(filePath);
|
|
@@ -39,7 +45,8 @@ export function configureLogger(values, silent = false) {
|
|
|
39
45
|
transports.push(new winston.transports.Console({
|
|
40
46
|
format: winston.format.combine(winston.format.colorize(), winston.format.timestamp(), winston.format.printf((_a) => {
|
|
41
47
|
var { level, message, timestamp } = _a, meta = __rest(_a, ["level", "message", "timestamp"]);
|
|
42
|
-
|
|
48
|
+
const srcLabel = source ? "[CLI] " : "";
|
|
49
|
+
return `${timestamp} ${srcLabel}[${level}] ${message} ${Object.keys(meta).length ? JSON.stringify(meta) : ""}`;
|
|
43
50
|
})),
|
|
44
51
|
}));
|
|
45
52
|
}
|
|
@@ -65,3 +72,6 @@ export function configureLogger(values, silent = false) {
|
|
|
65
72
|
log.silent = transports.length === 0 || silent === true;
|
|
66
73
|
return log;
|
|
67
74
|
}
|
|
75
|
+
function enableLoggingByLogLevel() {
|
|
76
|
+
pinggy.setDebugLogging(true);
|
|
77
|
+
}
|
|
@@ -14,168 +14,127 @@ export class TunnelOperations {
|
|
|
14
14
|
constructor() {
|
|
15
15
|
this.tunnelManager = TunnelManager.getInstance(); // Use singleton instance
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
tunnelid
|
|
29
|
-
remoteurls
|
|
30
|
-
tunnelconfig: pinggyOptionsToTunnelConfig(
|
|
31
|
-
status: newStatus(
|
|
32
|
-
stats
|
|
17
|
+
// --- Helper to construct TunnelResponse ---
|
|
18
|
+
buildTunnelResponse(tunnelid, tunnelConfig, configid, tunnelName) {
|
|
19
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20
|
+
const [status, stats, tlsInfo, greetMsg, remoteurls] = yield Promise.all([
|
|
21
|
+
this.tunnelManager.getTunnelStatus(tunnelid),
|
|
22
|
+
this.tunnelManager.getTunnelStats(tunnelid),
|
|
23
|
+
this.tunnelManager.getLocalserverTlsInfo(tunnelid),
|
|
24
|
+
this.tunnelManager.getTunnelGreetMessage(tunnelid),
|
|
25
|
+
this.tunnelManager.getTunnelUrls(tunnelid)
|
|
26
|
+
]);
|
|
27
|
+
return {
|
|
28
|
+
tunnelid,
|
|
29
|
+
remoteurls,
|
|
30
|
+
tunnelconfig: pinggyOptionsToTunnelConfig(tunnelConfig, configid, tunnelName, tlsInfo, greetMsg),
|
|
31
|
+
status: newStatus(status, TunnelErrorCodeType.NoError, ""),
|
|
32
|
+
stats
|
|
33
33
|
};
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
return newErrorResponse({
|
|
38
|
-
code: ErrorCode.ErrorStartingTunnel,
|
|
39
|
-
message: error instanceof Error ? error.message : 'Unknown error occurred while starting tunnel'
|
|
40
|
-
});
|
|
41
|
-
}
|
|
34
|
+
});
|
|
42
35
|
}
|
|
43
|
-
|
|
36
|
+
error(code, err, fallback) {
|
|
37
|
+
return newErrorResponse({
|
|
38
|
+
code,
|
|
39
|
+
message: err instanceof Error ? err.message : fallback
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// --- Operations ---
|
|
43
|
+
handleStart(config) {
|
|
44
44
|
return __awaiter(this, void 0, void 0, function* () {
|
|
45
45
|
try {
|
|
46
46
|
// Convert TunnelConfig -> PinggyOptions
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
47
|
+
const opts = tunnelConfigToPinggyOptions(config);
|
|
48
|
+
const { tunnelid, instance, tunnelName } = this.tunnelManager.createTunnel(Object.assign(Object.assign({}, opts), { configid: config.configid, tunnelName: config.configname }));
|
|
49
|
+
this.tunnelManager.startTunnel(tunnelid);
|
|
50
|
+
const tunnelPconfig = yield this.tunnelManager.getTunnelConfig("", tunnelid);
|
|
51
|
+
const resp = this.buildTunnelResponse(tunnelid, tunnelPconfig, config.configid, tunnelName);
|
|
52
|
+
return resp;
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
return this.error(ErrorCode.ErrorStartingTunnel, err, "Unknown error occurred while starting tunnel");
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
handleUpdateConfig(config) {
|
|
60
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
61
|
+
try {
|
|
62
|
+
const opts = tunnelConfigToPinggyOptions(config);
|
|
63
|
+
const tunnel = yield this.tunnelManager.updateConfig(Object.assign(Object.assign({}, opts), { configid: config.configid, tunnelName: config.configname }));
|
|
64
|
+
if (!tunnel.instance || !tunnel.tunnelConfig)
|
|
65
|
+
throw new Error("Invalid tunnel state after configuration update");
|
|
66
|
+
return this.buildTunnelResponse(tunnel.tunnelid, tunnel.tunnelConfig, config.configid, tunnel.tunnelName);
|
|
63
67
|
}
|
|
64
|
-
catch (
|
|
65
|
-
return
|
|
66
|
-
code: ErrorCode.InternalServerError,
|
|
67
|
-
message: error instanceof Error ? error.message : 'Failed to update tunnel configuration'
|
|
68
|
-
});
|
|
68
|
+
catch (err) {
|
|
69
|
+
return this.error(ErrorCode.InternalServerError, err, "Failed to update tunnel configuration");
|
|
69
70
|
}
|
|
70
71
|
});
|
|
71
72
|
}
|
|
72
73
|
handleList() {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
});
|
|
99
|
-
}
|
|
74
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
75
|
+
try {
|
|
76
|
+
const tunnels = yield this.tunnelManager.getAllTunnels();
|
|
77
|
+
return Promise.all(tunnels.map((t) => __awaiter(this, void 0, void 0, function* () {
|
|
78
|
+
var _a;
|
|
79
|
+
const stats = ((_a = this.tunnelManager.getTunnelStats(t.tunnelid)) !== null && _a !== void 0 ? _a : newStats());
|
|
80
|
+
const [status, config, tlsInfo, greetMsg] = yield Promise.all([
|
|
81
|
+
this.tunnelManager.getTunnelStatus(t.tunnelid),
|
|
82
|
+
this.tunnelManager.getTunnelConfig("", t.tunnelid),
|
|
83
|
+
this.tunnelManager.getLocalserverTlsInfo(t.tunnelid),
|
|
84
|
+
this.tunnelManager.getTunnelGreetMessage(t.tunnelid)
|
|
85
|
+
]);
|
|
86
|
+
return {
|
|
87
|
+
tunnelid: t.tunnelid,
|
|
88
|
+
remoteurls: t.remoteurls,
|
|
89
|
+
status: newStatus(status, TunnelErrorCodeType.NoError, ""),
|
|
90
|
+
stats,
|
|
91
|
+
tunnelconfig: pinggyOptionsToTunnelConfig(config, t.configid, t.tunnelName, tlsInfo, greetMsg)
|
|
92
|
+
};
|
|
93
|
+
})));
|
|
94
|
+
}
|
|
95
|
+
catch (err) {
|
|
96
|
+
return this.error(ErrorCode.InternalServerError, err, "Failed to list tunnels");
|
|
97
|
+
}
|
|
98
|
+
});
|
|
100
99
|
}
|
|
101
100
|
handleStop(tunnelid) {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
102
|
+
try {
|
|
103
|
+
const { configid } = this.tunnelManager.stopTunnel(tunnelid);
|
|
104
|
+
const managed = this.tunnelManager.getManagedTunnel("", tunnelid);
|
|
105
|
+
if (!(managed === null || managed === void 0 ? void 0 : managed.tunnelConfig))
|
|
106
|
+
throw new Error(`Tunnel config for ID "${tunnelid}" not found`);
|
|
107
|
+
return this.buildTunnelResponse(tunnelid, managed.tunnelConfig, configid, managed.tunnelName);
|
|
107
108
|
}
|
|
108
|
-
|
|
109
|
-
|
|
109
|
+
catch (err) {
|
|
110
|
+
return this.error(ErrorCode.TunnelNotFound, err, "Failed to stop tunnel");
|
|
110
111
|
}
|
|
111
|
-
|
|
112
|
-
tunnelid: stoppedTunnelId,
|
|
113
|
-
remoteurls: [],
|
|
114
|
-
tunnelconfig: pinggyOptionsToTunnelConfig(tunnelInstance.tunnelConfig, configid, tunnelInstance.tunnelName, this.tunnelManager.getLocalserverTlsInfo(tunnelid), this.tunnelManager.getTunnelGreetMessage(tunnelid)),
|
|
115
|
-
status: newStatus(this.tunnelManager.getTunnelStatus(stoppedTunnelId), TunnelErrorCodeType.NoError, ""),
|
|
116
|
-
stats: newStats()
|
|
117
|
-
};
|
|
118
|
-
return tunnelResponse;
|
|
119
|
-
}
|
|
120
|
-
catch (error) {
|
|
121
|
-
return newErrorResponse({
|
|
122
|
-
code: ErrorCode.TunnelNotFound,
|
|
123
|
-
message: error instanceof Error ? error.message : 'Failed to stop tunnel'
|
|
124
|
-
});
|
|
125
|
-
}
|
|
112
|
+
});
|
|
126
113
|
}
|
|
127
114
|
handleGet(tunnelid) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
115
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
116
|
+
try {
|
|
117
|
+
const managed = this.tunnelManager.getManagedTunnel("", tunnelid);
|
|
118
|
+
if (!(managed === null || managed === void 0 ? void 0 : managed.tunnelConfig))
|
|
119
|
+
throw new Error(`Tunnel config for ID "${tunnelid}" not found`);
|
|
120
|
+
return this.buildTunnelResponse(tunnelid, managed.tunnelConfig, managed.configid, managed.tunnelName);
|
|
133
121
|
}
|
|
134
|
-
|
|
135
|
-
|
|
122
|
+
catch (err) {
|
|
123
|
+
return this.error(ErrorCode.TunnelNotFound, err, "Failed to get tunnel information");
|
|
136
124
|
}
|
|
137
|
-
|
|
138
|
-
const stats = this.tunnelManager.getTunnelStats(tunnelid) ? this.tunnelManager.getTunnelStats(tunnelid) : tunnelInstance.instance.getLatestUsage();
|
|
139
|
-
const tunnelResponse = {
|
|
140
|
-
tunnelid: tunnelid,
|
|
141
|
-
remoteurls: this.tunnelManager.getTunnelUrls(tunnelid),
|
|
142
|
-
status: newStatus(tunnelState, TunnelErrorCodeType.NoError, ""),
|
|
143
|
-
stats: stats,
|
|
144
|
-
tunnelconfig: pinggyOptionsToTunnelConfig(tunnelInstance.tunnelConfig, tunnelInstance.configid, tunnelInstance.tunnelName, this.tunnelManager.getLocalserverTlsInfo(tunnelid), this.tunnelManager.getTunnelGreetMessage(tunnelid))
|
|
145
|
-
};
|
|
146
|
-
return tunnelResponse;
|
|
147
|
-
}
|
|
148
|
-
catch (error) {
|
|
149
|
-
return newErrorResponse({
|
|
150
|
-
code: ErrorCode.TunnelNotFound,
|
|
151
|
-
message: error instanceof Error ? error.message : 'Failed to get tunnel information'
|
|
152
|
-
});
|
|
153
|
-
}
|
|
125
|
+
});
|
|
154
126
|
}
|
|
155
127
|
handleRestart(tunnelid) {
|
|
156
128
|
return __awaiter(this, void 0, void 0, function* () {
|
|
157
129
|
try {
|
|
158
130
|
yield this.tunnelManager.restartTunnel(tunnelid);
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
}
|
|
164
|
-
const stats = this.tunnelManager.getTunnelStats(tunnelid) ? this.tunnelManager.getTunnelStats(tunnelid) : tunnelInstance.instance.getLatestUsage();
|
|
165
|
-
const tunnelResponse = {
|
|
166
|
-
tunnelid: tunnelid,
|
|
167
|
-
remoteurls: this.tunnelManager.getTunnelUrls(tunnelid),
|
|
168
|
-
tunnelconfig: pinggyOptionsToTunnelConfig(tunnelConfig, tunnelInstance.configid, tunnelInstance.tunnelName, this.tunnelManager.getLocalserverTlsInfo(tunnelid), this.tunnelManager.getTunnelGreetMessage(tunnelid)),
|
|
169
|
-
status: newStatus(this.tunnelManager.getTunnelStatus(tunnelid), TunnelErrorCodeType.NoError, ""),
|
|
170
|
-
stats: stats
|
|
171
|
-
};
|
|
172
|
-
return tunnelResponse;
|
|
131
|
+
const managed = this.tunnelManager.getManagedTunnel("", tunnelid);
|
|
132
|
+
if (!(managed === null || managed === void 0 ? void 0 : managed.tunnelConfig))
|
|
133
|
+
throw new Error(`Tunnel config for ID "${tunnelid}" not found`);
|
|
134
|
+
return this.buildTunnelResponse(tunnelid, managed.tunnelConfig, managed.configid, managed.tunnelName);
|
|
173
135
|
}
|
|
174
|
-
catch (
|
|
175
|
-
return
|
|
176
|
-
code: ErrorCode.TunnelNotFound,
|
|
177
|
-
message: error instanceof Error ? error.message : 'Failed to restart tunnel'
|
|
178
|
-
});
|
|
136
|
+
catch (err) {
|
|
137
|
+
return this.error(ErrorCode.TunnelNotFound, err, "Failed to restart tunnel");
|
|
179
138
|
}
|
|
180
139
|
});
|
|
181
140
|
}
|