diff --git a/bin/telebitd.js b/bin/telebitd.js index 0879391..46fd747 100755 --- a/bin/telebitd.js +++ b/bin/telebitd.js @@ -27,6 +27,7 @@ var snakeCopy = recase.snakeCopy.bind(recase); var TPLS = TOML.parse(fs.readFileSync(path.join(__dirname, "../lib/en-us.toml"), 'utf8')); var startTime = Date.now(); var connectTimes = []; +var isConnected = false; var TelebitRemote = require('../lib/daemon/index.js').TelebitRemote; @@ -628,17 +629,17 @@ function handleApi(req, res) { res.setHeader('Content-Type', 'application/json'); res.end(JSON.stringify( { module: 'status' - , port: (state.config.ipc && state.config.ipc.port || state._ipc.port || undefined) - , status: (state.config.disable ? 'disabled' : 'enabled') - , ready: ((state.config.relay && (state.config.token || state.config.agreeTos)) ? true : false) - , active: !!myRemote - , connected: 'maybe (todo)' , version: pkg.version - , servernames: state.servernames + , port: (state.config.ipc && state.config.ipc.port || state._ipc.port || undefined) + , enabled: !state.config.disable + , active: !!myRemote + , initialized: (state.config.relay && state.config.token && state.config.agreeTos) ? true : false + , connected: isConnected , proctime: Math.round(process.uptime() * 1000) , uptime: now - startTime - , runtime: connectTimes.length && (now - connectTimes[0]) || 0 + , runtime: isConnected && connectTimes.length && (now - connectTimes[0]) || 0 , reconnects: connectTimes.length + , servernames: state.servernames } )); } @@ -707,7 +708,8 @@ function handleApi(req, res) { res.end(JSON.stringify({"error":{"message":"unrecognized rpc"}})); } - if (!req.headers['content-length'] && !req.headers['content-type']) { + var hasLength = req.headers['content-length'] > 0; + if (!hasLength && !req.headers['content-type']) { route(); return; } @@ -1042,6 +1044,7 @@ function rawStartTelebitRemote(keepAlive) { } function onConnect() { + isConnected = true; connectTimes.unshift(Date.now()); console.info('[connect] relay established'); myRemote.removeListener('error', onConnectError); @@ -1060,6 +1063,7 @@ function rawStartTelebitRemote(keepAlive) { function onConnectError(err) { myRemote = null; + isConnected = false; if (handleError(err, 'onConnectError')) { if (!keepAlive.state) { reject(err); @@ -1075,6 +1079,7 @@ function rawStartTelebitRemote(keepAlive) { } function retryLoop() { + isConnected = false; console.warn('[Warn] disconnected. Will retry?', keepAlive.state); if (keepAlive.state) { safeReload(10 * 1000).then(resolve).catch(reject); diff --git a/lib/admin/index.html b/lib/admin/index.html index b10cbb7..9af0f31 100644 --- a/lib/admin/index.html +++ b/lib/admin/index.html @@ -7,7 +7,7 @@
-

Telebit (Remote) Setup

+

Telebit (Remote) Setup v{{ config.version }}

{{ views.flash.error }} @@ -115,6 +115,19 @@
+ + +
+ http://localhost:{{ status.port }} +
+ Proctime: {{ statusProctime }} +
+ Uptime: {{ statusUptime }} +
+ Runtime: {{ statusRuntime }} +
+ Reconnects: {{ status.reconnects }} +
{{ status }}
diff --git a/lib/admin/js/app.js b/lib/admin/js/app.js index 2cfedd5..a40a5bc 100644 --- a/lib/admin/js/app.js +++ b/lib/admin/js/app.js @@ -37,14 +37,26 @@ api.status = function apiStatus() { return json; }); }; -api.initialize = function apiInitialize() { +api.enable = function apiEnable() { var opts = { - url: "/api/xxinitxx" + url: "/api/enable" , method: "POST" - , headers: { - 'Content-Type': 'application/json' - } - , body: JSON.stringify(telebitState.config) + //, headers: { 'Content-Type': 'application/json' } + }; + return Telebit.reqLocalAsync(opts).then(function (resp) { + var json = resp.body; + appData.initResult = json; + window.alert("Error: [success] " + JSON.stringify(json, null, 2)); + return json; + }).catch(function (err) { + window.alert("Error: [init] " + (err.message || JSON.stringify(err, null, 2))); + }); +}; +api.disable = function apiDisable() { + var opts = { + url: "/api/disable" + , method: "POST" + //, headers: { 'Content-Type': 'application/json' } }; return Telebit.reqLocalAsync(opts).then(function (resp) { var json = resp.body; @@ -107,8 +119,8 @@ var TELEBIT_RELAYS = [ var PRODUCTION_ACME = 'https://acme-v02.api.letsencrypt.org/directory'; var STAGING_ACME = 'https://acme-staging-v02.api.letsencrypt.org/directory'; var appData = { - config: null -, status: null + config: {} +, status: {} , init: { teletos: true , letos: true @@ -181,11 +193,11 @@ var appMethods = { , betaRelay: function () { appData.init.relay = BETA_RELAY; } -, defaultRhubarb: function () { - appData.init.rhubarb = DEFAULT_RELAY; +, enable: function () { + api.enable(); } -, betaRhubarb: function () { - appData.init.rhubarb = BETA_RELAY; +, disable: function () { + api.disable(); } }; var appStates = { @@ -200,9 +212,15 @@ var appStates = { } , status: function () { appData.views.section = { status: true }; - return api.status().then(function (status) { - appData.status = status; - }); + var tok = setInterval(function () { + api.status().then(function (status) { + appData.status = status; + }); + }, 2000); + + return function cancelState() { + clearInterval(tok); + }; } }; @@ -216,23 +234,72 @@ function changeState(newstate) { } location.hash = newhash; } +/*globals Promise*/ window.addEventListener('hashchange', setState, false); function setState(/*ev*/) { //ev.oldURL //ev.newURL + if (appData.exit) { + appData.exit.then(function (exit) { + if ('function' === typeof appData.exit) { + exit(); + } + }); + } var parts = location.hash.substr(1).replace(/^\//, '').replace(/\/$/, '').split('/'); var fn = appStates; parts.forEach(function (s) { console.log("state:", s); fn = fn[s]; }); - fn(); + appData.exit = Promise.resolve(fn()); //appMethods.states[newstate](); } +function msToHumanReadable(ms) { + var uptime = ms; + var uptimed = uptime / 1000; + var minute = 60; + var hour = 60 * minute; + var day = 24 * hour; + var days = 0; + var times = []; + while (uptimed > day) { + uptimed -= day; + days += 1; + } + times.push(days + " days "); + var hours = 0; + while (uptimed > hour) { + uptimed -= hour; + hours += 1; + } + times.push(hours.toString().padStart(2, "0") + " h "); + var minutes = 0; + while (uptimed > minute) { + uptimed -= minute; + minutes += 1; + } + times.push(minutes.toString().padStart(2, "0") + " m "); + var seconds = Math.round(uptimed); + times.push(seconds.toString().padStart(2, "0") + " s "); + return times.join(''); +} + new Vue({ el: ".v-app" , data: appData +, computed: { + statusProctime: function () { + return msToHumanReadable(this.status.proctime); + } + , statusRuntime: function () { + return msToHumanReadable(this.status.runtime); + } + , statusUptime: function () { + return msToHumanReadable(this.status.uptime); + } + } , methods: appMethods });