hsync 0.19.0 → 0.21.0

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/Readme.md CHANGED
@@ -6,19 +6,31 @@ hsync is a [reverse-proxy](https://en.wikipedia.org/wiki/Reverse_proxy) client f
6
6
 
7
7
  You can share your local webserver as a secure public URL, as well as tunnel whatever tcp/ip traffic you'd like between two hsync clients.
8
8
 
9
+ ## installation
9
10
 
10
- ## basic usage
11
-
12
- ## install globally
11
+ ### npm
13
12
  `npm i -g hsync`
14
13
 
15
- ### run
14
+ ### or add to a webpage
15
+ ```
16
+ <script src="https://cdn.jsdelivr.net/npm/hsync/dist/hsync.min.js"></script>
17
+ ```
18
+ this gives you a `hsync` global variable.
19
+
20
+
21
+ ## run
16
22
  `hsync`
17
23
 
18
24
  ## run with npx
19
25
 
20
26
  `npx hsync`
21
27
 
28
+ ## run inside of a webpage
29
+
30
+ ```javascript
31
+ const hsyncCon = await hsync.dynamicConnect();
32
+ ```
33
+
22
34
  ## configuration
23
35
 
24
36
  by default hsync will connect to the default hsync.tech server and allow a connection for up to 4 hours.
package/cli.js CHANGED
@@ -4,6 +4,7 @@ const { program, Option } = require('commander');
4
4
  const pack = require('./package.json');
5
5
  const config = require('./config');
6
6
  const { createConnection } = require('./hsync');
7
+ const shell = require('./shell');
7
8
 
8
9
  program
9
10
  .name(pack.name)
@@ -18,17 +19,24 @@ program
18
19
  .addOption(new Option('-ltp, --listener-target-port <number>', 'target port for listener').env('HSYNC_LTP'))
19
20
  .addOption(new Option('-rip, --relay-inbound-port <number>', 'inbound port for remote relay requests').env('HSYNC_RIP'))
20
21
  .addOption(new Option('-rth, --relay-target-host <url>', 'target host for relay to open tcp connection on').env('HSYNC_RTH'))
21
- .addOption(new Option('-rtp, --relay-target-port <number>', 'target port for relay to open tcp connection on').env('HSYNC_RTP'));
22
+ .addOption(new Option('-rtp, --relay-target-port <number>', 'target port for relay to open tcp connection on').env('HSYNC_RTP'))
23
+ .addOption(new Option('-rwl, --relay-whitelist <string>', 'whitelist of domains that can access this relay').env('HSYNC_RWL'))
24
+ .addOption(new Option('-rbl, --relay-blacklist <string>', 'blacklist of domains that should be blocked from this relay').env('HSYNC_RBL'))
25
+ .addOption(new Option('-sh, --shell', 'shell to localhost and --port for piping data to a listener'));
22
26
 
23
27
  program.parse();
24
28
 
25
29
  const options = program.opts();
26
30
 
27
-
28
31
  if(options.port) {
29
32
  options.port = Number(options.port);
30
33
  }
31
34
 
35
+ if (options.shell) {
36
+ shell(options.port);
37
+ return;
38
+ }
39
+
32
40
  if(options.listenerLocalPort) {
33
41
  options.listenerLocalPort = options.listenerLocalPort.split(',').map((p) => Number(p));
34
42
  }
package/connection.js CHANGED
@@ -1,12 +1,17 @@
1
1
  const EventEmitter = require('events').EventEmitter;
2
- const b64id = require('b64id');
3
2
  const debug = require('debug')('hsync:info');
4
3
  const debugVerbose = require('debug')('hsync:verbose');
5
4
  const debugError = require('debug')('hsync:error');
6
- const { getRPCPeer, createServerPeer } = require('./lib/peers');
5
+ const { initPeers } = require('./lib/peers');
7
6
  const { createWebHandler, setNet: webSetNet } = require('./lib/web-handler');
8
- const { createSocketListenHandler, setNet: listenSetNet, receiveRelayData } = require('./lib/socket-listen-handler');
9
- const { createSocketRelayHandler, setNet: relaySetNet, receiveListenerData, connectSocket } = require('./lib/socket-relay-handler');
7
+ const {
8
+ setNet: listenSetNet,
9
+ initListeners,
10
+ } = require('./lib/socket-listeners');
11
+ const {
12
+ setNet: relaySetNet,
13
+ initRelays,
14
+ } = require('./lib/socket-relays');
10
15
  const fetch = require('./lib/fetch');
11
16
 
12
17
  debug.color = 3;
@@ -48,7 +53,7 @@ async function createHsync(config) {
48
53
 
49
54
  let dynamicTimeout;
50
55
 
51
- if (dynamicHost) {
56
+ if (dynamicHost && !hsyncSecret) {
52
57
  const result = await fetch.post(`${dynamicHost}/${hsyncBase}/dyn`, {});
53
58
  if (dynamicHost.toLowerCase().startsWith('https')) {
54
59
  hsyncServer = `wss://${result.url}`;
@@ -59,16 +64,19 @@ async function createHsync(config) {
59
64
  dynamicTimeout = result.timeout;
60
65
  }
61
66
 
62
- const hsyncClient = {};
63
- hsyncClient.config = config;
64
- // const peers = {};
65
- const socketListeners = {};
66
- const socketRelays= {};
67
+ const hsyncClient = {
68
+ setNet,
69
+ config,
70
+ };
71
+
72
+ hsyncClient.peers = initPeers(hsyncClient);
73
+ hsyncClient.listeners = initListeners(hsyncClient);
74
+ hsyncClient.relays = initRelays(hsyncClient);
75
+
67
76
  const events = new EventEmitter();
68
77
 
69
78
  hsyncClient.on = events.on;
70
79
  hsyncClient.emit = events.emit;
71
- // hsyncClient.peers = peers;
72
80
 
73
81
  let lastConnect;
74
82
  const connectURL = `${hsyncServer}${hsyncServer.endsWith('/') ? '' : '/'}${hsyncBase}`;
@@ -95,6 +103,9 @@ async function createHsync(config) {
95
103
  if ((error.code === 4) || (error.code === 5)) {
96
104
  debug('ending');
97
105
  mqConn.end();
106
+ if (globalThis.process) {
107
+ process.exit(1);
108
+ }
98
109
  }
99
110
  });
100
111
 
@@ -144,47 +155,19 @@ async function createHsync(config) {
144
155
  })
145
156
  }
146
157
 
147
- function getSocketListeners () {
148
- return Object.keys(socketListeners).map((id) => {
149
- return { info: socketListeners[id].info, id };
150
- });
151
- }
152
-
153
- function getSocketRelays () {
154
- return Object.keys(socketRelays).map((id) => {
155
- return { info: socketRelays[id].info, id };
156
- });
157
- }
158
-
159
- function addSocketListener (port, hostName, targetPort, targetHost) {
160
- // console.log('addSocketListener', port, hostName, targetPort, targetHost);
161
- const handler = createSocketListenHandler({port, hostName, targetPort, targetHost, hsyncClient});
162
- const id = b64id.generateId();
163
- socketListeners[id] = {handler, info: {port, hostName, targetPort, targetHost}, id};
164
- return getSocketListeners();
165
- }
166
-
167
- function addSocketRelay(port, hostName, targetPort, targetHost = 'localhost') {
168
- const handler = createSocketRelayHandler({port, hostName, targetPort, targetHost, hsyncClient});
169
- const id = b64id.generateId();
170
- socketRelays[id] = {handler, info: {port, hostName, targetPort, targetHost}, id};
171
- debug('relay added', port);
172
- return getSocketRelays();
173
- }
174
-
175
158
  const serverReplyMethods = {
176
159
  ping: (greeting) => {
177
160
  return `${greeting} back atcha from client. ${Date.now()}`;
178
161
  },
179
- addSocketListener,
180
- getSocketListeners,
181
- getSocketRelays,
182
- addSocketRelay,
162
+ addSocketListener: hsyncClient.addSocketListener,
163
+ getSocketListeners: hsyncClient.getSocketListeners,
164
+ addSocketRelay: hsyncClient.addSocketRelay,
165
+ getSocketRelays: hsyncClient.getSocketRelays,
183
166
  peerRpc: async (requestInfo) => {
184
167
  requestInfo.hsyncClient = hsyncClient;
185
168
  const { msg } = requestInfo;
186
169
  debug('peerRpc handler', requestInfo.fromHost, msg.method);
187
- const peer = getRPCPeer({hostName: requestInfo.fromHost, hsyncClient});
170
+ const peer = hsyncClient.peers.getRPCPeer({hostName: requestInfo.fromHost, hsyncClient});
188
171
  if (!msg.id) {
189
172
  // notification
190
173
  if (Array.isArray(msg.params)) {
@@ -219,19 +202,27 @@ async function createHsync(config) {
219
202
  debug('ping called', remotePeer.hostName, greeting);
220
203
  return `${greeting} back atcha, ${remotePeer.hostName}.`;
221
204
  },
222
- connectSocket,
223
- receiveListenerData,
224
- receiveRelayData,
205
+ validatePeer: (remotePeer, secret) => {
206
+ return hsyncClient.getPeer(remotePeer.hostName).myAuth === secret;
207
+ },
208
+ connectSocket: hsyncClient.connectSocket,
209
+ // closeListenerSocket: hsyncClient.closeListenerSocket,
210
+ // closeRelaySocket: hsyncClient.closeRelaySocket,
211
+ // receiveListenerData: hsyncClient.receiveListenerData,
212
+ // receiveRelayData: hsyncClient.receiveRelayData,
225
213
  };
226
214
 
227
- hsyncClient.serverPeer = createServerPeer(hsyncClient, serverReplyMethods);
215
+ hsyncClient.serverPeer = hsyncClient.peers.createServerPeer(hsyncClient, serverReplyMethods);
216
+ hsyncClient.serverPeer.notifications.onexternal_message((msg) => {
217
+ hsyncClient.emit('external_message', msg);
218
+ });
228
219
  hsyncClient.getPeer = (hostName) => {
229
- return getRPCPeer({hostName, hsyncClient});
220
+ return peers.getRPCPeer({ hostName });
230
221
  };
231
222
  hsyncClient.hsyncBase = hsyncBase;
232
223
  hsyncClient.endClient = endClient;
233
224
  hsyncClient.serverReplyMethods = serverReplyMethods;
234
- hsyncClient.getRPCPeer = getRPCPeer;
225
+ hsyncClient.getRPCPeer = hsyncClient.peers.getRPCPeer;
235
226
  hsyncClient.peerMethods = peerMethods;
236
227
  hsyncClient.hsyncSecret = hsyncSecret;
237
228
  hsyncClient.hsyncServer = hsyncServer;
@@ -255,7 +246,7 @@ async function createHsync(config) {
255
246
  lth = lth.substring(0, lth.length - 1);
256
247
  }
257
248
  const ltp = listenerTargetPort ? listenerTargetPort[i] : llp;
258
- addSocketListener(llp, myHostName, ltp, lth);
249
+ hsyncClient.addSocketListener({ port: llp, targetPort: ltp, targetHost: lth });
259
250
  debug('relaying local', llp, 'to', lth, ltp);
260
251
  }
261
252
  });
@@ -263,13 +254,15 @@ async function createHsync(config) {
263
254
 
264
255
  if (relayInboundPort) {
265
256
  relayInboundPort.forEach((rip, i) => {
266
- const rth = relayTargetHost ? relayTargetHost[i] : relayTargetHost[0] || 'localhost';
257
+ debug('relayInboundPort', rip, i, relayTargetHost);
258
+ const firstRth = relayTargetHost ? relayTargetHost[0] : null;
259
+ const rth = relayTargetHost ? relayTargetHost[i] : firstRth || 'localhost';
267
260
  if (rth) {
268
261
  if (rth.endsWith('/')) {
269
262
  rth = rth.substring(0, rth.length - 1);
270
263
  }
271
264
  const rtp = relayTargetPort ? relayTargetPort[i] : rip;
272
- addSocketRelay(rip, myHostName, rtp, rth);
265
+ hsyncClient.addSocketRelay({ port: rip, targetHost: rth, targetPort: rtp });
273
266
  debug('relaying inbound', rip, 'to', rth, rtp);
274
267
  }
275
268
  });
package/dist/hsync.js CHANGED
@@ -25,7 +25,7 @@ eval("let process = __webpack_require__.g.process || {env: {}};\n\nconst baseCon
25
25
  \***********************/
26
26
  /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
27
27
 
28
- eval("const EventEmitter = (__webpack_require__(/*! events */ \"./node_modules/events/events.js\").EventEmitter);\nconst b64id = __webpack_require__(/*! b64id */ \"./node_modules/b64id/index.js\");\nconst debug = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:info');\nconst debugVerbose = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:verbose');\nconst debugError = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:error');\nconst { getRPCPeer, createServerPeer } = __webpack_require__(/*! ./lib/peers */ \"./lib/peers.js\");\nconst { createWebHandler, setNet: webSetNet } = __webpack_require__(/*! ./lib/web-handler */ \"./lib/web-handler.js\");\nconst { createSocketListenHandler, setNet: listenSetNet, receiveRelayData } = __webpack_require__(/*! ./lib/socket-listen-handler */ \"./lib/socket-listen-handler.js\");\nconst { createSocketRelayHandler, setNet: relaySetNet, receiveListenerData, connectSocket } = __webpack_require__(/*! ./lib/socket-relay-handler */ \"./lib/socket-relay-handler.js\");\nconst fetch = __webpack_require__(/*! ./lib/fetch */ \"./lib/fetch.js\");\n\ndebug.color = 3;\ndebugVerbose.color = 2;\ndebugError.color = 1;\n\nlet mqtt;\n\nconsole.log('connection from hsync');\n\nfunction setNet(netImpl) {\n webSetNet(netImpl);\n listenSetNet(netImpl);\n relaySetNet(netImpl);\n}\n\nfunction setMqtt(mqttImpl) {\n mqtt = mqttImpl;\n}\n\nasync function createHsync(config) {\n let {\n hsyncServer,\n hsyncSecret,\n localHost,\n port,\n hsyncBase,\n keepalive,\n dynamicHost,\n listenerLocalPort,\n listenerTargetHost,\n listenerTargetPort,\n relayInboundPort,\n relayTargetHost,\n relayTargetPort,\n } = config;\n\n // console.log('config', config);\n\n let dynamicTimeout;\n\n if (dynamicHost) {\n const result = await fetch.post(`${dynamicHost}/${hsyncBase}/dyn`, {});\n if (dynamicHost.toLowerCase().startsWith('https')) {\n hsyncServer = `wss://${result.url}`;\n } else {\n hsyncServer = `ws://${result.url}`;\n }\n hsyncSecret = result.secret;\n dynamicTimeout = result.timeout;\n }\n\n const hsyncClient = {};\n hsyncClient.config = config;\n // const peers = {};\n const socketListeners = {};\n const socketRelays= {};\n const events = new EventEmitter();\n \n hsyncClient.on = events.on;\n hsyncClient.emit = events.emit;\n // hsyncClient.peers = peers;\n \n let lastConnect;\n const connectURL = `${hsyncServer}${hsyncServer.endsWith('/') ? '' : '/'}${hsyncBase}`;\n const myHostName = (new URL(connectURL)).hostname;\n hsyncClient.myHostName = myHostName;\n \n debug('connecting to', connectURL, '…' );\n const mqConn = mqtt.connect(connectURL, { password: hsyncSecret, username: myHostName, keepalive });\n mqConn.myHostName = myHostName;\n hsyncClient.mqConn = mqConn;\n\n const webHandler = config.webHandler || createWebHandler({myHostName, localHost, port, mqConn});\n hsyncClient.webHandler = webHandler;\n\n mqConn.on('connect', () => {\n const now = Date.now();\n debug('connected to', myHostName, lastConnect ? (now - lastConnect) : '', lastConnect ? 'since last connect' : '');\n lastConnect = now;\n hsyncClient.emit('connected', config);\n });\n\n mqConn.on('error', (error) => {\n debugError('error on mqConn', myHostName, error.code, error);\n if ((error.code === 4) || (error.code === 5)) {\n debug('ending');\n mqConn.end();\n }\n });\n\n mqConn.on('message', (topic, message) => {\n if (!topic) {\n return;\n }\n // message is Buffer\n const [name, hostName, segment3, action, segment5] = topic.split('/');\n debugVerbose('\\n↓ MQTT' , topic);\n if (name === 'web') {\n webHandler.handleWebRequest(hostName, segment3, action, message);\n return;\n } else if (name === 'msg') {\n const from = segment3;\n if (action === 'json') {\n try {\n const msg = JSON.parse(message.toString());\n msg.from = from;\n hsyncClient.emit('json', msg);\n } catch (e) {\n debugError('error parsing json message');\n }\n }\n else if (!action && (segment3 === 'srpc')) {\n hsyncClient.serverPeer.transport.receiveData(message.toString());\n }\n }\n\n });\n\n function endClient(force, callback) {\n if (force) {\n mqConn.end(force);\n if (webHandler.end) {\n webHandler.end();\n }\n return;\n }\n mqConn.end(force, (a, b) => {\n if (webHandler.end) {\n webHandler.end();\n }\n if (callback) {\n callback(a, b);\n }\n })\n }\n\n function getSocketListeners () {\n return Object.keys(socketListeners).map((id) => {\n return { info: socketListeners[id].info, id };\n });\n }\n\n function getSocketRelays () {\n return Object.keys(socketRelays).map((id) => {\n return { info: socketRelays[id].info, id };\n });\n }\n\n function addSocketListener (port, hostName, targetPort, targetHost) {\n // console.log('addSocketListener', port, hostName, targetPort, targetHost);\n const handler = createSocketListenHandler({port, hostName, targetPort, targetHost, hsyncClient});\n const id = b64id.generateId();\n socketListeners[id] = {handler, info: {port, hostName, targetPort, targetHost}, id};\n return getSocketListeners();\n }\n\n function addSocketRelay(port, hostName, targetPort, targetHost = 'localhost') {\n const handler = createSocketRelayHandler({port, hostName, targetPort, targetHost, hsyncClient});\n const id = b64id.generateId();\n socketRelays[id] = {handler, info: {port, hostName, targetPort, targetHost}, id};\n debug('relay added', port);\n return getSocketRelays();\n }\n\n const serverReplyMethods = {\n ping: (greeting) => {\n return `${greeting} back atcha from client. ${Date.now()}`;\n },\n addSocketListener,\n getSocketListeners,\n getSocketRelays,\n addSocketRelay,\n peerRpc: async (requestInfo) => {\n requestInfo.hsyncClient = hsyncClient;\n const { msg } = requestInfo;\n debug('peerRpc handler', requestInfo.fromHost, msg.method);\n const peer = getRPCPeer({hostName: requestInfo.fromHost, hsyncClient});\n if (!msg.id) {\n // notification\n if (Array.isArray(msg.params)) {\n msg.params.unshift(peer);\n }\n peer.transport.emit('rpc', msg);\n return { result: {}, id: msg.id};\n }\n const reply = {id: msg.id, jsonrpc:'2.0'};\n try {\n if (!peer.localMethods[msg.method]) {\n const notFoundError = new Error('method not found');\n notFoundError.code = -32601;\n throw notFoundError;\n }\n const result = await peer.localMethods[msg.method](requestInfo, ...msg.params);\n reply.result = result;\n return result;\n } catch (e) {\n debug('peer rpc error', e, msg);\n reply.error = {\n code: e.code || 500,\n message: e.toString(),\n };\n return reply;\n }\n }\n };\n\n const peerMethods = {\n ping: (remotePeer, greeting) => {\n debug('ping called', remotePeer.hostName, greeting);\n return `${greeting} back atcha, ${remotePeer.hostName}.`;\n },\n connectSocket,\n receiveListenerData,\n receiveRelayData,\n };\n\n hsyncClient.serverPeer = createServerPeer(hsyncClient, serverReplyMethods);\n hsyncClient.getPeer = (hostName) => {\n return getRPCPeer({hostName, hsyncClient});\n };\n hsyncClient.hsyncBase = hsyncBase;\n hsyncClient.endClient = endClient;\n hsyncClient.serverReplyMethods = serverReplyMethods;\n hsyncClient.getRPCPeer = getRPCPeer;\n hsyncClient.peerMethods = peerMethods;\n hsyncClient.hsyncSecret = hsyncSecret;\n hsyncClient.hsyncServer = hsyncServer;\n hsyncClient.dynamicTimeout = dynamicTimeout;\n const { host, protocol } = new URL(hsyncServer);\n if (protocol === 'wss:') {\n hsyncClient.webUrl = `https://${host}`;\n } else {\n hsyncClient.webUrl = `http://${host}`;\n }\n debug('url', host, protocol, hsyncClient.webUrl);\n hsyncClient.webAdmin = `${hsyncClient.webUrl}/${hsyncBase}/admin`;\n hsyncClient.webBase = `${hsyncClient.webUrl}/${hsyncBase}`;\n hsyncClient.port = port;\n\n if (listenerLocalPort) {\n listenerLocalPort.forEach((llp, i) => {\n let lth = listenerTargetHost ? listenerTargetHost[i] || listenerTargetHost[0] : null;\n if (lth) {\n if (lth.endsWith('/')) {\n lth = lth.substring(0, lth.length - 1);\n }\n const ltp = listenerTargetPort ? listenerTargetPort[i] : llp;\n addSocketListener(llp, myHostName, ltp, lth);\n debug('relaying local', llp, 'to', lth, ltp);\n }\n });\n }\n\n if (relayInboundPort) {\n relayInboundPort.forEach((rip, i) => {\n const rth = relayTargetHost ? relayTargetHost[i] : relayTargetHost[0] || 'localhost';\n if (rth) {\n if (rth.endsWith('/')) {\n rth = rth.substring(0, rth.length - 1);\n }\n const rtp = relayTargetPort ? relayTargetPort[i] : rip;\n addSocketRelay(rip, myHostName, rtp, rth);\n debug('relaying inbound', rip, 'to', rth, rtp);\n }\n });\n }\n\n return hsyncClient;\n}\n\nmodule.exports = {\n createHsync,\n setNet,\n setMqtt,\n};\n\n\n//# sourceURL=webpack://hsync/./connection.js?");
28
+ eval("const EventEmitter = (__webpack_require__(/*! events */ \"./node_modules/events/events.js\").EventEmitter);\nconst debug = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:info');\nconst debugVerbose = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:verbose');\nconst debugError = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:error');\nconst { initPeers } = __webpack_require__(/*! ./lib/peers */ \"./lib/peers.js\");\nconst { createWebHandler, setNet: webSetNet } = __webpack_require__(/*! ./lib/web-handler */ \"./lib/web-handler.js\");\nconst { \n setNet: listenSetNet,\n initListeners,\n} = __webpack_require__(/*! ./lib/socket-listeners */ \"./lib/socket-listeners.js\");\nconst {\n setNet: relaySetNet,\n initRelays,\n} = __webpack_require__(/*! ./lib/socket-relays */ \"./lib/socket-relays.js\");\nconst fetch = __webpack_require__(/*! ./lib/fetch */ \"./lib/fetch.js\");\n\ndebug.color = 3;\ndebugVerbose.color = 2;\ndebugError.color = 1;\n\nlet mqtt;\n\nconsole.log('connection from hsync');\n\nfunction setNet(netImpl) {\n webSetNet(netImpl);\n listenSetNet(netImpl);\n relaySetNet(netImpl);\n}\n\nfunction setMqtt(mqttImpl) {\n mqtt = mqttImpl;\n}\n\nasync function createHsync(config) {\n let {\n hsyncServer,\n hsyncSecret,\n localHost,\n port,\n hsyncBase,\n keepalive,\n dynamicHost,\n listenerLocalPort,\n listenerTargetHost,\n listenerTargetPort,\n relayInboundPort,\n relayTargetHost,\n relayTargetPort,\n } = config;\n\n // console.log('config', config);\n\n let dynamicTimeout;\n\n if (dynamicHost && !hsyncSecret) {\n const result = await fetch.post(`${dynamicHost}/${hsyncBase}/dyn`, {});\n if (dynamicHost.toLowerCase().startsWith('https')) {\n hsyncServer = `wss://${result.url}`;\n } else {\n hsyncServer = `ws://${result.url}`;\n }\n hsyncSecret = result.secret;\n dynamicTimeout = result.timeout;\n }\n\n const hsyncClient = {\n setNet,\n config,\n };\n\n hsyncClient.peers = initPeers(hsyncClient);\n hsyncClient.listeners = initListeners(hsyncClient);\n hsyncClient.relays = initRelays(hsyncClient);\n\n const events = new EventEmitter();\n \n hsyncClient.on = events.on;\n hsyncClient.emit = events.emit;\n \n let lastConnect;\n const connectURL = `${hsyncServer}${hsyncServer.endsWith('/') ? '' : '/'}${hsyncBase}`;\n const myHostName = (new URL(connectURL)).hostname;\n hsyncClient.myHostName = myHostName;\n \n debug('connecting to', connectURL, '…' );\n const mqConn = mqtt.connect(connectURL, { password: hsyncSecret, username: myHostName, keepalive });\n mqConn.myHostName = myHostName;\n hsyncClient.mqConn = mqConn;\n\n const webHandler = config.webHandler || createWebHandler({myHostName, localHost, port, mqConn});\n hsyncClient.webHandler = webHandler;\n\n mqConn.on('connect', () => {\n const now = Date.now();\n debug('connected to', myHostName, lastConnect ? (now - lastConnect) : '', lastConnect ? 'since last connect' : '');\n lastConnect = now;\n hsyncClient.emit('connected', config);\n });\n\n mqConn.on('error', (error) => {\n debugError('error on mqConn', myHostName, error.code, error);\n if ((error.code === 4) || (error.code === 5)) {\n debug('ending');\n mqConn.end();\n if (globalThis.process) {\n process.exit(1);\n }\n }\n });\n\n mqConn.on('message', (topic, message) => {\n if (!topic) {\n return;\n }\n // message is Buffer\n const [name, hostName, segment3, action, segment5] = topic.split('/');\n debugVerbose('\\n↓ MQTT' , topic);\n if (name === 'web') {\n webHandler.handleWebRequest(hostName, segment3, action, message);\n return;\n } else if (name === 'msg') {\n const from = segment3;\n if (action === 'json') {\n try {\n const msg = JSON.parse(message.toString());\n msg.from = from;\n hsyncClient.emit('json', msg);\n } catch (e) {\n debugError('error parsing json message');\n }\n }\n else if (!action && (segment3 === 'srpc')) {\n hsyncClient.serverPeer.transport.receiveData(message.toString());\n }\n }\n\n });\n\n function endClient(force, callback) {\n if (force) {\n mqConn.end(force);\n if (webHandler.end) {\n webHandler.end();\n }\n return;\n }\n mqConn.end(force, (a, b) => {\n if (webHandler.end) {\n webHandler.end();\n }\n if (callback) {\n callback(a, b);\n }\n })\n }\n\n const serverReplyMethods = {\n ping: (greeting) => {\n return `${greeting} back atcha from client. ${Date.now()}`;\n },\n addSocketListener: hsyncClient.addSocketListener,\n getSocketListeners: hsyncClient.getSocketListeners,\n addSocketRelay: hsyncClient.addSocketRelay,\n getSocketRelays: hsyncClient.getSocketRelays,\n peerRpc: async (requestInfo) => {\n requestInfo.hsyncClient = hsyncClient;\n const { msg } = requestInfo;\n debug('peerRpc handler', requestInfo.fromHost, msg.method);\n const peer = hsyncClient.peers.getRPCPeer({hostName: requestInfo.fromHost, hsyncClient});\n if (!msg.id) {\n // notification\n if (Array.isArray(msg.params)) {\n msg.params.unshift(peer);\n }\n peer.transport.emit('rpc', msg);\n return { result: {}, id: msg.id};\n }\n const reply = {id: msg.id, jsonrpc:'2.0'};\n try {\n if (!peer.localMethods[msg.method]) {\n const notFoundError = new Error('method not found');\n notFoundError.code = -32601;\n throw notFoundError;\n }\n const result = await peer.localMethods[msg.method](requestInfo, ...msg.params);\n reply.result = result;\n return result;\n } catch (e) {\n debug('peer rpc error', e, msg);\n reply.error = {\n code: e.code || 500,\n message: e.toString(),\n };\n return reply;\n }\n }\n };\n\n const peerMethods = {\n ping: (remotePeer, greeting) => {\n debug('ping called', remotePeer.hostName, greeting);\n return `${greeting} back atcha, ${remotePeer.hostName}.`;\n },\n validatePeer: (remotePeer, secret) => {\n return hsyncClient.getPeer(remotePeer.hostName).myAuth === secret;\n },\n connectSocket: hsyncClient.connectSocket,\n // closeListenerSocket: hsyncClient.closeListenerSocket,\n // closeRelaySocket: hsyncClient.closeRelaySocket,\n // receiveListenerData: hsyncClient.receiveListenerData,\n // receiveRelayData: hsyncClient.receiveRelayData,\n };\n\n hsyncClient.serverPeer = hsyncClient.peers.createServerPeer(hsyncClient, serverReplyMethods);\n hsyncClient.serverPeer.notifications.onexternal_message((msg) => {\n hsyncClient.emit('external_message', msg);\n });\n hsyncClient.getPeer = (hostName) => {\n return peers.getRPCPeer({ hostName });\n };\n hsyncClient.hsyncBase = hsyncBase;\n hsyncClient.endClient = endClient;\n hsyncClient.serverReplyMethods = serverReplyMethods;\n hsyncClient.getRPCPeer = hsyncClient.peers.getRPCPeer;\n hsyncClient.peerMethods = peerMethods;\n hsyncClient.hsyncSecret = hsyncSecret;\n hsyncClient.hsyncServer = hsyncServer;\n hsyncClient.dynamicTimeout = dynamicTimeout;\n const { host, protocol } = new URL(hsyncServer);\n if (protocol === 'wss:') {\n hsyncClient.webUrl = `https://${host}`;\n } else {\n hsyncClient.webUrl = `http://${host}`;\n }\n debug('url', host, protocol, hsyncClient.webUrl);\n hsyncClient.webAdmin = `${hsyncClient.webUrl}/${hsyncBase}/admin`;\n hsyncClient.webBase = `${hsyncClient.webUrl}/${hsyncBase}`;\n hsyncClient.port = port;\n\n if (listenerLocalPort) {\n listenerLocalPort.forEach((llp, i) => {\n let lth = listenerTargetHost ? listenerTargetHost[i] || listenerTargetHost[0] : null;\n if (lth) {\n if (lth.endsWith('/')) {\n lth = lth.substring(0, lth.length - 1);\n }\n const ltp = listenerTargetPort ? listenerTargetPort[i] : llp;\n hsyncClient.addSocketListener({ port: llp, targetPort: ltp, targetHost: lth });\n debug('relaying local', llp, 'to', lth, ltp);\n }\n });\n }\n\n if (relayInboundPort) {\n relayInboundPort.forEach((rip, i) => {\n debug('relayInboundPort', rip, i, relayTargetHost);\n const firstRth = relayTargetHost ? relayTargetHost[0] : null;\n const rth = relayTargetHost ? relayTargetHost[i] : firstRth || 'localhost';\n if (rth) {\n if (rth.endsWith('/')) {\n rth = rth.substring(0, rth.length - 1);\n }\n const rtp = relayTargetPort ? relayTargetPort[i] : rip;\n hsyncClient.addSocketRelay({ port: rip, targetHost: rth, targetPort: rtp });\n debug('relaying inbound', rip, 'to', rth, rtp);\n }\n });\n }\n\n return hsyncClient;\n}\n\nmodule.exports = {\n createHsync,\n setNet,\n setMqtt,\n};\n\n\n//# sourceURL=webpack://hsync/./connection.js?");
29
29
 
30
30
  /***/ }),
31
31
 
@@ -35,7 +35,7 @@ eval("const EventEmitter = (__webpack_require__(/*! events */ \"./node_modules/e
35
35
  \**********************/
36
36
  /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
37
37
 
38
- eval("const mqtt = __webpack_require__(/*! precompiled-mqtt */ \"./node_modules/precompiled-mqtt/dist/mqtt.browser.js\");\nconst buffer = __webpack_require__(/*! buffer */ \"./node_modules/buffer/index.js\");\nconst net = __webpack_require__(/*! net-web */ \"./node_modules/net-web/net-web.js\");\nconst { createHsync, setNet, setMqtt } = __webpack_require__(/*! ./connection */ \"./connection.js\");\nconst { setRTC } = __webpack_require__(/*! ./lib/peers */ \"./lib/peers.js\");\nconst rtc = __webpack_require__(/*! ./lib/rtc-web */ \"./lib/rtc-web.js\");\nconst config = __webpack_require__(/*! ./config */ \"./config.js\");\n\n\n// TODO need to make this work with web/service workers\nwindow.Buffer = buffer.Buffer;\n\nsetRTC(rtc);\nsetNet(net);\nsetMqtt(mqtt);\n\nasync function dynamicConnect(dynamicHost, useLocalStorage, configObj = {}) {\n if (typeof useLocalStorage === 'object') {\n configObj = useLocalStorage;\n }\n else {\n configObj.useLocalStorage = useLocalStorage;\n }\n\n const fullConfig = {...config, ...configObj};\n if (fullConfig.net) {\n setNet(fullConfig.net);\n }\n let con;\n if (useLocalStorage) {\n const localConfigStr = localStorage.getItem('hsyncConfig');\n if (localConfigStr) {\n const localConfig = JSON.parse(localConfigStr);\n if ((Date.now() - localConfig.created) < (localConfig.timeout * 0.66)) {\n fullConfig.hsyncSecret = localConfig.hsyncSecret;\n fullConfig.hsyncServer = localConfig.hsyncServer;\n } else {\n localStorage.removeItem('hsyncConfig');\n }\n }\n \n if (!fullConfig.hsyncSecret) {\n fullConfig.dynamicHost = dynamicHost || fullConfig.defaultDynamicHost;\n }\n \n con = await createHsync(fullConfig);\n \n if (fullConfig.dynamicHost) {\n const storeConfig = {\n hsyncSecret: con.hsyncSecret,\n hsyncServer: con.hsyncServer,\n timeout: con.dynamicTimeout,\n created: Date.now(),\n };\n localStorage.setItem('hsyncConfig', JSON.stringify(storeConfig));\n }\n\n return con;\n }\n\n fullConfig.dynamicHost = dynamicHost || fullConfig.defaultDynamicHost;\n con = await createHsync(fullConfig);\n\n return con;\n \n}\n\nfunction createConnection(configObj = {}) {\n const fullConfig = {...config, ...configObj};\n return createHsync(fullConfig);\n}\n\n\nconst hsync = globalThis.hsync || {\n createConnection,\n dynamicConnect,\n net,\n config,\n};\nglobalThis.hsync = hsync;\n\nmodule.exports = hsync;\n\n\n//# sourceURL=webpack://hsync/./hsync-web.js?");
38
+ eval("const mqtt = __webpack_require__(/*! precompiled-mqtt */ \"./node_modules/precompiled-mqtt/dist/mqtt.browser.js\");\nconst buffer = __webpack_require__(/*! buffer */ \"./node_modules/buffer/index.js\");\nconst net = __webpack_require__(/*! net-web */ \"./node_modules/net-web/net-web.js\");\nconst { createHsync, setNet, setMqtt } = __webpack_require__(/*! ./connection */ \"./connection.js\");\nconst { setRTC } = __webpack_require__(/*! ./lib/peers */ \"./lib/peers.js\");\nconst rtc = __webpack_require__(/*! ./lib/rtc-web */ \"./lib/rtc-web.js\");\nconst config = __webpack_require__(/*! ./config */ \"./config.js\");\n\n\n// TODO need to make this work with web/service workers\nwindow.Buffer = buffer.Buffer;\n\nsetRTC(rtc);\nsetNet(net);\nsetMqtt(mqtt);\n\nasync function dynamicConnect(configObj = { useLocalStorage: true }) {\n const fullConfig = {...config, ...configObj};\n fullConfig.dynamicHost = fullConfig.dynamicHost || fullConfig.defaultDynamicHost;\n if (fullConfig.net) {\n setNet(fullConfig.net);\n }\n let con;\n if (configObj.useLocalStorage) {\n const localConfigStr = localStorage.getItem('hsyncConfig');\n if (localConfigStr) {\n const localConfig = JSON.parse(localConfigStr);\n if ((Date.now() - localConfig.created) < (localConfig.timeout * 0.66)) {\n fullConfig.hsyncSecret = localConfig.hsyncSecret;\n fullConfig.hsyncServer = localConfig.hsyncServer;\n } else {\n localStorage.removeItem('hsyncConfig');\n }\n }\n \n con = await createHsync(fullConfig);\n \n if (!fullConfig.hsyncSecret) {\n const storeConfig = {\n hsyncSecret: con.hsyncSecret,\n hsyncServer: con.hsyncServer,\n timeout: con.dynamicTimeout,\n created: Date.now(),\n };\n localStorage.setItem('hsyncConfig', JSON.stringify(storeConfig));\n }\n\n return con;\n }\n\n con = await createHsync(fullConfig);\n\n return con;\n \n}\n\nfunction createConnection(configObj = {}) {\n const fullConfig = {...config, ...configObj};\n return createHsync(fullConfig);\n}\n\n\nconst hsync = globalThis.hsync || {\n createConnection,\n dynamicConnect,\n net,\n config,\n};\nglobalThis.hsync = hsync;\n\nmodule.exports = hsync;\n\n\n//# sourceURL=webpack://hsync/./hsync-web.js?");
39
39
 
40
40
  /***/ }),
41
41
 
@@ -45,7 +45,7 @@ eval("const mqtt = __webpack_require__(/*! precompiled-mqtt */ \"./node_modules/
45
45
  \**********************/
46
46
  /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
47
47
 
48
- eval("const fetch = __webpack_require__(/*! isomorphic-fetch */ \"./node_modules/isomorphic-fetch/fetch-npm-browserify.js\");\n\nfunction getContent(res) {\n const contentType = res.headers.get('content-type');\n if (contentType.startsWith('application/json')) {\n return res.json();\n }\n if (contentType.startsWith('text')) {\n return res.text();\n }\n return res.blob();\n}\n\nfunction handledFetch(path, options) {\n return fetch(path, options)\n .then((res) => {\n if (res.status >= 400) {\n const err = new Error('Bad response from server');\n err.status = res.status;\n return getContent(res)\n .then((content) => {\n err.content = content;\n throw err;\n });\n }\n return res;\n });\n}\n\nfunction apiFetch(path, options = {}) {\n let qs = '';\n if (typeof options.body === 'object') {\n options.body = JSON.stringify(options.body);\n }\n if (options.query) {\n if (Object.keys(options.query).length) {\n qs = `?${(new URLSearchParams(options.query)).toString()}`;\n }\n }\n Object.assign(options, { credentials: 'include' });\n options.headers = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n return handledFetch(`${path}${qs}`, options)\n .then(getContent);\n}\n\napiFetch.post = (path, body) => {\n return apiFetch(path, { method: 'POST', body });\n};\n\napiFetch.put = (path, body) => {\n return apiFetch(path, { method: 'PUT', body });\n};\n\napiFetch.del = (path, body = {}) => {\n return apiFetch(path, { method: 'DELETE', body });\n};\n\nmodule.exports = apiFetch;\n\n\n//# sourceURL=webpack://hsync/./lib/fetch.js?");
48
+ eval("const fetch = __webpack_require__(/*! isomorphic-fetch */ \"./node_modules/isomorphic-fetch/fetch-npm-browserify.js\");\n\nfunction getContent(res) {\n const contentType = res.headers.get('content-type');\n if (contentType.startsWith('application/json')) {\n return res.json();\n }\n if (contentType.startsWith('text')) {\n return res.text();\n }\n return res.blob();\n}\n\nasync function handledFetch(path, options) {\n const rawRes = await fetch(path, options);\n const content = await getContent(rawRes);\n if (rawRes.status >= 400) {\n const err = new Error('Bad response from server');\n err.status = rawRes.status;\n err.content = content;\n throw err;\n }\n return content;\n}\n\nfunction apiFetch(path, options = {}) {\n let qs = '';\n if (typeof options.body === 'object') {\n options.body = JSON.stringify(options.body);\n }\n if (options.query) {\n if (Object.keys(options.query).length) {\n qs = `?${(new URLSearchParams(options.query)).toString()}`;\n }\n }\n Object.assign(options, { credentials: 'include' });\n options.headers = {\n 'Content-Type': 'application/json',\n ...options.headers,\n };\n return handledFetch(`${path}${qs}`, options);\n}\n\napiFetch.post = (path, body) => {\n return apiFetch(path, { method: 'POST', body });\n};\n\napiFetch.put = (path, body) => {\n return apiFetch(path, { method: 'PUT', body });\n};\n\napiFetch.del = (path, body = {}) => {\n return apiFetch(path, { method: 'DELETE', body });\n};\n\nmodule.exports = apiFetch;\n\n\n//# sourceURL=webpack://hsync/./lib/fetch.js?");
49
49
 
50
50
  /***/ }),
51
51
 
@@ -55,7 +55,7 @@ eval("const fetch = __webpack_require__(/*! isomorphic-fetch */ \"./node_modules
55
55
  \**********************/
56
56
  /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
57
57
 
58
- eval("const rawr = __webpack_require__(/*! rawr */ \"./node_modules/rawr/index.js\");\nconst b64id = __webpack_require__(/*! b64id */ \"./node_modules/b64id/index.js\");\nconst debug = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:peers');\nconst EventEmitter = (__webpack_require__(/*! events */ \"./node_modules/events/events.js\").EventEmitter);\nconst buffer = __webpack_require__(/*! buffer */ \"./node_modules/buffer/index.js\");\nconst mqttPacket = __webpack_require__(/*! mqtt-packet-web */ \"./node_modules/mqtt-packet-web/index.js\");\n\nglobalThis.Buffer = buffer.Buffer;\n\nconst { handleSocketPacket } = __webpack_require__(/*! ./socket-map */ \"./lib/socket-map.js\");\nconst fetch = __webpack_require__(/*! ./fetch */ \"./lib/fetch.js\");\n\nconst peers = {};\n\nlet rtc;\n\nfunction setRTC(rtcImpl) {\n rtc = rtcImpl;\n}\n\nfunction createPacket(topic, payload) {\n let payloadStr = payload;\n // console.log('mqttPacket', { topic, payload });\n // if (payload instanceof Uint8Array) {\n // console.log('str payload', new TextDecoder().decode(payload));\n // }\n const packet = mqttPacket.generate({\n qos: 0,\n cmd: 'publish',\n topic,\n payload: payloadStr,\n });\n // console.log('packet', packet);\n return packet;\n}\n\nfunction parsePacket(packet) {\n const parser = mqttPacket.parser();\n return new Promise((resolve, reject) => {\n parser.on('packet', resolve);\n parser.on('error', reject);\n parser.parse(packet);\n });\n}\n\nfunction getRPCPeer(options = {}) {\n const { hostName, temporary, timeout = 10000, hsyncClient } = options;\n let peer = peers[hostName];\n if (!peer) {\n debug('CREATING peer', hostName);\n peer = createRPCPeer({hostName, hsyncClient, timeout});\n if (temporary) {\n peer.rpcTemporary = true;\n }\n peers[hostName] = peer;\n }\n return peer;\n}\n\nfunction createRPCPeer(options = {}) {\n const { hostName, hsyncClient, timeout = 10000, useRTC = true } = options;\n if (!hostName) {\n throw new Error('No hostname specified');\n }\n if (hostName === hsyncClient.myHostName) {\n throw new Error('Peer must be a different host');\n }\n const myAuth = b64id.generateId();\n const transport = new EventEmitter();\n const peer = rawr({transport, methods: Object.assign({}, hsyncClient.peerMethods), timeout, idGenerator: b64id.generateId});\n peer.hostName = hostName;\n peer.rtcEvents = new EventEmitter();\n peer.localMethods = Object.assign({}, hsyncClient.peerMethods);\n peer.sockets = {};\n\n peer.localMethods.rtcSignal = (peerInfo, signal) => {\n debug('rtcSignal', signal.type);\n if (signal.type === 'offer' && !peer.rtcCon && !signal.alreadySent) {\n rtc.answerPeer(peer, signal);\n } else if (signal.type === 'answer') {\n peer.handleRtcAnswer(signal);\n }\n return 'rtcSignal ok';\n }\n\n peer.rtcEvents.on('packet', async (packet) => {\n debug('↓ on packet', packet);\n let toParse = packet;\n try {\n if (packet instanceof Blob) {\n toParse = await packet.arrayBuffer();\n }\n const msg = await parsePacket(toParse);\n const [p1, p2, p3] = msg.topic.split('/');\n if (p1 === 'rpc') {\n transport.receiveData(JSON.parse(msg.payload.toString()));\n } else if (p1 === 'socketData') {\n handleSocketPacket(msg);\n } else if (p1 === 'test') {\n debug('test topic', msg.payload);\n } else {\n debug('other topic', msg.topic);\n }\n } catch (e) {\n debug('bad packet', e, packet);\n }\n });\n\n peer.rtcEvents.on('dcOpen', () => {\n debug('dcOpen');\n peer.packAndSend = (topic, payload) => {\n const packet = createPacket(topic, payload);\n if (topic === 'test') {\n debug('sending test packet', packet);\n }\n peer.rtcSend(packet);\n }\n // firefox is weird about the first bit of data, so send a test packet\n peer.packAndSend('test', 'test');\n });\n\n peer.rtcEvents.on('closed', () => {\n peer.dcOpen = false;\n delete peer.packAndSend;\n debug('rtc closed');\n for (s in peer.sockets) {\n try {\n debug('closing socket', s);\n peer.sockets[s].destroy();\n delete peer.sockets[s];\n } catch (e) {\n debug('error closing socket', e);\n }\n }\n });\n\n peer.rtcEvents.on('disconnected', () => {\n peer.dcOpen = false;\n delete peer.packAndSend;\n debug('rtc disconnected');\n for (s in peer.sockets) {\n try {\n debug('closing socket', s);\n peer.sockets[s].destroy();\n delete peer.sockets[s];\n } catch (e) {\n debug('error closing socket', e);\n }\n }\n });\n\n peer.connectRTC = async () => {\n debug('connectRTC');\n \n return new Promise(async (resolve, reject) => {\n try {\n const offer = await rtc.offerPeer(peer);\n peer.rtcEvents.once('dcOpen', () => {\n debug('dcOpen!');\n resolve(offer);\n });\n } catch (e) {\n reject(e);\n }\n });\n };\n\n transport.send = async (msg) => {\n const fullMsg = {\n msg,\n myAuth,\n toHost: hostName,\n fromHost: hsyncClient.webUrl,\n };\n\n debug('↑ peer rpc', peer.dcOpen ? 'RTC' : 'REST', `${hostName}/_hs/rpc`, msg.method);\n\n if (peer.dcOpen) {\n let payload = msg;\n if (typeof msg === 'object') {\n payload = JSON.stringify(payload);\n }\n const packet = createPacket('rpc', payload);\n peer.rtcSend(packet);\n return;\n }\n\n try {\n debug('fetching', fullMsg, useRTC);\n const result = await fetch.post(`${hostName}/_hs/rpc`, fullMsg);\n debug('fetch result', result);\n if (msg.id) {\n transport.receiveData({id: msg.id, result, jsonrpc: msg.jsonrpc});\n }\n // if (!peer.rtcCon && useRTC) {\n // debug('STARTING rtc creation');\n // rtc.offerPeer(peer);\n // }\n } catch(e) {\n debug('error sending peer RPC request', e);\n transport.receiveData({id: msg.id, error: e, method: msg.method, jsonrpc: msg.jsonrpc});\n }\n \n };\n\n transport.receiveData = (msg) => {\n if(typeof msg === 'string') {\n msg = JSON.parse(msg);\n }\n debug('↓ peer rpc receivedData', msg, msg.params);\n if (msg.params && Array.isArray(msg.params)) {\n debug('unshifting', msg.params);\n msg.params.unshift(peer);\n }\n transport.emit('rpc', msg);\n };\n\n peer.myAuth = myAuth;\n peer.hostName = hostName;\n return peer;\n}\n\nfunction createServerPeer(hsyncClient, methods) {\n const transport = new EventEmitter();\n transport.send = (msg) => {\n if(typeof msg === 'object') {\n msg = JSON.stringify(msg);\n }\n const topic = `srpc/${hsyncClient.myHostName}`;\n debug('↑ server rpc request', msg);\n hsyncClient.mqConn.publish(topic, Buffer.from(msg));\n };\n transport.receiveData = (msg) => {\n if(msg) {\n msg = JSON.parse(msg);\n }\n debug('↓ server rpc reply', msg.method, msg.id);\n transport.emit('rpc', msg);\n };\n const peer = rawr({transport, methods, timeout: 5000});\n return peer;\n}\n\nmodule.exports = {\n createRPCPeer,\n createServerPeer,\n getRPCPeer,\n setRTC,\n};\n\n\n//# sourceURL=webpack://hsync/./lib/peers.js?");
58
+ eval("const rawr = __webpack_require__(/*! rawr */ \"./node_modules/rawr/index.js\");\nconst b64id = __webpack_require__(/*! b64id */ \"./node_modules/b64id/index.js\");\nconst debug = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:peers');\nconst EventEmitter = (__webpack_require__(/*! events */ \"./node_modules/events/events.js\").EventEmitter);\nconst buffer = __webpack_require__(/*! buffer */ \"./node_modules/buffer/index.js\");\nconst mqttPacket = __webpack_require__(/*! mqtt-packet-web */ \"./node_modules/mqtt-packet-web/index.js\");\n\nglobalThis.Buffer = buffer.Buffer;\n\nconst { handleSocketPacket } = __webpack_require__(/*! ./socket-map */ \"./lib/socket-map.js\");\nconst fetch = __webpack_require__(/*! ./fetch */ \"./lib/fetch.js\");\n\nfunction createPacket(topic, payload) {\n let payloadStr = payload;\n const packet = mqttPacket.generate({\n qos: 0,\n cmd: 'publish',\n topic,\n payload: payloadStr,\n });\n // console.log('packet', packet);\n return packet;\n}\n\nfunction parsePacket(packet) {\n const parser = mqttPacket.parser();\n return new Promise((resolve, reject) => {\n parser.on('packet', resolve);\n parser.on('error', reject);\n parser.parse(packet);\n });\n}\n\n\nlet rtc;\n\nfunction setRTC(rtcImpl) {\n rtc = rtcImpl;\n}\n\nfunction initPeers(hsyncClient) {\n const cachedPeers = {};\n function getRPCPeer(options = {}) {\n const { hostName, temporary, timeout = 10000, hsyncClient } = options;\n let peer = cachedPeers[hostName];\n if (!peer) {\n debug('CREATING peer', hostName);\n peer = createRPCPeer({hostName, hsyncClient, timeout});\n peer.myAuth = b64id.generateId();\n if (temporary) {\n peer.rpcTemporary = true;\n }\n cachedPeers[hostName] = peer;\n }\n return peer;\n }\n \n function createRPCPeer(options = {}) {\n const { hostName, timeout = 10000, useRTC = true } = options;\n if (!hostName) {\n throw new Error('No hostname specified');\n }\n if (hostName === hsyncClient.myHostName) {\n throw new Error('Peer must be a different host');\n }\n const myAuth = b64id.generateId();\n const transport = new EventEmitter();\n const peer = rawr({transport, methods: Object.assign({}, hsyncClient.peerMethods), timeout, idGenerator: b64id.generateId});\n peer.hostName = hostName;\n peer.rtcEvents = new EventEmitter();\n peer.localMethods = Object.assign({}, hsyncClient.peerMethods);\n peer.sockets = {};\n \n peer.localMethods.rtcSignal = (peerInfo, signal) => {\n debug('rtcSignal', signal.type);\n if (signal.type === 'offer' && !peer.rtcCon && !signal.alreadySent) {\n rtc.answerPeer(peer, signal);\n } else if (signal.type === 'answer') {\n peer.handleRtcAnswer(signal);\n }\n return 'rtcSignal ok';\n }\n \n peer.rtcEvents.on('packet', async (packet) => {\n debug('↓ on packet', packet);\n let toParse = packet;\n try {\n if (packet instanceof Blob) {\n toParse = await packet.arrayBuffer();\n }\n const msg = await parsePacket(toParse);\n const [p1, p2, p3] = msg.topic.split('/');\n if (p1 === 'rpc') {\n const rpcMsg = JSON.parse(msg.payload.toString());\n debug('↓ peer RTC rpc', rpcMsg);\n // if (rpcMsg.method) {\n transport.receiveData(rpcMsg);\n // return;\n // }\n } else if (p1 === 'socketData') {\n handleSocketPacket(msg);\n } else if (p1 === 'test') {\n debug('test topic', msg.payload);\n } else {\n debug('other topic', msg.topic);\n }\n } catch (e) {\n debug('bad packet', e, packet);\n }\n });\n \n peer.rtcEvents.on('dcOpen', () => {\n debug('dcOpen');\n peer.packAndSend = (topic, payload) => {\n const packet = createPacket(topic, payload);\n if (topic === 'test') {\n debug('sending test packet', packet);\n }\n peer.rtcSend(packet);\n }\n // firefox is weird about the first bit of data, so send a test packet\n peer.packAndSend('test', 'test');\n });\n \n peer.rtcEvents.on('closed', () => {\n peer.dcOpen = false;\n delete peer.packAndSend;\n debug('rtc closed');\n for (s in peer.sockets) {\n try {\n debug('closing socket', s);\n peer.sockets[s].destroy();\n delete peer.sockets[s];\n } catch (e) {\n debug('error closing socket', e);\n }\n }\n });\n \n peer.rtcEvents.on('disconnected', () => {\n peer.dcOpen = false;\n delete peer.packAndSend;\n debug('rtc disconnected');\n for (s in peer.sockets) {\n try {\n debug('closing socket', s);\n peer.sockets[s].destroy();\n delete peer.sockets[s];\n } catch (e) {\n debug('error closing socket', e);\n }\n }\n });\n \n peer.connectRTC = async () => {\n debug('connectRTC');\n return new Promise(async (resolve, reject) => {\n try {\n const offer = await rtc.offerPeer(peer);\n debug('offer', offer);\n peer.rtcEvents.once('dcOpen', () => {\n debug('dcOpen!');\n resolve(offer);\n });\n } catch (e) {\n debug('error connecting to rtc', e);\n reject(e);\n }\n });\n };\n \n transport.send = async (msg) => {\n const fullMsg = {\n msg,\n myAuth,\n toHost: hostName,\n fromHost: hsyncClient.webUrl,\n };\n \n debug('↑ peer rpc', peer.dcOpen ? 'RTC' : 'REST', `${hostName}/_hs/rpc`, msg.method);\n \n if (peer.dcOpen) {\n let payload = msg;\n if (typeof msg === 'object') {\n payload = JSON.stringify(payload);\n }\n const packet = createPacket('rpc', payload);\n peer.rtcSend(packet);\n return;\n }\n \n try {\n const path = `${hostName}/_hs/rpc`;\n debug('fetching', path, fullMsg, useRTC);\n const result = await fetch.post(path, fullMsg);\n debug('fetch result', result);\n if (msg.id) {\n transport.receiveData({id: msg.id, result, jsonrpc: msg.jsonrpc});\n }\n } catch(e) {\n debug('error sending peer RPC request', e);\n if (msg.id) { // only send error if it's a request, not a notification\n transport.receiveData({\n id: msg.id,\n error: e.message,\n method: msg.method,\n jsonrpc: msg.jsonrpc\n });\n }\n }\n \n };\n \n transport.receiveData = (msg) => {\n debug('↓ transport.receiveData', msg);\n if(typeof msg === 'string') {\n msg = JSON.parse(msg);\n }\n debug('↓ peer rpc receivedData', msg);\n if (msg.params && Array.isArray(msg.params)) {\n debug('unshifting', msg.params);\n msg.params.unshift(peer);\n }\n transport.emit('rpc', msg);\n // debug('transport emitted', msg);\n };\n \n peer.myAuth = myAuth;\n peer.hostName = hostName;\n return peer;\n }\n \n function createServerPeer(hsyncClient, methods) {\n const transport = new EventEmitter();\n transport.send = (msg) => {\n if(typeof msg === 'object') {\n msg = JSON.stringify(msg);\n }\n const topic = `srpc/${hsyncClient.myHostName}`;\n debug('↑ server rpc outbound', msg);\n hsyncClient.mqConn.publish(topic, Buffer.from(msg));\n };\n transport.receiveData = (msg) => {\n if(msg) {\n msg = JSON.parse(msg);\n }\n debug('↓ server rpc inbound', msg);\n transport.emit('rpc', msg);\n };\n const peer = rawr({transport, methods, timeout: 5000});\n return peer;\n }\n\n hsyncClient.cachedPeers = cachedPeers;\n hsyncClient.getRPCPeer = getRPCPeer;\n hsyncClient.createServerPeer = createServerPeer;\n\n return {\n getRPCPeer,\n createRPCPeer,\n createServerPeer,\n };\n}\n\nmodule.exports = {\n initPeers,\n setRTC,\n};\n\n\n//# sourceURL=webpack://hsync/./lib/peers.js?");
59
59
 
60
60
  /***/ }),
61
61
 
@@ -65,17 +65,17 @@ eval("const rawr = __webpack_require__(/*! rawr */ \"./node_modules/rawr/index.j
65
65
  \************************/
66
66
  /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
67
67
 
68
- eval("const debug = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:rtc-web');\nconst debugError = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('errors');\n\nconst rtc = {\n PeerConnection: RTCPeerConnection,\n};\n\n\nconst defaultOptions = {\n // Recommended for libdatachannel\n // bundlePolicy: \"max-bundle\",\n iceServers: [{ 'urls': 'stun:stun.l.google.com:19302' }] \n};\n\nconst GATHERING_TIMEOUT = 4000;\n\nasync function offerPeer(peer) {\n\n const con = new RTCPeerConnection(defaultOptions);\n // window.rtc = rtc;\n\n peer.rtcCon = con;\n peer.rtcOfferer = true;\n \n let gatheringComplete = false;\n let offerSent = false;\n const start = Date.now();\n\n function sendOffer(alreadySent) {\n debug('send offer', alreadySent);\n const desc = con.localDescription;\n peer.methods.rtcSignal({type: desc.type, sdp: desc.sdp, alreadySent});\n }\n\n con.onicegatheringstatechange = (state) => {\n debug('state change', con.iceGatheringState);\n if (con.iceGatheringState === 'complete') {\n debug('icegathering done', Date.now() - start);\n gatheringComplete = true;\n // We only want to provide an answer once all of our candidates have been added to the SDP.\n sendOffer(offerSent);\n }\n }\n\n con.onicecandidate = (ice) => {\n debug('ice candidate', ice);\n };\n\n con.onconnectionstatechange = (event) => {\n debug('connection state', con.connectionState, event);\n if(con.connectionState === 'connected') {\n peer.connected = true;\n peer.rtcEvents.emit('connected', con);\n }\n };\n\n con.ondatachannel = (event) => {\n debug('dc from answerer', event);\n peer.dc = event.channel;\n };\n\n const dc = con.createDataChannel('from web');\n\n peer.dc = dc;\n dc.onmessage = (event) => { \n debug('dc.onmessage', event.data);\n peer.rtcEvents.emit('packet', event.data);\n };\n dc.onopen = (event) => { \n peer.dcOpen = true;\n peer.dc = dc;\n peer.rtcSend = (packet) => {\n dc.send(packet);\n };\n peer.rtcEvents.emit('dcOpen', dc);\n // dc.send('yo waddup from the browser');\n };\n\n const offer = await con.createOffer({offerToReceiveAudio:true, offerToReceiveVideo:true});\n await con.setLocalDescription(offer);\n\n setTimeout(() => {\n if (!gatheringComplete) {\n debug('didnt finish gathering');\n sendOffer();\n offerSent = true;\n }\n }, GATHERING_TIMEOUT);\n\n peer.handleRtcAnswer = (answer) => {\n debug('node handleRtcAnswer', answer.sdp.length);\n con.setRemoteDescription(answer);\n return 'web handleRtcAnswer ok';\n }\n}\n\nasync function answerPeer(peer, offer) {\n const options = {...defaultOptions, bundlePolicy: \"max-bundle\"};\n const con = new RTCPeerConnection(options);\n // window.rtc = rtc;\n\n peer.rtcCon = con;\n \n let gatheringComplete = false;\n const start = Date.now();\n\n function sendAnswer() {\n const desc = con.localDescription;\n peer.methods.rtcSignal({type: desc.type, sdp: desc.sdp});\n }\n\n con.onicegatheringstatechange = (state) => {\n if (con.iceGatheringState === 'complete') {\n gatheringComplete = true;\n debug('answerer icegathering done', Date.now() - start);\n sendAnswer();\n }\n }\n await con.setRemoteDescription(offer);\n\n let answer = await con.createAnswer();\n await con.setLocalDescription(answer);\n\n con.onicecandidate = (ice) => {\n debug('ice candidate', ice);\n };\n\n con.onconnectionstatechange = (event) => {\n debug('connection state', con.connectionState, event);\n if(con.connectionState === 'connected') {\n peer.connected = true;\n peer.rtcEvents.emit('connected', con);\n } else if (con.connectionState === 'disconnected') {\n peer.connected = false;\n peer.rtcEvents.emit('disconnected', con);\n peer.rtcCon = null;\n peer.dc = null;\n } else if (con.connectionState === 'closed') {\n peer.connected = false;\n peer.rtcEvents.emit('closed', con);\n peer.rtcCon = null;\n peer.dc = null;\n }\n };\n\n con.ondatachannel = (event) => {\n debug('ondatachannel', event);\n peer.dcOpen = true;\n peer.dc = event.channel;\n peer.rtcSend = (packet) => {\n peer.dc.send(packet);\n };\n peer.rtcEvents.emit('dcOpen', peer.dc);\n peer.dc.onmessage = (event) => {\n peer.rtcEvents.emit('packet', event.data);\n };\n };\n\n setTimeout(() => {\n if (!gatheringComplete) {\n debug('didnt finish gathering');\n sendAnswer();\n }\n }, GATHERING_TIMEOUT);\n\n}\n\n\nrtc.offerPeer = offerPeer;\nrtc.answerPeer = answerPeer;\n\nmodule.exports = rtc;\n\n//# sourceURL=webpack://hsync/./lib/rtc-web.js?");
68
+ eval("const debug = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:rtc-web');\nconst debugError = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('errors');\n\nconst rtc = {\n PeerConnection: RTCPeerConnection,\n};\n\n\nconst defaultOptions = {\n // Recommended for libdatachannel\n // bundlePolicy: \"max-bundle\",\n iceServers: [{ 'urls': 'stun:stun.l.google.com:19302' }] \n};\n\nconst GATHERING_TIMEOUT = 4000;\n\nasync function offerPeer(peer) {\n return new Promise(async (resolve, reject) => {\n const con = new RTCPeerConnection(defaultOptions);\n // window.rtc = rtc;\n\n peer.rtcCon = con;\n peer.rtcOfferer = true;\n \n let gatheringComplete = false;\n let offerSent = false;\n const start = Date.now();\n\n async function sendOffer(alreadySent) {\n debug('send offer', alreadySent);\n const desc = con.localDescription;\n try {\n const resp = await peer.methods.rtcSignal({type: desc.type, sdp: desc.sdp, alreadySent});\n resolve(resp);\n } catch (e) {\n debugError('error sending offer', e);\n reject(e);\n }\n }\n\n con.onicegatheringstatechange = (state) => {\n debug('state change', con.iceGatheringState);\n if (con.iceGatheringState === 'complete') {\n debug('icegathering done', Date.now() - start);\n gatheringComplete = true;\n // We only want to provide an answer once all of our candidates have been added to the SDP.\n sendOffer(offerSent);\n }\n }\n\n con.onicecandidate = (ice) => {\n debug('ice candidate', ice);\n };\n\n con.onconnectionstatechange = (event) => {\n debug('connection state', con.connectionState, event);\n if(con.connectionState === 'connected') {\n peer.connected = true;\n peer.rtcEvents.emit('connected', con);\n }\n };\n\n con.ondatachannel = (event) => {\n debug('dc from answerer', event);\n peer.dc = event.channel;\n };\n\n const dc = con.createDataChannel('from web');\n\n peer.dc = dc;\n dc.onmessage = (event) => { \n debug('dc.onmessage', event.data);\n peer.rtcEvents.emit('packet', event.data);\n };\n dc.onopen = (event) => { \n peer.dcOpen = true;\n peer.dc = dc;\n peer.rtcSend = (packet) => {\n dc.send(packet);\n };\n peer.rtcEvents.emit('dcOpen', dc);\n // dc.send('yo waddup from the browser');\n };\n\n const offer = await con.createOffer({offerToReceiveAudio:true, offerToReceiveVideo:true});\n await con.setLocalDescription(offer);\n\n setTimeout(() => {\n if (!gatheringComplete) {\n debug('didnt finish gathering');\n sendOffer();\n offerSent = true;\n }\n }, GATHERING_TIMEOUT);\n\n peer.handleRtcAnswer = (answer) => {\n debug('node handleRtcAnswer', answer.sdp.length);\n con.setRemoteDescription(answer);\n return 'web handleRtcAnswer ok';\n }\n });\n}\n\nasync function answerPeer(peer, offer) {\n const options = {...defaultOptions, bundlePolicy: \"max-bundle\"};\n const con = new RTCPeerConnection(options);\n // window.rtc = rtc;\n\n peer.rtcCon = con;\n \n let gatheringComplete = false;\n const start = Date.now();\n\n function sendAnswer() {\n const desc = con.localDescription;\n peer.methods.rtcSignal({type: desc.type, sdp: desc.sdp});\n }\n\n con.onicegatheringstatechange = (state) => {\n if (con.iceGatheringState === 'complete') {\n gatheringComplete = true;\n debug('answerer icegathering done', Date.now() - start);\n sendAnswer();\n }\n }\n await con.setRemoteDescription(offer);\n\n let answer = await con.createAnswer();\n await con.setLocalDescription(answer);\n\n con.onicecandidate = (ice) => {\n debug('ice candidate', ice);\n };\n\n con.onconnectionstatechange = (event) => {\n debug('connection state', con.connectionState, event);\n if(con.connectionState === 'connected') {\n peer.connected = true;\n peer.rtcEvents.emit('connected', con);\n } else if (con.connectionState === 'disconnected') {\n peer.connected = false;\n peer.rtcEvents.emit('disconnected', con);\n peer.rtcCon = null;\n peer.dc = null;\n } else if (con.connectionState === 'closed') {\n peer.connected = false;\n peer.rtcEvents.emit('closed', con);\n peer.rtcCon = null;\n peer.dc = null;\n }\n };\n\n con.ondatachannel = (event) => {\n debug('ondatachannel', event);\n peer.dcOpen = true;\n peer.dc = event.channel;\n peer.rtcSend = (packet) => {\n peer.dc.send(packet);\n };\n peer.rtcEvents.emit('dcOpen', peer.dc);\n peer.dc.onmessage = (event) => {\n peer.rtcEvents.emit('packet', event.data);\n };\n };\n\n setTimeout(() => {\n if (!gatheringComplete) {\n debug('didnt finish gathering');\n sendAnswer();\n }\n }, GATHERING_TIMEOUT);\n\n}\n\n\nrtc.offerPeer = offerPeer;\nrtc.answerPeer = answerPeer;\n\nmodule.exports = rtc;\n\n//# sourceURL=webpack://hsync/./lib/rtc-web.js?");
69
69
 
70
70
  /***/ }),
71
71
 
72
- /***/ "./lib/socket-listen-handler.js":
73
- /*!**************************************!*\
74
- !*** ./lib/socket-listen-handler.js ***!
75
- \**************************************/
72
+ /***/ "./lib/socket-listeners.js":
73
+ /*!*********************************!*\
74
+ !*** ./lib/socket-listeners.js ***!
75
+ \*********************************/
76
76
  /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
77
77
 
78
- eval("const b64id = __webpack_require__(/*! b64id */ \"./node_modules/b64id/index.js\");\nconst debug = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:listener');\nconst debugError = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:error');\n\nconst { getRPCPeer } = __webpack_require__(/*! ./peers */ \"./lib/peers.js\");\nconst { sockets } = __webpack_require__(/*! ./socket-map */ \"./lib/socket-map.js\");\n\nlet net;\n\nfunction setNet(netImpl) {\n net = netImpl;\n}\n\ndebugError.color = 1;\n\nfunction receiveRelayData(remotePeer, { socketId, data }) {\n debug('receiveRelayData', socketId, data, 'sockets', Object.keys(sockets));\n if (!sockets[socketId]) {\n throw new Error('listener has no matching socket for relay: ' + socketId);\n }\n let dataBuffer = data;\n if (typeof dataBuffer === 'string') {\n dataBuffer = Buffer.from(dataBuffer, 'base64');\n }\n sockets[socketId].write(dataBuffer);\n return 'receiveRelayData ok';\n}\n\nfunction createSocketListenHandler(options = {}) {\n const { hostName, port, targetPort, targetHost, hsyncClient } = options;\n debug('creating handler', port, targetHost);\n \n const rpcPeer = getRPCPeer({hostName: targetHost, hsyncClient});\n\n const socketServer = net.createServer(async (socket) => {\n\n if (!rpcPeer.rtcCon) {\n await rpcPeer.connectRTC();\n }\n\n socket.socketId = b64id.generateId();\n sockets[socket.socketId] = socket;\n rpcPeer.sockets[socket.socketId] = socket;\n socket.listenerSocket = true;\n debug('connected to local listener', port, socket.socketId);\n socket.peerConnected = false;\n const pubTopic = `msg/${hostName}/${hsyncClient.myHostName}/socketData/${socket.socketId}`;\n const closeTopic = `msg/${hostName}/${hsyncClient.myHostName}/socketClose/${socket.socketId}`;\n const dataQueue = [];\n\n async function sendData(data) {\n if (rpcPeer.packAndSend) {\n debug('sending data via rtc', hostName, socket.socketId, data.length);\n rpcPeer.packAndSend(`socketData/${socket.socketId}`, data);\n return;\n }\n debug('sending data via rpc', hostName, data.length);\n // hsyncClient.mqConn.publish(pubTopic, data);\n const result = await rpcPeer.methods.receiveListenerData({\n socketId: socket.socketId,\n data: Buffer.from(data).toString('base64'),\n });\n debug('sendData from Listener', result);\n }\n\n socket.on('data', async (data) => {\n debug('socket data', data ? data.length : '');\n // if (!socket.peerConnected) {\n // dataQueue.push(data);\n // return;\n // }\n sendData(data);\n });\n \n socket.on('close', () => {\n debug('listener socket closed', port, socket.socketId);\n if (sockets[socket.socketId]) {\n delete sockets[socket.socketId];\n }\n });\n \n socket.on('error', (error) => {\n debug('socket error', hostName, socket.socketId, error);\n if (sockets[socket.socketId]) {\n delete sockets[socket.socketId];\n }\n });\n \n try {\n debug('connecting remotely', socket.socketId, targetPort, rpcPeer.hostName, targetHost);\n const result = await rpcPeer.methods.connectSocket({\n socketId: socket.socketId,\n port: targetPort,\n hostName: rpcPeer.hostName,\n wut: 'huh',\n });\n debug('connect result', result);\n socket.peerConnected = true;\n dataQueue.forEach(sendData); \n } catch (e) {\n debugError('cant connect remotely', hostName, targetPort, e);\n if (sockets[socket.socketId]) {\n delete sockets[socket.socketId];\n }\n socket.end();\n }\n });\n\n socketServer.listen(port);\n\n function end() {\n const sockKeys = Object.keys(sockets);\n sockKeys.forEach((sk) => {\n try {\n sockets[sk].end();\n delete sockets[sk];\n }\n catch(e) {\n debug('error closing socket', e);\n }\n });\n }\n\n return {\n socketServer,\n sockets,\n end,\n };\n}\n\nmodule.exports = { \n createSocketListenHandler,\n receiveRelayData,\n setNet,\n};\n\n//# sourceURL=webpack://hsync/./lib/socket-listen-handler.js?");
78
+ eval("const b64id = __webpack_require__(/*! b64id */ \"./node_modules/b64id/index.js\");\nconst debug = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:listener');\nconst debugError = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:error');\n\nconst { sockets } = __webpack_require__(/*! ./socket-map */ \"./lib/socket-map.js\");\n\nlet net;\n\nfunction setNet(netImpl) {\n net = netImpl;\n}\n\ndebugError.color = 1;\n\nfunction initListeners(hsyncClient) {\n const socketListeners = {};\n\n function getSocketListeners() {\n const hKeys = Object.keys(socketListeners);\n debug('getSocketListeners', hKeys);\n let retVal = hKeys.map((hk) => {\n const l = socketListeners[hk];\n return {\n port: l.port,\n targetHost: l.targetHost,\n targetPort: l.targetPort,\n };\n });\n return retVal;\n }\n\n function addSocketListener(options = {}) {\n const { port, targetPort, targetHost } = options;\n debug('creating handler', port, targetHost);\n \n const rpcPeer = hsyncClient.getRPCPeer({ hostName: targetHost });\n\n const socketServer = net.createServer(async (socket) => {\n\n if (!rpcPeer.rtcCon) {\n try {\n debug('initiating connectRTC from socket listener');\n await rpcPeer.connectRTC();\n } catch (e) {\n debug('error connecting to rtc', e);\n socket.end();\n return;\n }\n }\n\n rpcPeer.notifications.oncloseListenerSocket((remotePeer, { socketId }) => {\n debug('closeListenerSocket', socketId, !!sockets[socketId]);\n if (sockets[socketId]) {\n sockets[socketId].end();\n delete sockets[socketId];\n return 'closeListenerSocket ok';\n }\n return `closeListenerSocket no matching socket for ${socketId}`;\n });\n\n socket.socketId = b64id.generateId();\n sockets[socket.socketId] = socket;\n rpcPeer.sockets[socket.socketId] = socket;\n socket.listenerSocket = true;\n debug('connected to local listener', port, socket.socketId);\n socket.peerConnected = false;\n // const pubTopic = `msg/${hostName}/${hsyncClient.myHostName}/socketData/${socket.socketId}`;\n // const closeTopic = `msg/${hostName}/${hsyncClient.myHostName}/socketClose/${socket.socketId}`;\n const dataQueue = [];\n\n async function sendData(data) {\n // TODO queue data if not connected\n if (rpcPeer.packAndSend) {\n debug('sending data via rtc', targetHost, socket.socketId, data.length);\n rpcPeer.packAndSend(`socketData/${socket.socketId}`, data);\n return;\n }\n // debug('sending data via rpc', targetHost, data.length);\n // // hsyncClient.mqConn.publish(pubTopic, data);\n // const result = await rpcPeer.methods.receiveListenerData({\n // socketId: socket.socketId,\n // data: Buffer.from(data).toString('base64'),\n // });\n // debug('sendData from Listener', result);\n }\n\n socket.on('data', async (data) => {\n debug('socket data', data ? data.length : '');\n // if (!socket.peerConnected) {\n // dataQueue.push(data);\n // return;\n // }\n sendData(data);\n });\n \n socket.on('close', (a, b, c) => {\n debug('listener socket closed', port, socket.socketId, a, b, c);\n if (sockets[socket.socketId]) {\n delete sockets[socket.socketId];\n try {\n rpcPeer.notifiers.closeRelaySocket({\n socketId: socket.socketId,\n });\n } catch (e) {\n debug('error closing relay socket', e);\n }\n }\n });\n \n socket.on('error', (error) => {\n debug('socket error', targetHost, socket.socketId, error);\n if (sockets[socket.socketId]) {\n delete sockets[socket.socketId];\n }\n });\n \n try {\n debug('connecting remotely', socket.socketId, targetPort, rpcPeer.hostName, targetHost);\n const result = await rpcPeer.methods.connectSocket({\n socketId: socket.socketId,\n port: targetPort,\n hostName: rpcPeer.hostName,\n });\n debug('connect result', result);\n socket.peerConnected = true;\n dataQueue.forEach(sendData); \n } catch (e) {\n debugError('cant connect remotely', targetHost, targetPort, e);\n if (sockets[socket.socketId]) {\n delete sockets[socket.socketId];\n }\n socket.end();\n }\n });\n\n socketServer.listen(port);\n\n function end() {\n const sockKeys = Object.keys(sockets);\n sockKeys.forEach((sk) => {\n try {\n if (sockets[sk].listenerSocket) {\n sockets[sk].end();\n delete sockets[sk];\n }\n }\n catch(e) {\n debug('error closing socket', e);\n }\n });\n }\n\n const listener = {\n socketServer,\n sockets,\n end,\n targetHost,\n targetPort,\n port,\n };\n\n socketListeners['p' + port] = listener;\n return listener;\n }\n\n hsyncClient.socketListeners = socketListeners;\n hsyncClient.addSocketListener = addSocketListener;\n // hsyncClient.receiveRelayData = receiveRelayData;\n hsyncClient.getSocketListeners = getSocketListeners;\n // hsyncClient.closeListenerSocket = closeListenerSocket;\n\n return {\n addSocketListener,\n // receiveRelayData,\n getSocketListeners,\n };\n}\n\nmodule.exports = { \n initListeners,\n setNet,\n};\n\n//# sourceURL=webpack://hsync/./lib/socket-listeners.js?");
79
79
 
80
80
  /***/ }),
81
81
 
@@ -89,13 +89,13 @@ eval("const debug = __webpack_require__(/*! debug */ \"./node_modules/debug/src/
89
89
 
90
90
  /***/ }),
91
91
 
92
- /***/ "./lib/socket-relay-handler.js":
93
- /*!*************************************!*\
94
- !*** ./lib/socket-relay-handler.js ***!
95
- \*************************************/
92
+ /***/ "./lib/socket-relays.js":
93
+ /*!******************************!*\
94
+ !*** ./lib/socket-relays.js ***!
95
+ \******************************/
96
96
  /***/ ((module, __unused_webpack_exports, __webpack_require__) => {
97
97
 
98
- eval("const debug = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:relay');\nconst debugError = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:error');\nconst { getRPCPeer } = __webpack_require__(/*! ./peers */ \"./lib/peers.js\");\nconst { sockets } = __webpack_require__(/*! ./socket-map */ \"./lib/socket-map.js\");\n\ndebugError.color = 1;\n\nlet net;\n\nfunction setNet(netImpl) {\n net = netImpl;\n}\n\nconst relays = {};\n\nfunction receiveListenerData(remotePeer, { socketId, data }) {\n debug('receiveListenerData', socketId, data, 'sockets', Object.keys(sockets));\n if (!sockets[socketId]) {\n throw new Error('relay has no matching socket for listener : ' + socketId);\n }\n let dataBuffer = data;\n if (typeof dataBuffer === 'string') {\n dataBuffer = Buffer.from(dataBuffer, 'base64');\n }\n sockets[socketId].write(dataBuffer);\n return 'receiveListenerData ok';\n}\n\nfunction connectSocket(remotePeer, { hsyncClient, fromHost, port, socketId}) {\n const relay = relays['p' + port];\n debug('connect relay', port, socketId);\n if (!relay) {\n throw new Error('no relay found for port: ' + port);\n }\n // const rpcPeer = getRPCPeer({hostName: fromHost, hsyncClient});\n // const relayDataTopic = `msg/${hostName}/${hsyncClient.myHostName}/relayData/${socketId}`;\n return new Promise((resolve, reject) => {\n const socket = new net.Socket();\n socket.socketId = socketId;\n sockets[socketId] = socket;\n socket.connect(relay.targetPort, relay.targetHost, () => {\n debug(`CONNECTED TO LOCAL SERVER`, socket.socketId, socket.hostName);\n resolve({socketId, targetHost: relay.targetHost, targetPort: relay.targetPort});\n });\n\n socket.on('data', async (data) => {\n debug(`data in ${socket.socketId}`, relay.targetPort, relay.targetHost, data.length);\n if (remotePeer.packAndSend) {\n debug('sending relay data via rtc', socket.socketId, data.length);\n remotePeer.packAndSend(`socketData/${socket.socketId}`, Buffer.from(data));\n return;\n }\n const result = await remotePeer.methods.receiveRelayData({\n socketId,\n data: Buffer.from(data).toString('base64'),\n });\n // const p = getRTCPeer(hostName, hsyncClient);\n // if (p.connected) {\n // p.send(`relayData/${socketId}`, data);\n // return;\n // }\n // hsyncClient.mqConn.publish(relayDataTopic, data);\n });\n socket.on('close', () => {\n debug(`LOCAL CONNECTION CLOSED`, socket.socketId, targetHost, targetPort);\n delete sockets[socket.socketId];\n });\n\n socket.on('error', (e) => {\n debugError(`LOCAL CONNECTION ERROR`, socket.socketId, targetHost, targetPort, e);\n delete sockets[socket.socketId];\n reject(e);\n });\n \n });\n\n}\n\n// function receiveSocketData(socketId, data) {\n// if (sockets[socketId]) {\n// debug('receiveSocketData', socketId, data.length);\n// sockets[socketId].write(data);\n// return 'ok';\n// }\n\n// throw new Error('socket not found: ' + socketId);\n// }\n\nfunction createSocketRelayHandler({hostName, port, targetPort, targetHost, hsyncClient}) {\n debug('creating relay', hostName, port, targetPort, targetHost);\n relays['p' + port] = {\n hostName,\n port,\n targetPort,\n targetHost,\n };\n}\n\nmodule.exports = {\n createSocketRelayHandler,\n connectSocket,\n // receiveSocketData,\n setNet,\n receiveListenerData,\n};\n\n//# sourceURL=webpack://hsync/./lib/socket-relay-handler.js?");
98
+ eval("const debug = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:relay');\nconst debugError = __webpack_require__(/*! debug */ \"./node_modules/debug/src/browser.js\")('hsync:error');\nconst { sockets } = __webpack_require__(/*! ./socket-map */ \"./lib/socket-map.js\");\n\ndebugError.color = 1;\n\nlet net;\n\nfunction setNet(netImpl) {\n net = netImpl;\n}\n\nfunction initRelays(hsyncClient) {\n const cachedRelays = {};\n\n function getSocketRelays() {\n const hKeys = Object.keys(cachedRelays);\n debug('getSocketListeners', hKeys);\n let retVal = hKeys.map((hk) => {\n const l = cachedRelays[hk];\n return {\n port: l.port,\n targetHost: l.targetHost,\n targetPort: l.targetPort,\n whitelist: l.whitelist || '',\n blacklist: l.blacklist || '',\n };\n });\n return retVal;\n }\n\n function connectSocket(remotePeer, { port, socketId }) {\n\n remotePeer.notifications.oncloseRelaySocket((remotePeer, { socketId }) => {\n debug('closeRelaySocket', socketId);\n if (sockets[socketId]) {\n sockets[socketId].end();\n delete sockets[socketId];\n return 'closeRelaySocket ok';\n }\n return `closeRelaySocket no matching socket for ${socketId}`;\n });\n\n const relay = cachedRelays['p' + port];\n debug('connect relay', port, socketId, remotePeer.hostName);\n if (!relay) {\n throw new Error('no relay found for port: ' + port);\n }\n\n // TODO: check white and black lists on remotePeer\n\n // const relayDataTopic = `msg/${hostName}/${hsyncClient.myHostName}/relayData/${socketId}`;\n return new Promise((resolve, reject) => {\n const socket = new net.Socket();\n socket.socketId = socketId;\n sockets[socketId] = socket;\n socket.connect(relay.targetPort, relay.targetHost, () => {\n debug(`CONNECTED TO LOCAL SERVER`, socket.socketId, socket.hostName, port);\n resolve({socketId, targetHost: relay.targetHost, targetPort: relay.targetPort});\n });\n\n socket.on('data', async (data) => {\n debug(`data in ${socket.socketId}`, relay.targetPort, relay.targetHost, data.length);\n // TODO: queue data if remotePeer is not ready\n if (remotePeer.packAndSend) {\n debug('sending relay data via rtc', socket.socketId, data.length);\n remotePeer.packAndSend(`socketData/${socket.socketId}`, Buffer.from(data));\n return;\n }\n });\n socket.on('close', async () => {\n debug(`LOCAL CONNECTION CLOSED`, socket.socketId);\n if (sockets[socket.socketId]) {\n try {\n await remotePeer.notifiers.closeListenerSocket({socketId});\n } catch (e) {\n debug('error closing socket', e);\n }\n delete sockets[socket.socketId];\n }\n });\n\n socket.on('error', (e) => {\n debugError(`LOCAL CONNECTION ERROR`, socket.socketId, e);\n delete sockets[socket.socketId];\n reject(e);\n });\n \n });\n\n }\n\n function addSocketRelay({whitelist, blacklist, port, targetPort, targetHost = 'localhost'}) {\n targetPort = targetPort || port;\n debug('creating relay', whitelist, blacklist, port, targetPort, targetHost);\n const newRelay = {\n whitelist,\n blacklist,\n port,\n targetPort,\n targetHost,\n };\n cachedRelays['p' + port] = newRelay;\n return newRelay;\n }\n\n hsyncClient.cachedRelays = cachedRelays;\n hsyncClient.addSocketRelay = addSocketRelay;\n hsyncClient.getSocketRelays = getSocketRelays;\n hsyncClient.connectSocket = connectSocket;\n \n return {\n // receiveListenerData,\n getSocketRelays,\n connectSocket,\n addSocketRelay,\n };\n}\n\nmodule.exports = {\n initRelays,\n setNet,\n};\n\n//# sourceURL=webpack://hsync/./lib/socket-relays.js?");
99
99
 
100
100
  /***/ }),
101
101