feat: 이미 읽은 메시지를 DB에서 처리
This commit is contained in:
@@ -6,8 +6,10 @@ use sammo\Session;
|
||||
use DateTimeInterface;
|
||||
use sammo\DB;
|
||||
use sammo\Enums\APIRecoveryType;
|
||||
use sammo\Enums\GeneralStorKey;
|
||||
use sammo\Enums\MessageType;
|
||||
use sammo\Json;
|
||||
use sammo\KVStorage;
|
||||
use sammo\Message;
|
||||
use sammo\TimeUtil;
|
||||
use sammo\Util;
|
||||
@@ -140,9 +142,19 @@ class GetRecentMessage extends \sammo\BaseAPI
|
||||
array_pop($result[$lastType]);
|
||||
}
|
||||
|
||||
$generalStor = KVStorage::getStorage($db, "general_{$generalID}");
|
||||
[$latestReadDiplomacyMsg, $latestReadPrivateMsg] = $generalStor->getValuesAsArray([
|
||||
GeneralStorKey::latestReadDiplomacyMsg,
|
||||
GeneralStorKey::latestReadPrivateMsg
|
||||
]);
|
||||
|
||||
$result['sequence'] = $nextSequence;
|
||||
$result['nationID'] = $nationID;
|
||||
$result['generalName'] = $generalName;
|
||||
$result['latestRead'] = [
|
||||
'diplomacy' => $latestReadDiplomacyMsg ?? 0,
|
||||
'private' => $latestReadPrivateMsg ?? 0,
|
||||
];
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
namespace sammo\Enums;
|
||||
|
||||
enum GeneralStorKey: string{
|
||||
case latestReadPrivateMsg = 'latestReadPrivateMsg';
|
||||
case latestReadDiplomacyMsg = 'latestReadDiplomacyMsg';
|
||||
}
|
||||
+10
-6
@@ -29,7 +29,7 @@ import type {
|
||||
GetFrontInfoResponse,
|
||||
GetHistoryResponse,
|
||||
GetMenuResponse,
|
||||
GetRecentRecordResponse,
|
||||
GetRecentRecordResponse,
|
||||
} from "./defs/API/Global";
|
||||
import type { CachedMapResult, CommandTableResponse, GeneralListResponse, ItemTypeKey, MapResult } from "./defs";
|
||||
import type { VoteDetailResult, VoteListResult } from "./defs/API/Vote";
|
||||
@@ -71,12 +71,12 @@ const apiRealPath = {
|
||||
amount: number;
|
||||
}>,
|
||||
GetUniqueItemAuctionDetail: GET as APICallT<{
|
||||
auctionID: number;
|
||||
auctionID: number;
|
||||
}, UniqueItemAuctionDetail>,
|
||||
GetUniqueItemAuctionList: GET as APICallT<undefined, UniqueItemAuctionList>,
|
||||
OpenUniqueAuction: POST as APICallT<{
|
||||
itemID: string,
|
||||
amount: number,
|
||||
itemID: string,
|
||||
amount: number,
|
||||
}, OpenAuctionResponse>,
|
||||
},
|
||||
Betting: {
|
||||
@@ -199,7 +199,11 @@ const apiRealPath = {
|
||||
SendMessage: POST as APICallT<{
|
||||
mailbox: number;
|
||||
text: string;
|
||||
}, ValidResponse & {msgID: number, msgType: MsgType}>
|
||||
}, ValidResponse & { msgID: number, msgType: MsgType }>,
|
||||
ReadLatestMessage: PATCH as APICallT<{
|
||||
type: 'diplomacy' | 'private';
|
||||
msgID: number;
|
||||
}>
|
||||
},
|
||||
Misc: {
|
||||
UploadImage: POST as APICallT<
|
||||
@@ -273,7 +277,7 @@ const apiRealPath = {
|
||||
troopID: number;
|
||||
troopName: string;
|
||||
}>,
|
||||
GetNationInfo: GET as APICallT<{full?: boolean}, NationInfoResponse>,
|
||||
GetNationInfo: GET as APICallT<{ full?: boolean }, NationInfoResponse>,
|
||||
},
|
||||
Troop: {
|
||||
NewTroop: POST as APICallT<{
|
||||
|
||||
@@ -255,21 +255,8 @@ const messageIndexedList: Record<MsgType, Ref<MsgItem[]>> = {
|
||||
diplomacy: messageDiplomacy,
|
||||
};
|
||||
|
||||
function generateLatestMsgState(msgType: MsgType) {
|
||||
const storageKey = `state.${serverID}.latestReadMsg.${msgType}`;
|
||||
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");
|
||||
const latestPrivateMsgToastInfo = ref<[string | undefined, number, number]>([undefined, 0, 0]);
|
||||
const latestDiplomacyMsgToastInfo = ref<[string | undefined, number, number]>([undefined, 0, 0]);
|
||||
|
||||
function readLatestMsg(msgType: MsgType) {
|
||||
const targetMap = {
|
||||
@@ -288,6 +275,13 @@ function readLatestMsg(msgType: MsgType) {
|
||||
if (toastID) {
|
||||
toasts.remove(toastID);
|
||||
}
|
||||
|
||||
if(msgType == "private" || msgType == "diplomacy"){
|
||||
void SammoAPI.Message.ReadLatestMessage({
|
||||
type: msgType,
|
||||
msgID: lastestReceivedID,
|
||||
});
|
||||
}
|
||||
target.value = [undefined, lastestReceivedID, lastestReceivedID];
|
||||
}
|
||||
|
||||
@@ -403,6 +397,27 @@ function updateMsgResponse(response: MsgResponse) {
|
||||
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);
|
||||
|
||||
for (const msgType of Object.keys(messageIndexedList) as (keyof typeof messageIndexedList)[]) {
|
||||
|
||||
@@ -58,6 +58,10 @@ export type MsgResponse = {
|
||||
nationID: number;
|
||||
generalName: string;
|
||||
sequence: number;
|
||||
latestRead?: {
|
||||
private: number;
|
||||
diplomacy: number;
|
||||
}
|
||||
};
|
||||
|
||||
export type MailboxItem = {
|
||||
|
||||
Reference in New Issue
Block a user