diff --git a/wsclient.js b/wsclient.js index 803beac..4e7c529 100644 --- a/wsclient.js +++ b/wsclient.js @@ -39,113 +39,140 @@ request.get('https://pokemap.hellabit.com:3000?access_token=' + token, { rejectU return; //*/ -var wstunneler = new WebSocket('wss://pokemap.hellabit.com:3000/?access_token=' + token, { rejectUnauthorized: false }); -wstunneler.on('open', function () { - console.log('[open] tunneler connected'); - var localclients = {}; + var tunnelUrl = 'wss://pokemap.hellabit.com:3000/?access_token=' + token; - /* - setInterval(function () { - console.log(''); - console.log('localclients.length:', Object.keys(localclients).length); - console.log(''); - }, 5000); - */ + function run() { + var wstunneler = new WebSocket(tunnelUrl, { rejectUnauthorized: false }); - //wstunneler.send(token); + function onOpen() { + console.log('[open] tunneler connected'); + var localclients = {}; - // BaaS / Backendless / noBackend / horizon.io - // user authentication - // a place to store data - // file management - // Synergy Teamwork Paradigm = Jabberwocky - var pack = require('tunnel-packer').pack; + /* + setInterval(function () { + console.log(''); + console.log('localclients.length:', Object.keys(localclients).length); + console.log(''); + }, 5000); + */ - function onMessage(opts) { - var cid = addrToId(opts); - console.log('[wsclient] onMessage:', cid); - var service = opts.service; - var port = services[service]; - var lclient; - var servername; - var str; - var m; + //wstunneler.send(token); - if (opts.data.byteLength < 20) { - if ('|__ERROR__|' === opts.data.toString('ascii') - || '|__END__|' === opts.data.toString('ascii')) { + // BaaS / Backendless / noBackend / horizon.io + // user authentication + // a place to store data + // file management + // Synergy Teamwork Paradigm = Jabberwocky + var pack = require('tunnel-packer').pack; + var handlers = { + onmessage: function (opts) { + var cid = addrToId(opts); + console.log('[wsclient] onMessage:', cid); + var service = opts.service; + var port = services[service]; + var lclient; + var servername; + var str; + var m; - console.log("['" + opts.data.toString('ascii') + "'] '" + cid + "'"); - if (localclients[cid]) { - localclients[cid].end(); + if (opts.data.byteLength < 20) { + if ('|__ERROR__|' === opts.data.toString('ascii')) { + handlers.onerror(opts); + return; + } + else if ('|__END__|' === opts.data.toString('ascii')) { + handlers.onend(opts); + return; + } + } + + function endWithError() { + wstunneler.send(pack(opts, Buffer.from('|__ERROR__|'), 'error'), { binary: true }); + } + + if (localclients[cid]) { + console.log("[=>] received data from '" + cid + "' =>", opts.data.byteLength); + localclients[cid].write(opts.data); + return; + } + else if ('http' === service) { + str = opts.data.toString(); + m = str.match(/(?:^|[\r\n])Host: ([^\r\n]+)[\r\n]*/im); + servername = (m && m[1].toLowerCase() || '').split(':')[0]; + } + else if ('https' === service) { + servername = sni(opts.data); + } + else { + endWithError(); + return; + } + + if (!servername) { + console.warn("|__ERROR__| no servername found for '" + cid + "'"); + console.warn(opts.data.toString()); + wstunneler.send(pack(opts, Buffer.from('|__ERROR__|'), 'error'), { binary: true }); + return; + } + + console.log("servername: '" + servername + "'"); + + lclient = localclients[cid] = net.createConnection({ port: port, host: '127.0.0.1' }, function () { + console.log("[=>] first packet from tunneler to '" + cid + "' as '" + opts.service + "'", opts.data.byteLength); + lclient.write(opts.data); + }); + lclient.on('data', function (chunk) { + console.log("[<=] local '" + opts.service + "' sent to '" + cid + "' <= ", chunk.byteLength, "bytes"); + console.log(JSON.stringify(chunk.toString())); + wstunneler.send(pack(opts, chunk), { binary: true }); + }); + lclient.on('error', function (err) { + console.error("[error] local '" + opts.service + "' '" + cid + "'"); + console.error(err); + delete localclients[cid]; + wstunneler.send(pack(opts, Buffer.from('|__ERROR__|'), 'error'), { binary: true }); + }); + lclient.on('end', function () { + console.log("[end] local '" + opts.service + "' '" + cid + "'"); + delete localclients[cid]; + wstunneler.send(pack(opts, Buffer.from('|__END__|'), 'end'), { binary: true }); + }); + } + , onend: function (opts) { + var cid = addrToId(opts); + console.log("[end] '" + cid + "'"); + handlers._onend(cid, opts); + } + , onerror: function (opts) { + var cid = addrToId(opts); + console.log("[error] '" + cid + "'", opts.code || '', opts.message); + handlers._onend(cid); + } + , _onend: function (cid) { + if (localclients[cid]) { + localclients[cid].end(); + } delete localclients[cid]; } - return; - } + }; + var machine = require('tunnel-packer').create(handlers); + + wstunneler.on('message', machine.fns.addChunk); } - function endWithError() { - wstunneler.send(pack(opts, Buffer.from('|__ERROR__|'), 'error'), { binary: true }); - } + wstunneler.on('open', onOpen); - if (localclients[cid]) { - console.log("[=>] received data from '" + cid + "' =>", opts.data.byteLength); - localclients[cid].write(opts.data); - return; - } - else if ('http' === service) { - str = opts.data.toString(); - m = str.match(/(?:^|[\r\n])Host: ([^\r\n]+)[\r\n]*/im); - servername = (m && m[1].toLowerCase() || '').split(':')[0]; - } - else if ('https' === service) { - servername = sni(opts.data); - } - else { - endWithError(); - return; - } + wstunneler.on('close', function () { + console.log('retry on close'); + setTimeout(run, 5000); + }); - if (!servername) { - console.warn("|__ERROR__| no servername found for '" + cid + "'"); - console.warn(opts.data.toString()); - wstunneler.send(pack(opts, Buffer.from('|__ERROR__|'), 'error'), { binary: true }); - return; - } - - console.log("servername: '" + servername + "'"); - - lclient = localclients[cid] = net.createConnection({ port: port, host: '127.0.0.1' }, function () { - - lclient.on('data', function (chunk) { - console.log("[<=] local '" + opts.service + "' sent to '" + cid + "' <= ", chunk.byteLength, "bytes"); - console.log(JSON.stringify(chunk.toString())); - wstunneler.send(pack(opts, chunk), { binary: true }); - }); - lclient.on('error', function (err) { - console.error("[error] local '" + opts.service + "' '" + cid + "'"); - console.error(err); - delete localclients[cid]; - wstunneler.send(pack(opts, Buffer.from('|__ERROR__|'), 'error'), { binary: true }); - }); - lclient.on('end', function () { - console.log("[end] local '" + opts.service + "' '" + cid + "'"); - delete localclients[cid]; - wstunneler.send(pack(opts, Buffer.from('|__END__|'), 'end'), { binary: true }); - }); - - console.log("[=>] first packet from tunneler to '" + cid + "' as '" + opts.service + "'", opts.data.byteLength); - lclient.write(opts.data); + wstunneler.on('error', function (err) { + console.error("[error] will retry on 'close'"); + console.error(err); }); } - var machine = require('tunnel-packer').create({ onMessage: onMessage }); - - wstunneler.on('message', machine.fns.addChunk); - - wstunneler.on('close', function () { - console.log('end'); - }); -}); + run(); }());