Websocket sending blob object instead of string - javascript

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.

Related

how to send commands to AWS Session manager websocket url using xterm.js?

I have a websocket url created by AWS. URL is created by aws ssm start session using .net sdk.
Start session method gives me streamUrl, token and session ID.
URL is in following format:
wss://ssmmessages.ap-south-1.amazonaws.com/v1/data-channel/sessionidhere?role=publish_subscribe
There is actual session id at placeof "sessionidhere" that I can not share.
I want to open terminal on web using xterm.js. I've read that xterm.js can connect to websocket URL, send messages and receive outputs.
My javascript code is here :
<!doctype html>
<html>
<head>
<link href="~/xterm.css" rel="stylesheet" />
<script src="~/Scripts/jquery-3.4.1.js"></script>
<script src="~/Scripts/bootstrap.js"></script>
<script src="~/xterm.js"></script>
</head>
<body>
<div id="terminal"></div>
<script type="text/javascript">
var term = new Terminal({
cursorBlink: "block"
});
var curr_line = "";
var entries = [];
term.open(document.getElementById('terminal'));
const ws = new WebSocket("wss://ssmmessages.ap-south-1.amazonaws.com/v1/data-channel/sessionid?role=publish_subscribe?token=tokenvalue");
var curr_line = "";
var entries = [];
term.write("web shell $ ");
term.prompt = () => {
if (curr_line) {
let data = {
method: "command", command: curr_line
}
ws.send(JSON.stringify(data));
}
};
term.prompt();
ws.onopen = function (e) {
alert("[open] Connection established");
alert("Sending to server");
var enc = new TextEncoder("utf-8"); // always utf-8
// console.log(enc.encode("This is a string converted to a Uint8Array"));
var data = "ls";
console.log(enc.encode(data));
alert(enc.encode(data));
ws.send(enc.encode(data));
alert(JSON.stringify(e));
};
ws.onclose = function (event) {
if (event.wasClean) {
alert(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
} else {
// e.g. server process killed or network down
// event.code is usually 1006 in this case
alert('[close] Connection died');
}
};
ws.onerror = function (error) {
alert(`[error] ${error.message}`);
};
// Receive data from socket
ws.onmessage = msg => {
alert(data);
term.write("\r\n" + JSON.parse(msg.data).data);
curr_line = "";
};
term.on("key", function (key, ev) {
//Enter
if (ev.keyCode === 13) {
if (curr_line) {
entries.push(curr_line);
term.write("\r\n");
term.prompt();
}
} else if (ev.keyCode === 8) {
// Backspace
if (curr_line) {
curr_line = curr_line.slice(0, curr_line.length - 1);
term.write("\b \b");
}
} else {
curr_line += key;
term.write(key);
}
});
// paste value
term.on("paste", function (data) {
curr_line += data;
term.write(data);
});
</script>
</body>
</html>
Now, the session is being opened, I am getting alert of connection established. It's being successful connection, but whenever I try to send commands, the connection is being closed by saying 'request to open data channel does not contain a token'. I've tried to send command in 3 ways.
First is :
ws.send("ls")
second:
let data = {
method: "command", command: curr_line
}
ws.send(JSON.stringify(data));
But facing same error i.e. request to open data channel does not contain token, connection died
third:
var enc = new TextEncoder("utf-8");
var data = "ls";
ws.send(enc.encode(data));
For third, I'm not getting any error, but not getting output too... Can someone please help?
The protocol used by AWS Session manager consists of the following :
open a websocket connection on the stream URL
send an authentication request composed of the following JSON stringified :
{
"MessageSchemaVersion": "1.0",
"RequestId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"TokenValue": "<YOUR-TOKEN-VALUE>"
}
From this moment the protocol is not JSON anymore. It is implemented in the offical Amazon SSM agent which is required if you want start a SSM session from the AWS CLI. The payload must be sent & receive according this binary format
I had exactly the same requirement as you few months ago so I've made an AWS Session manager client library : https://github.com/bertrandmartel/aws-ssm-session for nodejs and browser. If you want more information about how the protocol works, checkout this
The sample code available for browser use xterm.js
First clone the project and generate websocket URL and token using aws-api with some utility script :
git clone git#github.com:bertrandmartel/aws-ssm-session.git
cd aws-ssm-session
npm i
npm run build
node scripts/generate-session.js
which gives you :
{
SessionId: 'xxxxxx-xxxxxxxxxxxxxx',
TokenValue: 'YOUR_TOKEN',
StreamUrl: 'wss://ssmmessages.eu-west-3.amazonaws.com/v1/data-channel/user-xxxxxxxxxxxxxx?role=publish_subscribe'
}
Then serve the sample app :
npm install http-server -g
http-server -a localhost -p 3000
go to http://localhost:3000/test/web, enter the websocket URI and token :
The sample code for browser :
import { ssm } from "ssm-session";
var socket;
var terminal;
const termOptions = {
rows: 34,
cols: 197
};
function startSession(){
var tokenValue = document.getElementById("tokenValue").value;
var websocketStreamURL = document.getElementById("websocketStreamURL").value;
socket = new WebSocket(websocketStreamURL);
socket.binaryType = "arraybuffer";
initTerminal()
socket.addEventListener('open', function (event) {
ssm.init(socket, {
token: tokenValue,
termOptions: termOptions
});
});
socket.addEventListener('close', function (event) {
console.log("Websocket closed")
});
socket.addEventListener('message', function (event) {
var agentMessage = ssm.decode(event.data);
//console.log(agentMessage);
ssm.sendACK(socket, agentMessage);
if (agentMessage.payloadType === 1){
terminal.write(agentMessage.payload)
} else if (agentMessage.payloadType === 17){
ssm.sendInitMessage(socket, termOptions);
}
});
}
function stopSession(){
if (socket){
socket.close();
}
terminal.dispose()
}
function initTerminal() {
terminal = new window.Terminal(termOptions);
terminal.open(document.getElementById('terminal'));
terminal.onKey(e => {
ssm.sendText(socket, e.key);
});
terminal.on('paste', function(data) {
ssm.sendText(socket, data);
});
}

Sending image buffer to node.js tcp server

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

Manage multiple Websocket client connection with node.js

I'm implementing a websocket client in node and my webhook's trying to handle multiple connections from a chatbot service. For example: a new user income, a websocket connection is established on an external chatbot service. The websocket URL is obtained through XMLHttpRequest in my code. And then I use this url to connect to the chatbot service using the ws object (new WebSocket('wssUrlObtainedThroughAjaxRequest','default-protocol')). So each user have a WebSocket. The question is that my code runs sequentially. So if two people sends message to my webhook node, things don't works properly because parallelism. Well, I'll post example code here to make it better to understand.
const express = require('express');
const PORT = process.env.PORT || 8002;
let WebSocket = require('ws');
let CONNECTIONS = new Map();
...
...
...
const app = express()
.use(bodyparser.urlencoded({extended: false}))
.use(bodyparser.json());
app.post('/', (req, res) => {
...
...
...
} else if (req.body.type === 'MESSAGE') {
let DM = req.body.space.name;
let msg = req.body.message.text;
ws = (CONNECTIONS.get(DM)!=null) ? CONNECTIONS.get(DM) : null;
if(ws==null || ws.readyState==3){
controlws.gerarURLWS();
ws = new WebSocket(controlws.urlws, 'talk-protocol');
CONNECTIONS.set(DM,ws);
}
// Executes on websocket openning
ws.onopen = function (event) {
console.log('Canal aberto;');
keepAliveWS();
ws.send(JSON.stringify(msgKoreAi(msg)));
}
if(ws.readyState==1)
ws.send(JSON.stringify(msgKoreAi(msg)));
ws.onmessage = async function (event) {
let resp = JSON.parse(event.data);
if (resp.type == "bot_response") {
text = resp.message[0].component.payload.text;
if(text==null){ // tem quick reply
//mount card hangouts response
let qreplies = resp.message[0].component.payload.payload.quick_replies;
card = '{"sections": [{"widgets": [{"buttons": [';
for(let i=0; i<qreplies.length; i++){
if(i!=qreplies.length-1)
card+='{"textButton": {"text": "'+qreplies[i].payload+'","onClick": {"action": {"actionMethodName": "'+qreplies[i].payload+'"}}}},';
else
card+='{"textButton": {"text": "'+qreplies[i].payload+'","onClick": {"action": {"actionMethodName": "'+qreplies[i].payload+'"}}}}';
}
card+=']}]}],"name": "respostas"}';
card = JSON.parse(card);
text = resp.message[0].component.payload.payload.text;
{
await assyncMessage(DM, text);
await assyncMessage(DM, card);
}
return;
}
//Send assync messages if synchronous was already sent
if(res.headersSent){
{
return await assyncMessage(DM, text);
}
}
else
return res.json({text});
}
}
return;
}
...
...
...
app.listen(PORT, () => {
console.log(`Server is running in port - ${PORT}`);
});

Live search using socket.io

How can I create live search using socket.io?
I use RethinkDB + Node + Express + Socket.io + Redux + React, I am listening to event (it is changefeed created using rethinkdb), which sends me lets say 10 items on client side and displaying them using react.
Now I want to create live search, which sends query to server, searches for results in DB, returns first 10 results and sends them to client with socket.io
// emit events for changes
r.table('stackoverflow_questions')
.changes({ includeInitial: true, squash: true })
.limit(10)
.run(connection)
.then(changefeedSocketEvents(socket, 'topic'))
-
// Socket.io events for changefeed
module.exports = function (socket, entityName) {
return function (rows) {
rows.each(function (err, row) {
if (err) { return console.log(err) } else if (row.new_val && !row.old_val) {
socket.emit(entityName + ':insert', row.new_val)
} else if (row.new_val && row.old_val) {
socket.emit(entityName + ':update', row.new_val)
} else if (row.old_val && !row.new_val) {
socket.emit(entityName + ':delete', { id: row.old_val.id })
}
})
}
}
I don't have Idea how you can achieve that using socket.io, do you have to create custom socket event listeners on the fly for every custom query? (It sounds ridiculous to me, I think, that there should be a simple way)
I found a solution, here is a bare minimum example:
// server.js
const express = require('express')
const app = express()
const http = require('http')
const server = http.Server(app)
const io = require('socket.io')(server)
app.use(express.static('client'))
io.on('connection', function(client){
setInterval(() => io.emit('found', 'dfasdfadsfasdfasdf'), 5000)
console.log('connected with socket: ' + client.id)
client.on('search', function (text) {
const data = Math.random()
io.emit('found', data + text)
})
client.on('disconnect', function(){})
})
app.get('/')
server.listen(3000)
-
<!- index.html ->
<!DOCTYPE html>
<html>
<head>
<script src="/socket.io/socket.io.js"></script>
<script src="./client.js"></script>
<title>socket-io-live-search</title>
</head>
<body>
<div id='search'>
<input type ='text' />
</div>
</body>
</html>
-
// client.js
var socket = io()
const loaded = () => {
const inputEl = document.querySelector('#search input')
inputEl.oninput = (e) => socket.emit('search', e.target.value)
}
socket.on('found', (data) => console.log('found: ' + data))
document.addEventListener('DOMContentLoaded', loaded, false)

Websockets: send messages and notifications to all clients except sender

I am developing chat based on websockets and webrtc. I would like to send messages to all connected users except sender but I cannot find suitable solution. To be more specific, I would like to send notifications to other connected users that new user has joined to the chat.
I am trying to give a unique ID to every connected user, but the first assigned ID is re-writed by every new user and I cannot diferentiate users.
Server:
// list of users
var CLIENTS=[];
var id;
// web server is using 8081 port
var webSocketServer = new WebSocketServer.Server({ port: 8081 });
// check if connection is established
webSocketServer.on('connection', function(ws) {
id = Math.random();
CLIENTS[id] = ws;
CLIENTS.push(ws);
ws.on('message', function(message) {
console.log('received: %s', message);
var received = JSON.parse(message);
if(received.type == "login"){
ws.send(message); // send message to itself
/* *********************************************************** */
/* *** Here I trying to check if message comes from sender *** */
sendNotes(JSON.stringify({
user: received.name,
type: "notes"
}), ws, id);
/* *********************************************************** */
}else if(received.type == "message"){
sendAll(message); // broadcast messages to everyone including sender
}
});
ws.on('close', function() {
console.log('user ' + CLIENTS[ws] + ' left chat');
delete CLIENTS[ws];
});
});
function sendNotes(message, ws, id) {
console.log('sendNotes : ', id);
if (CLIENTS[id] !== ws) {
console.log('IF : ', message);
for (var i = 0; i < CLIENTS.length; i++) {
CLIENTS[i].send(message);
}
}else{
console.log('ELSE : ', message);
}
}
function sendAll(message) {
for (var i=0; i < CLIENTS.length; i++) {
CLIENTS[i].send(message); // broadcast messages to everyone including sender
}
}
Client:
loginButton.addEventListener("click", function(){
name = usernameInput.value;
if(name.length > 0){
socket.send(JSON.stringify({
type: "login",
name: name
}));
}
});
function sendData() {
var data = dataChannelSend.value;
var userName = document.getElementById('greetingUser').innerHTML;
socket.send(JSON.stringify({
username : userName, // fetch user name from browser, after login
type : "message",
message : data
}));
}
socket.onmessage = function(message) {
var envelope = JSON.parse(message.data);
switch(envelope.type) {
case "login":
onLogin(envelope);
break;
case "message":
showMessage(envelope);
break;
}
};
I would highly appreciate If you could give me any hint. Thanks
Here is a very simple way of sending to everyone connected except the sender.
Create a broadcast function on your webSocketServer instance that will
take two params.
...
var webSocketServer = new WebSocketServer.Server({ port: 8081 });
...
/*
* method: broadcast
* #data: the data you wanna send
* #sender: which client/ws/socket is sending
*/
webSocketServer.broadcast = function(data, sender) {
webSocketServer.clients.forEach(function(client) {
if (client !== sender) {
client.send(data)
}
})
}
...
// On your message callback.
ws.on('message', function(message) {
...
// Note that we're passing the (ws) here
webSocketServer.broadcast(message, ws);
})
That's it, the broadcast method will send to each connected client
except the one who is sending.
Ok, so we are now storing the CLIENTS in a way that allows us to uniquely identify each client that is connecting, and store arbitrary information about them for later retrieval.
The code below will send the "notes" message to all clients, and THEN add the newly connecting client to the "all clients" list.
SERVER.JS:
var http = require('http'),
Static = require('node-static'),
WebSocketServer = new require('ws'),
// list of users
/*
We are now storing client data like this:
CLIENTS = {
uniqueRandomClientID: {
socket: {}, // The socket that this client is connected on
clientDetails: { // Any details you might wish to store about this client
username: "",
etc: "etc"
}
}
};
So now to get at the socket for a client, it'll be: CLIENTS[uniqueRandomClientID].socket.
Or to show a client's username, it'll be: CLIENTS[uniqueRandomClientID].clientDetails.username.
You might want to write a 'getClientByUsername' function that iterates the CLIENTS array and returns the client with that username.
*/
CLIENTS = {},
// web server is using 8081 port
webSocketServer = new WebSocketServer.Server({ port: 8081 });
// check if connection is established
webSocketServer.on('connection', function(ws) {
console.log('connection is established');
// Now using a randomly generated ID to reference a client. Probably should be better than Math.random :D
var wsID = Math.floor(Math.random() * 1000);
ws.on('message', function(message) {
console.log('received: %s', message);
var received = JSON.parse(message);
if(received.type == "login"){
// If a client with this login name doesnt exist already, its a new client
if(!CLIENTS[wsID]) {
doBroadcast(
{
"newuser": received.name,
type: "notes"
}
);
// Now add this new client to the list
CLIENTS[wsID] = {
socket: ws,
clientDetails: {
username: received.name
}
};
}
} else if(received.type == "message") {
doBroadcast(message); // broadcast messages to everyone including sender
}
});
ws.on('close', function(_event) {
if(CLIENTS[wsID]) {
console.log('user ' + CLIENTS[wsID].clientDetails.username + ' left chat');
delete CLIENTS[wsID];
}
});
/*
* Added this to 'catch' errors rather than just red dump to console. I've never actually done anything with this myself (I *like* red text in my console), but I know this handler should be here :P
*/
ws.on('error', function(_error) {
console.log("error!");
console.log(_error);
});
/*
* Send an object to a client
*
* #param WebSocketClient _to - The client you want to send to (generally an index in the CLIENTS array, i.e CLIENTS["bobsusername123"]
* #param Object _message - A stringifyable JSON object. Complex ones can screw things up, but your basic key/value pairs are usually fine to send.
*/
function doSend(_to, _message) {
_to.send(JSON.stringify(_message));
};
// Added broadcast function to replace sendAll
// Notice how it JSON stringifies the data before sending
/*
* Broadcast a message to all clients
*
* #param Object _message - A stringifyable JSON object. Complex ones can screw things up, but your basic key/value pairs are usually fine to send.
*/
function doBroadcast(_message) {
for(var client in CLIENTS) {
if(!CLIENTS.hasOwnProperty(client)) continue;
doSend(CLIENTS[client].socket, _message);
}
};
});
var fileServer = new Static.Server('.');
http.createServer(function (req, res) {
fileServer.server(req, res);
}).listen(8080, function(){
console.log("Server is listening 8080 port.");
});
console.log("Server is running on 8080 and 8081 ports");
MY CLIENT.JS (for your reference):
var loginButton = document.getElementById("loginbutton"),
usernameInput = document.getElementById("usernameInput");
var SocketClient = function(_uri, _callbacks) {
this.uri = _uri;
this.callbacks = _callbacks;
};
SocketClient.prototype = {
send: function(_message) {
this.socket.send(_message);
},
connect: function() {
try {
this.socket = new WebSocket("ws://" + this.uri);
} catch(e) { return false; }
for(var callback in this.callbacks) {
if(!this.callbacks.hasOwnProperty(callback)) continue;
this.socket["on" + callback] = this.callbacks[callback];
}
return true;
}
};
var socketClient = new SocketClient(
"127.0.0.1:8081",
{
open: function() {
console.log("connected.");
},
message: function(_message) {
console.log("received data:");
console.log(_message);
},
close: function() {
console.log("closed.");
},
error: function(_error) {
console.log("error: ");
console.log(_error);
}
}
);
socketClient.connect();
loginButton.addEventListener("click", function(){
name = usernameInput.value;
if(name.length > 0){
socketClient.send(JSON.stringify({
type: "login",
name: name
}));
}
});
AND THE CLIENT.HTML TO GO WITH IT:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
</head>
<body>
<input type="text" id="usernameInput"/>
<button type="button" id="loginbutton">Login</button>
<script src="client.js"></script>
</body>
</html>
Ive tested this with NWJS v0.12.3 running the server and Firefox on the client.
This should work
const WebSocket = require('ws');
// Websocket variables
const wss = new WebSocket.Server({
port: 3000
});
console.log('Websocket active on port 3000...');
// New WebSocket Connection
wss.on('connection', function connection(ws) {
console.log('new connection')
// On Message Received
ws.on('message', function incoming(message) {
console.log(message)
// Send To Everyone Except Sender
wss.clients.forEach(function(client) {
if (client !== ws) client.send(message);
});
});
});

Categories