This repository has been archived on 2024-04-29. You can view files and clone it, but cannot push or open issues or pull requests.
node-fftcg/backend/session.coffee

155 lines
4.3 KiB
CoffeeScript
Raw Normal View History

# node libraries
redis = (require 'redis')
crypto = (require 'crypto')
logger = (require 'logging').default 'session'
2019-05-08 16:45:24 +00:00
# expiry times in days
EXPIRY =
2019-02-16 18:03:21 +00:00
# games expire 1 week after creation
2019-05-08 16:45:24 +00:00
game: 7
# logins expire 1 month after last action
2019-05-08 16:45:24 +00:00
login: 30
2019-02-16 18:15:49 +00:00
class FFTCGSESSION
constructor: ->
@db = redis.createClient
host: 'redis'
port: 6379
2019-06-04 14:58:44 +00:00
@db.on 'error', (err) ->
2019-02-16 18:15:49 +00:00
logger.error err.message
2019-05-28 15:42:21 +00:00
sessionKey: (digest) -> "session.#{digest}"
gameKey: (digest) -> "game.#{digest}"
start: (userid) ->
2019-02-16 18:15:49 +00:00
new Promise (resolve) =>
2019-05-28 15:42:21 +00:00
# hash userid
2019-02-16 18:15:49 +00:00
hmac = crypto.createHmac 'sha256', Math.random().toString()
2019-05-28 15:42:21 +00:00
hmac.update userid.toString()
2019-02-16 18:15:49 +00:00
digest = hmac.digest 'base64'
2019-05-28 15:42:21 +00:00
# push (hash, userid) into DB for the configured timespan
@db.setex (@sessionKey digest), EXPIRY.login * 86400, userid, =>
logger.info "OK '#{@sessionKey digest}' created"
2019-05-08 16:45:24 +00:00
# return cookie data
resolve
value: digest
properties:
expires: EXPIRY.login
2019-02-16 18:15:49 +00:00
2019-05-07 20:15:18 +00:00
destroy: (digest) ->
new Promise (resolve, reject) =>
# delete hash immediately
2019-05-28 15:42:21 +00:00
@db.del (@sessionKey digest), (err, res) =>
2019-05-07 20:15:18 +00:00
if res == 0
reject null
else
2019-05-28 15:42:21 +00:00
logger.info "OK '#{@sessionKey digest}' deleted"
2019-05-07 20:15:18 +00:00
resolve null
2019-02-16 18:15:49 +00:00
check: (digest) ->
new Promise (resolve, reject) =>
# refresh expiry timer on digest
2019-05-28 15:42:21 +00:00
@db.expire (@sessionKey digest), EXPIRY.login * 86400, (err, res) =>
if res == 0
reject null
else
@db.get (@sessionKey digest), (err, res) =>
logger.debug "OK '#{@sessionKey digest}' resumed"
resolve res
newGame: (userid) ->
new Promise (resolve, reject) =>
# generate hash
hmac = crypto.createHmac 'sha256', Math.random().toString()
hmac.update userid.toString()
digest = hmac.digest 'base64'
# insert game key
@db.hsetnx (@gameKey digest), 'owner', userid, (err, res) =>
2019-02-16 18:15:49 +00:00
if res == 0
2019-05-28 15:42:21 +00:00
@db.del (@gameKey digest)
2019-02-16 18:15:49 +00:00
reject null
else
2019-05-28 15:42:21 +00:00
@db.expire (@gameKey digest), EXPIRY.game * 86400, (err, res) =>
if res == 0
@db.del (@gameKey digest)
reject null
else
2019-06-03 20:28:32 +00:00
# add game to active set
@db.sadd (@gameKey 'active'), (@gameKey digest), (err, res) =>
# return game ID
logger.info "OK '#{@gameKey digest}' created"
resolve digest
getGames: ->
# function to return all active gameKeys
activeGameKeys = (set, cursor) =>
# start iteration
set ?= new Set()
cursor ?= '0'
return new Promise (resolve, reject) =>
# scan "active" gameKey
2019-06-04 14:58:44 +00:00
@db.sscan (@gameKey 'active'), cursor, 'COUNT', '100', (err, res) ->
2019-06-03 20:28:32 +00:00
# add to results set
cursor = res[0]
for key in res[1]
set.add key
if cursor == '0'
# done on cursor = 0
resolve set
else
# recursive call (resolve one step deeper)
allGames set, cursor
2019-06-04 14:58:44 +00:00
.then (set) ->
2019-06-03 20:28:32 +00:00
resolve set
2019-06-04 14:58:44 +00:00
activeGameKeys().then (set) ->
2019-06-03 20:28:32 +00:00
logger.info "game count: #{Array.from(set).length}"
2019-05-28 15:42:21 +00:00
joinGame: (digest, userid) ->
new Promise (resolve, reject) =>
# refresh expiry timer on digest
@db.expire (@gameKey digest), EXPIRY.game * 86400, (err, res) =>
if res == 0
reject null
else
# insert opponent value
@db.hsetnx (@gameKey digest), 'opponent', userid, (err, res) =>
if res == 0
reject null
else
# return game ID
logger.info "OK '#{@gameKey digest}' joined"
resolve digest
updateGame: (digest, state) ->
new Promise (resolve, reject) =>
# refresh expiry timer on digest
@db.expire (@gameKey digest), EXPIRY.game * 86400, (err, res) =>
if res == 0
reject null
else
# update state value
@db.hset (@gameKey digest), 'state', (JSON.stringify state), (err, res) =>
if res == 0
reject null
else
# return game ID
logger.info "OK '#{@gameKey digest}' updated"
resolve digest
2019-02-19 18:57:22 +00:00
module.exports = new FFTCGSESSION