Add in /clients and /client/:client_id status end points

This commit is contained in:
James Allen 2014-11-13 11:48:49 +00:00
parent 8b923d2fda
commit 0b18edeff3
9 changed files with 122 additions and 6 deletions

View file

@ -0,0 +1,37 @@
Utils = require "./Utils"
async = require "async"
module.exports = HttpController =
# The code in this controller is hard to unit test because of a lot of
# dependencies on internal socket.io methods. It is not critical to the running
# of ShareLaTeX, and is only used for getting stats about connected clients,
# and for checking internal state in acceptance tests. The acceptances tests
# should provide appropriate coverage.
_getConnectedClientView: (ioClient, callback = (error, client) ->) ->
client_id = ioClient.id
Utils.getClientAttributes ioClient, [
"project_id", "user_id", "first_name", "last_name", "email", "connected_time"
], (error, {project_id, user_id, first_name, last_name, email, connected_time}) ->
return callback(error) if error?
client = {client_id, project_id, user_id, first_name, last_name, email, connected_time}
client.rooms = []
for name, joined of ioClient.manager.roomClients[client_id]
if joined and name != ""
client.rooms.push name.replace(/^\//, "") # Remove leading /
callback(null, client)
getConnectedClients: (req, res, next) ->
io = req.app.get("io")
ioClients = io.sockets.clients()
async.map ioClients, HttpController._getConnectedClientView, (error, clients) ->
return next(error) if error?
res.json clients
getConnectedClient: (req, res, next) ->
{client_id} = req.params
io = req.app.get("io")
ioClient = io.sockets.socket(client_id)
HttpController._getConnectedClientView ioClient, (error, client) ->
return next(error) if error?
res.json client

View file

@ -1,6 +1,7 @@
Metrics = require "metrics-sharelatex"
logger = require "logger-sharelatex"
WebsocketController = require "./WebsocketController"
HttpController = require "./HttpController"
module.exports = Router =
# We don't want to send raw errors back to the client, in case they
@ -71,4 +72,8 @@ module.exports = Router =
# Don't return raw error to prevent leaking server side info
return callback {message: "Something went wrong"}
else
callback(null, args...)
callback(null, args...)
app.set("io", io)
app.get "/clients", HttpController.getConnectedClients
app.get "/clients/:client_id", HttpController.getConnectedClient

View file

@ -0,0 +1,14 @@
async = require "async"
module.exports = Utils =
getClientAttributes: (client, keys, callback = (error, attributes) ->) ->
attributes = {}
jobs = keys.map (key) ->
(callback) ->
client.get key, (error, value) ->
return callback(error) if error?
attributes[key] = value
callback()
async.series jobs, (error) ->
return callback(error) if error?
callback null, attributes

View file

@ -19,6 +19,8 @@ module.exports = WebsocketController =
err = new Error("not authorized")
logger.error {err, project_id, user_id, client_id: client.id}, "user is not authorized to join project"
return callback(err)
client.join project_id
client.set("privilege_level", privilegeLevel)
client.set("user_id", user_id)
@ -67,5 +69,4 @@ module.exports = WebsocketController =
_getClientData: (client, callback = (error, data) ->) ->
client.get "user_id", (error, user_id) ->
client.get "project_id", (error, project_id) ->
callback null, {client_id: client.id, project_id, user_id}
callback null, {client_id: client.id, project_id, user_id}

View file

@ -8,6 +8,7 @@
"url": "https://github.com/sharelatex/real-time-sharelatex.git"
},
"dependencies": {
"async": "^0.9.0",
"connect-redis": "^2.1.0",
"express": "^4.10.1",
"express-session": "^1.9.1",

View file

@ -41,6 +41,11 @@ describe "joinProject", ->
it "should return the protocolVersion", ->
@protocolVersion.should.equal 2
it "should have joined the project room", (done) ->
RealTimeClient.getConnectedClient @client.socket.sessionid, (error, client) =>
expect(@project_id in client.rooms).to.equal true
done()
describe "when not authorized", ->
before (done) ->
FixturesManager.setUpProject {
@ -60,3 +65,8 @@ describe "joinProject", ->
it "should return an error", ->
# We don't return specific errors
@error.message.should.equal "Something went wrong"
it "should not have joined the project room", (done) ->
RealTimeClient.getConnectedClient @client.socket.sessionid, (error, client) =>
expect(@project_id in client.rooms).to.equal false
done()

View file

@ -5,7 +5,7 @@ RealTimeClient = require "./helpers/RealTimeClient"
describe "Session", ->
describe "with an established session", ->
beforeEach (done) ->
before (done) ->
@user_id = "mock-user-id"
RealTimeClient.setSession {
user: { _id: @user_id }
@ -22,9 +22,19 @@ describe "Session", ->
expect(disconnected).to.equal false
done()
, 500
it "should appear in the list of connected clients", (done) ->
RealTimeClient.getConnectedClients (error, clients) =>
included = false
for client in clients
if client.client_id == @client.socket.sessionid
included = true
break
expect(included).to.equal true
done()
describe "without an established session", ->
beforeEach (done) ->
before (done) ->
RealTimeClient.unsetSession (error) =>
throw error if error?
@client = RealTimeClient.connect()
@ -34,8 +44,18 @@ describe "Session", ->
@client.on "disconnect", () ->
done()
it "not should appear in the list of connected clients", (done) ->
RealTimeClient.getConnectedClients (error, clients) =>
included = false
for client in clients
if client.client_id == @client.socket.sessionid
included = true
break
expect(included).to.equal false
done()
describe "without a valid user set on the session", ->
beforeEach (done) ->
before (done) ->
RealTimeClient.setSession {
foo: "bar"
}, (error) =>
@ -45,4 +65,14 @@ describe "Session", ->
it "should get disconnected", (done) ->
@client.on "disconnect", () ->
done()
it "not should appear in the list of connected clients", (done) ->
RealTimeClient.getConnectedClients (error, clients) =>
included = false
for client in clients
if client.client_id == @client.socket.sessionid
included = true
break
expect(included).to.equal false
done()

View file

@ -1,6 +1,7 @@
XMLHttpRequest = require("../../libs/XMLHttpRequest").XMLHttpRequest
io = require("socket.io-client")
request = require "request"
Settings = require "settings-sharelatex"
redis = require "redis-sharelatex"
rclient = redis.createClient(Settings.redis.web)
@ -37,4 +38,18 @@ module.exports = Client =
connect: (cookie) ->
client = io.connect("http://localhost:3026", 'force new connection': true)
return client
getConnectedClients: (callback = (error, clients) ->) ->
request.get {
url: "http://localhost:3026/clients"
json: true
}, (error, response, data) ->
callback error, data
getConnectedClient: (client_id, callback = (error, clients) ->) ->
request.get {
url: "http://localhost:3026/clients/#{client_id}"
json: true
}, (error, response, data) ->
callback error, data

View file

@ -51,6 +51,9 @@ describe 'WebsocketController', ->
.calledWith(@project_id, @user._id)
.should.equal true
it "should join the project room", ->
@client.join.calledWith(@project_id).should.equal true
it "should set the privilege level on the client", ->
@client.set.calledWith("privilege_level", @privilegeLevel).should.equal true