Node.js with ZeroMQ + Socket.io + scope for each client
I am writing a web application using node.js and express to provide aprs stream to each user via ZeroMQ and socket.io.
Concept: node.js app has full aprs stream sent to it by subscribing to publisher ZeroMQ. When a user visits a web page (which is a full screen map), a socket.io session is established and sends the bounds of the currently visible map area back to the server. The server can then cover the full channel to send only new points that are on the map for the user.
Most of the work works well, but it breaks down when more than one person is uploaded to the site. The scope of the currently viewed map becomes global and if you zoom / pan one map, it will start showing points at the new location for both browsers.
I need each socket.io session to keep its own scope and only get data from its unique scope bounds and be unique for each visitor. I tried zmqsocket.on "message", (data) ->
to inject a callback into the socket.io connection, but it still gives the same result (even with the mapbounds variable declared in the respective callbacks.)
The full source for the app can be found here: https://github.com/gmcintire/aprs.bz
If you want to test your application locally, you can clone my repo, run npm install
then coffee app.coffee
to get started. Just keep in mind that it will start streaming the full APRS stream from my ZeroMQ server which could be ~ 100Kb / s.
app.coffee
express = require("express")
routes = require("./routes")
geolib = require("geolib")
zmq = require("zmq")
zmqsocket = zmq.socket("sub")
zmqsocket.connect "tcp://stream.aprs.bz:12777"
zmqsocket.subscribe ""
app = module.exports = express.createServer()
io = require("socket.io").listen(app)
mapbounds = ""
io.sockets.on "connection", (socket) ->
#console.log socket
socket.on "mapmove", (mapcoords) ->
console.log mapbounds
mapbounds = mapcoords
zmqsocket.on "message", (data) ->
packet = JSON.parse(data)
#console.log packet
if packet.latitude? and packet.longitude? and (mapbounds != "")
insideMap = geolib.isPointInside
latitude: packet.latitude
longitude: packet.longitude
, [
latitude: mapbounds._northEast.lat
longitude: mapbounds._southWest.lng
,
latitude: mapbounds._northEast.lat
longitude: mapbounds._northEast.lng
,
latitude: mapbounds._southWest.lat
longitude: mapbounds._northEast.lng
,
latitude: mapbounds._southWest.lat
longitude: mapbounds._southWest.lng
]
if insideMap
console.log "\n--------------------------------------------------------\n"
io.sockets.emit "packet", packet
console.log packet
app.configure ->
app.set "views", __dirname + "/views"
app.set "view engine", "jade"
app.use express.bodyParser()
app.use express.methodOverride()
app.use app.router
app.use express.static(__dirname + "/public")
app.configure "development", ->
app.use express.errorHandler(
dumpExceptions: true
showStack: true
)
app.configure "production", ->
app.use express.errorHandler()
app.get "/", routes.index
if app.settings.env == "development"
app.listen 3000
else
app.listen 80
console.log "Express server listening on port %d in %s mode", app.address().port, app.settings.env
source to share
I have no experience with coffee, but I can see that you store your variables globally.
var mapboudns = 10
io.sockets.on('connection', function(socket){
socket.on("msg", function(data){
mapbounds = data.bounds; //new value of mapbounds is altered globally
});
});
try using something like:
socket.set("mapbounds", someNewValue);
and get the value later:
socket.get("mapbounds");
or use a collection to map each socket to its associated variables
source to share