Use variable to store active sessions

Keep session data in process for as long as the TCP connectoin is
open. Use redis if connection closes before the session is over.
This commit is contained in:
Zaid Abdulla committed 2016-08-29 00:17:01 -07:00
1 parent e6aab4229d
commit 41fb97adef
3 files changed
+68 -37

No files matched your search

+43 -14
View File
@@ -40,6 +40,7 @@
util = require 'util' util = require 'util'
zlib = require 'zlib' zlib = require 'zlib'
crypto = require 'crypto'
mongodb = require 'mongodb' mongodb = require 'mongodb'
config = require './config' config = require './config'
@@ -94,16 +95,13 @@ inform = (currentRequest, cwmpRequest) ->
cwmpVersion : currentRequest.sessionData.cwmpVersion cwmpVersion : currentRequest.sessionData.cwmpVersion
}) })
session.save(currentRequest.sessionData, (err, sessionId) ->
throw err if err
if !!cookiesPath = config.get('COOKIES_PATH', currentRequest.sessionData.deviceId) if !!cookiesPath = config.get('COOKIES_PATH', currentRequest.sessionData.deviceId)
res.headers['Set-Cookie'] = "session=#{sessionId}; Path=#{cookiesPath}" res.headers['Set-Cookie'] = "session=#{currentRequest.sessionData.sessionId}; Path=#{cookiesPath}"
else else
res.headers['Set-Cookie'] = "session=#{sessionId}" res.headers['Set-Cookie'] = "session=#{currentRequest.sessionData.sessionId}"
writeResponse(currentRequest, res) writeResponse(currentRequest, res)
) )
)
testSchedule = (schedule, timestamp) -> testSchedule = (schedule, timestamp) ->
@@ -268,6 +266,8 @@ sendRpcRequest = (currentRequest, id, rpcRequest) ->
if not rpcRequest? if not rpcRequest?
session.end(currentRequest.sessionData, (err, isNew) -> session.end(currentRequest.sessionData, (err, isNew) ->
throw err if err throw err if err
delete currentSessions.get(currentRequest.httpRequest.connection)[currentRequest.sessionData.sessionId]
if isNew if isNew
util.log("#{currentRequest.sessionData.deviceId}: New device registered") util.log("#{currentRequest.sessionData.deviceId}: New device registered")
@@ -293,10 +293,7 @@ sendRpcRequest = (currentRequest, id, rpcRequest) ->
cwmpVersion : currentRequest.sessionData.cwmpVersion cwmpVersion : currentRequest.sessionData.cwmpVersion
}) })
session.save(currentRequest.sessionData, (err) ->
throw err if err
writeResponse(currentRequest, res) writeResponse(currentRequest, res)
)
getSession = (httpRequest, callback) -> getSession = (httpRequest, callback) ->
@@ -307,9 +304,38 @@ getSession = (httpRequest, callback) ->
return callback() if not sessionId? return callback() if not sessionId?
session.load(sessionId, (err, sessionData) -> sessionData = currentSessions.get(httpRequest.connection)?[sessionId]
if sessionData?
return callback(null, sessionData)
setTimeout(() ->
db.redisClient.eval('local v=redis.call("get",KEYS[1]);redis.call("del",KEYS[1]);return v;', 1, "session_#{sessionId}", (err, sessionDataString) ->
return callback(err) if err or not sessionDataString
session.deserialize(sessionDataString, (err, sessionData) ->
return callback(err) if err
currentSessions.get(httpRequest.connection)[sessionId] = sessionData
callback(null, sessionData)
)
)
, 100
)
currentSessions = new WeakMap()
# When socket closes, store active sessions in redis
onConnection = (socket) ->
currentSessions.set(socket, {})
socket.on('close', () ->
sessions = currentSessions.get(socket)
for sessionId, sessionData of sessions
session.serialize(sessionData, (err, sessionDataString) ->
throw err if err throw err if err
return callback(sessionId, sessionData) db.redisClient.setex("session_#{sessionId}", sessionData.timeout, sessionDataString, (err) ->
throw err if err
)
)
) )
@@ -352,7 +378,8 @@ listener = (httpRequest, httpResponse) ->
stream.on('end', () -> stream.on('end', () ->
cwmpRequest = null cwmpRequest = null
getSession(httpRequest, f = (sessionId, sessionData) -> getSession(httpRequest, f = (err, sessionData) ->
throw err if err
cwmpRequest ?= soap.request(httpRequest, sessionData?.cwmpVersion) cwmpRequest ?= soap.request(httpRequest, sessionData?.cwmpVersion)
if not sessionData? if not sessionData?
if cwmpRequest.methodRequest?.type isnt 'Inform' if cwmpRequest.methodRequest?.type isnt 'Inform'
@@ -364,6 +391,10 @@ listener = (httpRequest, httpResponse) ->
return session.init(deviceId, cwmpRequest.cwmpVersion, cwmpRequest.sessionTimeout ? config.get('SESSION_TIMEOUT', deviceId), (err, sessionData) -> return session.init(deviceId, cwmpRequest.cwmpVersion, cwmpRequest.sessionTimeout ? config.get('SESSION_TIMEOUT', deviceId), (err, sessionData) ->
throw err if err throw err if err
sessionData.sessionId = crypto.randomBytes(8).toString('hex')
currentSessions.get(httpRequest.connection)[sessionData.sessionId] = sessionData
httpRequest.connection.setTimeout(sessionData.timeout * 1000) httpRequest.connection.setTimeout(sessionData.timeout * 1000)
db.getDueTasksAndFaults(deviceId, sessionData.timestamp, (err, dueTasks, faults) -> db.getDueTasksAndFaults(deviceId, sessionData.timestamp, (err, dueTasks, faults) ->
@@ -401,10 +432,7 @@ listener = (httpRequest, httpResponse) ->
methodResponse : {type : 'GetRPCMethodsResponse', methodList : ['Inform', 'GetRPCMethods', 'TransferComplete', 'RequestDownload']}, methodResponse : {type : 'GetRPCMethodsResponse', methodList : ['Inform', 'GetRPCMethods', 'TransferComplete', 'RequestDownload']},
cwmpVersion : currentRequest.sessionData.cwmpVersion cwmpVersion : currentRequest.sessionData.cwmpVersion
}) })
session.save(currentRequest.sessionData, (err) ->
throw err if err
writeResponse(currentRequest, res) writeResponse(currentRequest, res)
)
else if cwmpRequest.methodRequest.type is 'TransferComplete' else if cwmpRequest.methodRequest.type is 'TransferComplete'
throw new Error('ACS method not supported') throw new Error('ACS method not supported')
else if cwmpRequest.methodResponse? else if cwmpRequest.methodResponse?
@@ -469,3 +497,4 @@ listener = (httpRequest, httpResponse) ->
exports.listener = listener exports.listener = listener
exports.onConnection = onConnection
+4
View File
@@ -30,6 +30,7 @@ port = config.get("#{service.toUpperCase()}_PORT")
useHttps = config.get("#{service.toUpperCase()}_SSL") useHttps = config.get("#{service.toUpperCase()}_SSL")
serviceListener = require("./#{service}").listener serviceListener = require("./#{service}").listener
onConnection = require("./#{service}").onConnection
server = null server = null
@@ -77,6 +78,9 @@ if useHttps
else else
server = require('http').createServer(listener) server = require('http').createServer(listener)
if onConnection?
server.on('connection', onConnection)
db.connect((err) -> db.connect((err) ->
throw err if err throw err if err
server.listen(port, networkInterface) server.listen(port, networkInterface)
+21 -23
View File
@@ -15,8 +15,6 @@
# along with GenieACS. If not, see <http://www.gnu.org/licenses/>. # along with GenieACS. If not, see <http://www.gnu.org/licenses/>.
### ###
crypto = require 'crypto'
config = require './config' config = require './config'
common = require './common' common = require './common'
db = require './db' db = require './db'
@@ -1090,10 +1088,7 @@ rpcFault = (sessionData, id, faultResponse, callback) ->
return callback(null, faultResponse) return callback(null, faultResponse)
load = (id, callback) -> deserialize = (sessionDataString, callback) ->
db.redisClient.get("session_#{id}", (err, sessionDataString) ->
return callback(err) if err or not sessionDataString?
cache.getProvisionsAndVirtualParameters((err, hash, provisions, virtualParameters) -> cache.getProvisionsAndVirtualParameters((err, hash, provisions, virtualParameters) ->
return callback(err) if err return callback(err) if err
@@ -1129,15 +1124,9 @@ load = (id, callback) ->
return callback(null, sessionData) return callback(null, sessionData)
) )
)
save = (sessionData, callback) -> serialize = (sessionData, callback) ->
delete sessionData.syncState
delete sessionData.toLoad
delete sessionData.cache
sessionData.id ?= crypto.randomBytes(8).toString('hex')
deviceData = [] deviceData = []
keys = ['exist', 'object', 'writable', 'value'] keys = ['exist', 'object', 'writable', 'value']
iter = sessionData.deviceData.paths.find([], 99) iter = sessionData.deviceData.paths.find([], 99)
@@ -1154,15 +1143,24 @@ save = (sessionData, callback) ->
deviceData.push(e) deviceData.push(e)
oldDeviceData = sessionData.deviceData.deviceData oldDeviceData = sessionData.deviceData
sessionData.deviceData = deviceData oldSyncState = sessionData.syncState
sessionDataString = JSON.stringify(sessionData) oldToLoad = sessionData.toLoad
sessionData.deviceData = oldDeviceData oldCache = sessionData.cache
db.redisClient.setex("session_#{sessionData.id}", sessionData.timeout, sessionDataString, (err) -> sessionData.deviceData = deviceData
return callback(err, sessionData.id) delete sessionData.syncState
) delete sessionData.toLoad
return delete sessionData.cache
sessionDataString = JSON.stringify(sessionData)
sessionData.deviceData = oldDeviceData
sessionData.syncState = oldSyncState
sessionData.toLoad = sessionData.toLoad
sessionData.cache = sessionData.cache
return callback(null, sessionDataString)
end = (sessionData, callback) -> end = (sessionData, callback) ->
@@ -1182,5 +1180,5 @@ exports.rpcRequest = rpcRequest
exports.rpcResponse = rpcResponse exports.rpcResponse = rpcResponse
exports.rpcFault = rpcFault exports.rpcFault = rpcFault
exports.end = end exports.end = end
exports.save = save exports.serialize = serialize
exports.load = load exports.deserialize = deserialize