Skip to content

Commit 70cbd70

Browse files
authored
Merge pull request #25 from LibertyGlobal/astolcenburg-commonjs
Add CommonJS compatibility
2 parents e04fca7 + 282bf49 commit 70cbd70

7 files changed

Lines changed: 653 additions & 4 deletions

File tree

dist/thunderJS.cjs

Lines changed: 395 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,395 @@
1+
/**
2+
* If not stated otherwise in this file or this component's LICENSE file the
3+
* following copyright and licenses apply:
4+
*
5+
* Copyright 2021 Metrological
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the License);
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
'use strict';
21+
22+
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
23+
24+
var WebSocket = _interopDefault(require('ws'));
25+
26+
const requestsQueue = {};
27+
const listeners = {};
28+
29+
var requestQueueResolver = data => {
30+
if (typeof data === 'string') {
31+
let regex1 = /\\\\x([0-9A-Fa-f]{2})/g;
32+
let regex2 = /\\x([0-9A-Fa-f]{2})/g;
33+
data = data.normalize().replace(regex1, '');
34+
data = data.normalize().replace(regex2, '');
35+
data = JSON.parse(data);
36+
}
37+
if (data.id) {
38+
const request = requestsQueue[data.id];
39+
if (request) {
40+
if ('result' in data) request.resolve(data.result);
41+
else request.reject(data.error);
42+
delete requestsQueue[data.id];
43+
} else {
44+
console.log('no pending request found with id ' + data.id);
45+
}
46+
}
47+
};
48+
49+
var notificationListener = data => {
50+
if (typeof data === 'string') {
51+
let regex1 = /\\\\x([0-9A-Fa-f]{2})/g;
52+
let regex2 = /\\x([0-9A-Fa-f]{2})/g;
53+
data = data.normalize().replace(regex1, '');
54+
data = data.normalize().replace(regex2, '');
55+
data = JSON.parse(data);
56+
}
57+
if (!data.id && data.method) {
58+
const callbacks = listeners[data.method];
59+
if (callbacks && Array.isArray(callbacks) && callbacks.length) {
60+
callbacks.forEach(callback => {
61+
callback(data.params);
62+
});
63+
}
64+
}
65+
};
66+
67+
const protocol = 'ws://';
68+
const host = 'localhost';
69+
const endpoint = '/jsonrpc';
70+
const port = 80;
71+
var makeWebsocketAddress = options => {
72+
return [
73+
(options && options.protocol) || protocol,
74+
(options && options.host) || host,
75+
':' + ((options && options.port) || port),
76+
(options && options.endpoint) || endpoint,
77+
options && options.token ? '?token=' + options.token : null,
78+
].join('')
79+
};
80+
81+
const sockets = {};
82+
var connect = options => {
83+
return new Promise((resolve, reject) => {
84+
const socketAddress = makeWebsocketAddress(options);
85+
let socket = sockets[socketAddress];
86+
if (socket && socket.readyState === 1) return resolve(socket)
87+
if (socket && socket.readyState === 0) {
88+
const waitForOpen = () => {
89+
socket.removeEventListener('open', waitForOpen);
90+
resolve(socket);
91+
};
92+
return socket.addEventListener('open', waitForOpen)
93+
}
94+
if (socket == null) {
95+
if (options.debug) {
96+
console.log('Opening socket to ' + socketAddress);
97+
}
98+
socket = new WebSocket(socketAddress, (options && options.subprotocols) || 'notification');
99+
sockets[socketAddress] = socket;
100+
socket.addEventListener('message', message => {
101+
if (options.debug) {
102+
console.log(' ');
103+
console.log('API REPONSE:');
104+
console.log(JSON.stringify(message.data, null, 2));
105+
console.log(' ');
106+
}
107+
requestQueueResolver(message.data);
108+
});
109+
socket.addEventListener('message', message => {
110+
notificationListener(message.data);
111+
});
112+
socket.addEventListener('error', () => {
113+
notificationListener({
114+
method: 'client.ThunderJS.events.error',
115+
});
116+
sockets[socketAddress] = null;
117+
});
118+
const handleConnectClosure = event => {
119+
sockets[socketAddress] = null;
120+
reject(event);
121+
};
122+
socket.addEventListener('close', handleConnectClosure);
123+
socket.addEventListener('open', () => {
124+
notificationListener({
125+
method: 'client.ThunderJS.events.connect',
126+
});
127+
socket.removeEventListener('close', handleConnectClosure);
128+
socket.addEventListener('close', () => {
129+
notificationListener({
130+
method: 'client.ThunderJS.events.disconnect',
131+
});
132+
sockets[socketAddress] = null;
133+
});
134+
resolve(socket);
135+
});
136+
} else {
137+
sockets[socketAddress] = null;
138+
reject('Socket error');
139+
}
140+
})
141+
};
142+
143+
var makeBody = (requestId, plugin, method, params, version) => {
144+
if (params) {
145+
delete params.version;
146+
if (params.versionAsParameter) {
147+
params.version = params.versionAsParameter;
148+
delete params.versionAsParameter;
149+
}
150+
}
151+
const body = {
152+
jsonrpc: '2.0',
153+
id: requestId,
154+
method: [plugin, version, method].join('.'),
155+
};
156+
params || params === false
157+
?
158+
typeof params === 'object' && Object.keys(params).length === 0
159+
? null
160+
: (body.params = params)
161+
: null;
162+
return body
163+
};
164+
165+
var getVersion = (versionsConfig, plugin, params) => {
166+
const defaultVersion = 1;
167+
let version;
168+
if ((version = params && params.version)) {
169+
return version
170+
}
171+
return versionsConfig
172+
? versionsConfig[plugin] || versionsConfig.default || defaultVersion
173+
: defaultVersion
174+
};
175+
176+
let id = 0;
177+
var makeId = () => {
178+
id = id + 1;
179+
return id
180+
};
181+
182+
var execRequest = (options, body) => {
183+
return connect(options).then(connection => {
184+
connection.send(JSON.stringify(body));
185+
})
186+
};
187+
188+
var API = options => {
189+
return {
190+
request(plugin, method, params) {
191+
return new Promise((resolve, reject) => {
192+
const requestId = makeId();
193+
const version = getVersion(options.versions, plugin, params);
194+
const body = makeBody(requestId, plugin, method, params, version);
195+
if (options.debug) {
196+
console.log(' ');
197+
console.log('API REQUEST:');
198+
console.log(JSON.stringify(body, null, 2));
199+
console.log(' ');
200+
}
201+
requestsQueue[requestId] = {
202+
body,
203+
resolve,
204+
reject,
205+
};
206+
execRequest(options, body).catch(e => {
207+
reject(e);
208+
});
209+
})
210+
},
211+
}
212+
};
213+
214+
var DeviceInfo = {
215+
freeRam(params) {
216+
return this.call('systeminfo', params).then(res => {
217+
return res.freeram
218+
})
219+
},
220+
version(params) {
221+
return this.call('systeminfo', params).then(res => {
222+
return res.version
223+
})
224+
},
225+
};
226+
227+
var plugins = {
228+
DeviceInfo,
229+
};
230+
231+
function listener(plugin, event, callback, errorCallback) {
232+
const thunder = this;
233+
const index = register.call(this, plugin, event, callback, errorCallback);
234+
return {
235+
dispose() {
236+
const listener_id = makeListenerId(plugin, event);
237+
if (listeners[listener_id] === undefined) return
238+
listeners[listener_id].splice(index, 1);
239+
if (listeners[listener_id].length === 0) {
240+
unregister.call(thunder, plugin, event, errorCallback);
241+
}
242+
},
243+
}
244+
}
245+
const makeListenerId = (plugin, event) => {
246+
return ['client', plugin, 'events', event].join('.')
247+
};
248+
const register = function(plugin, event, callback, errorCallback) {
249+
const listener_id = makeListenerId(plugin, event);
250+
if (!listeners[listener_id]) {
251+
listeners[listener_id] = [];
252+
if (plugin !== 'ThunderJS') {
253+
const method = 'register';
254+
const request_id = listener_id
255+
.split('.')
256+
.slice(0, -1)
257+
.join('.');
258+
const params = {
259+
event,
260+
id: request_id,
261+
};
262+
this.api.request(plugin, method, params).catch(e => {
263+
if (typeof errorCallback === 'function') errorCallback(e.message);
264+
});
265+
}
266+
}
267+
listeners[listener_id].push(callback);
268+
return listeners[listener_id].length - 1
269+
};
270+
const unregister = function(plugin, event, errorCallback) {
271+
const listener_id = makeListenerId(plugin, event);
272+
delete listeners[listener_id];
273+
if (plugin !== 'ThunderJS') {
274+
const method = 'unregister';
275+
const request_id = listener_id
276+
.split('.')
277+
.slice(0, -1)
278+
.join('.');
279+
const params = {
280+
event,
281+
id: request_id,
282+
};
283+
this.api.request(plugin, method, params).catch(e => {
284+
if (typeof errorCallback === 'function') errorCallback(e.message);
285+
});
286+
}
287+
};
288+
289+
var thunderJS = options => {
290+
if (
291+
options.token === undefined &&
292+
typeof window !== 'undefined' &&
293+
window.thunder &&
294+
typeof window.thunder.token === 'function'
295+
) {
296+
options.token = window.thunder.token();
297+
}
298+
return wrapper({ ...thunder(options), ...plugins })
299+
};
300+
const resolve = (result, args) => {
301+
if (
302+
typeof result !== 'object' ||
303+
(typeof result === 'object' && (!result.then || typeof result.then !== 'function'))
304+
) {
305+
result = new Promise((resolve, reject) => {
306+
result instanceof Error === false ? resolve(result) : reject(result);
307+
});
308+
}
309+
const cb = typeof args[args.length - 1] === 'function' ? args[args.length - 1] : null;
310+
if (cb) {
311+
result.then(res => cb(null, res)).catch(err => cb(err));
312+
} else {
313+
return result
314+
}
315+
};
316+
const thunder = options => ({
317+
options,
318+
api: API(options),
319+
plugin: false,
320+
call() {
321+
const args = [...arguments];
322+
if (this.plugin) {
323+
if (args[0] !== this.plugin) {
324+
args.unshift(this.plugin);
325+
}
326+
}
327+
const plugin = args[0];
328+
const method = args[1];
329+
if (typeof this[plugin][method] == 'function') {
330+
return this[plugin][method](args[2])
331+
}
332+
return this.api.request.apply(this, args)
333+
},
334+
registerPlugin(name, plugin) {
335+
this[name] = wrapper(Object.assign(Object.create(thunder), plugin, { plugin: name }));
336+
},
337+
subscribe() {
338+
},
339+
on() {
340+
const args = [...arguments];
341+
if (['connect', 'disconnect', 'error'].indexOf(args[0]) !== -1) {
342+
args.unshift('ThunderJS');
343+
} else {
344+
if (this.plugin) {
345+
if (args[0] !== this.plugin) {
346+
args.unshift(this.plugin);
347+
}
348+
}
349+
}
350+
return listener.apply(this, args)
351+
},
352+
once() {
353+
console.log('todo ...');
354+
},
355+
});
356+
const wrapper = obj => {
357+
return new Proxy(obj, {
358+
get(target, propKey) {
359+
const prop = target[propKey];
360+
if (propKey === 'api') {
361+
return target.api
362+
}
363+
if (typeof prop !== 'undefined') {
364+
if (typeof prop === 'function') {
365+
if (['on', 'once', 'subscribe'].indexOf(propKey) > -1) {
366+
return function(...args) {
367+
return prop.apply(this, args)
368+
}
369+
}
370+
return function(...args) {
371+
return resolve(prop.apply(this, args), args)
372+
}
373+
}
374+
if (typeof prop === 'object') {
375+
return wrapper(
376+
Object.assign(Object.create(thunder(target.options)), prop, { plugin: propKey })
377+
)
378+
}
379+
return prop
380+
} else {
381+
if (target.plugin === false) {
382+
return wrapper(
383+
Object.assign(Object.create(thunder(target.options)), {}, { plugin: propKey })
384+
)
385+
}
386+
return function(...args) {
387+
args.unshift(propKey);
388+
return target.call.apply(this, args)
389+
}
390+
}
391+
},
392+
})
393+
};
394+
395+
module.exports = thunderJS;

0 commit comments

Comments
 (0)