mirror of https://gitee.com/bigwinds/arangodb
141 lines
4.0 KiB
JavaScript
141 lines
4.0 KiB
JavaScript
'use strict';
|
|
|
|
// //////////////////////////////////////////////////////////////////////////////
|
|
// / DISCLAIMER
|
|
// /
|
|
// / Copyright 2016 ArangoDB GmbH, Cologne, Germany
|
|
// /
|
|
// / Licensed under the Apache License, Version 2.0 (the "License")
|
|
// / you may not use this file except in compliance with the License.
|
|
// / You may obtain a copy of the License at
|
|
// /
|
|
// / http://www.apache.org/licenses/LICENSE-2.0
|
|
// /
|
|
// / Unless required by applicable law or agreed to in writing, software
|
|
// / distributed under the License is distributed on an "AS IS" BASIS,
|
|
// / WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// / See the License for the specific language governing permissions and
|
|
// / limitations under the License.
|
|
// /
|
|
// / Copyright holder is ArangoDB GmbH, Cologne, Germany
|
|
// /
|
|
// / @author Alan Plum
|
|
// //////////////////////////////////////////////////////////////////////////////
|
|
|
|
const assert = require('assert');
|
|
const arangodb = require('@arangodb');
|
|
const NOT_FOUND = arangodb.errors.ERROR_ARANGO_DOCUMENT_NOT_FOUND.code;
|
|
const UNIQUE_CONSTRAINT = arangodb.errors.ERROR_ARANGO_UNIQUE_CONSTRAINT_VIOLATED.code;
|
|
const db = arangodb.db;
|
|
const aql = arangodb.aql;
|
|
|
|
module.exports = function collectionStorage (cfg) {
|
|
if (typeof cfg === 'string' || cfg.isArangoCollection) {
|
|
cfg = {collection: cfg};
|
|
}
|
|
if (!cfg) {
|
|
cfg = {};
|
|
}
|
|
const autoUpdate = Boolean(cfg.autoUpdate !== false);
|
|
const pruneExpired = Boolean(cfg.pruneExpired);
|
|
const ttl = (cfg.ttl || 60 * 60) * 1000;
|
|
const collection = (
|
|
typeof cfg.collection === 'string'
|
|
? db._collection(cfg.collection)
|
|
: cfg.collection
|
|
);
|
|
assert(cfg.collection, 'Must pass a collection to store sessions');
|
|
assert(collection.isArangoCollection, `No such collection: ${cfg.collection}`);
|
|
return {
|
|
prune() {
|
|
return db._query(aql`
|
|
FOR session IN ${collection}
|
|
FILTER session.expires < DATE_NOW()
|
|
REMOVE session IN ${collection}
|
|
RETURN OLD._key
|
|
`).toArray();
|
|
},
|
|
fromClient(sid) {
|
|
try {
|
|
const now = Date.now();
|
|
const session = collection.document(sid);
|
|
if (session.expires < now) {
|
|
if (pruneExpired) {
|
|
collection.remove(session);
|
|
}
|
|
return null;
|
|
}
|
|
if (autoUpdate) {
|
|
collection.update(sid, {expires: now + ttl});
|
|
}
|
|
return {
|
|
_key: session._key,
|
|
uid: session.uid,
|
|
created: session.created,
|
|
data: session.data
|
|
};
|
|
} catch (e) {
|
|
if (e.isArangoError && e.errorNum === NOT_FOUND) {
|
|
return null;
|
|
}
|
|
throw e;
|
|
}
|
|
},
|
|
forClient(session) {
|
|
return session && session._key || null;
|
|
},
|
|
save(session) {
|
|
if (!session) {
|
|
return null;
|
|
}
|
|
const payload = {
|
|
uid: session.uid,
|
|
created: session.created,
|
|
expires: Date.now() + ttl,
|
|
data: session.data
|
|
};
|
|
if (!session._key) {
|
|
// generate a new key
|
|
let crypto = require('@arangodb/crypto');
|
|
while (true) {
|
|
payload._key = crypto.sha256(crypto.rand() + '-frontend');
|
|
try {
|
|
// test if key is already present in collection
|
|
const meta = collection.save(payload);
|
|
session._key = meta._key;
|
|
break;
|
|
} catch (e) {
|
|
if (!e.isArangoError || e.errorNum !== UNIQUE_CONSTRAINT) {
|
|
throw e;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
collection.replace(session._key, payload);
|
|
}
|
|
return session;
|
|
},
|
|
clear(session) {
|
|
if (!session || !session._key) {
|
|
return false;
|
|
}
|
|
try {
|
|
collection.remove(session);
|
|
} catch (e) {
|
|
if (e.isArangoError && e.errorNum === NOT_FOUND) {
|
|
return false;
|
|
}
|
|
throw e;
|
|
}
|
|
return true;
|
|
},
|
|
new() {
|
|
return {
|
|
uid: null,
|
|
created: Date.now(),
|
|
data: null
|
|
};
|
|
}
|
|
};
|
|
};
|