Skip to content

Commit

Permalink
Fix wrong push message when chat to offline user
Browse files Browse the repository at this point in the history
  • Loading branch information
yinxin630 committed Jul 28, 2021
1 parent 2979e03 commit cb08c70
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 65 deletions.
140 changes: 87 additions & 53 deletions packages/server/src/routes/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import Message, {
MessageDocument,
} from '@fiora/database/mongoose/models/message';
import Notification from '@fiora/database/mongoose/models/notification';
import History, { createOrUpdateHistory } from '@fiora/database/mongoose/models/history';
import History, {
createOrUpdateHistory,
} from '@fiora/database/mongoose/models/history';
import Socket from '@fiora/database/mongoose/models/socket';

import client from '../../../config/client';
Expand All @@ -36,12 +38,15 @@ async function pushNotification(
) {
const expo = new Expo({});

const content = message.type === 'text' ? message.content : `[${message.type}]`;
const content =
message.type === 'text' ? message.content : `[${message.type}]`;
const pushMessages = notificationTokens.map((notificationToken) => ({
to: notificationToken,
sound: 'default',
title: groupName || (message.from as any).username,
body: groupName ? `${(message.from as any).username}: ${content}` : content,
body: groupName
? `${(message.from as any).username}: ${content}`
: content,
data: { focus: message.to },
}));

Expand All @@ -50,7 +55,8 @@ async function pushNotification(
try {
const results = await expo.sendPushNotificationsAsync(chunk);
results.forEach((result) => {
const { status, message: errMessage } = result as ExpoPushErrorTicket;
const { status, message: errMessage } =
result as ExpoPushErrorTicket;
if (status === 'error') {
logger.warn('[Notification]', errMessage);
}
Expand Down Expand Up @@ -131,7 +137,10 @@ export async function sendMessage(ctx: Context<SendMessageData>) {
});
}

const user = await User.findOne({ _id: ctx.socket.user }, { username: 1, avatar: 1, tag: 1 });
const user = await User.findOne(
{ _id: ctx.socket.user },
{ username: 1, avatar: 1, tag: 1 },
);
if (!user) {
throw new AssertionError({ message: '用户不存在' });
}
Expand Down Expand Up @@ -166,7 +175,9 @@ export async function sendMessage(ctx: Context<SendMessageData>) {
const notificationTokens: string[] = [];
notifications.forEach((notification) => {
// Messages sent by yourself don’t push notification to yourself
if (notification.user._id.toString() === ctx.socket.user.toString()) {
if (
notification.user._id.toString() === ctx.socket.user.toString()
) {
return;
}
notificationTokens.push(notification.token);
Expand All @@ -179,19 +190,18 @@ export async function sendMessage(ctx: Context<SendMessageData>) {
);
}
} else {
const sockets = await Socket.find({ user: toUser?._id });
ctx.socket.emit(
sockets.map((socket) => socket.id),
'message',
messageData,
);
const targetSockets = await Socket.find({ user: toUser?._id });
const targetSocketIdList =
targetSockets?.map((socket) => socket.id) || [];
if (targetSocketIdList.length) {
ctx.socket.emit(targetSocketIdList, 'message', messageData);
}

const selfSockets = await Socket.find({ user: ctx.socket.user });
ctx.socket.emit(
selfSockets.map((socket) => socket.id),
'message',
messageData,
);
const selfSocketIdList = selfSockets?.map((socket) => socket.id) || [];
if (selfSocketIdList.length) {
ctx.socket.emit(selfSocketIdList, 'message', messageData);
}

const notificationTokens = await Notification.find({ user: toUser });
if (notificationTokens.length) {
Expand All @@ -211,7 +221,9 @@ export async function sendMessage(ctx: Context<SendMessageData>) {
* 获取一组联系人的最后历史消息
* @param ctx Context
*/
export async function getLinkmansLastMessages(ctx: Context<{ linkmans: string[] }>) {
export async function getLinkmansLastMessages(
ctx: Context<{ linkmans: string[] }>,
) {
const { linkmans } = ctx.data;
assert(Array.isArray(linkmans), '参数linkmans应该是Array');

Expand Down Expand Up @@ -241,7 +253,9 @@ export async function getLinkmansLastMessages(ctx: Context<{ linkmans: string[]
return messages;
}

export async function getLinkmansLastMessagesV2(ctx: Context<{ linkmans: string[] }>) {
export async function getLinkmansLastMessagesV2(
ctx: Context<{ linkmans: string[] }>,
) {
const { linkmans } = ctx.data;

const histories = await History.find({
Expand Down Expand Up @@ -283,24 +297,27 @@ export async function getLinkmansLastMessagesV2(ctx: Context<{ linkmans: string[
unread: number;
};
};
const responseData = linkmans.reduce((result: ResponseData, linkmanId, index) => {
const messages = linkmansMessages[index];
if (historyMap[linkmanId]) {
const messageIndex = messages.findIndex(
({ _id }) => _id.toString() === historyMap[linkmanId],
);
result[linkmanId] = {
messages: messages.slice(0, 15).reverse(),
unread: messageIndex === -1 ? 100 : messageIndex,
};
} else {
result[linkmanId] = {
messages: messages.reverse(),
unread: 0,
};
}
return result;
}, {});
const responseData = linkmans.reduce(
(result: ResponseData, linkmanId, index) => {
const messages = linkmansMessages[index];
if (historyMap[linkmanId]) {
const messageIndex = messages.findIndex(
({ _id }) => _id.toString() === historyMap[linkmanId],
);
result[linkmanId] = {
messages: messages.slice(0, 15).reverse(),
unread: messageIndex === -1 ? 100 : messageIndex,
};
} else {
result[linkmanId] = {
messages: messages.reverse(),
unread: 0,
};
}
return result;
},
{},
);

return responseData;
}
Expand All @@ -322,7 +339,10 @@ export async function getLinkmanHistoryMessages(
from: 1,
createTime: 1,
},
{ sort: { createTime: -1 }, limit: EachFetchMessagesCount + existCount },
{
sort: { createTime: -1 },
limit: EachFetchMessagesCount + existCount,
},
).populate('from', { username: 1, avatar: 1, tag: 1 });
await handleInviteV2Messages(messages);
const result = messages.slice(existCount).reverse();
Expand All @@ -333,7 +353,9 @@ export async function getLinkmanHistoryMessages(
* 获取默认群组的历史消息
* @param ctx Context
*/
export async function getDefaultGroupHistoryMessages(ctx: Context<{ existCount: number }>) {
export async function getDefaultGroupHistoryMessages(
ctx: Context<{ existCount: number }>,
) {
const { existCount } = ctx.data;

const group = await Group.findOne({ isDefault: true });
Expand All @@ -348,7 +370,10 @@ export async function getDefaultGroupHistoryMessages(ctx: Context<{ existCount:
from: 1,
createTime: 1,
},
{ sort: { createTime: -1 }, limit: EachFetchMessagesCount + existCount },
{
sort: { createTime: -1 },
limit: EachFetchMessagesCount + existCount,
},
).populate('from', { username: 1, avatar: 1, tag: 1 });
await handleInviteV2Messages(messages);
const result = messages.slice(existCount).reverse();
Expand All @@ -367,14 +392,18 @@ export async function deleteMessage(ctx: Context<{ messageId: string }>) {
const { messageId } = ctx.data;
assert(messageId, 'messageId不能为空');

assert(!client.disableDeleteMessage || ctx.socket.isAdmin, '已禁止撤回消息');
assert(
!client.disableDeleteMessage || ctx.socket.isAdmin,
'已禁止撤回消息',
);

const message = await Message.findOne({ _id: messageId });
if (!message) {
throw new AssertionError({ message: '消息不存在' });
}
assert(
ctx.socket.isAdmin || message.from.toString() === ctx.socket.user.toString(),
ctx.socket.isAdmin ||
message.from.toString() === ctx.socket.user.toString(),
'只能撤回本人的消息',
);

Expand All @@ -395,19 +424,24 @@ export async function deleteMessage(ctx: Context<{ messageId: string }>) {
} else {
// 私聊消息
const targetUserId = message.to.replace(ctx.socket.user.toString(), '');
const sockets = await Socket.find({ user: targetUserId });
ctx.socket.emit(
sockets.map((socket) => socket.id),
messageName,
messageData,
);
const targetSockets = await Socket.find({ user: targetUserId });
const targetSocketIdList =
targetSockets?.map((socket) => socket.id) || [];
if (targetSocketIdList) {
ctx.socket.emit(targetSocketIdList, messageName, messageData);
}

const selfSockets = await Socket.find({ user: ctx.socket.user });
ctx.socket.emit(
selfSockets.map((socket) => socket.id).filter((socketId) => socketId !== ctx.socket.id),
messageName,
messageData,
);
const selfSocketIdList = selfSockets?.map((socket) => socket.id) || [];
if (selfSocketIdList) {
ctx.socket.emit(
selfSocketIdList.filter(
(socketId) => socketId !== ctx.socket.id,
),
messageName,
messageData,
);
}
}

return {
Expand Down
50 changes: 38 additions & 12 deletions packages/server/src/routes/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@ import User, { UserDocument } from '@fiora/database/mongoose/models/user';
import Group, { GroupDocument } from '@fiora/database/mongoose/models/group';
import Friend, { FriendDocument } from '@fiora/database/mongoose/models/friend';
import Socket from '@fiora/database/mongoose/models/socket';
import Message, { handleInviteV2Messages } from '@fiora/database/mongoose/models/message';
import Message, {
handleInviteV2Messages,
} from '@fiora/database/mongoose/models/message';
import Notification from '@fiora/database/mongoose/models/notification';
import { getNewRegisteredUserIpKey, getNewUserKey, Redis } from '@fiora/database/redis/initRedis';
import {
getNewRegisteredUserIpKey,
getNewUserKey,
Redis,
} from '@fiora/database/redis/initRedis';

const { isValid } = Types.ObjectId;

Expand Down Expand Up @@ -55,7 +61,9 @@ async function handleNewUser(user: UserDocument, ip = '') {
await Redis.set(getNewUserKey(userId), userId, Redis.Day);

if (ip) {
const registeredCount = await Redis.get(getNewRegisteredUserIpKey(ip));
const registeredCount = await Redis.get(
getNewRegisteredUserIpKey(ip),
);
await Redis.set(
getNewRegisteredUserIpKey(ip),
(parseInt(registeredCount || '0', 10) + 1).toString(),
Expand All @@ -74,7 +82,9 @@ async function getUserNotificationTokens(user: UserDocument) {
* 注册新用户
* @param ctx Context
*/
export async function register(ctx: Context<{ username: string; password: string } & Environment>) {
export async function register(
ctx: Context<{ username: string; password: string } & Environment>,
) {
assert(!config.disableRegister, '注册功能已被禁用, 请联系管理员开通账号');

const { username, password, os, browser, environment } = ctx.data;
Expand All @@ -84,7 +94,9 @@ export async function register(ctx: Context<{ username: string; password: string
const user = await User.findOne({ username });
assert(!user, '该用户名已存在');

const registeredCountWithin24Hours = await Redis.get(getNewRegisteredUserIpKey(ctx.socket.ip));
const registeredCountWithin24Hours = await Redis.get(
getNewRegisteredUserIpKey(ctx.socket.ip),
);
assert(parseInt(registeredCountWithin24Hours || '0', 10) < 3, '系统错误');

const defaultGroup = await Group.findOne({ isDefault: true });
Expand Down Expand Up @@ -157,7 +169,9 @@ export async function register(ctx: Context<{ username: string; password: string
* 账密登录
* @param ctx Context
*/
export async function login(ctx: Context<{ username: string; password: string } & Environment>) {
export async function login(
ctx: Context<{ username: string; password: string } & Environment>,
) {
const { username, password, os, browser, environment } = ctx.data;
assert(username, '用户名不能为空');
assert(password, '密码不能为空');
Expand Down Expand Up @@ -226,7 +240,9 @@ export async function login(ctx: Context<{ username: string; password: string }
* token登录
* @param ctx Context
*/
export async function loginByToken(ctx: Context<{ token: string } & Environment>) {
export async function loginByToken(
ctx: Context<{ token: string } & Environment>,
) {
const { token, os, browser, environment } = ctx.data;
assert(token, 'token不能为空');

Expand Down Expand Up @@ -420,7 +436,9 @@ export async function deleteFriend(ctx: Context<{ userId: string }>) {
* 修改用户密码
* @param ctx Context
*/
export async function changePassword(ctx: Context<{ oldPassword: string; newPassword: string }>) {
export async function changePassword(
ctx: Context<{ oldPassword: string; newPassword: string }>,
) {
const { oldPassword, newPassword } = ctx.data;
assert(newPassword, '新密码不能为空');
assert(oldPassword !== newPassword, '新密码不能与旧密码相同');
Expand Down Expand Up @@ -497,7 +515,9 @@ export async function resetUserPassword(ctx: Context<{ username: string }>) {
* 更新用户标签, 需要管理员权限
* @param ctx Context
*/
export async function setUserTag(ctx: Context<{ username: string; tag: string }>) {
export async function setUserTag(
ctx: Context<{ username: string; tag: string }>,
) {
const { username, tag } = ctx.data;
assert(username !== '', 'username不能为空');
assert(tag !== '', 'tag不能为空');
Expand All @@ -516,7 +536,9 @@ export async function setUserTag(ctx: Context<{ username: string; tag: string }>

const sockets = await Socket.find({ user: user._id });
const socketIdList = sockets.map((socket) => socket.id);
ctx.socket.emit(socketIdList, 'changeTag', user.tag);
if (socketIdList.length) {
ctx.socket.emit(socketIdList, 'changeTag', user.tag);
}

return {
msg: 'ok',
Expand All @@ -526,7 +548,9 @@ export async function setUserTag(ctx: Context<{ username: string; tag: string }>
/**
* 获取指定在线用户 ip
*/
export async function getUserIps(ctx: Context<{ userId: string }>): Promise<string[]> {
export async function getUserIps(
ctx: Context<{ userId: string }>,
): Promise<string[]> {
const { userId } = ctx.data;
assert(userId, 'userId不能为空');
assert(isValid(userId), '不合法的userId');
Expand All @@ -545,7 +569,9 @@ function getUserOnlineStatusWrapper() {
expireTime: number;
}
> = {};
return async function getUserOnlineStatus(ctx: Context<{ userId: string }>) {
return async function getUserOnlineStatus(
ctx: Context<{ userId: string }>,
) {
const { userId } = ctx.data;
assert(userId, 'userId不能为空');
assert(isValid(userId), '不合法的userId');
Expand Down

0 comments on commit cb08c70

Please sign in to comment.