How to separate clients in an event based websocket implementation? - javascript
I'm writing my own event-based websocket wrapper, based on the ws package for node and having trouble separating clients on the server side.
I set up a test scenario where my client emits a message to the server and the server sends a "ping" back to that same client.
What happens is that my test scenario works perfectly with the first connected client, but as soon as another client connects, emit messages from the first client will ping to the other client (messages from second client will correctly ping to the second client).
It feels like the WebSocket is somehow shared between the two clients but I can't seem to find where this is happening.
//SERVER CODE
let events = {};
function WebSockServer(port) {
//Init server
const wss = new WebSocket.Server({
port,
clientTracking: true
}, () => {
if (events['open']) {
events['open'].callback();
}
});
wss.on('connection', ws => {
ws.id = uuidv4();
let sock = new WebSock(ws, wss);
if (events['connection']) {
events['connection'].callback(sock);
}
ws.on('message', json => {
console.log('received message from ' + ws.id);
const message = JSON.parse(json);
//Check flags
for (let key in message.flags) {
if (key === 'binary' && message.flags[key].length > 0) {
message.flags[key].forEach(binary => {
const parsed = Buffer.from(message.data[binary], 'utf-16');
message.data[binary] = parsed;
});
}
}
//Check if event handler exists & check if event is only to be triggered once
if (events[message.event] && !events[message.event].once) {
events[message.event].callback(message.data);
}
else if (events[message.event] && events[message.event].once) {
events[message.event].callback(message.data);
delete events[message.event];
}
else {
return;
}
});
ws.on('close', () => {
if (events['close']) {
console.log('client disconnected');
events['close'].callback(ws.id);
}
wss.clients.delete(ws);
});
});
//Create an event handler
this.on = function on(event, callback) {
events[event] = {callback, once: false};
return this;
}
wss.on('error', err => {
console.log('Server shut down.');
});
}
function WebSock(ws, wss) {
this.ws = ws;
this.id = ws.id;
//Create an event handler
this.on = function on(event, callback) {
events[event] = {callback, once: false};
return this;
}
//Create an event handler for one time use
this.once = function once(event, callback) {
events[event] = {callback, once: true};
return this;
}
//Emit message to socket
this.emit = function emit(event, data) {
let flags = {
binary: []
};
//Check for binary data
for (let key in data) {
if (Buffer.isBuffer(data[key])) {
const stringified = data[key].toJSON();
data[key] = stringified;
flags.binary.push(key);
}
}
const payload = JSON.stringify({event, data, flags});
this.ws.send(payload);
return this;
}
//Emit message to specific socket
this.emitTo = function emitTo(id, event, data) {
let destination;
let flags = {
binary: []
};
//Find socket
for (let socket of wss.clients) {
if (socket.id === id) {
destination = socket;
break;
}
}
//Check for binary data
for (let key in data) {
if (Buffer.isBuffer(data[key])) {
const stringified = data[key].toJSON();
data[key] = stringified;
flags.binary.push(key);
}
}
//Send message to socket
if (destination) {
//Check type
if (typeof event != 'string' || typeof data != 'object') {
throw new TypeError('event must be a string, data must be an object');
}
const payload = JSON.stringify({event, data, flags});
destination.send(payload);
return this;
}
}
}
module.exports = WebSockServer;
//CLIENT CODE
function webSock(url) {
const ws = new WebSocket(url);
let events = {};
//Create an event handler
this.on = function on(event, callback) {
events[event] = {callback, once: false};
return this;
}
//Create an event handler for one time use
this.once = function once(event, callback) {
events[event] = {callback, once: true};
return this;
}
//Emit message to server
this.emit = function emit(event, data) {
let flags = {
binary: []
};
//Check for binary data
for (let key in data) {
if (Buffer.isBuffer(data[key])) {
const stringified = data[key].toJSON();
data[key] = stringified;
flags.binary.push(key);
}
}
const payload = JSON.stringify({event, data, flags});
ws.send(payload);
return this;
}
ws.on('open', () => {
if (events['open']) {
events['open'].callback(ws);
}
});
ws.on('close', () => {
if (events['close']) {
events['close'].callback();
}
})
ws.on('message', json => {
const message = JSON.parse(json);
//Check flags
for (let key in message.flags) {
if (key === 'binary' && message.flags[key].length > 0) {
message.flags[key].forEach(buffer => {
const parsed = Buffer.from(message.data[buffer]);
message.data[buffer] = parsed;
});
}
}
//Check if event handler exists & check if event is only to be triggered once
if (events[message.event] && !events[message.event].once) {
events[message.event].callback(message.data);
}
else if (events[message.event] && events[message.event].once) {
events[message.event].callback(message.data);
delete events[message.event];
}
else {
return;
}
});
}
module.exports = webSock;
Any help would be much appreciated, I'm sure I'm missing something obvious.
Related
Broadcasting to all clients with Deno websocket
I want to add notifications to an application I've developed. Unfortunately, Deno has removed the ws package.(https://deno.land/std#0.110.0/ws/mod.ts) That's why I'm using the websocket inside the denon itself. Since it doesn't have many functions, I have to add some things myself. For example, sending all messages to open clients. What I want to do is when the pdf is created, a (data, message) comes from the socket and update the notifications on the page according to the incoming data. I keep all open clients in a Map. and when the pdf is created, I return this Map and send it to all sockets (data, message). However, this works for one time. server conf... import { path, paths, ctid, } from "../deps.ts"; const users = new Map(); const sockets = new Map() const userArr = []; export const startNotif = (socket,req) => { const claims = req.get("claims"); const org = req.get("org"); claims.org = org; console.log("connected") users.set(claims.sub, {"username":claims.sub,"socket":socket}) users.forEach((user)=>{ if(userArr.length === 0){ userArr.push(user) } else if(userArr.every((w)=> w.username !== user.username) ) userArr.push(user) }) sockets.set(org, userArr) function broadcastMessage(message) { sockets.get(org).map((u)=>{ console.log(u.socket.readyState) u.socket.send(message) }) } if (socket.readyState === 3) { sockets.delete(uid) return } const init = (msg) => { socket.send( JSON.stringify({ status: "creating", }) ); }; const ondata = async (msg) => { const upfilepath = path.join(paths.work, `CT_${msg.sid}_report.pdf`); try { const s=await Deno.readTextFile(upfilepath); if(s){ socket.send( JSON.stringify({ status: "end", }) ); } else { socket.send( JSON.stringify({ status: "creating", }) ); } } catch(e) { if(e instanceof Deno.errors.NotFound) console.error('file does not exists'); } }; const end = () => { try { const endTime = Date.now() const msg = "Your PDF has been created" const id = ctid(12) // random id create broadcastMessage( JSON.stringify({ id: id, date: endTime, status: "done", message: msg, read: 'negative', action: 'pdf' }) ); } catch (e) { console.log(400, "Cannot send.", e); } } socket.onmessage = async (e) => { const cmd = JSON.parse(e.data); if(cmd.bid === 'start'){ await init(cmd) } if(!cmd.bid && cmd.sid){ await ondata(cmd) } if(cmd.bid === 'end'){ await end(); } } socket.onerror = (e) => { console.log(e); }; } client conf... export const webSocketHandler = (request) => new Promise((res, rej) => { let url; if (!process.env.NODE_ENV || process.env.NODE_ENV === 'development') { url = `http://localhost:8080/api/notifications/ws`.replace('http', 'ws'); } else { url = `${window.location.origin}/api/notifications/ws`.replace('http', 'ws'); } const token = JSON.parse(sessionStorage.getItem('token')); const orgname = localStorage.getItem('orgname'); const protocol = `${token}_org_${orgname}`; const socket = new WebSocket(url, protocol); const response = Object.create({}); socket.onopen = function () { socket.send( JSON.stringify({ bid: 'start', }) ); }; socket.onmessage = function (event) { response.data = JSON.parse(event.data); if (response.data.status === 'creating') { socket.send( JSON.stringify({ sid: request.sid, }) ); } else if (response.data.status === 'end') { socket.send( JSON.stringify({ bid: 'end', }) ); } else if (response.data.status === 'done') { try { res(response); } catch (err) { rej(err); } } }; socket.onclose = function (event) { response.state = event.returnValue; }; socket.onerror = function (error) { rej(error); }; }); onclick function of button I use in component... const donwloadReport = async (type) => { const query = `?sid=${sid}&reportType=${type}`; const fileName = `CT_${sid}_report.${type}`; try { type === 'pdf' && setLoading(true); const response = await getScanReportAction(query); const request = { sid, }; webSocketHandler(request) .then((data) => { console.log(data); dispatch({ type: 'update', data: { id: data.data.id, date: data.data.date, message: data.data.message, action: data.data.action, read: data.data.read, }, }); }) .catch((err) => { console.log(err); }); if (type === 'html') { downloadText(response.data, fileName); } else { const blobUrl = await readStream(response.data); setLoading(false); downloadURL(blobUrl, fileName); } } catch (err) { displayMessage(err.message); } }; Everything works perfectly the first time. When I press the download button for the pdf, the socket works, then a data is returned and I update the notification count with the context I applied according to this data. Later I realized that this works in a single tab. When I open a new client in the side tab, my notification count does not increase. For this, I wanted to keep all sockets in Map and return them all and send a message to each socket separately. But in this case, when I press the download button for the second time, no data comes from the socket. Actually, I think that I should do the socket initialization process on the client in the context. When you do this, it starts the socket 2 times in a meaningless way. In summary, consider an application with organizations and users belonging to those organizations. If the clients of A, B, C users belonging to X organization are open at the same time and user A pressed a pdf download button, I want A, B, C users to be notified when the pdf is downloaded. I would be very grateful if someone could show me a way around this issue.
Have you looked at the BroadcastChannel API? Maybe that could solve your issue. See for example: Deno specific: https://medium.com/deno-the-complete-reference/broadcast-channel-in-deno-f76a0b8893f5 Web/Browser API: https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API
Unhandled error Error: Data cannot be encoded in JSON error at firebase serverless functions
I'm trying to deploy an api for my application. Using these codes raises Unhandled error "Error: Data cannot be encoded in JSON. const functions = require("firebase-functions"); const axios = require("axios"); exports.getDatas = functions.https.onCall(async (d)=>{ functions.logger.log(d["name"]); cname = d["name"]; ts1=d["ts1"]; ts2=d["ts2"]; const data = await axios.get( "https://api.coingecko.com/api/v3/coins/" + cname + "/market_chart/range?vs_currency=usd&from=" + ts1 + "&to=" + ts2, ); functions.logger.log(data); return {data: data}; }); The error log is Unhandled error Error: Data cannot be encoded in JSON: function httpAdapter(config) { return new Promise(function dispatchHttpRequest(resolvePromise, rejectPromise) { var onCanceled; function done() { if (config.cancelToken) { config.cancelToken.unsubscribe(onCanceled); } if (config.signal) { config.signal.removeEventListener('abort', onCanceled); } } var resolve = function resolve(value) { done(); resolvePromise(value); }; var rejected = false; var reject = function reject(value) { done(); rejected = true; rejectPromise(value); }; var data = config.data; var headers = config.headers; var headerNames = {}; Object.keys(headers).forEach(function storeLowerName(name) { headerNames[name.toLowerCase()] = name; }); // Set User-Agent (required by some servers) // See https://github.com/axios/axios/issues/69 if ('user-agent' in headerNames) { // User-Agent is specified; handle case where no UA header is desired if (!headers[headerNames['user-agent']]) { delete headers[headerNames['user-agent']]; } // Otherwise, use specified value } else { // Only set header if it hasn't been set in config headers['User-Agent'] = 'axios/' + VERSION; } if (data && !utils.isStream(data)) { if (Buffer.isBuffer(data)) { // Nothing to do... } else if (utils.isArrayBuffer(data)) { data = Buffer.from(new Uint8Array(data)); } else if (utils.isString(data)) { data = Buffer.from(data, 'utf-8'); } else { return reject(createError( 'Data after transformation must be a string, an ArrayBuffer, a Buffer, or a Stream', config )); } if (config.maxBodyLength > -1 && data.length > config.maxBodyLength) { return reject(createError('Request body larger than maxBodyLength limit', config)); } // Add Content-Length header if data exists if (!headerNames['content-length']) { headers['Content-Length'] = data.length; } } // HTTP basic authentication var auth = undefined; if (config.auth) { var username = config.auth.username || ''; var password = config.auth.password || ''; auth = username + ':' + password; } // Parse url var fullPath = buildFullPath(config.baseURL, config.url); var parsed = url.parse(fullPath); var protocol = parsed.protocol || 'http:'; if (!auth && parsed.auth) { var urlAuth = parsed.auth.split(':'); var urlUsername = urlAuth[0] || ''; var urlPassword = urlAuth[1] || ''; auth = urlUsername + ':' + urlPassword; } if (auth && headerNames.authorization) { delete headers[headerNames.authorization]; } var isHttpsRequest = isHttps.test(protocol); var agent = isHttpsRequest ? config.httpsAgent : config.httpAgent; var options = { path: buildURL(parsed.path, config.params, config.paramsSerializer).replace(/^\?/, ''), method: config.method.toUpperCase(), headers: headers, agent: agent, agents: { http: config.httpAgent, https: config.httpsAgent }, auth: auth }; if (config.socketPath) { options.socketPath = config.socketPath; } else { options.hostname = parsed.hostname; options.port = parsed.port; } var proxy = config.proxy; if (!proxy && proxy !== false) { var proxyEnv = protocol.slice(0, -1) + '_proxy'; var proxyUrl = process.env[proxyEnv] || process.env[proxyEnv.toUpperCase()]; if (proxyUrl) { var parsedProxyUrl = url.parse(proxyUrl); var noProxyEnv = process.env.no_proxy || process.env.NO_PROXY; var shouldProxy = true; if (noProxyEnv) { var noProxy = noProxyEnv.split(',').map(function trim(s) { return s.trim(); }); shouldProxy = !noProxy.some(function proxyMatch(proxyElement) { if (!proxyElement) { return false; } if (proxyElement === '*') { return true; } if (proxyElement[0] === '.' && parsed.hostname.substr(parsed.hostname.length - proxyElement.length) === proxyElement) { return true; } return parsed.hostname === proxyElement; }); } if (shouldProxy) { proxy = { host: parsedProxyUrl.hostname, port: parsedProxyUrl.port, protocol: parsedProxyUrl.protocol }; if (parsedProxyUrl.auth) { var proxyUrlAuth = parsedProxyUrl.auth.split(':'); proxy.auth = { username: proxyUrlAuth[0], password: proxyUrlAuth[1] }; } } } } if (proxy) { options.headers.host = parsed.hostname + (parsed.port ? ':' + parsed.port : ''); setProxy(options, proxy, protocol + '//' + parsed.hostname + (parsed.port ? ':' + parsed.port : '') + options.path); } var transport; var isHttpsProxy = isHttpsRequest && (proxy ? isHttps.test(proxy.protocol) : true); if (config.transport) { transport = config.transport; } else if (config.maxRedirects === 0) { transport = isHttpsProxy ? https : http; } else { if (config.maxRedirects) { options.maxRedirects = config.maxRedirects; } transport = isHttpsProxy ? httpsFollow : httpFollow; } if (config.maxBodyLength > -1) { options.maxBodyLength = config.maxBodyLength; } if (config.insecureHTTPParser) { options.insecureHTTPParser = config.insecureHTTPParser; } // Create the request var req = transport.request(options, function handleResponse(res) { if (req.aborted) return; // uncompress the response body transparently if required var stream = res; // return the last request in case of redirects var lastRequest = res.req || req; // if no content, is HEAD request or decompress disabled we should not decompress if (res.statusCode !== 204 && lastRequest.method !== 'HEAD' && config.decompress !== false) { switch (res.headers['content-encoding']) { /*eslint default-case:0*/ case 'gzip': case 'compress': case 'deflate': // add the unzipper to the body stream processing pipeline stream = stream.pipe(zlib.createUnzip()); // remove the content-encoding in order to not confuse downstream operations delete res.headers['content-encoding']; break; } } var response = { status: res.statusCode, statusText: res.statusMessage, headers: res.headers, config: config, request: lastRequest }; if (config.responseType === 'stream') { response.data = stream; settle(resolve, reject, response); } else { var responseBuffer = []; var totalResponseBytes = 0; stream.on('data', function handleStreamData(chunk) { responseBuffer.push(chunk); totalResponseBytes += chunk.length; // make sure the content length is not over the maxContentLength if specified if (config.maxContentLength > -1 && totalResponseBytes > config.maxContentLength) { // stream.destoy() emit aborted event before calling reject() on Node.js v16 rejected = true; stream.destroy(); reject(createError('maxContentLength size of ' + config.maxContentLength + ' exceeded', config, null, lastRequest)); } }); stream.on('aborted', function handlerStreamAborted() { if (rejected) { return; } stream.destroy(); reject(createError('error request aborted', config, 'ERR_REQUEST_ABORTED', lastRequest)); }); stream.on('error', function handleStreamError(err) { if (req.aborted) return; reject(enhanceError(err, config, null, lastRequest)); }); stream.on('end', function handleStreamEnd() { try { var responseData = responseBuffer.length === 1 ? responseBuffer[0] : Buffer.concat(responseBuffer); if (config.responseType !== 'arraybuffer') { responseData = responseData.toString(config.responseEncoding); if (!config.responseEncoding || config.responseEncoding === 'utf8') { responseData = utils.stripBOM(responseData); } } response.data = responseData; } catch (err) { reject(enhanceError(err, config, err.code, response.request, response)); } settle(resolve, reject, response); }); } }); // Handle errors req.on('error', function handleRequestError(err) { if (req.aborted && err.code !== 'ERR_FR_TOO_MANY_REDIRECTS') return; reject(enhanceError(err, config, null, req)); }); // set tcp keep alive to prevent drop connection by peer req.on('socket', function handleRequestSocket(socket) { // default interval of sending ack packet is 1 minute socket.setKeepAlive(true, 1000 * 60); }); // Handle request timeout if (config.timeout) { // This is forcing a int timeout to avoid problems if the `req` interface doesn't handle other types. var timeout = parseInt(config.timeout, 10); if (isNaN(timeout)) { reject(createError( 'error trying to parse `config.timeout` to int', config, 'ERR_PARSE_TIMEOUT', req )); return; } // Sometime, the response will be very slow, and does not respond, the connect event will be block by event loop system. // And timer callback will be fired, and abort() will be invoked before connection, then get "socket hang up" and code ECONNRESET. // At this time, if we have a large number of request, nodejs will hang up some socket on background. and the number will up and up. // And then these socket which be hang up will devoring CPU little by little. // ClientRequest.setTimeout will be fired on the specify milliseconds, and can make sure that abort() will be fired after connect. req.setTimeout(timeout, function handleRequestTimeout() { req.abort(); var transitional = config.transitional || defaults.transitional; reject(createError( 'timeout of ' + timeout + 'ms exceeded', config, transitional.clarifyTimeoutError ? 'ETIMEDOUT' : 'ECONNABORTED', req )); }); } if (config.cancelToken || config.signal) { // Handle cancellation // eslint-disable-next-line func-names onCanceled = function(cancel) { if (req.aborted) return; req.abort(); reject(!cancel || (cancel && cancel.type) ? new Cancel('canceled') : cancel); }; config.cancelToken && config.cancelToken.subscribe(onCanceled); if (config.signal) { config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled); } } // Send the request if (utils.isStream(data)) { data.on('error', function handleStreamError(err) { reject(enhanceError(err, config, null, req)); }).pipe(req); } else { req.end(data); } }); } at encode (/workspace/node_modules/firebase-functions/lib/common/providers/https.js:162:11) at encode (/workspace/node_modules/firebase-functions/lib/common/providers/https.js:156:22) at encode (/workspace/node_modules/firebase-functions/lib/common/providers/https.js:156:22) at encode (/workspace/node_modules/firebase-functions/lib/common/providers/https.js:156:22) at /workspace/node_modules/firebase-functions/lib/common/providers/https.js:334:22 at processTicksAndRejections (internal/process/task_queues.js:97:5) First logger logs the parameter i gave correctly and the logger that logs data is in this format: ...["api.coingecko.com:443::::::::::::::::::"]},"keepAliveMsecs":1000,"maxFreeSockets":256,"scheduling":"fifo","keepAlive":false,"maxSockets":null},"_removedConnection":false,"writable":true},"status":200,"data":{"prices":[[1615345414698,37.27069164629981],[1615349310788,36.95627388647297],[1615352802175,37.48630338203377],[1615356202751,37.46442850999597],[1615360079361,37.642735963063906],[1615363905145,38.29435586902702],[1615367492353,38.313292928237594],[1615370461299,38.75503558097479],[1615374138056,38.24406575020552],[1615377815960,38.237026584388175],[1615381321332,38.93964664468625],[1615384813000,39.262646397955635],[1615388739874,39.15882057568881],[1615392094129,38.94488140309047],[1615395966875,38.79820936257378],[1615399312625,38.51637055616189],[1615403055037,38.59237008394828],[1615406529740,38.44087305010874],[1615410281814,37.71855645797291],[1615414278815,38.374824600586976],[1615417716420,38.4538669693684],[1615421045728,37.62772478442999],[1615425672990,36.8826465121472],[1615429587089,37.41958697414903],[1615432278494,37.34865694722488],[1615435254265,37.16289143388951],[1615439122292,37.14731463575248],[1615442523394,36.801517989796814],[1615446290102,37.02248224990424],[1615450361470,36.164787531097126],[1615453299572,36.46191265162147],[1615457172317,36.174755169666334],[1615460886498,37.05778010952229],[1615464298322,37.336909500902365],[1615469586325,37.56497212211488],[1615472126260,37.83046394206218],[1615474882979,37.252561357731096],[1615478498201,36.56190097084664],[1615482336185,36.83824760787625],[1615485957910,36.89351702770813],[1615489642151,37.589229946501746],[1615493390438,37.33184737771527],[1615496666244,37.29234576242379],[1615500577712,37.284260441548426],[1616866645601,1137195941.0307472],[1616870299925,1089416195.9864128],[1616873841648,1074341877.495249],[1616877368137,1061555457.3375872],[1616880970910,1077775411.1216433],[1616884693948,1064594490.6022671],[1616887998472,1087481667.611567],[1616891397951,1068140794.5197278],[1616894759953,1078753362.1719048],[1616898371565,1053546315.1245787],[1616902002474,1052498816.7223371],[1616905584364,1026915395.5541993],[1616909101481,1022271206.3215427],[1616912730390,997185793.1210617],[1616916434482,972130048.6316774],[1616919928611,988711196.2721183],[1616923534317,987299160.6191593],[1616926264719,975360472.6011684],[1616930074136,958327264.7346151],[1616933292776,935085970.8922312],[1616936940791,896217168.3654604],[1616940936847,878876312.6707534],[1616944090304,890504985.5476977],[1616948321869,896715385.5657766],[1616952007508,870767231.0865391],[1616955544207,880601758.4610194],[1616958381375,896794852.1077055],[1616962022167,929362788.5783823],[1616966479654,927502494.4691795],[1616969648773,880385481.5284289],[1616973545649,862329007.9935848],[1616977463095,840138544.6360805],[1616980359587,849727926.595521],[1616984356096,820616225.3306137],[1616987602367,898085663.0760688],[1616990444958,890215727.4112909],[1616995470635,914823340.6343507],[1616999032159,890922230.685704],[1617002651977,937214914.0703756],[1617005329558,976030203.3879734],[1617009370471,1061898884.4388478],[1617012348377,1111994349.2592206],[1617015705482,1175310227.1595278],[1617019895549,1217044915.3900926],[1617022941451,1204239369.9336267],[1617027118715,1225123359.1178432],[1617031210170,1191418570.9198012],[1617033728601,1257085051.9742537],[1617037882992,1261291734.3667347],[1617041858553,1265805909.4506621],[1617044547418,1261869965.5784621],[1617049418534,1225924891.220988],[1617052450394,1200646247.466799],[1617055896172,1209247034.0807025],[1617059684123,1249662106.3996315],[1617062561979,837849935.5380555],[1617066155823,1261094295.2039979],[1617070572708,1244044711.3556864],[1617074210159,1178503497.252399],[1617077106612,1184744920.254339],[1617080571662,1219164970.9205332],[1617084836477,1174744890.1399443],[1617087739776,1236332180.5454476],[1617092763739,1121685108.4046226],[1617096303391,1074005978.1362224],[1617100013739,1075898891.906641],[1617102136947,1041120230.0169744],[1617106411165,1021062028.7444541],[1617110588848,1004207600.6385714],[1617114148509,983098685.435342],[1617117449987,983878432.6976557],[1617120868725,943893192.0239582],[1617123806180,948379973.8680001],[1617128347360,948328240.0510467],[1617131244094,923477307.6495335],[1617134866719,918321070.6284192],[1617138697011,960178009.2986945],[1617142067857,974105207.7725881],[1617146083923,973959760.0729104],[1617149999086,959500047.5209063],[1617153094367,1007753562.6156206],[1617156698445,1021534121.1115336],[1617160175611,1028067427.0339341],[1617163928330,1007755251.8882328],[1617166924538,1023240773.0466446],[1617171886674,1037535813.1806505],[1617175133694,1101375379.7094195],[1617178435173,1136688478.90344],[1617182857658,1208366620.2561867],[1617185353773,1208823054.3509212],[1617188828477,1234197192.568771],[1617193393471,1707076315.380663],[1617196301983,1845668637.7358408],[1617199516026,1901877634.1385415],[1617203681947,2015292037.1305778],[1617207515426,2141098631.115179],[1617210224998,2343473154.2871637],[1617214323265,2329074198.4966955],[1617217968405,2461828129.1798186],[1617221653017,2493042958.539376],[1617224582971,2532015555.7692595],[1617228589364,2508661361.110037],[1617232204720,2590057969.924583],[1617235260464,2749780924.550207],[1617239367664,2791689438.967896],[1617243152558,2778422749.5901804],[1617246573894,2802892972.2612605],[1617250114952,2795446026.902383],[1617253276300,2837092221.188881],[1617257741390,2957061611.281718],[1617261111556,3025594776.954216],[1617264301698,3140730366.12618],[1617267704421,3230797741.627739],[1617272276500,3247001347.7404704],[1617275862720,3182990384.8873067],[1617279129292,2889317168.9977646],[1617283053665,2753527702.506779],[1617287046529,2700392654.8781624],[1617290204012,2616296684.424929],[1617293298853,2494255828.9768047],[1617296557242,2383424694.8900166],[1617301325511,2288268623.177356],[1617303766777,2297155897.636895],[1617307669347,2314935325.319679],[1617311721980,2259716784.056617],[1617314946823,2267889595.9127536],[1617319572007,2174169254.528509],[1617323182318,2097690604.8152165],[1617326033792,2110975746.1916978],[1617329489226,2126100629.800452],[1617332409284,2193182655.044224],[1617337211709,2199847063.5248647],[1617340611316,2167549077.601362],[1617344146863,2110348803.8388174],[1617347361962,2023115590.5637138],[1617351380142,1864316761.5098753],[1617354151186,1788973202.0040677],[1617359277447,1731207666.0376515],[1617361312976,1418566500.3106787],[1617366169158,1693859181.5518322],[1617369860769,1656689094.290342],[1617372306072,1660176536.7450612],[1617376754676,1722154482.4234965],[1617379285817,1915067128.493045],[1617383311995,1982773491.2907202],[1617387963188,1985155493.939231],[1617391564495,1827213471.6221747],[1617395202777,1932891922.7380657],[1617398214973,1937931474.560893],[1617401809690,1961473630.4188676],[1617405699909,1952347409.661483],[1617409553080,2172811188.054834],[1617412963837,2431917537.219363],[1617416445822,2666886575.1140027],[1617420431122,2769520722.4907126],[1617422613890,2797409323.779513],[1617427393260,2895546310.6951184],[1617431058021,2894169435.883223],[1617433696700,2651591430.614699],[1617437513773,3448548871.8910036],[1617441138039,3537764498.5278754],[1617444820385,3662623380.0181885],[1617448128419,3729999481.3895626],[1617452094944,3741683833.307362],[1617457034540,3761774670.321721],[1617460631688,3809173022.555833],[1617464335978,3711591162.8519845],[1617467879738,3759143118.4621553],[1617471447610,3693936894.7524076],[1617474960418,3833857114.2069917],[1617478639837,3888109113.59996],[1617482233320,3857034438.9984646],[1617485821346,3898924734.2645984],[1617489477282,3952661186.2182713],[1617493109729,4002501827.9437523],[1617495709286,3872814933.0218143],[1617499443431,3939579930.8108554],[1617503699037,3663106636.5813146],[1617507443725,3808705623.491391],[1617510706891,3786240536.055139],[1617512446242,3717882675.3539762],[1617516040645,3722966733.2957063],[1617519813304,3482249884.952562],[1617523351916,3345586253.508183],[1617526909722,3327000473.8244348],[1617530664916,3181835266.2617188],[1617534176048,3094776290.1306324],[1617537924632,3064167829.684326],[1617541493704,3112790145.252149],[1617545018360,2989449570.670528],[1617548594506,3016965749.017692],[1617552471191,2973530338.557288],[1617555933696,2759208177.1915674],[1617559387440,2662906186.1813793],[1617563034515,2521716547.9565806],[1617566483711,2454800946.788864],[1617570325792,2412175803.4922743],[1617573668989,2381142461.766321],[1617577282876,2228904400.2017546],[1617580896737,2203439508.717633],[1617584514686,2083961834.3200803],[1617588367701,1922511436.832222],[1617591869391,1816453643.1859522],[1617595346098,1783362433.1356776],[1617599069131,1767878927.408502],[1617602711113,1782121869.0062866],[1617606278078,1784322317.8294444],[1617609891135,1785304724.1970084],[1617613319383,1792007217.4012969],[1617617302304,1808002080.6732872],[1617620901014,1821923720.87615],[1617624265084,1769426364.6123836],[1617629555312,1731155926.337212],[1617631504259,1735378701.9021676],[1617635133537,1942437073.2385755],[1617638780500,1938122743.6976163],[1617642119732,1932182393.8447528],[1617645707597,1918416705.3436842],[1617649325384,1925855235.7182896],[1617653252063,1944708214.0244768],[1617656889033,1932665022.73478],[1617660329160,1943687775.1192245],[1617663683699,1971924479.2343264],[1617667435208,2101421530.2666874],[1617672769205,2175322213.812557],[1617674524812,2168578229.7784457],[1617678186353,2149217571.1759067],[1617681915267,2132725563.885806],[1617685469475,1907950838.2268875],[1617689189705,2026223167.4473426],[1617692670953,1991840998.8517568],[1617696101989,1958389716.0448081],[1617699877898,2027665770.2623076],[1617703590445,2045913908.1590445],[1617707076556,2057724347.183567],[1617710622851,1722203248.9530182],[1617714225215,2160140597.446546],[1617717905528,2192080372.5552874],[1617721488585,2199844279.449877],[1617724918808,2244159138.5689125],[1617728548093,2263548854.897557],[1617732187891,2106855536.9938018],[1617735969816,2268365061.664965],[1617739538518,1863113060.588111],[1617742875565,2296819840.9881096],[1617746516853,2308037223.56185],[1617750327052,2297405821.9954567],[1617754017835,2215648462.217197],[1617758617023,2112353884.9607923],[1617761085616,2094123582.0260437],[1617764518134,2101292245.7045105],[1617768287923,2104106865.0792534],[1617771810289,2127056476.4717],[1617775566730,2152196953.3590703],[1617778865860,2160666464.579131],[1617782881414,2201171213.1865735],[1617786249160,2203934869.139618],[1617789807394,2329117281.806726],[1617793383957,2333039138.899913],[1617796986959,2491205752.3653517],[1617800521125,2652604590.3673797],[1617804331429,2692817000.168284],[1617807822435,2121796914.212729],[1617811418506,2538097921.330415],[1617815037057,2572049083.87979],[1617818698211,2550478468.4248347],[1617822347031,2541491737.3311806],[1617825969097,2609118564.630648],[1617829326876,2651351577.1099257],[1617833305171,2429954572.560337],[1617837011298,2435043578.3313527],[1617840572965,2394428204.082167],[1617843841041,2446826032.07983],[1617848315742,2395082349.188743],[1617850339793,2376349751.741466],[1617852591890,2385498650.2366877],[1617855126472,2380054416.699361],[1617858732962,2424505564.216302],[1617862619633,2434391633.272485],[1617865876330,2410962812.9744062],[1617869233838,2516114320.406959],[1617872539799,2437748581.3302546],[1617876293610,2247205079.171164],[1617880005259,2149347865.150653],[1617883394235,1893777066.5168178],[1617886836203,1757412804.559377],[1617892197847,1668727963.8671286],[1617894162445,1631584545.4824028],[1617897737215,1596293896.725426],[1617901282046,1525523967.3370435],[1617905003853,1370316987.26801],[1617908631874,1358993841.079183],[1617912335250,1404691449.9164236],[1617915995319,1379405950.1047523],[1617919567600,1366246502.7408085],[1617923270275,1289254721.1461022],[1617926622919,1386402238.6371279],[1617930228859,1384851642.1789908],[1617933705891,1365548610.2907162],[1617937372258,1357266138.9978309],[1617941122560,1335764096.6047564],[1617944870896,1322495289.1105938],[1617948462328,1283751933.8339043],[1617951863802,1272489837.990008],[1617955666499,1259096045.8789752],[1617958890026,1247182948.0102005],[1617962609987,1220448763.9536679],[1617966256703,1222538618.147044],[1617969964555,1148194206.4734476],[1617973333279,1199996169.7479842],[1617977646106,1154935691.529977],[1617980504476,1144564005.003322],[1617984273306,1132822242.6037295],[1617987925282,1136733019.0246003],[1617991396077,1139090847.1565342],[1617994822351,1133169530.4839995],[1617998615234,1113274570.5832539],[1618002141094,1094805189.6349592],[1618005876460,1035579604.067034],[1618009282025,1090335224.3969038],[1618013035782,1063984405.5106469],[1618016519119,1058097513.8615906],[1618020114108,1065381128.0365001]]}} When this code invoked it logs data correctly but i can not return it at last. Anyone can help?
The problem appears to be that you're trying to return the entire Axios response. This cannot be serialised as JSON due to circular references. Simply return the response data instead. You can also make your URL construction simpler (and safer) using the params option exports.getDatas = functions.https.onCall(async ({ name, ts1, ts2 }) => { functions.logger.log(name); // 👇 note the destructure here const { data } = await axios.get( `https://api.coingecko.com/api/v3/coins/${encodeURIComponent(name)}/market_chart/range`, { params: { vs_currency: "usd", from: ts1, to: ts2, } } ); functions.logger.log(data); return { data }; });
NodeJS unable to modify a class obj
this is my first post in this forum. So please forgive me the misstakes. I want to write a NodeJS server which runs a WebSocket Server (npm ws module). The NodeJS server contains also a Class Obj which i want to modify a funciton afterwards over the Websocket server. My Problem is the modified functjion cant acces global variables. Can someone help if there is a solution for this problem or why this happes because if you do this without the Websocket it works. Here is the code: Server code: const WebSocket = require('ws'); // WebSocket Server const wss = new WebSocket.Server({ port: 8080 }); wss.on('connection', function connection(ws) { ws.on('message', function incoming(message) { try { message = JSON.parse(message); if (message.type == "handler") { handler.modify(message.data); console.log("modifyed"); } if (message.type == "func") { handler.modify_func(message.data); console.log("modifyed"); } if (message.type == "run") { eval(message.data); } } catch (error) { } }); }); // Modifying class class Handler { constructor() { this.functions = []; } modify(data) { let temp_class = new Function('return ' + data)(); temp_class.functions.forEach(element => { if (this.functions.indexOf(element) == -1) { this.functions.push(element) } this[element] = temp_class[element]; }); } modify_func(data) { let temp_func = new Function('return ' + data)(); this[temp_func.name] = temp_func; } test_func_from_orginal() { console.log("test_func_from_orginal says:"); console.log(test_val); } } var test_val = "this is the global variable"; var handler = new Handler(); Client code: const WebSocket = require('ws'); //WebSocket Client var ws = new WebSocket('ws://localhost:8080'); ws.on('open', function open(event) { // ws.send(JSON.stringify({ type: "handler", data: Handler.toString() })) ws.send(JSON.stringify({ type: "func", data: test_func_from_func.toString() })) console.log("open") }); //Class Module class Handler { static get functions() { return ["test"]; } static test_func_from_class() { console.log("test_func_from_class sayes:") console.log(test_val); } } function test_func_from_func() { console.log("test_func_from_func sayes:") console.log(test_val); } setTimeout(function () { ws.send(JSON.stringify({ type: "run", data: 'handler.test_func_from_orginal()' })) }, 1000); // setTimeout(function () { ws.send(JSON.stringify({ type: "run", data: 'handler.test_func_from_class()' })) }, 1000); setTimeout(function () { ws.send(JSON.stringify({ type: "run", data: 'handler.test_func_from_func()' })) }, 1000);
Ok, so this is what it's all about - a simple mistake. If you cut out all the websocket stuff (which is not really relevant here, as strings, and not contexts, got passed from and back anyway), you'll get this: class ServerHandler { constructor() { this.functions = []; } modify(data) { let temp_class = new Function('return ' + data)(); // not sure why not just `eval(data)` btw temp_class.functions.forEach(funcName => { if (this.functions.indexOf(funcName) == -1) { this.functions.push(funcName) } this[funcName] = temp_class[funcName]; }); } } class ClientHandler { static get functions() { return ["test_func_from_class"]; // not "test" as in your example // you actually don't even need this registry: // all the static methods can be collected in runtime } static test_func_from_class() { console.log("test_func_from_class sayes:") console.log(test_val); } } var test_val = 42; var handler = new ServerHandler(); handler.modify(ClientHandler.toString()); eval(`handler.test_func_from_class()`); // 42 This all works fine, as there's no longer a mismatch between a name of method stored in static get functions ("test") and actual name of that method ("test_func_from_class"). The trick is that all the static functions created along with that temporary class are scoped the same way any other entity created in ServerHandler; that's how they 'see' that test_val. But 'works' here is about mere possibility of this approach from technical perspective, and not about feasibility. Both new Function and eval with arbitrary input are very dangerous security holes - and they're left wide open here.
I found now a solution for my problem. Server Code const WebSocket = require('ws'); // WebSocket Server const wss = new WebSocket.Server({ port: 8080 }); wss.on('connection', function connection(ws) { ws.on('message', function incoming(message) { message = JSON.parse(message); try { if (message.type == "run") { eval(message.data); } if (message.type == "obj_handler") { handler.modify(JSON.parse(message.data)); } } catch (error) { console.log(error); } // console.log('received: %s', message); }); ws.send('something'); }); class ServerHandler { constructor() { this.data = "hi"; } modify(data) { for (const func in data) { this[func] = eval(data[func]); } } } var test_val = 42; var handler = new ServerHandler(); Client Code: const WebSocket = require('ws'); //WebSocket Client try { var ws = new WebSocket('ws://localhost:8080'); ws.on('open', function open(event) { ws.send(JSON.stringify({ type: "obj_handler", data: update.convert() })) }); } catch (error) { } // Needed Update with 2 new Functions update = { func_test_global: () => { console.log(test_val); }, func_test_this: _ => { console.log(this.data); }, convert: function () { let new_update = {}; for (const func in this) { if (func != "convert") new_update[func] = "" + this[func]; } return JSON.stringify(new_update) } } // setTimeout(function () { ws.send(JSON.stringify({ type: "run", data: 'handler.func_test_global()' })) }, 1000); // setTimeout(function () { ws.send(JSON.stringify({ type: "run", data: 'handler.func_test_this()' })) }, 1000);
TypeError: Cannot read property 'charCodeAt' of undefined - Button sometimes does not work
I'm updating a Facebook ChatBot to DialogFlow Version 2. I have a problem with buttons, they don't work the first time, but if the user sends a text message, and then try again, the buttons start working. I'm working whit Heroku and Node.js, these are the results of heroku log This is my function sendToDialogFlow async function sendToDialogFlow(sender, textString, params) { try { const sessionPath = sessionClient.sessionPath( config.GOOGLE_PROJECT_ID, sessionIds.get(sender) ); const request = { session: sessionPath, queryInput: { text: { text: textString, languageCode: config.DF_LANGUAGE_CODE, }, }, queryParams: { payload: { data: params } } }; const responses = await sessionClient.detectIntent(request); const result = responses[0].queryResult; handleDialogFlowResponse(sender, result); } catch (e) { console.log('error'); console.log(e); } } And here it is handleDialogFlowResponse function function handleDialogFlowResponse(sender, response) { let responseText = response.fulfillmentMessages.fulfillmentText; let messages = response.fulfillmentMessages; let action = response.action; let contexts = response.outputContexts; let parameters = response.parameters; var delay = 4000; if (isDefined(action)) { sendTypingOn(sender); setTimeout(function(){ sendTypingOff(sender); handleDialogFlowAction(sender, action, messages, contexts, parameters); },delay); } else if (isDefined(messages) && (messages.length == 1 && messages[0].type != 0 || messages.length > 1) ) { sendTypingOn(sender); setTimeout(function(){ sendTypingOff(sender); handleMessages(messages, sender); },delay); } else if (responseText == '' && !isDefined(action)) { } else if (isDefined(responseText)) { sendTypingOn(sender); setTimeout(function(){ sendTypingOff(sender); sendTextMessage(sender, responseText); },delay); } } Thank you
Comparing 2 attributes using the function "some"
var e = require("./myApp.js"); var myServer = e.CreateServer(1337); myServer.Register("/", "GET", function (req, res) { res.end("J") }); myServer.Register("/", "GET", function (req, res) { res.end("Ja") }); myServer.Start(); This is my "Wrapper": module.exports = (function () { function _createServer(port) { var routingTable = []; var port = port; var server = require('http').createServer(); function _start() { server.listen(port); console.log("Server was started"); }; function RegisterRecord(url, method, fnc) { this.url = url; this.method = method; this.fnc = fnc; }; function _register(newUrl, newMethod, newFnc) { if (_checkInput(newUrl, newMethod)) console.log("Register failed! Record with same URL and Method already exist"); else { routingTable.push(new RegisterRecord(newUrl, newMethod, newFnc)); console.log("Register success!"); } }; function _checkInput(newUrl, newMethod) { return routingTable.some(function fnc(record) { record.url == newUrl && record.method == newMethod }); }; return { Start: _start, Register: _register, ShutDown: _shutDown }; }; return { CreateServer: _createServer }; })(); So the most important functions are "_register" and "checkInput". My aim is that the same URL and Method are only allowed on time in the array routingTable. So when I execute the programm, the Command Promp prints two times Register success. But "/" and "GET" should only be allowed one time. How can I compare the URL and method so that they can be unique? PS: The "Wrapper" is in the JS File "./MyApp.js"
You need filter: function _checkInput(newUrl, newMethod) { return routingTable .filter( function(el) { return el.url === newUrl && el.method === newMethod; }) .length > 0; }; Upd. Of course, you can use the some - you just forgot to return a value from it: function _checkInput(newUrl, newMethod) { return routingTable .some( function(el) { // Need return return el.url === newUrl && el.method === newMethod; }) };