Node wss Websocket works on Desktop, not on Mobile - node.js

I'm trying to get my phone's orientation data to send to a local server via node's WebSocket (ws) library. In my research, it seems that orientation data is only accessible using ssl, so this will only work if I have a wss/https. I've got a node server working with a self-signed certificate, and it works fine on a desktop browser, but when I run it on my iphone, I end up getting an error message when it tries to connect. Code below, any suggestions/alternatives are greatly appreciated! (I'm more of a graphics/multimedia programmer, so certain web/server terms could be lost on me)
client.js:
let socket = new WebSocket("wss://192.168.0.10:3000");
socket.onopen = function(e) {
alert("[open] Connection established ");
alert("Sending to server");
socket.send("Hello");
};
socket.onmessage = function(event) {
alert(`[message] Data received from server: ${event.data}`);
};
socket.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');
}
};
socket.onerror = function(error) {
alert(`[error] ${error.message}`);
};
function showCoords(event) {
var x = event.clientX;
var y = event.clientY;
var coords = "X coords: " + x + ", Y coords: " + y;
console.log(coords);
socket.send(coords);
}
server.js:
var express = require('express');
var app = express();
const https = require('https');
const fs = require('fs');
// var cors = require('cors');
const options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
const WebSocket = require('ws');
// var server = app.listen(3000);
const server = https.createServer(options, app);
const wss = new WebSocket.Server({ server });
wss.on('connection', function connection(ws) {
ws.on('message', function message(msg) {
console.log("WS connect "+msg);
});
});
app.use(express.static('public'));
console.log('socket server is running');
server.listen(3000, function () {
console.log('Example app listening on port 3000! Go to https://localhost:3000/')
console.log('')
const ws = new WebSocket(`wss://localhost:${server.address().port}`, {
rejectUnauthorized: false
});
ws.on('open', function open() {
ws.send('All glory to WebSockets! '+server.address().port);
});
})
function newConnection(socket) {
console.log(socket.id);
socket.on('mouse', mouseMsg);
function mouseMsg(data){
socket.broadcast.emit('mouse', data);
console.log(data);
}
}
index.html
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style type="text/css">
.garden {
position: relative;
width : 200px;
height: 200px;
border: 5px solid #CCC;
border-radius: 10px;
}
.ball {
position: absolute;
top : 90px;
left : 90px;
width : 20px;
height: 20px;
background: green;
border-radius: 100%;
}
</style>
<title>Detecting device orientation - Orientation_example - code sample</title>
<script src="sketch.js"></script>
</head>
<body>
<main>
<div onclick="showCoords(event)" class="garden">
<div class="ball"></div>
</div>
<pre class="output"></pre>
<script>
var ball = document.querySelector('.ball');
var garden = document.querySelector('.garden');
var output = document.querySelector('.output');
var maxX = garden.clientWidth - ball.clientWidth;
var maxY = garden.clientHeight - ball.clientHeight;
function handleOrientation(event) {
var x = event.alpha; // In degree in the range [-180,180]
var y = event.beta; // In degree in the range [-90,90]
output.innerHTML = "beta : " + y + "\n";
// output.innerHTML += "gamma: " + y + "\n";
// Because we don't want to have the device upside down
// We constrain the x value to the range [-90,90]
if (x > 90) { x = 90};
if (x < -90) { x = -90};
// To make computation easier we shift the range of
// x and y to [0,180]
x += 90;
y += 90;
// 10 is half the size of the ball
// It center the positioning point to the center of the ball
ball.style.top = (maxY*y/180 - 10) + "px";
ball.style.left = (maxX*x/180 - 10) + "px";
}
window.addEventListener('deviceorientation', handleOrientation);
</script>
</main>
</body>
</html>

You should be able to do this with https://ngrok.com/. Once you install ngrok (you will need a free account). Run your server and client. Point ngrok to your client local port i.e. 8000 ~/ngrok http 8000 copy the returned https url i.e. https://xxxxxxxx.ngrok.io on your device.

Related

How to structure the NodeJs code

I am new to the NodeJs. I have created a simple application using socket.io. I know that I can use ExpressJs framework but I am not getting overall idea as to how to separate the code and divide them into multiple pages so that debugging and maintenance is easily.
I am not understanding how to structure the code and where to write the socket.io code or any other NodeJs code in general.
Should I create new folder and files? If yes then how?
My code: app.js
var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
var ent = require('ent');
var fs = require('fs');
var cntActiveProductSupport = 0;
var cntActiveCustomer = 0;
var support_socket_id = '';
app.get('/',function (req, res) {
res.sendFile(__dirname+'/index.html');
});
app.get('/product_support',function (req, res) {
res.sendFile(__dirname+'/admin.html');
});
io.sockets.on('connection',function(socket,username){
//Each Socket in Socket.IO is identified by a random, unguessable, unique identifier Socket#id
console.log(socket.id);
//total number of connections
console.log(io.engine.clientsCount);
socket.on('support_connected',function(username){
username = ent.encode(username);
socket.username = username;
socket.broadcast.emit('support_connected',username);
//get socket id of all connected sockets
Object.keys(io.sockets.sockets).forEach(function(id) {
console.log("ID:",id) // socketId
});
cntActiveProductSupport++;
support_socket_id = socket.id;
});
socket.on('new_client',function(username){
var client_socket_id = socket.id;
username = ent.encode(username);
socket.username = username;
socket.broadcast.emit('new_client',{ username: username, socket_id: socket.id, support_socket_id: support_socket_id });
socket.to(client_socket_id).emit('client_connected',{ username: username, support_socket_id: support_socket_id });
cntActiveCustomer++;
});
socket.on('message',function(data){
//socket.disconnect(true); use this if you want to disconnect client from server
//client which sent the message
var client_socket_id = socket.id;
var message = ent.encode(data.message);
// sending to individual socketid (private message)
//socket.to(socketId).emit('hey', 'I just met you');
socket.to(support_socket_id).emit('message', {username: socket.username,message:message, client_socket_id: client_socket_id});
});
socket.on('support_messaging',function(data){
message = ent.encode(data.message);
var customer_socket_id = data.customer_socket_id;
//socket.broadcast.emit('message', {username: socket.username,message:message});
// sending to individual socketid (private message)
socket.broadcast.to(customer_socket_id).emit('message', {username: socket.username,message:message});
//socket.to(socketId).emit('hey', 'I just met you');
//It's the same command as for rooms, that's because:
//"For your convenience, each socket automatically joins a room identified by this id."
});
socket.on('typing',function(username){
socket.broadcast.emit('typing', username);
});
socket.on('stopped-typing',function(){
socket.broadcast.emit('stopped-typing');
});
});
server.listen(8080);
My code: index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Real-time Super Chat!</title>
<style>
#zone_chat strong {
color: white;
background-color: black;
padding: 2px;
}
#writeup {
font-size:9px;
color: gray;
margin: 5px 0px;
}
</style>
</head>
<body>
<h4>Real-time Super Chat!</h4>
<form action="/" method="post" id="chat_form" autocomplete="off">
<input type="text" name="message" id="message" placeholder="Your message..." size="50" />
<input type="submit" id="send_message" value="Send" />
<input type="hidden" id="support_socket_id" value=""/>
<div id="writeup"></div>
</form>
<section id="chat_zone">
</section>
<script
src="https://code.jquery.com/jquery-3.3.1.js"
integrity="sha256-2Kok7MbOyxpgUVvAk/HJ2jigOSYS2auK4Pfzbm7uH60="
crossorigin="anonymous"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
// Connecting to socket.io
var socket = io.connect('http://localhost:8080');
var socketConnected = false;
// The username is requested, sent to the server and displayed in the title
var username = prompt('What\'s your username?');
//var username = 'Deepak';
socket.emit('new_client', username);
document.title = username + ' - ' + document.title;
socket.on('connect', function() {
socketConnected = true;
console.log('Connected! ID: ' + socket.id);
});
socket.on('client_connected', function(data){
$('#support_socket_id').val(data.support_socket_id);
});
socket.on('disconnect', function() {
socketConnected = false;
console.log('Disconnected!');
});
// When a message is received it's inserted in the page
socket.on('message', function(data) {
insertMessage(data.username, data.message)
});
// When a new client connects, the information is displayed
// socket.on('new_client', function(username) {
// $('#chat_zone').prepend('<p><em>' + username + ' has joined the chat!</em></p>');
// });
socket.on('typing',function(username){
$('#writeup').html(username + ' is typing...');
});
socket.on('stopped-typing',function(){
$('#writeup').html('');
});
$(document).ready(function () {
$('#message').on('focus',function(){
socket.emit('typing',username);
});
$('#message').on('blur',function(){
socket.emit('stopped-typing',username);
});
// When the form is sent, the message is sent and displayed on the page
$('#chat_form').submit(function () {
var message = $('#message').val();
var support_socket_id = $('#support_socket_id').val();
socket.emit('message', { message:message, support_socket_id:support_socket_id }); // Sends the message to the others
insertMessage(username, message); // Also displays the message on our page
$('#message').val('').focus(); // Empties the chat form and puts the focus back on it
return false; // Blocks 'classic' sending of the form
});
});
// Adds a message to the page
function insertMessage(username, message) {
$('#chat_zone').prepend('<p><strong>' + username + '</strong> ' + message + '</p>');
}
</script>
</body>
</html>
You should create node modules in order to maintain the code structure. For example create routes folder and put all the route in there and separate them like users.js is a route file to cater routing related to user. As you are using socket.io you can create a separate module for socket.io functions and use them in your routes.
This link might help you: https://nodejs.org/api/modules.html
I hope it helps.
App Structure: routes, enter image description here

NGROK + WEB-SERVER + NODE.JS + WEBSOCKET + NPM

I have a web server on localhost and I connect to this server with my phone via ngrock. Up here very well, since ngrock creates a url, for example http://94815c96.ngrok.io that redirects me to localhost:8888, where I can see my project and files.
Then I need to connect my web-server through websocket and make a chat application, for this I have installed npm and node.js and I run the command node filename.js, which this filename.js file creates a socket that listens on port 1337 and on the side of the web-server opens the websocket on port 1337. If i do it via web-browser on my local device it works, but when I try it via mobile phone with the ngrock url it return an error that cannot connect to WebSocket Server.
The code that I use is simple. I have one html called frontend.html to view and output the chat application, another file called chat-client.js that opens the connection to websocket on port 1337 and the last file is called chat-server.js that listens on port 1337. The code for each file is this one below here:
frontend.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebSockets - Simple chat</title>
<style>
* { font-family:tahoma; font-size:12px; padding:0px; margin:0px; }
p { line-height:18px; }
div { width:500px; margin-left:auto; margin-right:auto;}
#content { padding:5px; background:#ddd; border-radius:5px; overflow-y: scroll;
border:1px solid #CCC; margin-top:10px; height: 160px; }
#input { border-radius:2px; border:1px solid #ccc;
margin-top:10px; padding:5px; width:400px; }
#status { width:88px; display:block; float:left; margin-top:15px; }
</style>
</head>
<body>
<div id="content"></div>
<div>
<span id="status">Connecting...</span>
<input type="text" id="input" disabled="disabled" />
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script src="./chat-frontend.js"></script>
</body>
</html>
chat-client.js:
$(function () {
"use strict";
// for better performance - to avoid searching in DOM
var content = $('#content');
var input = $('#input');
var status = $('#status');
// my color assigned by the server
var myColor = false;
// my name sent to the server
var myName = false;
// if user is running mozilla then use it's built-in WebSocket
window.WebSocket = window.WebSocket || window.MozWebSocket;
// if browser doesn't support WebSocket, just show some notification and exit
if (!window.WebSocket) {
content.html($('<p>', { text: 'Sorry, but your browser doesn\'t '
+ 'support WebSockets.'} ));
input.hide();
$('span').hide();
return;
}
// open connection
var connection = new WebSocket('ws://127.0.0.1:1337');
connection.onopen = function () {
// first we want users to enter their names
input.removeAttr('disabled');
status.text('Choose name:');
};
connection.onerror = function (error) {
// just in there were some problems with conenction...
content.html($('<p>', { text: 'Sorry, but there\'s some problem with your '
+ 'connection or the server is down.' } ));
};
// most important part - incoming messages
connection.onmessage = function (message) {
// try to parse JSON message. Because we know that the server always returns
// JSON this should work without any problem but we should make sure that
// the massage is not chunked or otherwise damaged.
try {
var json = JSON.parse(message.data);
} catch (e) {
console.log('This doesn\'t look like a valid JSON: ', message.data);
return;
}
// NOTE: if you're not sure about the JSON structure
// check the server source code above
if (json.type === 'color') { // first response from the server with user's color
myColor = json.data;
status.text(myName + ': ').css('color', myColor);
input.removeAttr('disabled').focus();
// from now user can start sending messages
} else if (json.type === 'history') { // entire message history
// insert every single message to the chat window
for (var i=0; i < json.data.length; i++) {
addMessage(json.data[i].author, json.data[i].text,
json.data[i].color, new Date(json.data[i].time));
}
} else if (json.type === 'message') { // it's a single message
input.removeAttr('disabled'); // let the user write another message
addMessage(json.data.author, json.data.text,
json.data.color, new Date(json.data.time));
} else {
console.log('Hmm..., I\'ve never seen JSON like this: ', json);
}
};
/**
* Send mesage when user presses Enter key
*/
input.keydown(function(e) {
if (e.keyCode === 13) {
var msg = $(this).val();
if (!msg) {
return;
}
// send the message as an ordinary text
connection.send(msg);
$(this).val('');
// disable the input field to make the user wait until server
// sends back response
input.attr('disabled', 'disabled');
// we know that the first message sent from a user their name
if (myName === false) {
myName = msg;
}
}
});
/**
* This method is optional. If the server wasn't able to respond to the
* in 3 seconds then show some error message to notify the user that
* something is wrong.
*/
setInterval(function() {
if (connection.readyState !== 1) {
status.text('Error');
input.attr('disabled', 'disabled').val('Unable to comminucate '
+ 'with the WebSocket server.');
}
}, 3000);
/**
* Add message to the chat window
*/
function addMessage(author, message, color, dt) {
content.prepend('<p><span style="color:' + color + '">' + author + '</span> # ' +
+ (dt.getHours() < 10 ? '0' + dt.getHours() : dt.getHours()) + ':'
+ (dt.getMinutes() < 10 ? '0' + dt.getMinutes() : dt.getMinutes())
+ ': ' + message + '</p>');
}
});
chat-server.js
// http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/
"use strict";
// Optional. You will see this name in eg. 'ps' or 'top' command
process.title = 'node-chat';
// Port where we'll run the websocket server
var webSocketsServerPort = 1337;
// websocket and http servers
var webSocketServer = require('websocket').server;
var http = require('http');
/**
* Global variables
*/
// latest 100 messages
var history = [ ];
// list of currently connected clients (users)
var clients = [ ];
/**
* Helper function for escaping input strings
*/
function htmlEntities(str) {
return String(str).replace(/&/g, '&').replace(/</g, '<')
.replace(/>/g, '>').replace(/"/g, '"');
}
// Array with some colors
var colors = [ 'red', 'green', 'blue', 'magenta', 'purple', 'plum', 'orange' ];
// ... in random order
colors.sort(function(a,b) { return Math.random() > 0.5; } );
/**
* HTTP server
*/
var server = http.createServer(function(request, response) {
// Not important for us. We're writing WebSocket server, not HTTP server
});
server.listen(webSocketsServerPort, function() {
console.log((new Date()) + " Server is listening on port " + webSocketsServerPort);
});
/**
* WebSocket server
*/
var wsServer = new webSocketServer({
// WebSocket server is tied to a HTTP server. WebSocket request is just
// an enhanced HTTP request. For more info http://tools.ietf.org/html/rfc6455#page-6
httpServer: server
});
// This callback function is called every time someone
// tries to connect to the WebSocket server
wsServer.on('request', function(request) {
console.log((new Date()) + ' Connection from origin ' + request.origin + '.');
// accept connection - you should check 'request.origin' to make sure that
// client is connecting from your website
// (http://en.wikipedia.org/wiki/Same_origin_policy)
var connection = request.accept(null, request.origin);
// we need to know client index to remove them on 'close' event
var index = clients.push(connection) - 1;
var userName = false;
var userColor = false;
console.log((new Date()) + ' Connection accepted.');
// send back chat history
if (history.length > 0) {
connection.sendUTF(JSON.stringify( { type: 'history', data: history} ));
}
// user sent some message
connection.on('message', function(message) {
if (message.type === 'utf8') { // accept only text
if (userName === false) { // first message sent by user is their name
// remember user name
userName = htmlEntities(message.utf8Data);
// get random color and send it back to the user
userColor = colors.shift();
connection.sendUTF(JSON.stringify({ type:'color', data: userColor }));
console.log((new Date()) + ' User is known as: ' + userName
+ ' with ' + userColor + ' color.');
} else { // log and broadcast the message
console.log((new Date()) + ' Received Message from '
+ userName + ': ' + message.utf8Data);
// we want to keep history of all sent messages
var obj = {
time: (new Date()).getTime(),
text: htmlEntities(message.utf8Data),
author: userName,
color: userColor
};
history.push(obj);
history = history.slice(-100);
// broadcast message to all connected clients
var json = JSON.stringify({ type:'message', data: obj });
for (var i=0; i < clients.length; i++) {
clients[i].sendUTF(json);
}
}
}
});
// user disconnected
connection.on('close', function(connection) {
if (userName !== false && userColor !== false) {
console.log((new Date()) + " Peer "
+ connection.remoteAddress + " disconnected.");
// remove user from the list of connected clients
clients.splice(index, 1);
// push back user's color to be reused by another user
colors.push(userColor);
}
});
});
Command to execute ngrok
Execute node with chat-server.js
Error returned by ngrok
You need to expose to the world your second port 1337, which is used by WebSockets. You would need to have 2 separate ngrok instances running and forwarding 1337 and 8888 ports. Also in chat-client.js line "ws://127.0.0.1:1337" should be changed for the new ngrok forwarding url (for example ws://111111.ngrok.io)

socket.io, webrtc, nodejs video chat app getting errors over https: ERR_SSL_PROTOCOL_ERROR, 404 (Not Found), and ERR_CONNECTION_TIMED_OUT

I have put together a video chat app using socket.io, webrtc, nodejs from this online tutorial from github but now I am getting errors when converting it to be used over https:
Request URL:https://telemed.caduceususa.com/socket.io/?EIO=3&transport=polling&t=1479396416422-0
Request Method:GET
Status Code:404 Not Found
Remote Address:10.9.2.169:443
Other errors I have gotten in this process are as follows:
When I try to declare a different PORT I get - ERR_SSL_PROTOCOL_ERROR,
When I try to declare port 80 or 8080 i get: ERR_CONNECTION_TIMED_OUT
Something is going wrong on this line inside socket.io.js:
xhr.send(this.data);
I am running a node.js server on Windows Server 2012 and I have set up IIS to serve up the server on PORT 80. I have created the subdomain https://telemed.caduceususa.com in DNS and have purchased a trusted SSL cert to run the site over HTTPS.
Here is the excerpt of code from the dev tools that contains the above line that is causing the error as well as my other code:
/**
* Creates the XHR object and sends the request.
*
* #api private
*/
Request.prototype.create = function(){
var opts = { agent: this.agent, xdomain: this.xd, xscheme: this.xs, enablesXDR: this.enablesXDR };
// SSL options for Node.js client
opts.pfx = this.pfx;
opts.key = this.key;
opts.passphrase = this.passphrase;
opts.cert = this.cert;
opts.ca = this.ca;
opts.ciphers = this.ciphers;
opts.rejectUnauthorized = this.rejectUnauthorized;
var xhr = this.xhr = new XMLHttpRequest(opts);
var self = this;
try {
debug('xhr open %s: %s', this.method, this.uri);
xhr.open(this.method, this.uri, this.async);
if (this.supportsBinary) {
// This has to be done after open because Firefox is stupid
// https://stackoverflow.com/questions/13216903/get-binary-data-with-xmlhttprequest-in-a-firefox-extension
xhr.responseType = 'arraybuffer';
}
if ('POST' == this.method) {
try {
if (this.isBinary) {
xhr.setRequestHeader('Content-type', 'application/octet-stream');
} else {
xhr.setRequestHeader('Content-type', 'text/plain;charset=UTF-8');
}
} catch (e) {}
}
// ie6 check
if ('withCredentials' in xhr) {
xhr.withCredentials = true;
}
if (this.hasXDR()) {
xhr.onload = function(){
self.onLoad();
};
xhr.onerror = function(){
self.onError(xhr.responseText);
};
} else {
xhr.onreadystatechange = function(){
if (4 != xhr.readyState) return;
if (200 == xhr.status || 1223 == xhr.status) {
self.onLoad();
} else {
// make sure the `error` event handler that's user-set
// does not throw in the same tick and gets caught here
setTimeout(function(){
self.onError(xhr.status);
}, 0);
}
};
}
debug('xhr data %s', this.data);
xhr.send(this.data);
}
Here is the server.js file:
var fs = require('fs');
var hskey = fs.readFileSync('ssl/telemed_internal_server.key');
var hscert = fs.readFileSync('ssl/telemed_internal_cert.pem');
var ca = fs.readFileSync('ssl/telemed_internal_key.pem');
var credentials = {
ca: ca,
key: hskey,
cert: hscert
};
var static = require('node-static');
var https = require('https');
var util = require('util');
var file = new(static.Server)();
var app = https.createServer(credentials, function (req, res) {
file.serve(req, res);
}).listen(process.env.PORT || 80);
var io = require('socket.io').listen(app);
io.sockets.on('connection', function (socket){
// convenience function to log server messages on the client
function log(){
var array = [">>> Message from server: "];
for (var i = 0; i < arguments.length; i++) {
array.push(arguments[i]);
}
socket.emit('log', array);
}
// when receive sdp, broadcast sdp to other user
socket.on('sdp', function(data){
console.log('Received SDP from ' + socket.id);
socket.to(data.room).emit('sdp received', data.sdp);
});
// when receive ice candidate, broadcast sdp to other user
socket.on('ice candidate', function(data){
console.log('Received ICE candidate from ' + socket.id + ' ' + data.candidate);
socket.to(data.room).emit('ice candidate received', data.candidate);
});
socket.on('message', function (message) {
log('Got message:', message);
// for a real app, would be room only (not broadcast)
socket.broadcast.emit('message', message);
});
socket.on('create or join', function (room) {
// join room
var existingRoom = io.sockets.adapter.rooms[room];
var clients = [];
if(existingRoom){
clients = Object.keys(existingRoom);
}
if(clients.length == 0){
socket.join(room);
io.to(room).emit('empty', room);
}
else if(clients.length == 1){
socket.join(room);
socket.to(room).emit('joined', room, clients.length + 1);
}
// only allow 2 users max per room
else{
socket.emit('full', room);
}
});
socket.on('error', function(error){
console.error(error);
})
});
Here is the main.js (config) file:
//my signalling server
var serverIP = "https://telemed.caduceususa.com/";
// RTCPeerConnection Options
var server = {
// Uses Google's STUN server
iceServers: [{
"url": "stun:stun4.l.google.com:19302"
},
{
url: 'turn:numb.viagenie.ca',
credential: 'muazkh',
username: 'webrtc#live.com'
}]
};
// various other development IPs
// var serverIP = "https://192.168.43.241:2013";
// var serverIP = "https://10.0.11.196:2013";
var localPeerConnection, signallingServer;
var btnSend = document.getElementById('btn-send');
var btnVideoStop = document.getElementById('btn-video-stop');
var btnVideoStart = document.getElementById('btn-video-start');
var btnVideoJoin = document.getElementById('btn-video-join');
var localVideo = document.getElementById('local-video');
var remoteVideo = document.getElementById('remote-video');
var inputRoomName = document.getElementById('room-name');
var localStream, localIsCaller;
btnVideoStop.onclick = function(e) {
e.preventDefault();
// stop video stream
if (localStream != null) {
localStream.stop();
}
// kill all connections
if (localPeerConnection != null) {
localPeerConnection.removeStream(localStream);
localPeerConnection.close();
signallingServer.close();
localVideo.src = "";
remoteVideo.src = "";
}
btnVideoStart.disabled = false;
btnVideoJoin.disabled = false;
btnVideoStop.disabled = true;
}
btnVideoStart.onclick = function(e) {
e.preventDefault();
// is starting the call
localIsCaller = true;
initConnection();
}
btnVideoJoin.onclick = function(e) {
e.preventDefault();
// just joining a call, not offering
localIsCaller = false;
initConnection();
}
function initConnection() {
var room = inputRoomName.value;
if (room == undefined || room.length <= 0) {
alert('Please enter room name');
return;
}
// start connection!
connect(room);
btnVideoStart.disabled = true;
btnVideoJoin.disabled = true;
btnVideoStop.disabled = false;
}
// WEBRTC STUFF STARTS HERE
// Set objects as most are currently prefixed
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection ||
window.webkitRTCPeerConnection || window.msRTCPeerConnection;
window.RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription ||
window.webkitRTCSessionDescription || window.msRTCSessionDescription;
navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia ||
navigator.webkitGetUserMedia || navigator.msGetUserMedia;
window.SignallingServer = window.SignallingServer;
var sdpConstraints = {
optional: [],
mandatory: {
OfferToReceiveVideo: true,
}
}
function connect(room) {
// create peer connection
localPeerConnection = new RTCPeerConnection(server);
// create local data channel, send it to remote
navigator.getUserMedia({
video: true,
audio: true
}, function(stream) {
// get and save local stream
trace('Got stream, saving it now and starting RTC conn');
// must add before calling setRemoteDescription() because then
// it triggers 'addstream' event
localPeerConnection.addStream(stream);
localStream = stream;
// show local video
localVideo.src = window.URL.createObjectURL(stream);
// can start once have gotten local video
establishRTCConnection(room);
}, errorHandler)
}
function establishRTCConnection(room) {
// create signalling server
signallingServer = new SignallingServer(room, serverIP);
signallingServer.connect();
// a remote peer has joined room, initiate sdp exchange
signallingServer.onGuestJoined = function() {
trace('guest joined!')
// set local description and send to remote
localPeerConnection.createOffer(function(sessionDescription) {
trace('set local session desc with offer');
localPeerConnection.setLocalDescription(sessionDescription);
// send local sdp to remote
signallingServer.sendSDP(sessionDescription);
});
}
// got sdp from remote
signallingServer.onReceiveSdp = function(sdp) {
// get stream again
localPeerConnection.addStream(localStream);
trace(localStream)
// if local was the caller, set remote desc
if (localIsCaller) {
trace('is caller');
trace('set remote session desc with answer');
localPeerConnection.setRemoteDescription(new RTCSessionDescription(
sdp));
}
// if local is joining a call, set remote sdp and create answer
else {
trace('set remote session desc with offer');
localPeerConnection.setRemoteDescription(new RTCSessionDescription(
sdp), function() {
trace('make answer')
localPeerConnection.createAnswer(function(
sessionDescription) {
// set local description
trace('set local session desc with answer');
localPeerConnection.setLocalDescription(
sessionDescription);
// send local sdp to remote too
signallingServer.sendSDP(sessionDescription);
});
});
}
}
// when received ICE candidate
signallingServer.onReceiveICECandidate = function(candidate) {
trace('Set remote ice candidate');
localPeerConnection.addIceCandidate(new RTCIceCandidate(candidate));
}
// when room is full, alert user
signallingServer.onRoomFull = function(room) {
window.alert('Room "' + room +
'"" is full! Please join or create another room');
}
// get ice candidates and send them over
// wont get called unless SDP has been exchanged
localPeerConnection.onicecandidate = function(event) {
if (event.candidate) {
//!!! send ice candidate over via signalling channel
trace("Sending candidate");
signallingServer.sendICECandidate(event.candidate);
}
}
// when stream is added to connection, put it in video src
localPeerConnection.onaddstream = function(data) {
remoteVideo.src = window.URL.createObjectURL(data.stream);
}
}
function errorHandler(error) {
console.error('Something went wrong!');
console.error(error);
}
function trace(text) {
console.info(text);
}
Here is the signalling server:
function trace(text){
console.info(text);
}
// Connects to signalling server with given room and IP
// has methods to exchange SDP and ICE candidates
var SignallingServer = function(room, socketServer){
this.room = room;
this.socket = io.connect(socketServer);
this.socket.on('full', function (room){
trace('Room ' + room + ' is full');
this.onRoomFull(room);
}.bind(this));
this.socket.on('empty', function (room){
this.isInitiator = true;
trace('Room ' + room + ' is empty');
});
this.socket.on('join', function (room){
trace('Making request to join room ' + room);
});
this.socket.on('joined', function (room, numClients){
trace('New user has joined ' + room);
trace('Room has ' + numClients + ' clients');
//ask host to initiate sdp transfer
this.onGuestJoined();
}.bind(this));
this.socket.on('sdp received', function(sdp){
trace('Received SDP ');
trace(sdp);
this.onReceiveSdp(sdp);
}.bind(this));
this.socket.on('ice candidate received', function(candidate){
trace('Received ICE candidate ');
trace(candidate);
this.onReceiveICECandidate(candidate);
}.bind(this));
this.socket.on('log', function (array){
console.log.apply(console, array);
});
}
SignallingServer.prototype = {
connect: function(){
if (this.room !== '') {
trace('Joining room ' + this.room);
this.socket.emit('create or join', this.room);
}
},
close: function(){
trace('Disconnecting')
this.socket.disconnect();
},
sendSDP: function(sdp){
trace('sending sdp')
this.socket.emit('sdp', {
room: this.room,
sdp: sdp
});
},
sendICECandidate: function(candidate){
trace('sending ice candidate');
this.socket.emit('ice candidate', {
room: this.room,
candidate: candidate
});
},
onReceiveSdp: function(sdp){
trace('Placeholder function: Received SDP')
},
onGuestJoined: function(){
trace('Placeholder function: Guest joined room')
},
onReceiveICECandidate: function(candidate){
trace('Placeholder function: Received ICE candidate')
},
onRoomFull: function(room){
trace('Placeholder function: Room is full!');
}
}
window.SignallingServer = SignallingServer;
AND FINALLY THE HTML (CAN SOMEONE ALSO EXPLAIN WHAT LIVERELOAD.JS IS?):
<!doctype html>
<!--[if lt IE 7]>
<html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="">
<![endif]-->
<!--[if IE 7]>
<html class="no-js lt-ie9 lt-ie8" lang="">
<![endif]-->
<!--[if IE 8]>
<html class="no-js lt-ie9" lang="">
<![endif]-->
<!--[if gt IE 8]>
<!-->
<html class="no-js" lang="">
<!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title></title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="css/bootstrap.min.css">
<style>
body {
padding-top: 50px;
padding-bottom: 20px;
}
</style>
<link rel="stylesheet" href="css/bootstrap-theme.min.css">
<link rel="stylesheet" href="css/main.css">
<script src="js/vendor/modernizr-2.8.3-respond-1.4.2.min.js"></script>
</head>
<body>
<!--[if lt IE 8]>
<p class="browserupgrade">
You are using an <strong>outdated</strong>
browser. Please
upgrade your browser
to improve your experience.
</p>
<![endif]-->
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">WebRTC Video Chat</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<!-- chatroom name form -->
<form class="navbar-form navbar-right form-inline">
<div class="form-group">
<input class="form-control" type="text" id="room-name" placeholder="Room name"/>
</div>
<button class="btn btn-primary" id="btn-video-start">Start</button>
<button class="btn btn-default" id="btn-video-join">Join</button>
<button class="btn btn-default" disabled id="btn-video-stop">Stop</button>
</form>
</div>
<!--/.navbar-collapse --> </div>
</nav>
<div class="container main">
<div class="row videos">
<div class="remote-video">
<video width="280" height="250" autoplay id="remote-video"></video>
</div>
<div class="local-video">
<video width="280" height="250" autoplay id="local-video" muted></video>
</div>
</div>
</div>
</div>
<!-- /container -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.11.2.min.js"><\/script>')</script>
<script src="js/vendor/bootstrap.min.js"></script>
<script src="js/vendor/socket.io.js"></script>
<script src="js/main.js"></script>
<script src="js/signalling.js"></script>
<script src="//localhost:9010/livereload.js"></script>
</body>
</html>

nodejs jade_ unexpected token 'indent'

i have a problem in this code (anyway sorry for my short Eng.)
i think this is a right code but don't know why it makes errors about indentation? any solutions or advices for this code :( ??
u can ignore the Korean that i wrote in this code
- if (!isSuccess)
script
alert('cannot make a chat room.');
location.href = '/enter';
- else
h3 room title :
span#roomName= roomName
input#leave(type='button', value='나가기')
#chatWindow(style='width:400px; height:400px; overflow:auto; border:1px solid #000; float:left; margin-right:10px;')
div(style='width:100px; height:400px; overflow:auto; border:1px solid #000;')
p 참가자
ul#attendants
each attendant in attendants
li(id='attendant-'+attendant)= attendant
form
span#myName #{nickName}
input(type='text', style='width:300px;')#message
input(type='submit', value='보내기')
script(type='text/javascript')
$(document).ready(function() {
var room = io.connect('/room');
var chatWindow = $('#chatWindow');
var messageBox = $('#message');
var myName = $('#myName').text();
var attendants = $('#attendants');
var showMessage = function(msg) {
chatWindow.append($('<p>').text(msg));
chatWindow.scrollTop(chatWindow.height());
};
room.on('connect', function() {
room.emit('join', {roomName:$('#roomName').text(), nickName:myName});
});
room.on('joined', function(data) {
if(data.isSuccess) {
showMessage(data.nickName + '님이 입장하셨습니다.');
attendants.append($('<li>')
.attr('id', 'attendant-'+data.nickName)
.text(data.nickName));
}
});
room.on('message', function(data) {
showMessage(data.nickName + ' : ' + data.msg);
});
room.on('leaved', function(data) {
showMessage(data.nickName + '님이 나가셨습니다.');
$('#attendant-'+data.nickName).remove();
});
$('form').submit(function(e) {
e.preventDefault();
var msg = messageBox.val();
if ($.trim(msg) !== '') {
showMessage(myName + ' : ' + msg);
room.json.send({nickName:myName, msg:msg});
messageBox.val('');
}
});
$('#leave').click(function(e) {
room.emit('leave', {nickName:myName});
location.href='/enter';
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
If you want to add multiple lines/blocks when you're writing inline JS/CSS you need to add a .
script.
alert('cannot make a chat room.');
location.href = '/enter';
script(type='text/javascript').
$(document).ready(function() {
var room = io.connect('/room');

Why does my node.js / socket.io app not work on iOS6?

I thought the whole point of socket.io was to not have to worry about modern browsers? lol
Anyway, I am new to socket programming. I have a small app that simply mimics mouse movements.
You open several browsers and when you move the mouse, your actions are recorded in the other browsers. It moves a small square. Kinda cool. However, when I open it on my iPad (iOS6) nothing! Sockets isn't connecting. I even put an alert message in the connect event and nothing.
Works in IE, FF and Chrome just fine on my laptop. The only difference is that my dev machine uses localhost while the iPad uses my machine's IP. However, when I connect to my local IP on my laptop, it still works. Just not in Safari/iPad.
Here is my server.
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
fs = require('fs');
app.listen(80);
function handler(req, res) {
var file = __dirname + '/public/index.html';
fs.readFile(file,
function(err, data) {
if(err) {
res.writeHead(500);
return res.end('Error loading index.html');
}
res.writeHead(200);
res.end(data);
}
);
}
var rooms = ['abc', 'test1'];
var sockets = [];
io.sockets.on('connection', function(socket) {
sockets.push(socket);
socket.on('m', function(data) {
socket.broadcast.to(socket.room).emit('relay', {msg: 'MouseX: ' + data.x + ' MouseY: ' + data.y, x: data.x, y: data.y});
});
socket.on('join', function(room) {
socket.join(room);
socket.emit('updateStatus', {msg: 'Joined room ' + room});
console.log('Joined room ' + room);
});
});
Here is my client:
<!doctype html>
<html>
<head>
<style>
body {
padding: 40px;
}
#cursor {
background:white;
border:1px solid black;
color: white;
display: block;
height:24px;
padding:6px;
position:absolute;
width:24px;
z-index:20;
}
</style>
</head>
<body>
<input id='msg' type='text' size='100' /><br />
<input id='box' type='text' size='100' />
<div id='cursor'></div>
<script src='/socket.io/lib/socket.io.js'></script>
<script>
var socket = io.connect('http://localhost');
var b = document.getElementById('box');
var m = document.getElementById('msg');
var c = document.getElementById('cursor');
// join custom room
socket.on('connect', function() {
socket.emit('join', 'abc');
});
// update status messages from server
socket.on('updateStatus', function(data) {
m.setAttribute('value', data.msg);
});
socket.on('relay', function(data) {
b.setAttribute('value', data.msg);
c.style.left = parseInt(data.x) + 'px';
c.style.top = parseInt(data.y) + 'px';
});
document.onmousemove = function(event) {
event = event || window.event;
socket.emit('m', {x: event.clientX, y: event.clientY});
}
</script>
</body>
</html>
Localhost is local to the machine. You're IP should use a ip address or domain name:
something like:
io.connect('192.168.1.110');
or io.connect('test.myapp.com');

Resources