Parcourir la source

使用mongo记录设备ID

flyzto il y a 2 semaines
Parent
commit
746afb3698
1 fichiers modifiés avec 72 ajouts et 8 suppressions
  1. 72 8
      server/models/Clients.js

+ 72 - 8
server/models/Clients.js

@@ -1,12 +1,28 @@
+import mongoose from 'mongoose';
 import path from 'path';
 import { fileURLToPath } from 'url';
 
 import Cache from '../libs/cache.js';
 
+const { Schema } = mongoose;
+
 const __filename = fileURLToPath(import.meta.url);
 const __dirname = path.dirname(__filename);
 const ClientsCacheFile = path.join(__dirname, '../data/clients.cache');
 
+const clientSettingSchema = new Schema({
+  _id: {
+    required: true,
+    type: String,
+  },
+  deviceId: {
+    required: true,
+    type: Number,
+  },
+}, { timestamps: true });
+
+const ClientSetting = mongoose.model('ClientSetting', clientSettingSchema);
+
 const CLIENT_HEADER_FIELDS = [
   'X-Device',
   'X-Version',
@@ -34,6 +50,8 @@ const CLIENT_FIELD_NAMES = {
 
 const CLIENTS = {
   Items: {},
+  LegacySettings: {},
+  Settings: {},
 };
 
 let saveTimer = null;
@@ -91,11 +109,12 @@ const recordRequest = (req) => {
   const key = getClientKey(headers);
   const now = Date.now();
   const current = CLIENTS.Items[key] ?? {};
+  const setting = CLIENTS.Settings[key] ?? {};
 
   CLIENTS.Items[key] = {
     key,
     ...clientFields,
-    deviceId: current.deviceId,
+    deviceId: setting.deviceId ?? current.deviceId,
     ip: getClientIp(req),
     route,
     firstRequestTime: current.firstRequestTime ?? now,
@@ -109,37 +128,74 @@ const recordRequest = (req) => {
 
 const getClients = () => {
   return Object.values(CLIENTS.Items)
+  .map(client => ({
+    ...client,
+    deviceId: CLIENTS.Settings[client.key]?.deviceId ?? client.deviceId,
+  }))
   .sort((a, b) => (b.lastRequestTime ?? 0) - (a.lastRequestTime ?? 0));
 }
 
-const updateClient = ({ key, deviceId } = {}) => {
+const updateClient = async ({ key, deviceId } = {}) => {
   if (!key || !CLIENTS.Items[key]) {
     return Promise.reject(new Error('CLIENT_NOT_FOUND'));
   }
   if (deviceId === undefined || deviceId === null || deviceId === '') {
+    delete CLIENTS.Settings[key];
     delete CLIENTS.Items[key].deviceId;
+    await ClientSetting.deleteOne({ _id: key });
     saveClientsToCache();
-    return Promise.resolve(CLIENTS.Items[key]);
+    return CLIENTS.Items[key];
   }
   const parsedDeviceId = Number(deviceId);
   if (!Number.isInteger(parsedDeviceId)) {
     return Promise.reject(new Error('DEVICE_ID_INVALID'));
   }
+  await ClientSetting.findByIdAndUpdate(
+    key,
+    { $set: { deviceId: parsedDeviceId } },
+    { new: true, upsert: true },
+  );
+  CLIENTS.Settings[key] = { deviceId: parsedDeviceId };
   CLIENTS.Items[key] = {
     ...CLIENTS.Items[key],
     deviceId: parsedDeviceId,
   };
   saveClientsToCache();
-  return Promise.resolve(CLIENTS.Items[key]);
+  return CLIENTS.Items[key];
 }
 
-const deleteClient = (key) => {
+const deleteClient = async (key) => {
   if (!key || !CLIENTS.Items[key]) {
     return Promise.reject(new Error('CLIENT_NOT_FOUND'));
   }
   delete CLIENTS.Items[key];
+  delete CLIENTS.Settings[key];
+  await ClientSetting.deleteOne({ _id: key });
   saveClientsToCache();
-  return Promise.resolve();
+}
+
+const loadClientSettings = async () => {
+  const legacyEntries = Object.entries(CLIENTS.LegacySettings);
+  if (legacyEntries.length) {
+    await Promise.all(legacyEntries.map(([key, setting]) => {
+      return ClientSetting.updateOne(
+        { _id: key },
+        { $setOnInsert: { deviceId: setting.deviceId } },
+        { upsert: true },
+      );
+    }));
+    CLIENTS.LegacySettings = {};
+  }
+
+  const settings = await ClientSetting.find().lean();
+  CLIENTS.Settings = settings.reduce((map, setting) => {
+    map[setting._id] = { deviceId: setting.deviceId };
+    if (CLIENTS.Items[setting._id]) {
+      CLIENTS.Items[setting._id].deviceId = setting.deviceId;
+    }
+    return map;
+  }, {});
+  return CLIENTS.Settings;
 }
 
 function saveClientsToCache() {
@@ -147,7 +203,7 @@ function saveClientsToCache() {
     clearTimeout(saveTimer);
     saveTimer = null;
   }
-  Cache.setData(ClientsCacheFile, CLIENTS);
+  Cache.setData(ClientsCacheFile, { Items: CLIENTS.Items });
 }
 
 function loadClientsFromCache() {
@@ -156,9 +212,16 @@ function loadClientsFromCache() {
     return;
   }
   CLIENTS.Items = cachedClients.Items;
+  Object.values(CLIENTS.Items).forEach(client => {
+    if (Number.isInteger(client.deviceId)) {
+      CLIENTS.LegacySettings[client.key] = { deviceId: client.deviceId };
+    }
+    delete client.deviceId;
+  });
 }
 
 loadClientsFromCache();
+loadClientSettings().catch(() => {});
 
 process.on('exit', saveClientsToCache);
 process.on('SIGINT', () => {
@@ -176,7 +239,8 @@ const Clients = {
   getClients,
   updateClient,
   deleteClient,
+  loadClientSettings,
 };
 
-export { recordRequest, getClients, updateClient, deleteClient };
+export { recordRequest, getClients, updateClient, deleteClient, loadClientSettings };
 export default Clients;