feat: 이미 읽은 메시지를 DB에서 처리

This commit is contained in:
2023-03-25 02:09:23 +09:00
parent 5294aefbbd
commit 9206b74500
6 changed files with 115 additions and 21 deletions
@@ -6,8 +6,10 @@ use sammo\Session;
use DateTimeInterface; use DateTimeInterface;
use sammo\DB; use sammo\DB;
use sammo\Enums\APIRecoveryType; use sammo\Enums\APIRecoveryType;
use sammo\Enums\GeneralStorKey;
use sammo\Enums\MessageType; use sammo\Enums\MessageType;
use sammo\Json; use sammo\Json;
use sammo\KVStorage;
use sammo\Message; use sammo\Message;
use sammo\TimeUtil; use sammo\TimeUtil;
use sammo\Util; use sammo\Util;
@@ -140,9 +142,19 @@ class GetRecentMessage extends \sammo\BaseAPI
array_pop($result[$lastType]); array_pop($result[$lastType]);
} }
$generalStor = KVStorage::getStorage($db, "general_{$generalID}");
[$latestReadDiplomacyMsg, $latestReadPrivateMsg] = $generalStor->getValuesAsArray([
GeneralStorKey::latestReadDiplomacyMsg,
GeneralStorKey::latestReadPrivateMsg
]);
$result['sequence'] = $nextSequence; $result['sequence'] = $nextSequence;
$result['nationID'] = $nationID; $result['nationID'] = $nationID;
$result['generalName'] = $generalName; $result['generalName'] = $generalName;
$result['latestRead'] = [
'diplomacy' => $latestReadDiplomacyMsg ?? 0,
'private' => $latestReadPrivateMsg ?? 0,
];
return $result; return $result;
} }
@@ -0,0 +1,52 @@
<?php
namespace sammo\API\Message;
use sammo\DB;
use sammo\Enums\APIRecoveryType;
use sammo\Enums\GeneralStorKey;
use sammo\Enums\MessageType;
use sammo\KVStorage;
use sammo\Session;
use sammo\Validator;
class ReadLatestMessage extends \sammo\BaseAPI
{
public function validateArgs(): ?string
{
//type이 개인 메시지 혹은 외교 메시지여야함
$v = new Validator($this->args);
$v->rule('required', ['type', 'msgID'])
->rule('in', 'type', [MessageType::private->value, MessageType::diplomacy->value])
->rule('int', 'msgID');
if (!$v->validate()) {
return $v->errorStr();
}
return null;
}
public function getRequiredSessionMode(): int
{
return static::REQ_GAME_LOGIN | static::REQ_READ_ONLY;
}
public function launch(Session $session, ?\DateTimeInterface $modifiedSince, ?string $reqEtag): null | string | array | APIRecoveryType
{
$db = DB::db();
$generalID = $session->generalID;
$generalStor = KVStorage::getStorage($db, "general_{$generalID}");
$type = MessageType::from($this->args['type']);
$msgID = $this->args['msgID'];
$storKey = GeneralStorKey::latestReadPrivateMsg;
if($type == MessageType::diplomacy){
$storKey = GeneralStorKey::latestReadDiplomacyMsg;
}
$oldValue = $generalStor->getValue($storKey);
if($oldValue === null || $oldValue < $msgID){
$generalStor->setValue($storKey, $msgID);
}
return null;
}
}
+7
View File
@@ -0,0 +1,7 @@
<?php
namespace sammo\Enums;
enum GeneralStorKey: string{
case latestReadPrivateMsg = 'latestReadPrivateMsg';
case latestReadDiplomacyMsg = 'latestReadDiplomacyMsg';
}
+10 -6
View File
@@ -29,7 +29,7 @@ import type {
GetFrontInfoResponse, GetFrontInfoResponse,
GetHistoryResponse, GetHistoryResponse,
GetMenuResponse, GetMenuResponse,
GetRecentRecordResponse, GetRecentRecordResponse,
} from "./defs/API/Global"; } from "./defs/API/Global";
import type { CachedMapResult, CommandTableResponse, GeneralListResponse, ItemTypeKey, MapResult } from "./defs"; import type { CachedMapResult, CommandTableResponse, GeneralListResponse, ItemTypeKey, MapResult } from "./defs";
import type { VoteDetailResult, VoteListResult } from "./defs/API/Vote"; import type { VoteDetailResult, VoteListResult } from "./defs/API/Vote";
@@ -71,12 +71,12 @@ const apiRealPath = {
amount: number; amount: number;
}>, }>,
GetUniqueItemAuctionDetail: GET as APICallT<{ GetUniqueItemAuctionDetail: GET as APICallT<{
auctionID: number; auctionID: number;
}, UniqueItemAuctionDetail>, }, UniqueItemAuctionDetail>,
GetUniqueItemAuctionList: GET as APICallT<undefined, UniqueItemAuctionList>, GetUniqueItemAuctionList: GET as APICallT<undefined, UniqueItemAuctionList>,
OpenUniqueAuction: POST as APICallT<{ OpenUniqueAuction: POST as APICallT<{
itemID: string, itemID: string,
amount: number, amount: number,
}, OpenAuctionResponse>, }, OpenAuctionResponse>,
}, },
Betting: { Betting: {
@@ -199,7 +199,11 @@ const apiRealPath = {
SendMessage: POST as APICallT<{ SendMessage: POST as APICallT<{
mailbox: number; mailbox: number;
text: string; text: string;
}, ValidResponse & {msgID: number, msgType: MsgType}> }, ValidResponse & { msgID: number, msgType: MsgType }>,
ReadLatestMessage: PATCH as APICallT<{
type: 'diplomacy' | 'private';
msgID: number;
}>
}, },
Misc: { Misc: {
UploadImage: POST as APICallT< UploadImage: POST as APICallT<
@@ -273,7 +277,7 @@ const apiRealPath = {
troopID: number; troopID: number;
troopName: string; troopName: string;
}>, }>,
GetNationInfo: GET as APICallT<{full?: boolean}, NationInfoResponse>, GetNationInfo: GET as APICallT<{ full?: boolean }, NationInfoResponse>,
}, },
Troop: { Troop: {
NewTroop: POST as APICallT<{ NewTroop: POST as APICallT<{
+30 -15
View File
@@ -255,21 +255,8 @@ const messageIndexedList: Record<MsgType, Ref<MsgItem[]>> = {
diplomacy: messageDiplomacy, diplomacy: messageDiplomacy,
}; };
function generateLatestMsgState(msgType: MsgType) { const latestPrivateMsgToastInfo = ref<[string | undefined, number, number]>([undefined, 0, 0]);
const storageKey = `state.${serverID}.latestReadMsg.${msgType}`; const latestDiplomacyMsgToastInfo = ref<[string | undefined, number, number]>([undefined, 0, 0]);
const latestReadMsgID = parseInt(localStorage.getItem(storageKey) ?? "0");
const obj = ref<[string | undefined, number, number]>([undefined, latestReadMsgID, latestReadMsgID]);
watch(obj, ([, newMsgID], [, oldMsgID]) => {
if (newMsgID == oldMsgID) {
return;
}
localStorage.setItem(storageKey, newMsgID.toString());
});
return obj;
}
const latestPrivateMsgToastInfo = generateLatestMsgState("private");
const latestDiplomacyMsgToastInfo = generateLatestMsgState("diplomacy");
function readLatestMsg(msgType: MsgType) { function readLatestMsg(msgType: MsgType) {
const targetMap = { const targetMap = {
@@ -288,6 +275,13 @@ function readLatestMsg(msgType: MsgType) {
if (toastID) { if (toastID) {
toasts.remove(toastID); toasts.remove(toastID);
} }
if(msgType == "private" || msgType == "diplomacy"){
void SammoAPI.Message.ReadLatestMessage({
type: msgType,
msgID: lastestReceivedID,
});
}
target.value = [undefined, lastestReceivedID, lastestReceivedID]; target.value = [undefined, lastestReceivedID, lastestReceivedID];
} }
@@ -403,6 +397,27 @@ function updateMsgResponse(response: MsgResponse) {
return; return;
} }
if(response.latestRead){
const newDiplomacyIdx = response.latestRead.diplomacy;
const [diplomacyToastID, diplomacyLatestMsgID] = latestDiplomacyMsgToastInfo.value;
if(diplomacyLatestMsgID < newDiplomacyIdx){
if(diplomacyToastID){
toasts.remove(diplomacyToastID);
}
latestDiplomacyMsgToastInfo.value = [undefined, newDiplomacyIdx, newDiplomacyIdx];
}
const newPrivateIdx = response.latestRead.private;
const [privateToastID, privateLatestMsgID] = latestPrivateMsgToastInfo.value;
if(privateLatestMsgID < newPrivateIdx){
if(privateToastID){
toasts.remove(privateToastID);
}
latestPrivateMsgToastInfo.value = [undefined, newPrivateIdx, newPrivateIdx];
}
}
lastSequence.value = Math.max(lastSequence.value, response.sequence); lastSequence.value = Math.max(lastSequence.value, response.sequence);
for (const msgType of Object.keys(messageIndexedList) as (keyof typeof messageIndexedList)[]) { for (const msgType of Object.keys(messageIndexedList) as (keyof typeof messageIndexedList)[]) {
+4
View File
@@ -58,6 +58,10 @@ export type MsgResponse = {
nationID: number; nationID: number;
generalName: string; generalName: string;
sequence: number; sequence: number;
latestRead?: {
private: number;
diplomacy: number;
}
}; };
export type MailboxItem = { export type MailboxItem = {