Changing twitter stream predicates (Node.js, socket.io) - javascript

I am constructing a twitter stream with Twit where the user can change the search term from the client.
The searchwords would be saved in a buffer and added to the stream in accordance with Twitters reconnection rules.
My code looks something like this:
var Twit = require('twit');
var T = new Twit({
consumer_key: 'xxxxxxxxx'
, consumer_secret: 'xxxxxxxxx'
, access_token: 'xxxxxxxxx'
, access_token_secret: 'xxxxxxxxx'
})
var searchStr = "orange";
var stream = T.stream('statuses/filter', { track: searchStr });
setInterval(function(){
newSearchStr = getNewSearchStr();
stream.stop();
stream = T.stream('statuses/filter', { track: newSearchStr});
},60*5*1000);
io.sockets.on('connection', function(socket) {
//SAVE USER AND INTITIAL SEARCH CRITERIA
// ...
stream.on('tweet', function (tweet) {
socket.emit('data',tweet);
});
socket.on('setSearchStr', function (searchStr) {
//SAVE SEARCH TO BUFFER FOR getNewSearchStr() TO OBTAIN
});
});
My problem is reinitializing the stream with new searches.
In the inteval-function stream.stop() does stop the stream (and stream.start() works too) but stream = T.stream(... opens a new connection instead of updating the current one. Thus the stream the user is listening to is disconnicted and the user stops recieving data until refreshing the browser.
Any ideas on how to do this with Twit? Any practical differences between clients? Other suggestions?
EDIT:
The answer for a similiar question has a outdated link. I would really like to see the page with "instructions how change the predicates and making the user experience as smooth as possible"

Perhaps not best practise, but I eventually solved the problem by directly editing the stream object:
setInterval(function(){
//check if criteria has changed
if(stream.params.track != searchStr){
console.log("Reconnecting with " + searchStr);
stream.stop();
stream.params.track = searchStr;
stream.start();
}
else {
console.log("Criteria unchanged");
}
},60*5*1000);

Related

NodeJS Websocket use variable in HTML (with express?)

I have been searching for two days now looking for a solution that might work for me. Sadly I have only seen examples and guides on how to setup a websocket server (that sends messages back and forth to clients) and a websocket client (that resides in browser). None of these really work for me, and I am not sure how to achieve what I want here.
Basically I have the following websocket:
require('dotenv').config()
const WebSocket = require('ws');
var connection = new WebSocket('ws://XXX');
connection.onopen = function () {
connection.send(JSON.stringify({"authenticate":process.env.API}));
connection.send(JSON.stringify({"XXX":"YYY"}));
connection.send(JSON.stringify({
"db" : "unique_id",
"query" : {
"table" : "users"
}
}));
};
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
};
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
var myResponse = JSON.parse(e.data);
var qList = myResponse.results;
};
What I want to do is have my nodeJS-script running, for example an express script with a html page, that also includes the response from onmessage. Why I am complicating this instead of just using the websocket client-side is that I cannot send my auth-code publicly.
Hope I have been clear enough, let me know if you are unsure of my question!
PS. If you think I would be better off using another websocket-script such as Socket.io - I have been looking at them and have not gotten much wiser sadly.
You have a lot of options. Probably the easiest is to export the connection. At the bottom of the file, e.g. module.exports = connection
Then in the express application, import the connection, e.g. const connection = require('./path/connection');
Then make a function that calls itself at a given interval and sends the appropriate message.
Then within the Express app you can use something like connection.on('message', (data, flags) => // do stuff);
Your other option is to create a store object. E.g.
// ./store.js
class store {
constructor() {
this.wsMaterial = {};
}
add(wsInfo) {
this.wsMaterial[key] = wsInfo
}
get store() {
return this.wsMaterial
}
}
module.exports = new store()
Then import the store and updated it, e.g.
// ./websocket file
const store = require('./store');
...
connection.onmessage = function (e) {
console.log('Server: ' + e.data);
var myResponse = JSON.parse(e.data);
var qList = myResponse.results;
store.add(qList)
};
Then from Express...
// ./express.js
const store = require('./store');
store.get // all of your stuff;

Unsupported URL with post data from IOS to backend service

I want to use webrtc in an IOS (Swift) project. I find so much difficulties to implement it properly. So I searched for an library so I can get how it is implemented to do it later myself.
I found this project:
https://github.com/sushilthe/webrtc-ios-swift
It works fine with https://apprtc.appspot.com. But it is making a POST? request when you want to join a room:
Base url:
https://apprtc.appspot.com/
Part that is appended to the base:
static NSString *kARDRoomServerRegisterFormat =
#"%#/join/%#";
Result:
https://apprtc.appspot.com/join/'roomnr'
I have build a server with some resources from the internet:
$(document).ready(function() { //wait for DOM to be ready for JS execution
easyrtc.setVideoDims(1280, 768);
easyrtc.easyApp('vcdemo', 'self', ['peer'], connectSuccess, failureCallback); //connect to easyrtc app; initiate media sources and elements
});
//global state variables
var myEasyrtcId; //id of client in the signaling framework
//global functions
var connectSuccess = function(easyrtcid) { //join room as defined by "room" parameter in URL
myEasyrtcId = easyrtcid;
console.log('Connect successful. My id is ' + myEasyrtcId + '.');
var room = decodeURIComponent((new RegExp('[?|&]room=' + '([^&;]+?)(&|#|;|$)'). //retrieve room name from URL
exec(location.search) || [, ""])[1].replace(/\+/g, '%20')) || null;
console.log('join room: ' + room);
easyrtc.joinRoom(room, null, joinSuccess, failureCallback);
};
var failureCallback = function(errorCode, errorMsg) { //log error
console.log(errorCode);
console.log(errorMsg);
};
var joinSuccess = function(roomName) { //listen for peers joining the room
setTimeout(function() {
console.log('successfully joined room: ' + roomName);
var peers = easyrtc.getRoomOccupantsAsArray(roomName) || []; //get list of client connected to room
console.log('peers: ' + peers);
var peersLength = peers.length;
if (peersLength > 2) { //support only 1-1 video conferences
alert('The meeting room is already full. ' +
'Only the two peers connecting first will be allowed access.');
} else if(peersLength === 1) { //if no other peer is connected
console.log('waiting for peer to connect...');
} else if(peers[0] != myEasyrtcId) {//get peer id
easyrtc.call(peers[0]);
} else {
easyrtc.call(peers[1]);
}
}, 100);
};
This works perfect in chrome and firefox via this url:
localhost:8080/?room=123
And I can connect to that stream when I reuse that room number. Perfect!
So I thought I can implement that in the app, I have changed the serverHostUrl to: client?.serverHostUrl = "192.168.1.59:8080"
And the other variable:
static NSString *kARDRoomServerRegisterFormat = #"%#/?room=%#";
But I get an error when it try's to submit the url:
Client Connecting
2016-10-17 19:24:51.151795 WebRTC iOS Swift[3944:1036130] Registering with room server.
2016-10-17 19:24:51.151900 WebRTC iOS Swift[3944:1036130] url = 192.168.1.59:8080/?room=123
2016-10-17 19:24:51.207496 WebRTC iOS Swift[3944:1036130] Error posting data: unsupported URL
Client Disconnected
I have searched a few hours why this is happening. But I can't find the problem. Thank you very much!
EDIT
The Code where it goes wrong:
The roomURL is: 192.168.1.59:8080/?room=123 at that moment.
[NSURLConnection sendAsyncPostToURL:roomURL
withData:nil
completionHandler:^(BOOL succeeded, NSData *data) {
ARDAppClient *strongSelf = weakSelf;
if (!succeeded) {
NSError *error = [self roomServerNetworkError];
[strongSelf.delegate appClient:strongSelf didError:error];
completionHandler(nil);
return;
}
ARDRegisterResponse *response =
[ARDRegisterResponse responseFromJSONData:data];
completionHandler(response);
}];

Net.Socket instances don't go away in NodeJS

I'm trying to recreate the functionality of a hardware serial server with Node and it's actually working, but I'm getting errors from socket instances that have been closed.
Here's a simplified version of the app to show what I'm doing...
var net = require('net');
var SerialPort = require('serialport');
var connectionCounter = 0;
var port = new SerialPort('/dev/ttyUSB0', function () {
var server = net.createServer();
server.on('connection',function(socket) {
connectionCounter++;
var connNumber = connectionCounter;
socket.on('error', function () {
console.log('socket ' + connNumber + ' errored');
});
socket.on('data', function(data) {
port.write(data);
});
port.on('data', function(data) {
socket.write(data);
});
});
server.listen(8887, '127.0.0.1');
}
});
So the first chunk of code that's sent into the 8887 port works fine, and it returns the data back out through the socket. The errors start on the second chunk. In the example, I'm keeping a count of the socket instances and outputting the socket instance number with the error. So as the program runs, the number of sockets instances keeps going up. The most recent instance will eventually handle the data, but I can't figure out what I need to delete to clean up all of the previous socket instances so they'll stop trying to process the incoming data.
I've tried socket.end() and socket.destroy(), but those don't seem to work . Do I need to go as far as deleting the server itself and recreating it?
If anyone ever finds this and cares about what was going wrong, I was setting an event listener on the serialport object every time a new net socket was created. So even though I was deleting the socket every time it was closed, the serialport listener was trying to send data to all of the old deleted sockets. So the solution was to removeListeners from the serialport object upon closing the net socket.
you can use array for storing sockets later on you can delete. this is sample code hope you got the idea
var net = require('net');
var SerialPort = require('serialport');
var connectionCounter = 0;
var mySockets = [];
var port = new SerialPort('/dev/ttyUSB0', function () {
var server = net.createServer();
server.on('connection',function(socket) {
mySockets.push(socket);
connectionCounter++;
var connNumber = connectionCounter;
socket.on('error', function () {
console.log('socket ' + connNumber + ' errored');
});
socket.on('data', function(data) {
port.write(data);
});
port.on('data', function(data) {
socket.write(data);
});
});
server.listen(8887, '127.0.0.1');
}
//get the sockets you want to delete
var s = mySockets.pop();
s = null;
});

Socket.io: How to uniquely identify a connection on client and server?

My app supports multiple socket.io clients from the same host (IP address). For diagnostics, I need to be able correlate client and server logs to identify which client the server is talking to. Does socket.io provide a way to uniquely identify a connection?
What I do is that within /routes/socket.js, I have these added to my requires:
var thisApp = require('../app');
var cookieSig = require('express/node_modules/cookie-signature');
var cookie = require('cookie');
var connect = require('express/node_modules/connect')
, parseSignedCookie = connect.utils.parseSignedCookie;
This answer assumes you have a session store of some kind that you can access via thisApp.thisStore. In my case, in the main app.js, I set up a session store using kcbanner's connect-mongo (available via npm and github.com) using a MongoDB back-end hosted on MongoLab for mine. In the session store, for each session, you can have a unique username, or some other identifier that goes along with that session. Really, you can tack any data you want to that session. That's how you'd tell them apart.
The code I use looks like this:
module.exports = function (socket) {
socket.on('taste:cookie', function (data, callback) {
console.log("taste:cookie function running");
//get the session ID
var sid = data.sid;
sid = parseSignedCookie(sid['connect.sid'], "mySecret");
console.log("sid: ",sid);
//get the handshake cookie
var hssid = cookie.parse(socket.handshake.headers.cookie);
hssid = parseSignedCookie(hssid['connect.sid'], "mySecret");
console.log("hssid: %s",hssid);
if(sid) {
if(sid['connect.sid']) {
sid = sid['connect.sid'].slice(2);
console.log("sliced the sid: %s",sid);
sid = cookieSig.unsign(sid, "mySecret");
hssid = sid;
}
if(hssid != sid) {
console.log("browser cookie not set right; rectifying...");
data.sid = hssid;
sid = hssid;
}
else console.log("browser cookie was set right");
}
thisApp.thisStore.get(sid, function(err, gotsession) {
if(err || !gotsession) {
//handle error
return;
} else {
if(gotsession.username) {
callback(0, {username:gotsession.username});
}
else callback(1, {username:""});
}
});
});
Maybe there's a more elegant way to do this, but this does work.
You can use session+cookies: Here's a library that you can use or learn from: session-socket.io.
You'll find plenty of examples on their README page.

Creating a map of ids to sockets and vice versa in Node.js

I'm trying to manage a bunch of socket connections. My app is basically an http server that receives posts and passes these along to a socket. When clients open a socket connection, they send a connect message with an id:
{"m":"connect","id":"1"}
The app then saves this id and socket in the id2socket and socket2id maps. On disconnect, the socket/id pair is deleted from the maps.
A post will also contain an id, which indicates the post data should be sent to the socket with that id.
That's great, and this works fine for a single open socket. However, when I have more than one socket open, and then I close a socket, that disconnect wipes everything from the map. I think my understanding of sockets in node is incomplete- is there only a single socket object that is used in the callback? Is there a better way to manage my open socket connections and ids?
start server:
>>node server.js
TCP server listening on 127.0.0.1:5280
HTTP server listening on 127.0.0.1:9002
telnet in:
>>telnet localhost 5280
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
{"m":"connect","id":"123"}
{"m":"connect","id":"123","success":"true"}
server after connection:
>>Connection from 127.0.0.1:57572
received data: {"m":"connect","id":"123"}
id: 1
m: connect
associating uid 1 with socket [object Object]
do a post:
python post.py {"foo":"bar"}
So this works fine for several open sockets (as long as 1 device is id 123, server has this hardwired for now). However, as soon as you close one connection all the socket connections are removed from the map.
Here's my code:
python script to do post:
import sys
import json
import httplib, urllib, urllib2
values = json.loads('{"foo":"bar"}')
headers = {"Content-type": "application/json"}
conn = httplib.HTTPConnection('127.0.0.1', 9002)
headers = {"Content-type": "application/json"}
conn.request("POST", "", json.dumps(values), headers)
response = conn.getresponse()
print "response.status: "+response.status
print "response.reason: "+response.reason
print "response.read: "+response.read()
conn.close()
node server (http and tcp), hardwired to send data to device '123' on post:
var net = require('net'); // tcp-server
var http = require("http"); // http-server
var qs = require('querystring'); // http-post
// Map of sockets to devices
var id2socket = new Object;
var socket2id = new Object;
// Setup a tcp server
var server_plug = net.createServer(function(socket) {
// Event handlers
socket.addListener("connect", function(conn) {
console.log("Connection from " + socket.remoteAddress + ":" + socket.remotePort );
});
socket.addListener("data", function(data) {
console.log("received data: " + data);
try {
request = JSON.parse(data);
response = request;
if(request.m !== undefined && request['id'] !== undefined){ // hack on 'id', id is js obj property
console.log("id: "+request['id']);
console.log("m: "+request.m);
if(request.m == 'connect'){
console.log("associating uid " + request['id'] + " with socket " + socket);
id2socket[request['id']] = socket;
socket2id[socket] = request['id'];
response.success = 'true';
} else {
response.success = 'true';
}
}
socket.write(JSON.stringify(response));
} catch (SyntaxError) {
console.log('Invalid JSON:' + data);
socket.write('{"success":"false","response":"invalid JSON"}');
}
});
socket.on('end', function() {
id = socket2id[socket]
console.log("socket disconnect by id " + id);
// wipe out the stored info
console.log("removing from map socket:"+socket+" id:"+id);
delete id2socket[id];
delete socket2id[socket];
});
socket.on('timeout', function() {
console.log('socket timeout');
});
});
// Setup http server
var server_http = http.createServer(
// Function to handle http:post requests, need two parts to it
// http://jnjnjn.com/113/node-js-for-noobs-grabbing-post-content/
function onRequest(request, response) {
request.setEncoding("utf8");
request.addListener("data", function(chunk) {
request.content += chunk;
});
request.addListener("end", function() {
console.log("post received!");
//console.log("Request received: "+request.content);
if (request.method == 'POST') {
//var json = qs.parse(request.content);
//console.log("Post: "+json);
// HACK TO TEST STUFF:
// send a message to one of the open sockets
try {
var socket = id2socket['123']; //hardwired
socket.write('{"m":"post"}');
} catch (Error) {
console.log("Cannot find socket with id "+'123');
}
}
});
}
);
// Fire up the servers
var HOST = '127.0.0.1';
var PORT = 5280;
var PORT2 = 9002;
server_plug.listen(PORT, HOST);
console.log("TCP server listening on "+HOST+":"+PORT);
server_http.listen(PORT2);
console.log("HTTP server listening on "+HOST+":"+PORT2);
Objects only take strings as keys for their properties. As your log shows, a socket object is converted into the string "[object Object]". As a result, socket #2 overwrites the id from socket #1 in the object, because all sockets are converted into the same string key. So, there is only one property in the object at all times, because all sockets come down to the same key. When you try to remove the id for socket #2, the single property is deleted and the object is empty.
You seem to want a custom property for each separate socket when used as a key. You can use WeakMaps for this. WeakMaps do allow objects as keys (as opposed to string-only keys), but as they're relatively new they may contain bugs at the moment.
(Note that the id2socket map can just be a plain object, because numbers are converted into strings just fine, and each number has its own, distinct string representation*.)
Using WeakMaps is as follows:
var socket2id = new WeakMap; // as if you were doing: var socket2id = {};
socket2id.set(socket, id); // as if you were doing: socket2id[socket] = id;
socket2id.get(socket); // as if you were doing: socket2id[socket];
socket2id.delete(socket); // as if you were doing: delete socket2id[socket];
Make sure to run with node --harmony (>= 0.7) or node --harmony_weakmaps (<= 0.6).
* 0 and -0 are exceptions, but you shouldn't be using -0 anyway because 0 === -0, so it's difficult to differ between them.

Categories

Resources