Skip to content

Commit

Permalink
feat: support sessions via session middleware
Browse files Browse the repository at this point in the history
  • Loading branch information
simplymichael committed Jun 14, 2024
1 parent 3c79c94 commit 5182378
Show file tree
Hide file tree
Showing 5 changed files with 159 additions and 39 deletions.
91 changes: 91 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"license": "Private",
"dependencies": {
"awilix": "10.0.2",
"connect-redis": "7.1.1",
"cookie-parser": "1.4.6",
"cors": "2.8.5",
"debug": "4.3.5",
Expand Down
25 changes: 18 additions & 7 deletions src/app.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const path = require("node:path");
const RedisStore = require("connect-redis").default;
const cors = require("cors");
const express = require("express");
const cookieParser = require("cookie-parser");
Expand All @@ -7,10 +8,12 @@ const bootstrap = require("./bootstrap");
const providers = require("./bootstrap/providers");
const config = require("./config");
const container = require("./framework/component/container");
const Connections = require("./framework/connections");
const { StatusCodes, StatusTexts } = require("./framework/component/http");
const Router = require("./framework/component/router");
const view = require("./framework/component/view");
const { convertBackSlashToForwardSlash } = require("./framework/lib/string");
const session = require("./middleware/session");

const router = new Router();
const allowedOrigins = config.get("app.allowedOrigins");
Expand All @@ -36,24 +39,26 @@ const corsOptions = {
* @return {Object} An Express app instance.
*/
module.exports = function createApp({ webRouter, apiRouter }) {
/*
* Our first action is to bootstrap (aka, register) the services.
* This way, any registered services are available to route handlers
* (via req.app.resolve(serviceName)) and other files.
*/
bootstrap(config, providers);

if(typeof webRouter !== "function" && typeof apiRouter !== "function") {
throw new Error(
"createApp 'options' object expects either or both of " +
"the following function members: `webRouter`, `apiRouter`."
);
}

/*
* Our first action is to bootstrap (aka, register) the services.
* This way, any registered services are available to route handlers
* (via req.app.resolve(serviceName)) and other files.
*/
bootstrap(config, providers);

const app = express();
const STATUS_CODES = Object.assign(Object.create(null), StatusCodes);
const STATUS_TEXTS = Object.assign(Object.create(null), StatusTexts);

let sessionStore;

/*
* Make the app a DI Container.
*
Expand All @@ -70,6 +75,11 @@ module.exports = function createApp({ webRouter, apiRouter }) {
}
}

if(config.get("session.storageDriver") === "redis") {
const redisClient = Connections.get("redis", config.get("redis"));
sessionStore = new RedisStore({ client: redisClient });
}

/*
* Disable the X-Powered-By header
*/
Expand All @@ -85,6 +95,7 @@ module.exports = function createApp({ webRouter, apiRouter }) {
app.use(express.static(convertBackSlashToForwardSlash(path.join(__dirname, "public"))));
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session(config, sessionStore));
app.use(cors(corsOptions));

/*
Expand Down
47 changes: 47 additions & 0 deletions src/framework/connections/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const RedisStore = require("../component/connector/redis");
const createObjectStore = require("../component/registry");

const registry = createObjectStore();

module.exports = class Connections {
static get(key, options) {
key = key.toLowerCase();

if(!registry.contains(key)) {
switch(key) {
case "redis":
registry.add("redis", Connections.#connectToRedis(options));
break;
}
}

return registry.get(key);
}

static #connectToRedis(redisCreds) {
try {
const redisStore = new RedisStore(redisCreds);
const redisClient = redisStore.getClient();
const log = Connections.#log.bind(Connections);

// TO DO: Use a proper log service for this.
redisClient.on("error", (e) => log("Redis error", require("node:util").inspect(e)));
redisClient.on("connect", () => log("Redis connection established"));

setTimeout(async function() {
if(!redisStore.connecting() && !redisStore.connected()) {
await redisStore.connect();
}
}, 1000);

return redisClient;
} catch(e) {
// TO DO: Use a proper log service for this.
log("Redis error", require("node:util").inspect(e));
}
}

static #log(message) {
console.log(message);
}
};
34 changes: 2 additions & 32 deletions src/service-providers/cache-service-provider.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const RedisStore = require("../framework/component/connector/redis");
const Connections = require("../framework/connections");
const CacheFactory = require("../framework/factory/cache");
const ServiceProvider = require("./service-provider");

Expand All @@ -22,7 +22,7 @@ module.exports = class CacheServiceProvider extends ServiceProvider {
} else if(defaultCache === "memory") {
cacheParams.store = defaultCacheData.store;
} else if(defaultCache === "redis") {
const redisClient = this.#connectToRedis(config.get("redis"));
const redisClient = Connections.get("redis", config.get("redis"));

cacheParams.connection = redisClient;
}
Expand All @@ -36,34 +36,4 @@ module.exports = class CacheServiceProvider extends ServiceProvider {
return cache;
});
}


#connectToRedis(redisCreds) {
try {
const redisStore = new RedisStore(redisCreds);
const redisClient = redisStore.getClient();
const log = this.#log.bind(this);

// TO DO: Use a proper log service for this.
redisClient.on("error", (e) => log("Redis error", require("node:util").inspect(e)));
redisClient.on("connect", () => log("Redis connection established"));

setTimeout(async function() {
if(!redisStore.connecting() && !redisStore.connected()) {
await redisStore.connect();
}
}, 1000);

return redisClient;
} catch(e) {
// TO DO: Use a proper log service for this.
log("Redis error", require("node:util").inspect(e));
}
}

#log(message) {
if(this.container().resolve("config").get("app.environment") !== "test") {
console.log(message);
}
}
};

0 comments on commit 5182378

Please sign in to comment.