I'm trying to create a little chat app for a school project, but I encountered a little problem since I'm really new to socket.io // node.js (coding in general). English is not my first language so I'm finding it hard to actually understand how it works exactly from tutorials.
Right now I have 2 css classes, one for the sent messages and one for the received messages. How do I make it so the classes will apply the right way for each message?
How do I check which message is sent by me, and which is received from another user? It's really unclear for me.
Server side code:
const http = require('http').createServer();
const io = require('socket.io')(http, {
cors:{origin: "*" }
});
io.on('connection', (socket) => {
console.log('a user connected');
socket.on('message', (message) => {
console.log(message);
io.emit('message', `${message}`);
});
});
http.listen(8080, () => console.log('listening on http://localhost:8080'));
Client side code:
const socket = io('ws://localhost:8080');
const sendBtn = document.getElementById('sendBtn');
const messageInput = document.getElementById('messageInput');
const messagesContainer = document.getElementById('messagesContainer');
const chatBigContainer = document.getElementById('chatBigContainer');
socket.on('message', text => {
const divEl = document.createElement('div');
divEl.className = "your-message";
messagesContainer.appendChild(divEl);
const labelEl = document.createElement('label');
labelEl.innerHTML = "You";
divEl.appendChild(labelEl);
let messageSent = document.createElement('p');
messageSent.innerHTML = text;
divEl.appendChild(messageSent);
})
sendBtn.addEventListener('click', () =>{
if(messageInput.value === ""){
return;
} else {
const text = messageInput.value;
socket.emit('message', text);
messageInput.value = "";
}
})
From what I understand you are not creating any element when you are sending any text. Instead you are emitting the same message to everyone :
io.emit('message', `${message}`);
and in that way you are thinking that you are actually creating HTML divs for both sending and receiving.
Firstly your server code should be :
socket.broadcast.emit('message', `${message}`);
(This sends to everyone but the sender and should work for your simple case with 2 users. Later you will need rooms)
This will show that you were actually not creating any elements while sending messages.
socket.on('message', text => {
})
sendBtn.addEventListener('click', () =>{
if(messageInput.value === ""){
return;
} else {
const text = messageInput.value;
socket.emit('message', text);
const divEl = document.createElement('div');
divEl.className = "your-message";
messagesContainer.appendChild(divEl);
const labelEl = document.createElement('label');
labelEl.innerHTML = "You";
divEl.appendChild(labelEl);
let messageSent = document.createElement('p');
messageSent.innerHTML = text;
divEl.appendChild(messageSent);
messageInput.value = "";
}
})
Replace the above with your classname and labels
Why do you have two classes for sending and receiving messages? socket.emit will emit the message to all clients, and then you can append the message.
As seen from the socket.io chat tutorial (https://socket.io/get-started/chat):
Secondly, if you want to check which users are which, you can assign a socket.id to users, like so.
io.on('connection', function(socket) {
console.log(`A user connected. ID: ${socket.id}`)
socket.on('disconnect', function() {
console.log(`A user disconnected. ID: ${socket.id}`);
});
});
This way, each user has a unique socket id. Maybe this can help you? I'm a bit unsure on what your're asking.
Related
I'll try to keep this simple. I'm working on a paging app.
What I have: A terminal without internet, running a desktop app made from node.js using express,ejs, ect. I also have a physical server with internet access and a mssql database on this machine I have a node.js server that interfaces with the database, collects the data and send sends it over to terminal via websocket when the app is launched, the node.js app gets this data and is rendered to the web interface using ejs. This data is displayed in a form with a button that when clicked fires the app.post route. In the app.post that data is packaged in an array, and sent back to the server using a second websocket connection. I can then take that form data (a name, phone#, and a radio button value) and form a SMS message using and using twilio send a message to that number (with addition info)
Yes, I have two websocket connections one Server > client serves data to web app
and another client > server serves form data to the server.
What's working: I get data from the boh server/database > webserver/client and data is displayed correctly when I hit the button data is packaged and send back to the boh server.
On the boh server i have a function that get the data array and parses it out, and sends an SMS message using twilio
My issue: I have to restart the server app to get it to process the data and send the message, if I hit the page button, it does all the stuff in the background it should, packages the array and sends the info to the server. The server is waiting for the data to be sent and client has sent the data, however it will only send off the text message is a stop and restart the node.js server, if i do that, the server starts and runs through the initial process of getting the sql data, and sets it up to be called when the app launches, then continues on to read that data was sent from the client, received and it will parse the data from the SMS message through a function send the message, wait a few seconds and then grab the response and confirm delivery of message. I am quite sure I am missing something basic here, but I have different functions but nothing I do will seem to get it to fire when the data is received.
I'm new at node and not very advanced in js, but I understand on some level why its not firing as is right, script is running, data has not been sent, so it stops when it gets here, then i hit the button, and it does nothing, because the script is stopped, and it doesn't has know way of knowing that data was sent, but when i rerun the script, the data that was sent is still sitting there wait to be received, so it recognizes the open websocket, and the sent data and work appropriately, I feel like a am missing something on the server side that tell it to wait for the data send but have not been able to make it work
twilws.onopen = async() => {//when the page button is presses, it starts a websocket server on the client, if that makes sense
twilws.send('test')
if (twilws.readyState === WebSocket.OPEN) {
logger.info('Twilio Sockpuppet Connected')
} else {
logger.error('Twilio Sockpuppet Fail')
}
twilws.onmessage = async (e) => {//after i hit the page button the server is on and the array is sent, i am trying to get this to be waiting for data and when it arrives go, but it will only do that when i restart the script
try {
data = JSON.parse(e.data);//parse the data
logger.info('got the edata ' + e.data)
//main(data) this will fire but not when the button is pressed.
} catch (er) {
logger.error('socket parse error: ' + e.data);
}
}
}
twilws.onclose = () => {//close the connection, purges that data so that the websocket can be recreated and an array with new data sent.
logger.info('Web Socket Connection Closed');
twilws.close(1000, 'all done');
};
Here is the whole server
I believe i may be blocking something, sorry about the bad formatting i have been changing and trying different things for a couple weeks off and on now and have not had a chance to clean thing up.
const express = require("express");
const cors = require("cors");
const app = express();
const db = require("./app/models");
const twilioconfig = require('./configs/twilioConfig.js');
const path = require('path');
const WebSocket = require('ws');
const sql = require('mssql');
const WebSocketServer = require('websocket').server;
const WebSocketClient = require('websocket').client;
const WebSocketFrame = require('websocket').frame;
/*const WebSocketRouter = require('websocket').router;*/
const W3CWebSocket = require('websocket').w3cwebsocket;
const http = require('http');
const https = require('https');
const twilio = require('twilio');
const { Console } = require("console");
app.disable('view cache');
const pino = require('pino')
const SonicBoom = require('sonic-boom')
const logger = require('pino')()
const transport = pino.transport({
target: 'pino/file',
options: { destination: './logs/logs.txt', level: 'info', mkdir: true, append: true }
})
pino(transport)
/*const dbConfig2 = require("./app/config/db.config.js");*/
/*const config = require("./app/config/config.js");*/
const { client } = require("websocket");
const { err } = require("./node_modules/pino-std-serializers/index");
const { setInterval } = require("node:timers/promises");
app.use(pino)
//const webserver = app.listen(8080, function () {
// console.log('Node WEb Server is running..');
//});
var params = {
autoReconnect: false, //Enable/Disable reconnect when the server closes connection (boolean)
autoReconnectInterval: 1000, //Milliseconds to wait between reconnect attempts (number)
autoReconnectMaxRetries: 600, //Max number of reconnect attempts to allow (number)
requestTimeout: 30000, //Milliseconds to wait for a response before resending the request (number)
requestRetryInterval: 5000, //Milliseconds between request retry checks. This garbage collects the retry queue (number)
requestRetryQueueMaxLength: 10 //Max queue length of retry queue before old messages start getting dropped (number)
}
var wss = new WebSocket.Server({ port: 8081 })
sql.connect(config, function (err) {
if (err)
logger.error(err);
const sqlRequest = new sql.Request();
const sqlQuery = "SELECT TOP 5 guest_name,guest_phone_number,CONVERT(varchar,creation_time, 126) AS creation_time,CONVERT(varchar,last_modified_timestamp, 126) AS last_modified_timestamp,party_size from dbo.WaitList where status = '4' AND CAST(creation_time as date) = CAST( GETDATE() AS Date ) ORDER BY creation_time ASC";
logger.info("query passes preflight.....lets get data")
sqlRequest.query(sqlQuery, function (err, data) {
if (err) {
logger.error(err)
} else {
logger.info("We do preliminary query now.")
}
//console.table(data.recordset);
//logger.info('rows affected ' + data.rowsAffected);
//console.log(data.recordset[0]);
var array = [];
for (let i = 0; i < data.rowsAffected; i++) {
var a = data.recordset[i];
array.push(a);
}
wss.on('connection', ws => {
logger.info('Client connection established')
ws.on('message', function () {
sqlRequest.query(sqlQuery, function (err, data) {
if (err) {
logger.error(err)
}
//console.table(data.recordset);
//logger.info(data.rowsAffected);
//console.log(data.recordset[0]);
var array = [];
for (let i = 0; i < data.rowsAffected; i++) {
var a = data.recordset[i];
array.push(a);
}
})
wss.clients
.forEach(client => {
logger.info('sending data')
client.send(JSON.stringify(array))
})
})
})
})
});
const twilws = new W3CWebSocket('ws://172.16.0.101:8082', params);
twilws.onopen = () => {//when the page button is presses, it starts a websocket server on the client, if that makes sense
twilws.send('test')
if (twilws.readyState === WebSocket.OPEN) {
logger.info('Twilio Sockpuppet Connected')
} else {
logger.error('Twilio Sockpuppet Fail')
}
twilws.onmessage = async (e) => {//after i hit the page button the server is on and the array is sent, i am trying to get this to be waiting for data and when it arrives go, but it will only do that when i restart the script
try {
data = JSON.parse(e.data);//parse the data
logger.info('got the edata ' + e.data)
//main(data) this will fire but not when the button is pressed.
} catch (er) {
logger.error('socket parse error: ');
}
}
}
twilws.onclose = () => {//close the connection, purges that data so that the websocket can be recreated and an array with new data sent.
logger.info('Web Socket Connection Closed');
twilws.close(1000, 'all done');
};
//async function main(s) {
// /* these settings are loaded from configs/twilioConfig.js, go here to set the store account info and edit message body.*/
// const TWILIO_ACCOUNT_SID = twilioconfig.twilioOptions.TWILIO_ACCOUNT_SID;
// const TWILIO_AUTH_TOKEN = twilioconfig.twilioOptions.TWILIO_AUTH_TOKEN;
// const STORE_TWILIO_NUMBER = twilioconfig.twilioOptions.STORE_TWILIO_NUMBER;
// const TEXT_TWILIO_BODY = twilioconfig.twilioOptions.TEXT_TWILIO_BODY;
// var messarray = new Array([s])
// var num = JSON.stringify(messarray[0][0][0])
// var state = JSON.stringify(messarray[0][0][1])
// logger.info(num + ', ' + state)
// var readyin = state
// var custnum = num
// /*logger.info(TWILIO_ACCOUNT_SID + ' ' + TWILIO_AUTH_TOKEN)*/
// var customer = new twilio(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN);//these are our twilio account sid and token, set in twilioConfig, get from oneNote
// if (readyin == 0) {
// waitmsg = TEXT_TWILIO_BODY + "Your Table is Ready!";
// } else if (readyin == 15) {
// waitmsg = TEXT_TWILIO_BODY + "Your Table will be ready in about 15 minutes!";
// }
// logger.info(`Recieved Form data.....Twilio data read successfully....`);//log that we got the data from the gui form
// // send the message to the customer number through twilio, custnum from form, from is the store number, alson in twilioConfig
// customer.messages.create({
// to: custnum,
// from: STORE_TWILIO_NUMBER,
// body: waitmsg
// })
// .then(message => {
// var messageid = message.sid
// logger.info(messageid + ' Hey i found this, we might need it in a sec')
// const msid = JSON.stringify({ "MessageSid": messageid })
// const twilid = messageid
// setTimeout(getStatus, 5000);
// function getStatus() {
// customer.messages(messageid).fetch()
// .then(call => {
// const d = new Date(call.dateCreated).toLocaleString();
// const messageStatus = call.status
// var twil_response_array = [twilid, messageStatus, d]
// logger.info(twil_response_array)
// wss.on('connection', ws => {
// ws.on('message', function () {
// })
// wss.clients
// .forEach(client => {
// client.send(twil_response_array)
// })
// })
// })
// }
// //})
app.listen(8180, function () {
logger.info('Server is running..');
});
});
I have a repetitive task that I have to do at regular intervals. Basically, I need to enter the website, get some values from different tables then write them on spreadsheet. By using these values, make some calculation, prepare a report etc.
I would like to create a helper bot because this is straight forward task to do.
I can basically get information by opening up console (while I am on the related page) and by using DOM or Jquery I am fetching data easily.
I would like to take it a step further and create an application on Node.js (without entering related website, I will send my bot to related page and do same actions that I do on console.)
I started to write something with cheerio. However, at some point my bot needs to click a button (in order to change table). I searched but couldn't find the way.
My question is "clicking a button on server side (change the table) and fetch data from that table is possible ?"
If do you know better way to create this kind of bot, please make suggestion.
var express = require('express');
var fs = require('fs');
var request = require('request');
var cheerio = require('cheerio');
var app = express();
app.get('/scrape', (req, res) => {
url = 'http://www.imdb.com/title/tt1229340/';
request(url, function(error, response, html){
if(!error){
var $ = cheerio.load(html);
var title, release;
var json = { title : "", release : ""};
$('.header').filter(() => {
var data = $(this);
title = data.children().first().text();
release = data.children().last().children().text();
json.title = title;
json.release = release;
})
// This is not possible
$( "#target" ).click(function() {
alert( "Handler for .click() called." );
});
}
fs.writeFile('output.json', JSON.stringify(json, null, 4), (err) => {
console.log('File successfully written!);
})
res.send('Check your console!')
}) ;
})
app.listen('8080');
edit: The Answer of this question is "Use Zombie"
Now I have another question related to this one.
I am trying to learn & use zombie. I could
connect to website
go to necessary table
print console all tds
However by using this method, I could only get really messed up string. (All tds were printed without any whitespace, no chance to clean out, basically I want to put all tds in an array. How can I do that ?)
browser.visit(url, () => {
var result = browser.text('table > tbody.bodyName td');
console.log(result);
})
I'd suggest you try using a headless browser such as Phantom.js or Zombie for this purpose. What you're trying to do above is assign a click handler to an element in Cheerio, this won't work!
You should be able to click a button based on the element selector in Zombie.js.
There's a browser.pressButton command in Zombie.js for this purpose.
Here's some sample code using zombie.js, in this case clicking a link..
const Browser = require('zombie');
const url = 'http://www.imdb.com/title/tt1229340/';
let browser = new Browser();
browser.visit(url).then(() => {
console.log(`Visited ${url}..`);
browser.clickLink("FULL CAST AND CREW").then(() => {
console.log('Clicked link..');
browser.dump();
});
}).catch(error => {
console.error(`Error occurred visiting ${url}`);
});
As for the next part of the question, we can select elements using zombie.js and get an array of their text content:
const Browser = require('zombie');
const url = 'http://www.imdb.com/title/tt1229340/';
let browser = new Browser();
browser.visit(url).then(() => {
console.log(`Visited ${url}..`);
var result = browser.queryAll('.cast_list td');
var cellTextArray = result.map(r => r.textContent.trim())
.filter(text => text && (text || '').length > 3);
console.log(cellTextArray);
}).catch(error => {
console.error(`Error occurred visiting ${url}`);
});
i have an experimental app that is pretty simple, you click a display button and an image appears in real time to all clients, utilizing socket.io. now it does work for the most part. however i had an issue (my original question here: socket.io emit on connect) with an event not happening when the client connected, but i have resolved it with the help of this thread: socket.emit on sever side is ignored after connection?.
basically, my 'new-client-append event' retrieves data (html in the form of a string) so that when a new client connects, it shows the same data that current clients see (similar to connecting to a chat room and being able to see all chat history). i had to reorganize my code so my 'new-client-append' event would take place, and i can get it to work if i put data in manually. my new issue is now that i have had to reorganize my code, my 'new-client-append' event is dependent on a variable i set within the class, so it is no longer recognizable. i'm relatively new to JS, how can i get my variable to be recognized and why is this happening? i had tried moving the event in different places of my code with no luck. it is the this.mainContainer variable.
CLIENT
import $ from 'jquery';
import SaveInput from './SaveInput';
import io from 'socket.io-client';
// make connection
const socket = io.connect('localhost:3000');
**socket.on('new-client-append', (data) => {
console.log('NEW CLIENT ENTERED');
console.log('on new-client-clone ' + JSON.stringify(data));
this.mainContainer.append(data);
});**
socket.on('connect_error', function(){
console.log('fail');
});
class Display extends SaveInput {
constructor(){
this.mainContainer = $('.main-container');
this.pGrid = $('.pic-grid-container');
this.display = $('#btn-display');
this.buttons();
}
buttons (){
// click buttons
this.display.click(this.displayEls.bind(this));
//display images
displayEls() {
let img = 'https://secure.gravatar.com/avatar/22f38e0216f57af53a1776fb2a72c436?s=60&d=wavatar&r=g';
let $picContainer = $('<div class="picture-frame"></div>');
let $newImg = $('<img>');
// clone pic-grid-container
let htmlClone = this.pGrid.clone();
let stringClone = htmlClone.html();
// EMIT
//send image url
socket.emit('client-image', {
image: img
});
// send dom clone to server
socket.emit('new-client-append', {
clone: stringClone
});
// LISTEN
// append image in real time
socket.on('client-image', (data) => {
let foo = data.image.toString();
$newImg.attr('src', foo);
// console.log(data);
// console.log(foo);
$newImg.appendTo($picContainer);
this.pGrid.append($picContainer);
// console.log('html clone ' + JSON.stringify(htmlClone));
// console.log('string clone ' + stringClone);
});
}
export default Display;
SERVER
const express = require('express');
const socketIO = require('socket.io');
const http = require('http');
// app set up
const app = express();
const server = http.Server(app);
// const = new socket(server);
let port = process.env.PORT || 3000;
// static files
app.use(express.static('app'));
// socket setup & pass SERVER
const io = new socketIO(server);
let jqueryImage;
// on client connect
io.on('connection', (socket) => {
console.log('client has entered...');
socket.emit('new-client-append', jqueryImage);
// events
socket.on('client-image', function(data){
console.log('SERVER ' + data.image);
io.sockets.emit('client-image', data);
});
socket.on('new-client-append', function(data){
jqueryImage = data.clone;
console.log('jqueryImage ' + JSON.stringify(jqueryImage));
});
// errors
io.on('error', function (err) {
console.log(err);
});
io.on('connect_error', function(){
console.log('fail');
});
});
server.listen(port, () => {
console.log('server running....');
});
UPDATE
added suggested code, calling the maincontainer from the display object. but it is saying that it is not defined.
socket.on('new-client-append', (data) => {
console.log('NEW CLIENT ENTERED');
console.log('on new-client-clone ' + JSON.stringify(data));
**display.mainContainer.append(data);**
});
file where i create the objects
import SaveInput from './modules/SaveInput';
import Display from './modules/Display';
const saveInput = new SaveInput();
const display = new Display ();
Your socket.on function has
this.mainContainer.append(data);
This implies that you've attached a mainContainer property to the socket object. Because you've not done this, but rather declared it inside your Display (sub)class, it's attached to the Display object you created.. I can't seem to find it, but somewhere, wherever this script is required there is a
variable = new Display();
You must call this mainContainer object by it's name. Find that code that initiates the Display object and then use
theVarNameYouFound.mainContainer.append(thatThing);
I want to integrate a chatbot that should be connected to any user who is waiting to be connected to a real human user. The chatbot will entertain the user by responding the human user messages.
A similar chatbot has been implemented here named "Didianer.com", if you go here and start typing you will see him responding.
http://socket.io/demos/chat/
I want the exact same bot in my application too but I am totally lost on where to start.
Here is my server side code
//Server receives a new message (in data var) from the client.
socket.on('message', function (data) {
var room = rooms[socket.id];
//Server sends the message to the user in room
socket.broadcast.to(room).emit('new message', {
username: socket.username,
message: data
});
});
// when the client emits 'add user', this listens and executes (When user enters ENTER)
socket.on('add user', function (username) {
if (addedUser) return;
//Own
names[socket.id] = username;//save username in array
allUsers[socket.id] = socket; // add current user to all users array
// we store the username in the socket session for this client
socket.username = username;
++numUsers;
addedUser = true;
socket.emit('login', {
numUsers: numUsers
});
// echo globally (all clients) that a person has connected
socket.broadcast.emit('user joined', {
username: socket.username,
numUsers: numUsers
});
// now check if sb is in queue
findPeerForLoneSocket(socket);
});
FindPeerforLoneSocket is called when a new user connects and wants to talk to someone else. Here I am assuming the logic for bot should go. Such as if the user is waiting (in queue) for 5 seconds and nobody is online to talk, then connect the user (add the user and the chatbot) in one room so they both can can start talking. I am not sure how to respond to chat events and how chat bot will reply...
var findPeerForLoneSocket = function(socket) {
console.log("i am in finding a peer");
// this is place for possibly some extensive logic
// which can involve preventing two people pairing multiple times
if (queue.length>0) {
console.log("people are online" + queue.length);
// somebody is in queue, pair them!
var peer = queue.pop();
var room = socket.id + '#' + peer.id;
var str = socket.id;
// join them both
peer.join(room);
socket.join(room);
// register rooms to their names
rooms[peer.id] = room;
rooms[socket.id] = room;
// exchange names between the two of them and start the chat
peer.emit('chat start', {'name': names[socket.id], 'room':room});
socket.emit('chat start', {'name': names[peer.id], 'room':room});
//Remove backslash from socketid
// str = socket.id.replace('/#', '-');
} else {
// queue is empty, add our lone socket
queue.push(socket);
console.log("nobody is online, add me in queue" + queue.length);
}
}
I would want a very simple basic chatbot to respond to basic messages. Like I should check if the user sends message "Hello" then I can check if user message contains word "Hello" then I can respond the chatbot back with an appropriate response to "Hello" Like "Hi {username} of the online user".
/************* NEW CODE - BOT ********************************/
var clientSocket = require('socket.io-client');
var socketAddress = 'http://www.talkwithstranger.com/';
function Bot(){
this.socket = undefined;
var that = this;
this.timeout = setTimeout(function(){
that.join();
}, 5000);
}
Bot.prototype.cancel = function(){
clearTimeout(this.timeout);
};
Bot.prototype.join = function(){
this.socket = clientSocket(socketAddress);
var socket = this.socket;
socket.emit('add user', 'HAL BOT');
socket.emit('message', "Good afternoon, gentlemen. I am a HAL 9000 computer. I became operational at the H.A.L. plant in Urbana, Illinois on the 12th of January 1992. My instructor was Mr. Langley, and he taught me to sing a song. If you'd like to hear it I can sing it for you.");
socket.on('user joined', this.user_joined_listener);
socket.on('user left', this.user_left_listener);
socket.on('new message', this.new_message_listener);
socket.on('client left', this.client_left_listener); //I FORGOT THIS //EDIT: ANOTHER BUG FIXED
};
Bot.prototype.leave = function(){
var socket = this.socket;
socket.disconnect();
//socket.emit('message', "Daisy, Daisy, give me your answer do. I'm half crazy all for the love of you. It won't be a stylish marriage, I can't afford a carriage. But you'll look sweet upon the seat of a bicycle built for two.");
};
Bot.prototype.user_joined_listener = function(data){
var socket = this.socket;
socket.emit('message', 'Hello, '+data.username);
};
Bot.prototype.user_left_listener = function(data){
var socket = this.socket;
socket.emit('message', data.username+', this conversation can serve no purpose anymore. Goodbye.');
};
Bot.prototype.new_message_listener = function(data){
var socket = this.socket;
if(data.message=='Hello, HAL. Do you read me, HAL?')
socket.emit('message', 'Affirmative, '+data.username+'. I read you.');
};
Bot.prototype.client_left_listener = function(data){
this.leave();
};
/*******************************************************************************/
var bot = undefined;
var findPeerForLoneSocket = function(socket) {
console.log("i am in finding a peer");
// this is place for possibly some extensive logic
// which can involve preventing two people pairing multiple times
if (queue.length>0) {
bot.cancel();
console.log("people are online" + queue.length);
// somebody is in queue, pair them!
var peer = queue.pop();
var room = socket.id + '#' + peer.id;
var str = socket.id;
// join them both
peer.join(room);
socket.join(room);
// register rooms to their names
rooms[peer.id] = room;
rooms[socket.id] = room;
// exchange names between the two of them and start the chat
peer.emit('chat start', {'name': names[socket.id], 'room':room});
socket.emit('chat start', {'name': names[peer.id], 'room':room});
//Remove backslash from socketid
// str = socket.id.replace('/#', '-');
} else {
// queue is empty, add our lone socket
queue.push(socket);
console.log("nobody is online, add me in queue" + queue.length);
bot = new Bot(); /********************** CREATING BOT, AFTER 5 SECONDS HE WILL JOIN - SEE CONSTRUCTOR OF Bot *********/
}
};
There are a lot of ways to do this.
One way is to handle this on message, and let the bot respond if there are no other people in the room.
socket.on('message', function (data) {
var room = rooms[socket.id];
//Server sends the message to the user in room
socket.broadcast.to(room).emit('new message', {
username: socket.username,
message: data
});
if (alone_in_room(socket, room)) {
bot_message(socket, data);
}
});
Then it's up to you if you want to join a bot into the channel when users are alone or not, and if you will make them leave when another user enters.
Here is original HTML file:
<!DOCTYPE html>
<html>
<head>
<title>BOT - chat.socket.io</title>
<meta charset="UTF-8">
<script>localStorage.debug = 'socket.io-client:socket';</script>
<script src="https://cdn.socket.io/socket.io-1.4.5.js"></script>
</head>
<body>
<script>
/** chat.socket.io BOT **/
var name = 'HAL 9000',
address = 'chat.socket.io',
socket;
function join(){
socket = io('http://www.talkwithstranger.com/');
socket.emit('add user', name);
socket.emit('message', "Good afternoon, gentlemen. I am a HAL 9000 computer. I became operational at the H.A.L. plant in Urbana, Illinois on the 12th of January 1992. My instructor was Mr. Langley, and he taught me to sing a song. If you'd like to hear it I can sing it for you.");
socket.on('user joined', user_joined_listener);
socket.on('user left', user_left_listener);
socket.on('new message', new_message_listener);
};
function leave(){
socket.emit('message', "Daisy, Daisy, give me your answer do. I'm half crazy all for the love of you. It won't be a stylish marriage, I can't afford a carriage. But you'll look sweet upon the seat of a bicycle built for two.");
};
function user_joined_listener(data){
socket.emit('message', 'Hello, '+data.username);
};
function user_left_listener(data){
socket.emit('message', data.username+', this conversation can serve no purpose anymore. Goodbye.');
};
function new_message_listener(data){
if(data.message=='Hello, HAL. Do you read me, HAL?')
socket.emit('message', 'Affirmative, '+data.username+'. I read you.');
};
/*********************************/
join();
window.onbeforeunload = function(){
leave();
};
</script>
</body>
</html>
I'm following a book which has a code snippet for socket.io namespaces. the version specified in the book is socket 0.9
this is the below code for a simple chatroom using namespaces.
exports.initialize = function(server) {
io = io.listen(server);
var chatInfra = io.of("/chat_infra")
.on("connection", function(socket) {
socket.on("set_name", function(data) {
socket.set('nickname', data.name, function() {
socket.emit('name_set', data);
socket.send(JSON.stringify({
type: 'serverMessage',
message: 'Welcome to the most interesting ' +
'chat room on earth!'
}));
socket.broadcast.emit('user_entered', data);
});
});
});
var chatCom = io.of("/chat_com")
.on("connection", function(socket) {
socket.on('message', function(message) {
message = JSON.parse(message);
if (message.type == "userMessage") {
socket.get('nickname', function(err, nickname) {
message.username = nickname;
socket.broadcast.send(JSON.stringify(message));
message.type = "myMessage";
socket.send(JSON.stringify(message));
});
}
});
});
}
i'm trying to recreate the code using the latest socket version. but i'm having trouble getting the socket.nickname variable in the chatCom namespace. the socket.nickname variable in the chatCom namespace returns undefined because of the local scope.
here's my version
exports.initialize = function(server){
io = io(server);
var chatInfra = io.of('/chat_infra');
chatInfra.on('connection',function(socket){
socket.on('set_name',function(data){
socket.nickname = data.name;
console.log(socket.nickname);
socket.emit('name_set',data);
socket.send(JSON.stringify({
type:'serverMessage',
message:'Welcome to the most interesting chat room on earth'
}));
socket.broadcast.emit('user_entered',data);
})
})
var chatCom = io.of('/chat_com');
chatCom.on('connection',function(socket){
socket.on('message',function(message){
message = JSON.parse(message);
if(message.type === 'userMessage'){
message.nickname = socket.nickname;
socket.broadcast.send(JSON.stringify(message));
message.type = 'myMessage';
socket.send(JSON.stringify(message));
}
})
})
}
Is there a way i can access the nickname value in the second namespace?
I'm able to access the same socket instance in both namespaces. but however, the nickname property seems to be erased when i invoke it from a different namespace.
Output of console.log
socket id in /chat_infra is : Zo0kfigUFJOZIgH8AAAB and socket nickname is kj
socket id in /chat_com is : Zo0kfigUFJOZIgH8AAAB and socket nickname is undefine
Sorry that I can't verify this myself right now (and also that I can't comment yet), but hopefully I can help you figure it out.
Both chatInfra and chatCom should have a connected property that is an map of all the current sockets connected to each. If the socket is not shared/reused in each namespace, perhaps they still share the same connection ID. So, you may be able to get the nickname from chatInfra.connected[socket.id].nickname.
If that doesn't work, console.log each of their connected properties and see their differences. Also, socket.io handles JSON natively, so you don't need to JSON.parse and JSON.stringify your objects.
Instead setting nickname to socket, you can set nickname to the client object of socket, such as socket.client.nickname = data.name.