tunnelmole
Advanced tools
Comparing version 2.3.2 to 2.3.3
@@ -39,3 +39,3 @@ #!/usr/bin/env node | ||
`) | ||
.version('2.2.13') | ||
.version('2.3.3') | ||
.arguments('[arg0]') | ||
@@ -42,0 +42,0 @@ .option('--set-api-key <apiKey>', 'Set your API key. After purchasing a subscription you can copy and paste the command shown on the page') |
@@ -13,4 +13,5 @@ import { initStorage, storage } from "../node-persist/storage.js"; | ||
console.info("API Key " + apiKey + " is set\n"); | ||
process.exit(0); | ||
}; | ||
export { getApiKey, setApiKey }; | ||
//# sourceMappingURL=api-key-service.js.map |
@@ -1,11 +0,6 @@ | ||
import config from '../config.js'; | ||
import HostipWebSocket from './websocket/host-ip-websocket.js'; | ||
import { initialise } from './messages/types.js'; | ||
import { messageHandlers } from '../message-handlers.js'; | ||
import log from './logging/log.js'; | ||
import { getClientId, initialiseClientId } from './identity/client-id-service.js'; | ||
import { getApiKey } from './identity/api-key-service.js'; | ||
import validator from 'validator'; | ||
import { initialiseClientId } from './identity/client-id-service.js'; | ||
import { initStorage } from './node-persist/storage.js'; | ||
import { eventHandler, URL_ASSIGNED } from './events/event-handler.js'; | ||
import { setUpAutoReconnect } from './websocket/setup-auto-reconnect.js'; | ||
import { connect } from './websocket/connect.js'; | ||
export default async function tunnelmole(options) { | ||
@@ -19,95 +14,8 @@ await initStorage(); | ||
if (options.setApiKey) { | ||
return; | ||
return "We are simply setting the API key here. No need to set up a tunnel"; | ||
} | ||
const connect = () => { | ||
const websocket = new HostipWebSocket(config.hostip.endpoint); | ||
const websocketIsReady = websocket.readyState === 1; | ||
const sendInitialiseMessage = async () => { | ||
var _a; | ||
log("Sending initialise message"); | ||
const initialiseMessage = { | ||
type: initialise, | ||
clientId: await getClientId() | ||
}; | ||
// Set api key if we have one available | ||
const apiKey = await getApiKey(); | ||
if (typeof apiKey === 'string') { | ||
initialiseMessage.apiKey = apiKey; | ||
} | ||
// Handle passed subdomain param if present | ||
let domain = (_a = options.domain) !== null && _a !== void 0 ? _a : undefined; | ||
if (typeof domain === 'string') { | ||
// Remove protocols in case they were passed by mistake as the "domain" | ||
domain = domain.replace('http://', ''); | ||
domain = domain.replace('https://', ''); | ||
if (!validator.isURL(domain)) { | ||
console.info("Invalid domain name passed, please use the format mydomain.tunnelmole.net"); | ||
return Promise.resolve(); | ||
} | ||
const domainParts = domain.split('.'); | ||
const subdomain = domainParts[0]; | ||
initialiseMessage.subdomain = subdomain; | ||
} | ||
websocket.sendMessage(initialiseMessage); | ||
}; | ||
// There seems to be a bug where on a second run, the websocket is re-used and is in a ready state | ||
// Send initialise message now if this is the case, otherwise set the open event to trigger the initialise message | ||
if (websocketIsReady) { | ||
sendInitialiseMessage(); | ||
} | ||
else { | ||
websocket.on('open', sendInitialiseMessage); | ||
} | ||
websocket.on('message', (text) => { | ||
const message = JSON.parse(text); | ||
if (typeof message.type !== 'string') { | ||
console.error("Invalid message, type is missing or invalid"); | ||
} | ||
// Errors should be handled in the handler itself. If it gets here it will be thrown. | ||
if (typeof messageHandlers[message.type] !== 'function') { | ||
console.error("Handler not found for message type " + message.type); | ||
} | ||
const handler = messageHandlers[message.type]; | ||
handler(message, websocket, options); | ||
}); | ||
// Log messages if debug is enabled | ||
websocket.on('message', (text) => { | ||
const message = JSON.parse(text); | ||
log(Date.now() + " Received " + message.type + " message:", "info"); | ||
log(message, 'info'); | ||
}); | ||
// Log errors | ||
websocket.on('error', (error) => { | ||
log(Date.now() + "Caught an error:", "error"); | ||
console.error(error); | ||
}); | ||
// Handle close event for reconnection, only for custom subdomains | ||
if (typeof options.domain === 'string') { | ||
websocket.on('close', () => { | ||
attemptReconnection(); | ||
}); | ||
} | ||
return websocket; | ||
}; | ||
connect(); | ||
// Handle automatic reconnection if a custom subdomain is used. Use a delay with exponential backoff. | ||
// Random subdomains would not work here - the client would not be able to re-use the same domain and would get a different random subdomain on reconnection | ||
let reconnectAttempts = 0; | ||
const maxReconnectDelay = 30000; // Maximum delay of 30 seconds | ||
const baseReconnectDelay = 1000; // Start with 1 second | ||
const attemptReconnection = () => { | ||
/* | ||
reconnectAttempts += 1; | ||
const reconnectDelay = Math.min(baseReconnectDelay * Math.pow(2, reconnectAttempts - 1), maxReconnectDelay); | ||
setTimeout(() => { | ||
log(`Got disconnected, attempting to reconnect... `, "warning"); | ||
connect(); | ||
}, reconnectDelay); | ||
*/ | ||
}; | ||
// Every 6 hours, reset reconnectAttempts. This should keep reconnections fast for long lived connections. | ||
setInterval(() => { | ||
reconnectAttempts = 0; | ||
}, 21600000); | ||
// Listen for the URL assigned event and return it | ||
const websocket = await connect(options); | ||
// Set up auto reconnect | ||
setUpAutoReconnect(options, websocket); | ||
// Return the URL as soon as its assigned | ||
return new Promise((resolve) => { | ||
@@ -114,0 +22,0 @@ eventHandler.on(URL_ASSIGNED, (url) => { |
{ | ||
"name": "tunnelmole", | ||
"version": "2.3.2", | ||
"version": "2.3.3", | ||
"description": "Tunnelmole, an open source ngrok alternative. Instant public URLs for any http/https based application. Available as a command line application or as an NPM dependency for your code. Stable and maintained. Good test coverage. Works behind firewalls", | ||
@@ -5,0 +5,0 @@ "main": "dist/src/index.js", |
@@ -17,2 +17,3 @@ import { initStorage, storage } from "../node-persist/storage.js" | ||
console.info("API Key " + apiKey + " is set\n"); | ||
process.exit(0); | ||
} | ||
@@ -19,0 +20,0 @@ |
@@ -1,13 +0,7 @@ | ||
import config from '../config.js'; | ||
import HostipWebSocket from './websocket/host-ip-websocket.js'; | ||
import InitialiseMessage from './messages/initialise-message.js'; | ||
import { initialise } from './messages/types.js'; | ||
import { messageHandlers } from '../message-handlers.js'; | ||
import log from './logging/log.js'; | ||
import { getClientId, initialiseClientId } from './identity/client-id-service.js'; | ||
import { getApiKey, setApiKey } from './identity/api-key-service.js'; | ||
import { initialiseClientId } from './identity/client-id-service.js'; | ||
import { Options } from './options.js'; | ||
import validator from 'validator'; | ||
import { initStorage } from './node-persist/storage.js'; | ||
import { eventHandler, URL_ASSIGNED } from './events/event-handler.js'; | ||
import { setUpAutoReconnect } from './websocket/setup-auto-reconnect.js'; | ||
import { connect } from './websocket/connect.js'; | ||
@@ -24,117 +18,11 @@ export default async function tunnelmole(options: Options): Promise<string> { | ||
if (options.setApiKey) { | ||
return; | ||
return "We are simply setting the API key here. No need to set up a tunnel"; | ||
} | ||
const connect = () => { | ||
const websocket = new HostipWebSocket(config.hostip.endpoint); | ||
const websocketIsReady = websocket.readyState === 1; | ||
const websocket = await connect(options); | ||
const sendInitialiseMessage = async () => { | ||
log("Sending initialise message"); | ||
// Set up auto reconnect | ||
setUpAutoReconnect(options, websocket); | ||
const initialiseMessage: InitialiseMessage = { | ||
type: initialise, | ||
clientId: await getClientId() | ||
}; | ||
// Set api key if we have one available | ||
const apiKey = await getApiKey(); | ||
if (typeof apiKey === 'string') { | ||
initialiseMessage.apiKey = apiKey; | ||
} | ||
// Handle passed subdomain param if present | ||
let domain = options.domain ?? undefined; | ||
if (typeof domain === 'string') { | ||
// Remove protocols in case they were passed by mistake as the "domain" | ||
domain = domain.replace('http://', ''); | ||
domain = domain.replace('https://', ''); | ||
if (!validator.isURL(domain)) { | ||
console.info("Invalid domain name passed, please use the format mydomain.tunnelmole.net"); | ||
return Promise.resolve(); | ||
} | ||
const domainParts = domain.split('.'); | ||
const subdomain = domainParts[0]; | ||
initialiseMessage.subdomain = subdomain; | ||
} | ||
websocket.sendMessage(initialiseMessage); | ||
} | ||
// There seems to be a bug where on a second run, the websocket is re-used and is in a ready state | ||
// Send initialise message now if this is the case, otherwise set the open event to trigger the initialise message | ||
if (websocketIsReady) { | ||
sendInitialiseMessage(); | ||
} else { | ||
websocket.on('open', sendInitialiseMessage); | ||
} | ||
websocket.on('message', (text: string) => { | ||
const message = JSON.parse(text); | ||
if (typeof message.type !== 'string') { | ||
console.error("Invalid message, type is missing or invalid"); | ||
} | ||
// Errors should be handled in the handler itself. If it gets here it will be thrown. | ||
if (typeof messageHandlers[message.type] !== 'function') { | ||
console.error("Handler not found for message type " + message.type); | ||
} | ||
const handler = messageHandlers[message.type]; | ||
handler(message, websocket, options); | ||
}); | ||
// Log messages if debug is enabled | ||
websocket.on('message', (text: string) => { | ||
const message = JSON.parse(text); | ||
log(Date.now() + " Received " + message.type + " message:", "info"); | ||
log(message, 'info'); | ||
}); | ||
// Log errors | ||
websocket.on('error', (error) => { | ||
log(Date.now() + "Caught an error:", "error"); | ||
console.error(error); | ||
}); | ||
// Handle close event for reconnection, only for custom subdomains | ||
if (typeof options.domain === 'string') { | ||
websocket.on('close', () => { | ||
attemptReconnection(); | ||
}); | ||
} | ||
return websocket; | ||
} | ||
connect(); | ||
// Handle automatic reconnection if a custom subdomain is used. Use a delay with exponential backoff. | ||
// Random subdomains would not work here - the client would not be able to re-use the same domain and would get a different random subdomain on reconnection | ||
let reconnectAttempts = 0; | ||
const maxReconnectDelay = 30000; // Maximum delay of 30 seconds | ||
const baseReconnectDelay = 1000; // Start with 1 second | ||
const attemptReconnection = () => { | ||
/* | ||
reconnectAttempts += 1; | ||
const reconnectDelay = Math.min(baseReconnectDelay * Math.pow(2, reconnectAttempts - 1), maxReconnectDelay); | ||
setTimeout(() => { | ||
log(`Got disconnected, attempting to reconnect... `, "warning"); | ||
connect(); | ||
}, reconnectDelay); | ||
*/ | ||
}; | ||
// Every 6 hours, reset reconnectAttempts. This should keep reconnections fast for long lived connections. | ||
setInterval(() => { | ||
reconnectAttempts = 0; | ||
}, 21600000); | ||
// Listen for the URL assigned event and return it | ||
// Return the URL as soon as its assigned | ||
return new Promise((resolve) => { | ||
@@ -141,0 +29,0 @@ eventHandler.on(URL_ASSIGNED, (url: string) => { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
106690
192
1613