Jelajahi Sumber

add support for no redis

Pouria Ezzati 1 tahun lalu
induk
melakukan
c18ff4ba2f

+ 1 - 0
.example.env

@@ -26,6 +26,7 @@ DB_POOL_MAX=10
 DB_FILENAME=data
 
 # Redis host and port
+REDIS_ENABLED=false
 REDIS_HOST=127.0.0.1
 REDIS_PORT=6379
 REDIS_PASSWORD=

+ 1 - 0
server/env.js

@@ -25,6 +25,7 @@ const env = cleanEnv(process.env, {
   DB_SSL: bool({ default: false }),
   DB_POOL_MIN: num({ default: 0 }),
   DB_POOL_MAX: num({ default: 10 }),
+  REDIS_ENABLED: bool({ default: false }),
   REDIS_HOST: str({ default: "127.0.0.1" }),
   REDIS_PORT: num({ default: 6379 }),
   REDIS_PASSWORD: str({ default: "" }),

+ 9 - 3
server/handlers/auth.handler.js

@@ -199,7 +199,9 @@ async function changePassword(req, res) {
 async function generateApiKey(req, res) {
   const apikey = nanoid(40);
   
-  redis.remove.user(req.user);
+  if (env.REDIS_ENABLED) {
+    redis.remove.user(req.user);
+  }
   
   const [user] = await query.user.update({ id: req.user.id }, { apikey });
   
@@ -296,7 +298,9 @@ async function changeEmailRequest(req, res) {
     }
   );
   
-  redis.remove.user(updatedUser);
+  if (env.REDIS_ENABLED) {
+    redis.remove.user(updatedUser);
+  }
   
   if (updatedUser) {
     await mail.changeEmail({ ...updatedUser, email });
@@ -336,7 +340,9 @@ async function changeEmail(req, res, next) {
       }
     );
   
-    redis.remove.user(foundUser);
+    if (env.REDIS_ENABLED) {
+      redis.remove.user(foundUser);
+    }
   
     if (user) {
       const token = utils.signToken(user);

+ 4 - 1
server/handlers/domains.handler.js

@@ -3,6 +3,7 @@ const { Handler } = require("express");
 const { CustomError, sanitize } = require("../utils");
 const query = require("../queries");
 const redis = require("../redis");
+const env = require("../env");
 
 async function add(req, res) {
   const { address, homepage } = req.body;
@@ -44,7 +45,9 @@ async function remove(req, res) {
     throw new CustomError("Could not delete the domain.", 500);
   }
 
-  redis.remove.domain(updatedDomain);
+  if (env.REDIS_ENABLED) {
+    redis.remove.domain(updatedDomain);
+  }
 
   if (req.isHTML) {
     const domains = (await query.domain.get({ user_id: req.user.id })).map(sanitize.domain);

+ 11 - 10
server/queries/domain.queries.js

@@ -1,22 +1,19 @@
 const redis = require("../redis");
 const utils = require("../utils");
 const knex = require("../knex");
+const env = require("../env");
 
 async function find(match) {
-  if (match.address) {
+  if (match.address && env.REDIS_ENABLED) {
     const cachedDomain = await redis.client.get(redis.key.domain(match.address));
     if (cachedDomain) return JSON.parse(cachedDomain);
   }
 
   const domain = await knex("domains").where(match).first();
 
-  if (domain) {
-    redis.client.set(
-      redis.key.domain(domain.address),
-      JSON.stringify(domain),
-      "EX",
-      60 * 60 * 6
-    );
+  if (domain && env.REDIS_ENABLED) {
+    const key = redis.key.domain(domain.address);
+    redis.client.set(key, JSON.stringify(domain), "EX", 60 * 15);
   }
 
   return domain;
@@ -55,7 +52,9 @@ async function add(params) {
   // Query domain instead of using returning as sqlite and mysql don't support it
   const domain = await knex("domains").where("id", id).first();
 
-  redis.remove.domain(domain);
+  if (env.REDIS_ENABLED) {
+    redis.remove.domain(domain);
+  }
 
   return domain;
 }
@@ -67,7 +66,9 @@ async function update(match, update) {
 
   const domains = await knex("domains").select("*").where(match);
 
-  domains.forEach(redis.remove.domain);
+  if (env.REDIS_ENABLED) {
+    domains.forEach(redis.remove.domain);
+  }
 
   return domains;
 }

+ 8 - 9
server/queries/host.queries.js

@@ -1,9 +1,10 @@
 const redis = require("../redis");
 const utils = require("../utils");
 const knex = require("../knex");
+const env = require("../env");
 
 async function find(match) {
-  if (match.address) {
+  if (match.address && env.REDIS_ENABLED) {
     const cachedHost = await redis.client.get(redis.key.host(match.address));
     if (cachedHost) return JSON.parse(cachedHost);
   }
@@ -12,13 +13,9 @@ async function find(match) {
     .where(match)
     .first();
 
-  if (host) {
-    redis.client.set(
-      redis.key.host(host.address),
-      JSON.stringify(host),
-      "EX",
-      60 * 60 * 6
-    );
+  if (host && env.REDIS_ENABLED) {
+    const key = redis.key.host(host.address);
+    redis.client.set(key, JSON.stringify(host), "EX", 60 * 15);
   }
 
   return host;
@@ -51,7 +48,9 @@ async function add(params) {
   // Query domain instead of using returning as sqlite and mysql don't support it
   const host = await knex("hosts").where("id", id);
 
-  redis.remove.host(host);
+  if (env.REDIS_ENABLED) {
+    redis.remove.host(host);
+  }
 
   return host;
 }

+ 14 - 6
server/queries/link.queries.js

@@ -3,6 +3,7 @@ const bcrypt = require("bcryptjs");
 const utils = require("../utils");
 const redis = require("../redis");
 const knex = require("../knex");
+const env = require("../env");
 
 const CustomError = utils.CustomError;
 
@@ -87,7 +88,7 @@ async function get(match, params) {
 }
 
 async function find(match) {
-  if (match.address && match.domain_id) {
+  if (match.address && match.domain_id && env.REDIS_ENABLED) {
     const key = redis.key.link(match.address, match.domain_id);
     const cachedLink = await redis.client.get(key);
     if (cachedLink) return JSON.parse(cachedLink);
@@ -99,9 +100,9 @@ async function find(match) {
     .leftJoin("domains", "links.domain_id", "domains.id")
     .first();
   
-  if (link) {
+  if (link && env.REDIS_ENABLED) {
     const key = redis.key.link(link.address, link.domain_id);
-    redis.client.set(key, JSON.stringify(link), "EX", 60 * 60 * 2);
+    redis.client.set(key, JSON.stringify(link), "EX", 60 * 15);
   }
   
   return link;
@@ -141,7 +142,10 @@ async function remove(match) {
   }
 
   const deletedLink = await knex("links").where("id", link.id).delete();
-  redis.remove.link(link);
+
+  if (env.REDIS_ENABLED) {
+    redis.remove.link(link);
+  }
   
   return { isRemoved: !!deletedLink, link };
 }
@@ -159,7 +163,9 @@ async function batchRemove(match) {
   
   await deleteQuery.delete();
   
-  links.forEach(redis.remove.link);
+  if (env.REDIS_ENABLED) {
+    links.forEach(redis.remove.link);
+  }
 }
 
 async function update(match, update) {
@@ -174,7 +180,9 @@ async function update(match, update) {
 
   const links = await knex("links").select('*').where(match);
 
-  links.forEach(redis.remove.link);
+  if (env.REDIS_ENABLED) {
+    links.forEach(redis.remove.link);
+  }
   
   return links;
 }

+ 14 - 7
server/queries/user.queries.js

@@ -4,9 +4,10 @@ const { v4: uuid } = require("uuid");
 const utils = require("../utils");
 const redis = require("../redis");
 const knex = require("../knex");
+const env = require("../env");
 
 async function find(match) {
-  if (match.email || match.apikey) {
+  if ((match.email || match.apikey) && env.REDIS_ENABLED) {
     const key = redis.key.user(match.email || match.apikey);
     const cachedUser = await redis.client.get(key);
     if (cachedUser) return JSON.parse(cachedUser);
@@ -19,13 +20,13 @@ async function find(match) {
 
   const user = await query.first();
   
-  if (user) {
+  if (user && env.REDIS_ENABLED) {
     const emailKey = redis.key.user(user.email);
-    redis.client.set(emailKey, JSON.stringify(user), "EX", 60 * 60 * 1);
+    redis.client.set(emailKey, JSON.stringify(user), "EX", 60 * 15);
   
     if (user.apikey) {
       const apikeyKey = redis.key.user(user.apikey);
-      redis.client.set(apikeyKey, JSON.stringify(user), "EX", 60 * 60 * 1);
+      redis.client.set(apikeyKey, JSON.stringify(user), "EX", 60 * 15);
     }
   }
   
@@ -48,7 +49,9 @@ async function add(params, user) {
     await knex("users").insert(data);
   }
   
-  redis.remove.user(user);
+  if (env.REDIS_ENABLED) {
+    redis.remove.user(user);
+  }
   
   return {
     ...user,
@@ -74,7 +77,9 @@ async function update(match, update, methods) {
 
   const users = await query.select("*");
 
-  users.forEach(redis.remove.user);
+  if (env.REDIS_ENABLED) {
+    users.forEach(redis.remove.user);
+  }
   
   return users;
 }
@@ -82,7 +87,9 @@ async function update(match, update, methods) {
 async function remove(user) {
   const deletedUser = await knex("users").where("id", user.id).delete();
   
-  redis.remove.user(user);
+  if (env.REDIS_ENABLED) {
+    redis.remove.user(user);
+  }
   
   return !!deletedUser;
 }

+ 4 - 4
server/queries/visit.queries.js

@@ -3,6 +3,7 @@ const { isAfter, subDays, subHours, set, format } = require("date-fns");
 const utils = require("../utils");
 const redis = require("../redis");
 const knex = require("../knex");
+const env = require("../env");
 
 async function add(params) {
   const data = {
@@ -67,7 +68,7 @@ async function add(params) {
 }
 
 async function find(match, total) {
-  if (match.link_id) {
+  if (match.link_id && env.REDIS_ENABLED) {
     const key = redis.key.stats(match.link_id);
     const cached = await redis.client.get(key);
     if (cached) return JSON.parse(cached);
@@ -180,10 +181,9 @@ async function find(match, total) {
     updatedAt: new Date()
   };
 
-  if (match.link_id) {
-    const cacheTime = utils.getStatsCacheTime(total);
+  if (match.link_id && env.REDIS_ENABLED) {
     const key = redis.key.stats(match.link_id);
-    redis.client.set(key, JSON.stringify(response), "EX", cacheTime);
+    redis.client.set(key, JSON.stringify(response), "EX", 60);
   }
 
   return response;

+ 23 - 8
server/queues/queues.js

@@ -10,15 +10,30 @@ const redis = {
   ...(env.REDIS_PASSWORD && { password: env.REDIS_PASSWORD })
 };
 
-const visit = new Queue("visit", { redis });
-visit.clean(5000, "completed");
-visit.process(6, path.resolve(__dirname, "visit.js"));
-visit.on("completed", job => job.remove());
+let visit;
+
+if (env.REDIS_ENABLED) {
+  visit = new Queue("visit", { redis });
+  visit.clean(5000, "completed");
+  visit.process(6, path.resolve(__dirname, "visit.js"));
+  visit.on("completed", job => job.remove());
+  
+  // TODO: handler error
+  // visit.on('error', function (error) {
+  //   console.log('error');
+  // });
+} else {
+  const visitProcessor = require(path.resolve(__dirname, "visit.js"));
+  visit = {
+    add(data) {
+      visitProcessor({ data }).catch(function(error) {
+        console.error("Add visit error: ", error);
+      });
+    }
+  }
+}
+
 
-// TODO: handler error
-// visit.on('error', function (error) {
-//   console.log('error');
-// })
 
 module.exports = { 
   visit,

+ 10 - 6
server/redis.js

@@ -2,12 +2,16 @@ const Redis = require("ioredis");
 
 const env = require("./env");
 
-const client = new Redis({
-  host: env.REDIS_HOST,
-  port: env.REDIS_PORT,
-  db: env.REDIS_DB,
-  ...(env.REDIS_PASSWORD && { password: env.REDIS_PASSWORD })
-});
+let client;
+
+if (env.REDIS_ENABLED) {
+  client = new Redis({
+    host: env.REDIS_HOST,
+    port: env.REDIS_PORT,
+    db: env.REDIS_DB,
+    ...(env.REDIS_PASSWORD && { password: env.REDIS_PASSWORD })
+  });
+}
 
 const key = {
   link: (address, domain_id, user_id) => `${address}-${domain_id || ""}-${user_id || ""}`,

+ 0 - 14
server/utils/utils.js

@@ -73,22 +73,10 @@ function getShortURL(address, domain) {
   return { link, url };
 }
 
-const getRedisKey = {
-  // TODO: remove user id and make domain id required
-  link: (address, domain_id, user_id) => `${address}-${domain_id || ""}-${user_id || ""}`,
-  domain: (address) => `d-${address}`,
-  host: (address) => `h-${address}`,
-  user: (emailOrKey) => `u-${emailOrKey}`
-};
-
 function getStatsLimit() {
   return env.DEFAULT_MAX_STATS_PER_LINK || 100000000;
 };
 
-function getStatsCacheTime(total) {
-  return (total > 50000 ? ms("5 minutes") : ms("1 minutes")) / 1000
-};
-
 function statsObjectToArray(obj) {
   const objToArr = (key) =>
     Array.from(Object.keys(obj[key]))
@@ -317,9 +305,7 @@ module.exports = {
   generateId,
   getDifferenceFunction,
   getInitStats,
-  getRedisKey,
   getShortURL,
-  getStatsCacheTime,
   getStatsLimit,
   getStatsPeriods,
   isAdmin,