XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

SpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 1 Star 0
返回提交历史

XFEstudio/SpaceNinjaServer

feat: minBuildVersion for inbox messages (#3733)

Also moved the responsibility of filtering out old messages for the delta request to MongoDB. Closes #3729 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3733 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>

0f74aacf
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

6 个文件 +57 -36
Modified src/controllers/api/inboxController.ts +9 -17
@@ -6,10 +6,11 @@ import {
6 6 deleteAllMessagesReadNonCin,
7 7 deleteMessageRead,
8 8 exportInboxMessage,
9 getAllMessagesSorted,
9 getMessagesSorted,
10 10 type IMessageCreationTemplate
11 11 } from "../../services/inboxService.ts";
12 12 import {
13 buildVersionToInt,
13 14 getAccountForRequest,
14 15 getAccountFromSuffixedName,
15 16 getSuffixedName,
@@ -37,6 +38,7 @@ export const inboxController: RequestHandler = async (req, res) => {
37 38 const { deleteId, lastMessage: latestClientMessageId, messageId } = req.query;
38 39
39 40 const account = await getAccountForRequest(req);
41 const buildLabel = "ignoreBuildLabel" in req.query ? undefined : account.BuildLabel;
40 42
41 43 if (deleteId) {
42 44 if (deleteId === "DeleteAllRead") {
@@ -124,30 +126,19 @@ export const inboxController: RequestHandler = async (req, res) => {
124 126 res.json({ InventoryChanges: inventoryChanges });
125 127 } else if (latestClientMessageId) {
126 128 await createNewEventMessages(account);
127 const messages = await Inbox.find({ ownerId: account._id }).sort({ date: 1 });
128
129 const latestClientMessage = messages.find(m => m._id.toString() === parseOid(latestClientMessageId as string));
130
131 if (!latestClientMessage) {
132 logger.debug(`this should only happen after DeleteAllRead `);
133 res.json({
134 Inbox: messages.map(x => exportInboxMessage(x, account.BuildLabel)) satisfies IMessageClient[]
135 });
136 return;
137 }
138 const newMessages = messages.filter(m => m.date > latestClientMessage.date);
129 const newMessages = await getMessagesSorted(account._id, buildLabel, parseOid(latestClientMessageId as string));
139 130
140 131 if (newMessages.length === 0) {
141 132 res.send("no-new");
142 133 return;
143 134 }
144 135
145 res.json({ Inbox: newMessages.map(x => exportInboxMessage(x, account.BuildLabel)) satisfies IMessageClient[] });
136 res.json({ Inbox: newMessages.map(x => exportInboxMessage(x, buildLabel)) satisfies IMessageClient[] });
146 137 } else {
147 138 //newly created event messages must be newer than account.LatestEventMessageDate
148 139 await createNewEventMessages(account);
149 const messages = await getAllMessagesSorted(account._id);
150 const inbox = messages.map(x => exportInboxMessage(x, account.BuildLabel));
140 const messages = await getMessagesSorted(account._id, buildLabel);
141 const inbox = messages.map(x => exportInboxMessage(x, buildLabel));
151 142 res.json({ Inbox: inbox satisfies IMessageClient[] });
152 143 }
153 144 };
@@ -289,7 +280,8 @@ const createNewEventMessages = async (account: TAccountDocument): Promise<void>
289 280 transmission: "/Lotus/Sounds/Dialog/Shadowgrapher/Vendor/DSGInbox0011AspirantZorba",
290 281 startDate: new Date(),
291 282 QuestReq: "/Lotus/Types/Keys/PriestFrameQuest/PriestQuestKeyChain",
292 CrossPlatform: true
283 CrossPlatform: true,
284 minBuildVersion: buildVersionToInt(gameToBuildVersion["42.0.0"])
293 285 });
294 286 }
295 287
Modified src/controllers/api/loginController.ts +8 -9
@@ -4,7 +4,13 @@ import { config, getReflexiveAddress } from "../../services/configService.ts";
4 4 import { buildConfig } from "../../services/buildConfigService.ts";
5 5
6 6 import { Account } from "../../models/loginModel.ts";
7 import { createAccount, createNonce, getUsernameFromEmail, isCorrectPassword } from "../../services/loginService.ts";
7 import {
8 buildVersionToInt,
9 createAccount,
10 createNonce,
11 getUsernameFromEmail,
12 isCorrectPassword
13 } from "../../services/loginService.ts";
8 14 import {
9 15 Platform,
10 16 type IDatabaseAccountJson,
@@ -203,14 +209,7 @@ const createLoginResponse = (request: Request, account: IDatabaseAccountJson, bu
203 209 resp.HUB = `${myUrlBase}/api/`;
204 210
205 211 // The MatchmakingBuildId is a 64-bit integer represented as a decimal string. On live, the value is seemingly random per build, but really any value that is different across builds should work.
206 const [year, month, day, hour, minute] = buildLabel.split(".").map(x => parseInt(x));
207 resp.MatchmakingBuildId = (
208 year * 1_00_00_00_00 +
209 month * 1_00_00_00 +
210 day * 1_00_00 +
211 hour * 1_00 +
212 minute
213 ).toString();
212 resp.MatchmakingBuildId = buildVersionToInt(buildLabel).toString();
214 213 }
215 214 if (version_compare(buildLabel, gameToBuildVersion["33.0.0"]) >= 0) {
216 215 if (version_compare(buildLabel, gameToBuildVersion["40.0.0"]) >= 0) {
Modified src/models/inboxModel.ts +15 -4
@@ -6,7 +6,15 @@ import type { IMongoDateWithLegacySupport, IOid, IOidWithLegacySupport, ITypeCou
6 6
7 7 export interface IMessageClient extends Omit<
8 8 IMessageDatabase,
9 "_id" | "globaUpgradeId" | "date" | "startDate" | "endDate" | "ownerId" | "attVisualOnly" | "expiry"
9 | "_id"
10 | "globaUpgradeId"
11 | "date"
12 | "startDate"
13 | "endDate"
14 | "ownerId"
15 | "attVisualOnly"
16 | "expiry"
17 | "minBuildVersion"
10 18 > {
11 19 _id?: IOid;
12 20 globaUpgradeId?: IOidWithLegacySupport; // [sic]
@@ -17,10 +25,11 @@ export interface IMessageClient extends Omit<
17 25 }
18 26
19 27 export interface IMessageDatabase extends IMessage {
20 ownerId: Types.ObjectId;
28 ownerId: Types.ObjectId; // SNS-specific
21 29 globaUpgradeId?: Types.ObjectId; // [sic]
22 30 date: Date; //created at
23 attVisualOnly?: boolean;
31 attVisualOnly?: boolean; // SNS-specific
32 minBuildVersion?: number; // SNS-specific
24 33 _id: Types.ObjectId;
25 34 }
26 35
@@ -143,7 +152,8 @@ const messageSchema = new Schema<IMessageDatabase>(
143 152 acceptAction: String,
144 153 declineAction: String,
145 154 hasAccountAction: Boolean,
146 RegularCredits: Number
155 RegularCredits: Number,
156 minBuildVersion: Number
147 157 },
148 158 { id: false }
149 159 );
@@ -160,6 +170,7 @@ messageSchema.set("toJSON", {
160 170 delete returnedObject.ownerId;
161 171 delete returnedObject.attVisualOnly;
162 172 delete returnedObject.expiry;
173 delete returnedObject.minBuildVersion;
163 174
164 175 // oid & date conversions done in inboxService's exportInboxMessage
165 176 }
Modified src/services/inboxService.ts +18 -4
@@ -1,11 +1,25 @@
1 1 import { toMongoDate2, toOid2 } from "../helpers/inventoryHelpers.ts";
2 2 import type { IMessageClient, IMessageDatabase, TMessageDocument } from "../models/inboxModel.ts";
3 3 import { Inbox } from "../models/inboxModel.ts";
4 import type { Types } from "mongoose";
4 import type { FilterQuery, Types } from "mongoose";
5 import { buildVersionToInt } from "./loginService.ts";
5 6
6 export const getAllMessagesSorted = async (accountId: string | Types.ObjectId): Promise<TMessageDocument[]> => {
7 const inbox = await Inbox.find({ ownerId: accountId }).sort({ date: -1 });
8 return inbox;
7 export const getMessagesSorted = async (
8 accountId: string | Types.ObjectId,
9 buildLabel: string | undefined,
10 afterId?: string | Types.ObjectId
11 ): Promise<TMessageDocument[]> => {
12 const query: FilterQuery<IMessageDatabase> = { ownerId: accountId };
13 if (buildLabel) {
14 query.$or = [
15 { minBuildVersion: { $exists: false } },
16 { minBuildVersion: { $lte: buildVersionToInt(buildLabel) } }
17 ];
18 }
19 if (afterId) {
20 query._id = { $gt: afterId };
21 }
22 return await Inbox.find(query).sort({ date: -1 });
9 23 };
10 24
11 25 export const deleteMessageRead = async (messageId: string | Types.ObjectId): Promise<void> => {
Modified src/services/loginService.ts +5 -0
@@ -159,3 +159,8 @@ export const stripUnicodeSuffix = (name: string): string => {
159 159 }
160 160 return name;
161 161 };
162
163 export const buildVersionToInt = (buildVersion: string): number => {
164 const [year, month, day, hour, minute] = buildVersion.split(".").map(x => parseInt(x));
165 return year * 1_00_00_00_00 + month * 1_00_00_00 + day * 1_00_00 + hour * 1_00 + minute;
166 };
Modified static/webui/script.js +2 -2
@@ -5013,11 +5013,11 @@ document.querySelectorAll("#sidebar .nav-link").forEach(function (elm) {
5013 5013
5014 5014 async function markAllAsRead() {
5015 5015 await revalidateAuthz();
5016 const { Inbox } = await fetch("/api/inbox.php?" + window.authz).then(x => x.json());
5016 const { Inbox } = await fetch("/api/inbox.php?" + window.authz + "&ignoreBuildLabel=1").then(x => x.json());
5017 5017 let any = false;
5018 5018 for (const msg of Inbox) {
5019 5019 if (!msg.r) {
5020 await fetch("/api/inbox.php?" + window.authz + "&messageId=" + msg.messageId.$oid);
5020 await fetch("/api/inbox.php?" + window.authz + "&ignoreBuildLabel=1&messageId=" + msg.messageId.$oid);
5021 5021 any = true;
5022 5022 }
5023 5023 }