Sending image buffer to node.js tcp server - javascript

I am trying to send image data from my TCP client to my TCP server both written in node.js
I have already tried doing it this way
client:
function onData(socket, data) {
var data = Buffer.from(data).toString()
var arg = data.split(',')
var event = arg[0]
console.log(event)
if (event == 'screenshot') {
console.log(hostname)
console.log('control client uid ' + arg[1] + 'then we screenshot')
screenshot()
.then(img => {
console.log(img)
socket.write('screenshotData,' + ',' + hostname + ',' + img)
socket.write('stdout,' + arg[2] + ',Screenshot')
})
.catch(err => {
console.log(err)
socket.write('error', err)
})
}
}
server:
sock.on('data', function(data) {
//right here i need to parse the first 'EVENT' part of the text so i can get cusotom tcp events and
var data = Buffer.from(data).toString()
var arg = data.split(',')
var event = arg[0]
if (event == 'screenshotData') {
agentName = arg[1]
img = arg[2]
console.log('agent-name ' + agentName)
console.log('screnshotdata' + img)
var dt = dateTime.create()
var formattedTime = dt.format('Y-m-d-H-M-S')
var folder = 'adminPanel/screenshots/'
var filename = formattedTime + '-' + agentName + '.png'
console.log(filename)
fs.writeFile(folder + filename, img, function(err) {
console.log(err)
})
}
})
I had to build some rudimentary event system in TCP. If you know a better way then let me know. Anyways, the client takes a screenshot and then it does socket.write('screenshotData', + ',' + hostname + ',' img).
But it sends the data in multiple chunks as my console is showing random gibberish as a new event many times so I don't even know how I would do this. Any help would be great.

You are treating your TCP stream as a message-oriented protocol, in addition to mixing encodings (your image Buffer is simply concatenated into the string).
I suggest you switch TCP streams with websockets. The interface remains largely the same (read replaced with message events, stuff like that) but it actually behaves like you are expecting.
Working server:
const WebSocket = require('ws');
const fs = require('fs');
const PORT = 3000;
const handleMessage = (data) => {
const [action, payload] = data.split(',');
const imageData = Buffer.from(payload, 'base64');
const imageHandle = fs.createWriteStream('screenshot.jpg');
imageHandle.write(imageData);
imageHandle.end();
console.log(`Saved screenshot (${imageData.length} bytes)`);
};
const wss = new WebSocket.Server({port: PORT});
wss.on('connection', (ws) => {
console.log('Opened client');
ws.on('message', (data)=>handleMessage(data));
});
console.log('Server started');
client:
const WebSocket = require('ws');
const screenshot = require('screenshot-desktop');
const PORT = 3000;
const sendImage = ( client, image ) => {
const payload = image.toString('base64');
const message = ["screenshot", payload].join(',');
console.log(`Sending ${image.length} bytes in message ${message.length} bytes`);
client.send(
message,
() => {
console.log('Done');
process.exit(0);
}
);
};
const client = new WebSocket('ws://localhost:'+PORT+'/');
client.on('open', () => {
console.log('Connected');
screenshot().then( image => sendImage(client, image) );
});

if you specifically want to transfer an image type file, then the best-suggested way is to deal with b64 data. i.e convert your image to a b64 and send the data over a channel, and after receiving it in the server, you can convert it into a .jpg/.png again.
For reference https://www.npmjs.com/package/image-to-base64

Related

UDP pinger timeout in javascript dgram node

So, for a course i'm taking, we're coding a UDP pinger in Javascript, using Node.js and Dgram. We've been given the following assignment:
Create the client code for an application. Your client should send 10 ping messages to the target UDP server. For each message, your client should calculate the round trip time from when the package is sent to when the response is received. Should a package be dropped along the way, the client is to handle this as well. This should be done by having the client wait 1 second for a response after sending each package. If no reply is received, the client should log accordingly (package lost, no response, timeout, etc.) and send a new package to try again. However, the total amount of packages sent should still only be 10. The client should also calculate a percentage of packages lost/no response received, and log this before connection is closed.
THis if course seems rather straight forward, and I thought so. I've been coding it for a while, and I'm almost finished, but I'm having issues with the aspect of making the client send a package, await response, and then act accordingly.
So far, what my code does is basically to send a ping, and when a pong is received, it sends another ping. What I can't figure out is how to make it log that a response wasn't received before sending the next package. In other words, I know how to make it react to a received response, I just don't know how to make it respond if no response is given within a set timeframe. I've tried playing around with if-statements and loops, as well as async functions, but I haven't made it work yet, so now I'm asking for help.
Code is here:
const dgram = require("dgram");
const ms = require("ms");
var client = dgram.createSocket("udp4");
const PORT = 8000;
const HOST = "localhost";
let today = "";
let t0 = "";
let t1 = "";
let RTT = "";
let sentPackages = "";
let receivedPackages = "";
const messageOutbound = Buffer.from("You Up?");
sendPackage();
const x = setInterval(sendPackage, 1000);
client.on("message", (message, remote) => {
receivedPackages++
today = new Date();
t1 = today.getTime();
console.log(
`Message from: ${remote.address}:${remote.port} saying: ${message}`
);
RTT = ms(t1 - t0, { long: true });
console.log(RTT);
const x = setInterval(sendPackage, 1000);
});
client.on('error', (err) => {
console.log(`server error:\n${err.stack}`);
server.close();
});
async function sendPackage() {
if (sentPackages < 10) {
client.send(messageOutbound, 0, messageOutbound.length, PORT, HOST, () => {
sentPackages++
let today = new Date();
t0 = today.getTime();
console.log(
`message has been sent to ${HOST}:${PORT}. Message sent at: ${t0}`
);
});
} else {
calculateLoss();
client.close();
}
};
function calculateLoss() {
let amountLost = sentPackages - receivedPackages;
let percentageLoss = amountLost / sentPackages * 100
console.log(amountLost);
console.log(percentageLoss +"% of packages lost");
};
I would use async / await to simply wait 1000ms / 1s between messages, then keep track of all messages in an array.
We identify messages with a uuid, so we can ensure that messages we receive can be matched to those we send.
We can then log all the required statistics afterwards:
const dgram = require("dgram");
const uuid = require('uuid');
const PORT = 8000;
const HOST = "localhost";
const client = dgram.createSocket("udp4");
// Array that keeps track of the messages we send
let messages = [];
// When we get a message, decode it and update our message list accordingly...
client.on("message", (messageBuffer, remote) => {
let receivedMessage = bufferToMessage(messageBuffer);
// Find the message we sent and set the response time accordingly.
let message = messages.find(message => message.uuid === (receivedMessage ||{}).uuid);
if (message) {
message.responseTimestamp = new Date().getTime();
}
});
client.on('error', (err) => {
console.log(`server error:\n${err.stack}`);
server.close();
});
function createMessage() {
return { uuid: uuid.v4() };
}
function messageToBuffer(message) {
return Buffer.from(JSON.stringify(message), "utf-8");
}
function bufferToMessage(buffer) {
try {
return JSON.parse(buffer.toString("utf-8"));
} catch (error) {
return null;
}
}
// Wait for timeout milliseconds
function wait(timeout) {
return new Promise(resolve => setTimeout(resolve, timeout));
}
function sendMessage(message, port, host) {
// Save the messages to our list...
messages.push(message);
console.log(`Sending message #${messages.length}...`);
// Set the time we send out message...
message.sentTimestamp = new Date().getTime();
let messageBuffer = messageToBuffer(message);
return new Promise((resolve, reject) => {
client.send(messageBuffer, 0, messageBuffer.length, port, host, (error, bytes) => {
if (error) {
reject(error);
} else {
resolve(bytes);
}
})
});
}
async function sendMessages(messageCount, port, host, timeout) {
for(let messageIndex = 0; messageIndex < messageCount; messageIndex++) {
let message = createMessage();
await sendMessage(message, port, host);
await wait(timeout);
if (message.responseTimestamp) {
console.log(`Response received after ${message.responseTimestamp - message.sentTimestamp} ms...`);
} else {
console.log(`No response received after ${timeout} ms...`);
}
}
logStatistics(messages);
}
function logStatistics(messages) {
let messagesSent = messages.length;
let messagesReceived = messages.filter(m => m.responseTimestamp).length;
let messagesLost = messagesSent - messagesReceived;
console.log(`Total messages sent: ${messagesSent}`);
console.log(`Total messages received: ${messagesReceived}`);
console.log(`Total messages lost: ${messagesLost} / ${(100*messagesLost / (messages.length || 1) ).toFixed(2)}%`);
if (messagesReceived > 0) {
console.log(`Average response interval:`, messages.filter(m => m.responseTimestamp).reduce((averageTime, message) => {
averageTime += (message.responseTimestamp - message.sentTimestamp) / messagesReceived;
return averageTime;
}, 0) + " ms");
}
}
sendMessages(10, PORT, HOST, 1000);

How can I open multiple WebSocket streams

I am trying to stream data from the Binance WebSocket API, I have it working for one symbol at a time.
if ("WebSocket" in window) {
//open websocket
var symbols = getSymbol();
//console.log(symbols);
symbols.forEach(function(entry) {
console.log(entry);
})
var ws = new WebSocket("wss://stream.binance.com:9443/ws/btcusdt#miniTicker")
ws.onopen = function() {
console.log("Binance connected...");
};
ws.onmessage = function(evt) {
var r_msg = evt.data;
var jr_msg = JSON.parse(r_msg);
}
ws.onclose = function() {
console.log("Binance disconnected");
}
} else {
alert("WebSocket is NOT supported");
}
the line var symbols = getSymbol(); creates an array of 431 symbols, my logic (and what I am trying to achieve) is to add the new websocket() to the forEach and stream price data from all of the currency pairs.
I'm not sure if this is possible at all or what a better solution would be but I wish to stream and display live data from the api.
Your idea about putting the new WebSocket() inside the for-each should work. However,
I'm not sure if you are allowed to opening hundreds of web sockets from the same tab, and there could also be some performance issues related to it.
According to the API documentation, it is possible to open just one web socket which will send you data from a list of streams, or even just all streams. Just construct the URLs like this:
Specific streams: wss://stream.binance.com:9443/ws/stream1/stream2/stream3
All streams: wss://stream.binance.com:9443/ws/!miniTicker#arr
Here is a code sample that takes these things into consideration. By default this code uses the URL for all streams, but it also has the code (commented out) that uses specific streams.
let streams = [
"ethbtc#miniTicker","bnbbtc#miniTicker","wavesbtc#miniTicker","bchabcbtc#miniTicker",
"bchsvbtc#miniTicker","xrpbtc#miniTicker","tusdbtc#miniTicker","eosbtc#miniTicker",
"trxbtc#miniTicker","ltcbtc#miniTicker","xlmbtc#miniTicker","bcptbtc#miniTicker",
"adabtc#miniTicker","zilbtc#miniTicker","xmrbtc#miniTicker","stratbtc#miniTicker",
"zecbtc#miniTicker","qkcbtc#miniTicker","neobtc#miniTicker","dashbtc#miniTicker","zrxbtc#miniTicker"
];
let trackedStreams = [];
//let ws = new WebSocket("wss://stream.binance.com:9443/ws/" + streams.join('/'));
let ws = new WebSocket("wss://stream.binance.com:9443/ws/!miniTicker#arr");
ws.onopen = function() {
console.log("Binance connected...");
};
ws.onmessage = function(evt) {
try {
let msgs = JSON.parse(evt.data);
if (Array.isArray(msgs)) {
for (let msg of msgs) {
handleMessage(msg);
}
} else {
handleMessage(msgs)
}
} catch (e) {
console.log('Unknown message: ' + evt.data, e);
}
}
ws.onclose = function() {
console.log("Binance disconnected");
}
function handleMessage(msg) {
const stream = msg.s;
if (trackedStreams.indexOf(stream) === -1) {
document.getElementById('streams').innerHTML += '<br/>' + stream + ': <span id="stream_' + stream + '"></span>';
trackedStreams.push(stream);
document.getElementById('totalstreams').innerText = trackedStreams.length;
}
document.getElementById('stream_' + stream).innerText = msg.v;
}
<span id="totalstreams"></span> streams tracked<br/>
Total traded base asset volume:<br/>
<div id="streams"></div>

Websocket sending blob object instead of string

I am somehow able to run Websocket but the problem is that it is sending me object blob on on message event while i want to send the text.
Here is my websocket server code:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 })
var sockets = [];
wss.on('connection', ws => {
//var id = ws.upgradeReq.headers['sec-websocket-key'];
//console.log("New connection id ::", id);
//w.send(id);
sockets.push(ws);
console.log("New client connected"+ ws);
ws.on('message', message => {
console.log(`Received message => ${message}`)
//var id = ws.upgradeReq.headers['sec-websocket-key'];
//var mes = JSON.parse(message);
//sockets[message.to].send(mes.message);
// console.log('Message on :: ', id);
//console.log('On message :: ', message);
sockets.forEach(w=> {
w.send(message);
});
})
ws.send('Welcome by server!')
})
Client side Code Excerpt
connection.onmessage = (e) => {
document.getElementById("ReceviedText").innerHTML += ("<li>" + e.data + "</li>");
// ReceviedText
console.log(e.data);
console.log(e);
var reader = new FileReader(e.data);
console.log(reader.result);
//console.log(reader.readAsText());
console.log(reader.readAsText(e.data));
}
I found that I can convert blob to string using file reader but it returning null.
I had the same issue with an object array. Fixed it by converting the data as a JSON string with JSON.stringify. On the client, you can get the data with JSON.parse.
Server
sockets.forEach(w => {
w.send(JSON.stringify(message));
});
Client
connection.onmessage = (message: object) => {
console.log(JSON.parse(message['data']));
}
I also faced the same issue. I can fix it by adding {binary:isBinary} in Server.
Here is my code:-
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(data,isBinary) {
wss.clients.forEach(function each(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(data, { binary: isBinary });
}
})
})
})
I had the same issue when I send the message via firefox web socket client extension.
On the server side, I fixed it by converting the data as a JSON string with JSON.stringify. On the client, you can get the data with JSON.parse.
Server
wss.clients.forEach(function each(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
console.log('data %s', data);
// client.send(data);
// this is to solve the issue where web socket client
// send data as blob instead of string
client.send(JSON.stringify(data));
}
});
Client
ws.onmessage = (e) => {
const arr = JSON.parse(e.data).data;
let newData = '';
arr.forEach((element) => {
newData+=String.fromCharCode(element);
});
console.log('newData ', newData);
};
I have resolved this issue..:
//index.js (Server)
const express = require('express');
const http = require('http');
const WebSocket = require("ws");
const PORT = 3000;
const server = http.createServer(express);
const wss = new WebSocket.Server({server});
wss.on('connection',function connection(ws){
ws.on('message',function incoming(message){
console.log("Received: "+message);
wss.clients.forEach(function each(client){
if(client!==ws && client.readyState===WebSocket.OPEN)
{
client.send(JSON.stringify(message));
}
});
});
});
server.listen(PORT,()=>console.log(`Server is listening to PORT ${PORT}`));
<!-- index.html page -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Client 1</title>
</head>
<body>
<input type="text" name="messageBox" id="messageBox">
<button type="button" id="sendBtn">Send</button>
<div class="container">
<div class="receive-message">
<p id="message"></p>
</div>
</div>
</body>
<script type="text/javascript">
var sendBtn = document.getElementById("sendBtn");
var messageBox = document.getElementById("messageBox");
var socket = new WebSocket("ws://localhost:3000");
sendBtn.addEventListener("click",()=>{
let val = messageBox.value;
socket.send(val);
});
socket.addEventListener("open",function(event){
socket.send("Connected.....");
});
socket.addEventListener('message',function(event){
var string_arr =JSON.parse(event['data']).data;
var string = "";
string_arr.forEach(element => {
string+=String.fromCharCode(element);
});
console.log(string);
});
</script>
</html>
FileReader.readAsText() is an event based API, as mentioned in MDN docs.
So you need to set reader.onload:
const reader = new FileReader();
reader.onload = function(evt) {
console.log(evt.target.result);
};
reader.readAsText(e.data);
Also, Blob.text() can be used.
websocket.addEventListener("message", e => {
e.data.text().then(txt=>console.log(txt))
});
Docs describes the difference between these two:
Blob.text() returns a promise, whereas FileReader.readAsText() is an
event based API. Blob.text() always uses UTF-8 as encoding, while
FileReader.readAsText() can use a different encoding depending on the
blob's type and a specified encoding name.
on the server side
ws.on('message', function message(data, isBinary) {
wss.clients.forEach(function each(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(data, { binary: isBinary });
}
});
});
and on the client side
socket.addEventListener('message', (event, isBinary) =>
console.log(event.data)
})
the isBinary parameter solved the problem for me
I had a particularly confusing situation, while using Koa, that required the client side to do double duty:
//server side
myCtx.websocket.send( JSON.stringify( message ) );
// client side
let msg = JSON.parse( event.data );
let data = JSON.parse( String.fromCharCode( ...msg.data ) );
On the server if I just sent the message, it would show up as a blob on the client side.
On the client side, after I parsed the event.data the data was a binary array, [ 123, 34, 116...] so had to do the String.fromCharCode() call. The three dots ... is the javascript spreader operator, to get the whole array.

Problems with sending data to HL7 server using node.js

I'm just trying to make a simple HL7 MLLP client using node.js
I made some code that creates connection with HL7 server via socket. It sends some data to server. Then it waits for some answer. For testing purposes I use HAPI TestPanel 2.0.1.
So, I have an issue. When I send data using my script to HAPI TestPanel, testpanel don't anwser me. In the testpanel's log it says that my client has connected to it and than nothing. When I turned on a debug option in testpanel, Log says that testpanel recieved bytes from my client, end then nothing else.
What is the wrong with my script?
Can anyone help me?
Thank you!
Here is my script:
const net = require('net');
const VT = String.fromCharCode(0x0b);
const FS = String.fromCharCode(0x1c);
const CR = String.fromCharCode(0x0d);
const clientOptions = {
host: '127.0.0.1',
port: 49360
};
const client = net.createConnection(clientOptions, () => {
var reqdata = 'MSH|^~\\&|HOSP|HIS|HOSP|PACS|20180104150804||ORM^O01|1|T|2.3\nZDS|1.2.398.7.1.1.2.494.0.1^^Application^DICOM';
reqdata = VT + reqdata + CR + FS + CR;
console.log(`${new Date()} connected to HL7 server!`);
console.log(reqdata);
client.write(new Buffer(reqdata, encoding = "utf8"));
});
client.on('data', (data) => {
var ansData = data.toString();
console.log(`${new Date()} HL7 answer data: ${ansData}`);
client.end();
});
client.on('error', (err) => {
var reqerror = `${new Date()} problem with request: ${err.message}`;
console.error(reqerror);
client.end();
console.log(`${new Date()} disconnected from HL7 server`);
});
client.on('end', () => {
console.log(`${new Date()} disconnected from HL7 server`);
});
Here is a screenshot of a testpanel's log:
Well, you are writing MLLP correctly:
reqdata = VT + reqdata + CR + FS + CR;
Though the first CR is not needed and following is OK:
reqdata = VT + reqdata + FS + CR;
But, the message that is received on HAPI Test Panel looks gibberish. The message is being HTML formatted somewhere. Review your code to keep it simple text.

IPFS in Javascript 'cat' function doesn't work

I created this testcase to prove that the cat method is not working for me using the IPFS javascript library. What am I doing wrong ? My console output does not draw anything from within the 'node.files.cat' function, its as if that (err,filestream) callback is not being called at all. I I know my multihash is somewhat working because if I change it I get a fatal error. However right now it is seemingly just locking up and pausing after NODE READY.
const IPFS = require('ipfs')
const path = require('path')
const os = require('os')
const fs = require('fs')
console.log('ipfs test ')
var mhash = "Qmc5LfkMVAhvzip2u2RjRBRhgVthtSokHsz4Y5bgaBCW2R";
// Create the IPFS node instance
const node = new IPFS()
node.on('ready', () => {
// Your node is now ready to use \o/
console.log('NODE READY')
/*
THIS WORKS
var test_rstream = fs.createReadStream( path.join(__dirname, '.', '/public/sample_land_file.json') )
var wstream = fs.createWriteStream(os.tmpdir() + '/lobc_cache/'+'Qmc5LfkMVAhvzip2u2RjRBRhgVthtSokHsz4Y5bgaBCW2R');
wstream.on('finish', function() {
console.log('Written ' + wstream.bytesWritten + ' ' + wstream.path);
test_rstream.close()
});
test_rstream.pipe(wstream);
*/
node.files.cat("Qmc5LfkMVAhvzip2u2RjRBRhgVthtSokHsz4Y5bgaBCW2R", function (err, filestream) {
console.log('WHY ISNT THIS FIRING ') // i never see this logged
console.log(filestream)
console.log(os.tmpdir())
if (!fs.existsSync(os.tmpdir() + '/lobc_cache')){
fs.mkdirSync(os.tmpdir() + '/lobc_cache');
}
var wstream = fs.createWriteStream(os.tmpdir() + '/lobc_cache/'+'Qmc5LfkMVAhvzip2u2RjRBRhgVthtSokHsz4Y5bgaBCW2R');
result = '';
wstream.on('finish', function() {
console.log('Written ' + wstream.bytesWritten + ' ' + wstream.path);
filestream.close()
});
filestream.pipe(wstream);
// wstream.end();
// file will be a stream containing the data of the file requested
})
// stopping a node
node.stop(() => {
// node is now 'offline'
})
})
node.on('start', () => {
console.log('NODE START')
})
This looks like a bug. A quick way to solve it is just to put the node.files.cat inside the callback for .on('ready'). Seems that bitswap is dropping requests before the node is online.
Let me know if this works.

Categories