TeactN: Prevent race condition in async action handlers

This commit is contained in:
Alexander Zinchuk 2022-04-08 20:59:55 +02:00
parent 439e78ad82
commit fbe03b556b
13 changed files with 231 additions and 236 deletions

View File

@ -150,12 +150,12 @@ addActionHandler('restartBot', async (global, actions, payload) => {
addActionHandler('loadTopInlineBots', async (global) => {
const { lastRequestedAt } = global.topInlineBots;
if (lastRequestedAt && getServerTime(global.serverTimeOffset) - lastRequestedAt < TOP_PEERS_REQUEST_COOLDOWN) {
return undefined;
return;
}
const result = await callApi('fetchTopInlineBots');
if (!result) {
return undefined;
return;
}
const { ids, users } = result;
@ -170,7 +170,7 @@ addActionHandler('loadTopInlineBots', async (global) => {
lastRequestedAt: getServerTime(global.serverTimeOffset),
},
};
return global;
setGlobal(global);
});
addActionHandler('queryInlineBot', async (global, actions, payload) => {

View File

@ -678,14 +678,14 @@ addActionHandler('updateChatMemberBannedRights', async (global, actions, payload
const user = selectUser(global, userId);
if (!chat || !user) {
return undefined;
return;
}
if (isChatBasicGroup(chat)) {
chat = await callApi('migrateChat', chat);
if (!chat) {
return undefined;
return;
}
actions.openChat({ id: chat.id });
@ -698,7 +698,7 @@ addActionHandler('updateChatMemberBannedRights', async (global, actions, payload
const chatAfterUpdate = selectChat(global, chatId);
if (!chatAfterUpdate || !chatAfterUpdate.fullInfo) {
return undefined;
return;
}
const { members, kickedMembers } = chatAfterUpdate.fullInfo;
@ -706,7 +706,7 @@ addActionHandler('updateChatMemberBannedRights', async (global, actions, payload
const isBanned = Boolean(bannedRights.viewMessages);
const isUnblocked = !Object.keys(bannedRights).length;
return updateChat(global, chatId, {
setGlobal(updateChat(global, chatId, {
fullInfo: {
...chatAfterUpdate.fullInfo,
...(members && isBanned && {
@ -723,7 +723,7 @@ addActionHandler('updateChatMemberBannedRights', async (global, actions, payload
kickedMembers: kickedMembers.filter((m) => m.userId !== userId),
}),
},
});
}));
});
addActionHandler('updateChatAdmin', async (global, actions, payload) => {
@ -734,13 +734,13 @@ addActionHandler('updateChatAdmin', async (global, actions, payload) => {
let chat = selectChat(global, chatId);
const user = selectUser(global, userId);
if (!chat || !user) {
return undefined;
return;
}
if (isChatBasicGroup(chat)) {
chat = await callApi('migrateChat', chat);
if (!chat) {
return undefined;
return;
}
actions.openChat({ id: chat.id });
@ -752,7 +752,7 @@ addActionHandler('updateChatAdmin', async (global, actions, payload) => {
const chatAfterUpdate = await callApi('fetchFullChat', chat);
if (!chatAfterUpdate?.fullInfo) {
return undefined;
return;
}
const { adminMembers } = chatAfterUpdate.fullInfo;
@ -760,7 +760,7 @@ addActionHandler('updateChatAdmin', async (global, actions, payload) => {
global = getGlobal();
return updateChat(global, chatId, {
setGlobal(updateChat(global, chatId, {
fullInfo: {
...chatAfterUpdate.fullInfo,
...(adminMembers && isDismissed && {
@ -774,7 +774,7 @@ addActionHandler('updateChatAdmin', async (global, actions, payload) => {
)),
}),
},
});
}));
});
addActionHandler('updateChat', async (global, actions, payload) => {
@ -784,7 +784,7 @@ addActionHandler('updateChat', async (global, actions, payload) => {
const chat = selectChat(global, chatId);
if (!chat) {
return undefined;
return;
}
setGlobal(updateManagementProgress(getGlobal(), ManagementProgress.InProgress));
@ -801,7 +801,7 @@ addActionHandler('updateChat', async (global, actions, payload) => {
: undefined,
]);
return updateManagementProgress(getGlobal(), ManagementProgress.Complete);
setGlobal(updateManagementProgress(getGlobal(), ManagementProgress.Complete));
});
addActionHandler('toggleSignatures', (global, actions, payload) => {
@ -818,7 +818,7 @@ addActionHandler('toggleSignatures', (global, actions, payload) => {
addActionHandler('loadGroupsForDiscussion', async (global) => {
const groups = await callApi('fetchGroupsForDiscussion');
if (!groups) {
return undefined;
return;
}
const addedById = groups.reduce((result, group) => {
@ -831,13 +831,13 @@ addActionHandler('loadGroupsForDiscussion', async (global) => {
global = getGlobal();
global = addChats(global, addedById);
return {
setGlobal({
...global,
chats: {
...global.chats,
forDiscussionIds: Object.keys(addedById),
},
};
});
});
addActionHandler('linkDiscussionGroup', async (global, actions, payload) => {
@ -933,24 +933,24 @@ addActionHandler('loadMoreMembers', async (global) => {
const { chatId } = selectCurrentMessageList(global) || {};
const chat = chatId ? selectChat(global, chatId) : undefined;
if (!chat || isChatBasicGroup(chat)) {
return undefined;
return;
}
const offset = (chat.fullInfo?.members?.length) || undefined;
const result = await callApi('fetchMembers', chat.id, chat.accessHash!, 'recent', offset);
if (!result) {
return undefined;
return;
}
const { members, users } = result;
if (!members || !members.length) {
return undefined;
return;
}
global = getGlobal();
global = addUsers(global, buildCollectionByKey(users, 'id'));
global = addChatMembers(global, chat, members);
return global;
setGlobal(global);
});
addActionHandler('addChatMembers', async (global, actions, payload) => {
@ -1008,12 +1008,12 @@ addActionHandler('setChatEnabledReactions', async (global, actions, payload) =>
addActionHandler('loadChatSettings', async (global, actions, payload) => {
const { chatId } = payload!;
const chat = selectChat(global, chatId);
if (!chat) return undefined;
if (!chat) return;
const settings = await callApi('fetchChatSettings', chat);
if (!settings) return undefined;
if (!settings) return;
return updateChat(getGlobal(), chat.id, { settings });
setGlobal(updateChat(getGlobal(), chat.id, { settings }));
});
async function loadChats(

View File

@ -1,4 +1,6 @@
import { addActionHandler, getActions, getGlobal } from '../../index';
import {
addActionHandler, getActions, getGlobal, setGlobal,
} from '../../index';
import { initApi, callApi } from '../../../api/gramjs';
@ -165,15 +167,15 @@ addActionHandler('disconnect', () => {
addActionHandler('loadNearestCountry', async (global) => {
if (global.connectionState !== 'connectionStateReady') {
return undefined;
return;
}
const authNearestCountry = await callApi('fetchNearestCountry');
return {
setGlobal({
...getGlobal(),
authNearestCountry,
};
});
});
addActionHandler('setDeviceToken', (global, actions, deviceToken) => {

View File

@ -9,12 +9,12 @@ import { isChatBasicGroup } from '../../helpers';
addActionHandler('checkPublicLink', async (global, actions, payload) => {
const { chatId } = selectCurrentMessageList(global) || {};
if (!chatId) {
return undefined;
return;
}
// No need to check the username if already in progress
if (global.management.progress === ManagementProgress.InProgress) {
return undefined;
return;
}
const { username } = payload!;
@ -30,14 +30,14 @@ addActionHandler('checkPublicLink', async (global, actions, payload) => {
global, isUsernameAvailable ? ManagementProgress.Complete : ManagementProgress.Error,
);
global = updateManagement(global, chatId, { isUsernameAvailable });
return global;
setGlobal(global);
});
addActionHandler('updatePublicLink', async (global, actions, payload) => {
const { chatId } = selectCurrentMessageList(global) || {};
let chat = chatId && selectChat(global, chatId);
if (!chatId || !chat) {
return undefined;
return;
}
const { username } = payload!;
@ -49,7 +49,7 @@ addActionHandler('updatePublicLink', async (global, actions, payload) => {
chat = await callApi('migrateChat', chat);
if (!chat) {
return undefined;
return;
}
actions.openChat({ id: chat.id });
@ -60,7 +60,7 @@ addActionHandler('updatePublicLink', async (global, actions, payload) => {
global = getGlobal();
global = updateManagementProgress(global, result ? ManagementProgress.Complete : ManagementProgress.Error);
global = updateManagement(global, chatId, { isUsernameAvailable: undefined });
return global;
setGlobal(global);
});
addActionHandler('updatePrivateLink', (global) => {
@ -93,18 +93,18 @@ addActionHandler('loadExportedChatInvites', async (global, actions, payload) =>
} = payload!;
const peer = selectChat(global, chatId);
const admin = selectUser(global, adminId || global.currentUserId);
if (!peer || !admin) return undefined;
if (!peer || !admin) return;
const result = await callApi('fetchExportedChatInvites', {
peer, admin, isRevoked, limit,
});
if (!result) {
return undefined;
return;
}
const update = isRevoked ? { revokedInvites: result } : { invites: result };
return updateManagement(getGlobal(), chatId, update);
setGlobal(updateManagement(getGlobal(), chatId, update));
});
addActionHandler('editExportedChatInvite', async (global, actions, payload) => {
@ -112,7 +112,7 @@ addActionHandler('editExportedChatInvite', async (global, actions, payload) => {
chatId, link, isRevoked, expireDate, usageLimit, isRequestNeeded, title,
} = payload!;
const peer = selectChat(global, chatId);
if (!peer) return undefined;
if (!peer) return;
const result = await callApi('editExportedChatInvite', {
peer,
@ -124,7 +124,7 @@ addActionHandler('editExportedChatInvite', async (global, actions, payload) => {
title,
});
if (!result) {
return undefined;
return;
}
const { oldInvite, newInvite } = result;
@ -140,10 +140,10 @@ addActionHandler('editExportedChatInvite', async (global, actions, payload) => {
invites.push(newInvite);
}
return updateManagement(global, chatId, {
setGlobal(updateManagement(global, chatId, {
invites,
revokedInvites,
});
}));
});
addActionHandler('exportChatInvite', async (global, actions, payload) => {
@ -151,7 +151,7 @@ addActionHandler('exportChatInvite', async (global, actions, payload) => {
chatId, expireDate, usageLimit, isRequestNeeded, title,
} = payload!;
const peer = selectChat(global, chatId);
if (!peer) return undefined;
if (!peer) return;
const result = await callApi('exportChatInvite', {
peer,
@ -161,14 +161,14 @@ addActionHandler('exportChatInvite', async (global, actions, payload) => {
title,
});
if (!result) {
return undefined;
return;
}
global = getGlobal();
const invites = global.management.byChatId[chatId].invites || [];
return updateManagement(global, chatId, {
setGlobal(updateManagement(global, chatId, {
invites: [...invites, result],
});
}));
});
addActionHandler('deleteExportedChatInvite', async (global, actions, payload) => {
@ -176,22 +176,22 @@ addActionHandler('deleteExportedChatInvite', async (global, actions, payload) =>
chatId, link,
} = payload!;
const peer = selectChat(global, chatId);
if (!peer) return undefined;
if (!peer) return;
const result = await callApi('deleteExportedChatInvite', {
peer,
link,
});
if (!result) {
return undefined;
return;
}
global = getGlobal();
const managementState = global.management.byChatId[chatId];
return updateManagement(global, chatId, {
setGlobal(updateManagement(global, chatId, {
invites: managementState?.invites?.filter((invite) => invite.link !== link),
revokedInvites: managementState?.revokedInvites?.filter((invite) => invite.link !== link),
});
}));
});
addActionHandler('deleteRevokedExportedChatInvites', async (global, actions, payload) => {
@ -200,20 +200,20 @@ addActionHandler('deleteRevokedExportedChatInvites', async (global, actions, pay
} = payload!;
const peer = selectChat(global, chatId);
const admin = selectUser(global, adminId || global.currentUserId);
if (!peer || !admin) return undefined;
if (!peer || !admin) return;
const result = await callApi('deleteRevokedExportedChatInvites', {
peer,
admin,
});
if (!result) {
return undefined;
return;
}
global = getGlobal();
return updateManagement(global, chatId, {
setGlobal(updateManagement(global, chatId, {
revokedInvites: [],
});
}));
});
addActionHandler('loadChatInviteImporters', async (global, actions, payload) => {
@ -222,7 +222,7 @@ addActionHandler('loadChatInviteImporters', async (global, actions, payload) =>
} = payload!;
const peer = selectChat(global, chatId);
const offsetUser = selectUser(global, offsetUserId);
if (!peer || (offsetUserId && !offsetUser)) return undefined;
if (!peer || (offsetUserId && !offsetUser)) return;
const result = await callApi('fetchChatInviteImporters', {
peer,
@ -232,21 +232,21 @@ addActionHandler('loadChatInviteImporters', async (global, actions, payload) =>
limit,
});
if (!result) {
return undefined;
return;
}
global = getGlobal();
const currentInviteInfo = global.management.byChatId[chatId]?.inviteInfo;
if (!currentInviteInfo?.invite || currentInviteInfo.invite.link !== link) {
return undefined;
return;
}
return updateManagement(global, chatId, {
setGlobal(updateManagement(global, chatId, {
inviteInfo: {
...currentInviteInfo,
importers: result,
},
});
}));
});
addActionHandler('loadChatInviteRequesters', async (global, actions, payload) => {
@ -255,7 +255,7 @@ addActionHandler('loadChatInviteRequesters', async (global, actions, payload) =>
} = payload!;
const peer = selectChat(global, chatId);
const offsetUser = selectUser(global, offsetUserId);
if (!peer || (offsetUserId && !offsetUser)) return undefined;
if (!peer || (offsetUserId && !offsetUser)) return;
const result = await callApi('fetchChatInviteImporters', {
peer,
@ -266,21 +266,21 @@ addActionHandler('loadChatInviteRequesters', async (global, actions, payload) =>
isRequested: true,
});
if (!result) {
return undefined;
return;
}
global = getGlobal();
const currentInviteInfo = global.management.byChatId[chatId]?.inviteInfo;
if (!currentInviteInfo?.invite || currentInviteInfo.invite.link !== link) {
return undefined;
return;
}
return updateManagement(global, chatId, {
setGlobal(updateManagement(global, chatId, {
inviteInfo: {
...currentInviteInfo,
requesters: result,
},
});
}));
});
addActionHandler('loadChatJoinRequests', async (global, actions, payload) => {
@ -289,7 +289,7 @@ addActionHandler('loadChatJoinRequests', async (global, actions, payload) => {
} = payload!;
const peer = selectChat(global, chatId);
const offsetUser = selectUser(global, offsetUserId);
if (!peer || (offsetUserId && !offsetUser)) return undefined;
if (!peer || (offsetUserId && !offsetUser)) return;
const result = await callApi('fetchChatInviteImporters', {
peer,
@ -299,11 +299,11 @@ addActionHandler('loadChatJoinRequests', async (global, actions, payload) => {
isRequested: true,
});
if (!result) {
return undefined;
return;
}
global = getGlobal();
return updateChat(global, chatId, { joinRequests: result });
setGlobal(updateChat(global, chatId, { joinRequests: result }));
});
addActionHandler('hideChatJoinRequest', async (global, actions, payload) => {
@ -312,22 +312,22 @@ addActionHandler('hideChatJoinRequest', async (global, actions, payload) => {
} = payload!;
const peer = selectChat(global, chatId);
const user = selectUser(global, userId);
if (!peer || !user) return undefined;
if (!peer || !user) return;
const result = await callApi('hideChatJoinRequest', {
peer,
user,
isApproved,
});
if (!result) return undefined;
if (!result) return;
global = getGlobal();
const targetChat = selectChat(global, chatId);
if (!targetChat) return undefined;
if (!targetChat) return;
return updateChat(global, chatId, {
setGlobal(updateChat(global, chatId, {
joinRequests: targetChat.joinRequests?.filter((importer) => importer.userId !== userId),
});
}));
});
addActionHandler('hideAllChatJoinRequests', async (global, actions, payload) => {
@ -335,38 +335,38 @@ addActionHandler('hideAllChatJoinRequests', async (global, actions, payload) =>
chatId, isApproved, link,
} = payload!;
const peer = selectChat(global, chatId);
if (!peer) return undefined;
if (!peer) return;
const result = await callApi('hideAllChatJoinRequests', {
peer,
isApproved,
link,
});
if (!result) return undefined;
if (!result) return;
global = getGlobal();
const targetChat = selectChat(global, chatId);
if (!targetChat) return undefined;
if (!targetChat) return;
return updateChat(global, chatId, {
setGlobal(updateChat(global, chatId, {
joinRequests: [],
fullInfo: {
...targetChat.fullInfo,
recentRequesterIds: [],
requestsPending: 0,
},
});
}));
});
addActionHandler('hideChatReportPanel', async (global, actions, payload) => {
const { chatId } = payload!;
const chat = selectChat(global, chatId);
if (!chat) return undefined;
if (!chat) return;
const result = await callApi('hideChatReportPanel', chat);
if (!result) return undefined;
if (!result) return;
return updateChat(getGlobal(), chatId, {
setGlobal(updateChat(getGlobal(), chatId, {
settings: undefined,
});
}));
});

View File

@ -164,23 +164,21 @@ addActionHandler('loadMessage', async (global, actions, payload) => {
const chat = selectChat(global, chatId);
if (!chat) {
return undefined;
return;
}
const message = await loadMessage(chat, messageId, replyOriginForId);
if (message && threadUpdate) {
const { lastMessageId, isDeleting } = threadUpdate;
return updateThreadUnreadFromForwardedMessage(
setGlobal(updateThreadUnreadFromForwardedMessage(
getGlobal(),
message,
chatId,
lastMessageId,
isDeleting,
);
));
}
return undefined;
});
addActionHandler('sendMessage', (global, actions, payload) => {
@ -961,17 +959,17 @@ addActionHandler('loadSeenBy', async (global, actions, payload) => {
const { chatId, messageId } = payload;
const chat = selectChat(global, chatId);
if (!chat) {
return undefined;
return;
}
const result = await callApi('fetchSeenBy', { chat, messageId });
if (!result) {
return undefined;
return;
}
return updateChatMessage(getGlobal(), chatId, messageId, {
setGlobal(updateChatMessage(getGlobal(), chatId, messageId, {
seenByUserIds: result,
});
}));
});
addActionHandler('saveDefaultSendAs', (global, actions, payload) => {
@ -996,21 +994,23 @@ addActionHandler('loadSendAs', async (global, actions, payload) => {
const { chatId } = payload;
const chat = selectChat(global, chatId);
if (!chat) {
return undefined;
return;
}
const result = await callApi('fetchSendAs', { chat });
if (!result) {
return updateChat(getGlobal(), chatId, {
setGlobal(updateChat(getGlobal(), chatId, {
sendAsIds: [],
});
}));
return;
}
global = getGlobal();
global = addUsers(global, buildCollectionByKey(result.users, 'id'));
global = addChats(global, buildCollectionByKey(result.chats, 'id'));
global = updateChat(global, chatId, { sendAsIds: result.ids });
return global;
setGlobal(global);
});
async function loadPinnedMessages(chat: ApiChat) {
@ -1053,19 +1053,19 @@ addActionHandler('loadSponsoredMessages', async (global, actions, payload) => {
const { chatId } = payload;
const chat = selectChat(global, chatId);
if (!chat) {
return undefined;
return;
}
const result = await callApi('fetchSponsoredMessages', { chat });
if (!result) {
return undefined;
return;
}
global = getGlobal();
global = updateSponsoredMessage(global, chatId, result.messages[0]);
global = addUsers(global, buildCollectionByKey(result.users, 'id'));
global = addChats(global, buildCollectionByKey(result.chats, 'id'));
return global;
setGlobal(global);
});
addActionHandler('viewSponsoredMessage', (global, actions, payload) => {

View File

@ -1,4 +1,4 @@
import { addActionHandler, getGlobal } from '../../index';
import { addActionHandler, getGlobal, setGlobal } from '../../index';
import { callApi } from '../../../api/gramjs';
import * as mediaLoader from '../../../util/mediaLoader';
import { ApiAppConfig, ApiMediaFormat } from '../../../api/types';
@ -22,7 +22,7 @@ let interactionLocalId = 0;
addActionHandler('loadAvailableReactions', async () => {
const result = await callApi('getAvailableReactions');
if (!result) {
return undefined;
return;
}
// Preload animations
@ -35,10 +35,10 @@ addActionHandler('loadAvailableReactions', async () => {
}
});
return {
setGlobal({
...getGlobal(),
availableReactions: result,
};
});
});
addActionHandler('interactWithAnimatedEmoji', (global, actions, payload) => {
@ -198,16 +198,16 @@ addActionHandler('setDefaultReaction', async (global, actions, payload) => {
const result = await callApi('setDefaultReaction', { reaction });
if (!result) {
return undefined;
return;
}
return {
setGlobal({
...getGlobal(),
appConfig: {
...global.appConfig,
defaultReaction: reaction,
} as ApiAppConfig,
};
});
});
addActionHandler('stopActiveEmojiInteraction', (global, actions, payload) => {
@ -224,7 +224,7 @@ addActionHandler('loadReactors', async (global, actions, payload) => {
const chat = selectChat(global, chatId);
const message = selectChatMessage(global, chatId, messageId);
if (!chat || !message) {
return undefined;
return;
}
const offset = message.reactors?.nextOffset;
@ -236,7 +236,7 @@ addActionHandler('loadReactors', async (global, actions, payload) => {
});
if (!result) {
return undefined;
return;
}
global = getGlobal();
@ -247,7 +247,7 @@ addActionHandler('loadReactors', async (global, actions, payload) => {
const { nextOffset, count, reactions } = result;
return updateChatMessage(global, chatId, messageId, {
setGlobal(updateChatMessage(global, chatId, messageId, {
reactors: {
nextOffset,
count,
@ -256,7 +256,7 @@ addActionHandler('loadReactors', async (global, actions, payload) => {
...reactions,
],
},
});
}));
});
addActionHandler('loadMessageReactions', (global, actions, payload) => {

View File

@ -25,7 +25,7 @@ addActionHandler('updateProfile', async (global, actions, payload) => {
const { currentUserId } = global;
if (!currentUserId) {
return undefined;
return;
}
setGlobal({
@ -69,12 +69,12 @@ addActionHandler('updateProfile', async (global, actions, payload) => {
}
}
return {
setGlobal({
...getGlobal(),
profileEdit: {
progress: ProfileEditProgress.Complete,
},
};
});
});
addActionHandler('checkUsername', async (global, actions, payload) => {
@ -82,7 +82,7 @@ addActionHandler('checkUsername', async (global, actions, payload) => {
// No need to check the username if profile update is already in progress
if (global.profileEdit && global.profileEdit.progress === ProfileEditProgress.InProgress) {
return undefined;
return;
}
setGlobal({
@ -96,29 +96,29 @@ addActionHandler('checkUsername', async (global, actions, payload) => {
const isUsernameAvailable = await callApi('checkUsername', username);
global = getGlobal();
return {
setGlobal({
...global,
profileEdit: {
...global.profileEdit!,
isUsernameAvailable,
},
};
});
});
addActionHandler('loadWallpapers', async () => {
const result = await callApi('fetchWallpapers');
if (!result) {
return undefined;
return;
}
const global = getGlobal();
return {
setGlobal({
...global,
settings: {
...global.settings,
loadedWallpapers: result.wallpapers,
},
};
});
});
addActionHandler('uploadWallpaper', async (global, actions, payload) => {
@ -146,19 +146,19 @@ addActionHandler('uploadWallpaper', async (global, actions, payload) => {
const result = await callApi('uploadWallpaper', file);
if (!result) {
return undefined;
return;
}
const { wallpaper } = result;
global = getGlobal();
if (!global.settings.loadedWallpapers) {
return undefined;
return;
}
const firstWallpaper = global.settings.loadedWallpapers[0];
if (!firstWallpaper || firstWallpaper.slug !== UPLOADING_WALLPAPER_SLUG) {
return undefined;
return;
}
const withLocalMedia = {
@ -169,7 +169,7 @@ addActionHandler('uploadWallpaper', async (global, actions, payload) => {
},
};
return {
setGlobal({
...global,
settings: {
...global.settings,
@ -178,13 +178,13 @@ addActionHandler('uploadWallpaper', async (global, actions, payload) => {
...global.settings.loadedWallpapers.slice(1),
],
},
};
});
});
addActionHandler('loadBlockedContacts', async (global) => {
const result = await callApi('fetchBlockedContacts');
if (!result) {
return undefined;
return;
}
global = getGlobal();
@ -205,7 +205,7 @@ addActionHandler('loadBlockedContacts', async (global) => {
},
};
return global;
setGlobal(global);
});
addActionHandler('blockContact', async (global, actions, payload) => {
@ -213,10 +213,10 @@ addActionHandler('blockContact', async (global, actions, payload) => {
const result = await callApi('blockContact', contactId, accessHash);
if (!result) {
return undefined;
return;
}
return addBlockedContact(getGlobal(), contactId);
setGlobal(addBlockedContact(getGlobal(), contactId));
});
addActionHandler('unblockContact', async (global, actions, payload) => {
@ -227,7 +227,7 @@ addActionHandler('unblockContact', async (global, actions, payload) => {
if (isPrivate) {
const user = selectUser(global, contactId);
if (!user) {
return undefined;
return;
}
accessHash = user.accessHash;
@ -235,22 +235,22 @@ addActionHandler('unblockContact', async (global, actions, payload) => {
const result = await callApi('unblockContact', contactId, accessHash);
if (!result) {
return undefined;
return;
}
return removeBlockedContact(getGlobal(), contactId);
setGlobal(removeBlockedContact(getGlobal(), contactId));
});
addActionHandler('loadAuthorizations', async () => {
const result = await callApi('fetchAuthorizations');
if (!result) {
return undefined;
return;
}
return {
setGlobal({
...getGlobal(),
activeSessions: result,
};
});
});
addActionHandler('terminateAuthorization', async (global, actions, payload) => {
@ -258,29 +258,29 @@ addActionHandler('terminateAuthorization', async (global, actions, payload) => {
const result = await callApi('terminateAuthorization', hash);
if (!result) {
return undefined;
return;
}
global = getGlobal();
return {
setGlobal({
...global,
activeSessions: global.activeSessions.filter((session) => session.hash !== hash),
};
});
});
addActionHandler('terminateAllAuthorizations', async (global) => {
const result = await callApi('terminateAllAuthorizations');
if (!result) {
return undefined;
return;
}
global = getGlobal();
return {
setGlobal({
...global,
activeSessions: global.activeSessions.filter((session) => session.isCurrent),
};
});
});
addActionHandler('loadNotificationExceptions', async (global) => {
@ -288,10 +288,10 @@ addActionHandler('loadNotificationExceptions', async (global) => {
const result = await callApi('fetchNotificationExceptions', { serverTimeOffset });
if (!result) {
return undefined;
return;
}
return addNotifyExceptions(getGlobal(), result);
setGlobal(addNotifyExceptions(getGlobal(), result));
});
addActionHandler('loadNotificationSettings', async (global) => {
@ -300,10 +300,10 @@ addActionHandler('loadNotificationSettings', async (global) => {
serverTimeOffset,
});
if (!result) {
return undefined;
return;
}
return replaceSettings(getGlobal(), result);
setGlobal(replaceSettings(getGlobal(), result));
});
addActionHandler('updateNotificationSettings', async (global, actions, payload) => {
@ -311,10 +311,10 @@ addActionHandler('updateNotificationSettings', async (global, actions, payload)
const result = await callApi('updateNotificationSettings', peerType, { isSilent, shouldShowPreviews });
if (!result) {
return undefined;
return;
}
return updateNotifySettings(getGlobal(), peerType, isSilent, shouldShowPreviews);
setGlobal(updateNotifySettings(getGlobal(), peerType, isSilent, shouldShowPreviews));
});
addActionHandler('updateWebNotificationSettings', (global, actions, payload) => {
@ -333,19 +333,19 @@ addActionHandler('updateContactSignUpNotification', async (global, actions, payl
const result = await callApi('updateContactSignUpNotification', isSilent);
if (!result) {
return undefined;
return;
}
return replaceSettings(getGlobal(), { hasContactJoinedNotifications: !isSilent });
setGlobal(replaceSettings(getGlobal(), { hasContactJoinedNotifications: !isSilent }));
});
addActionHandler('loadLanguages', async () => {
const result = await callApi('fetchLanguages');
if (!result) {
return undefined;
return;
}
return replaceSettings(getGlobal(), { languages: result });
setGlobal(replaceSettings(getGlobal(), { languages: result }));
});
addActionHandler('loadPrivacySettings', async (global) => {
@ -362,18 +362,24 @@ addActionHandler('loadPrivacySettings', async (global) => {
if (
!phoneNumberSettings || !lastSeenSettings || !profilePhotoSettings || !forwardsSettings || !chatInviteSettings
) {
return undefined;
return;
}
global = getGlobal();
global.settings.privacy.phoneNumber = phoneNumberSettings;
global.settings.privacy.lastSeen = lastSeenSettings;
global.settings.privacy.profilePhoto = profilePhotoSettings;
global.settings.privacy.forwards = forwardsSettings;
global.settings.privacy.chatInvite = chatInviteSettings;
return global;
setGlobal({
...global,
settings: {
...global.settings,
privacy: {
...global.settings.privacy,
phoneNumber: phoneNumberSettings,
lastSeen: lastSeenSettings,
profilePhoto: profilePhotoSettings,
forwards: forwardsSettings,
chatInvite: chatInviteSettings,
},
},
});
});
addActionHandler('setPrivacyVisibility', async (global, actions, payload) => {
@ -384,7 +390,7 @@ addActionHandler('setPrivacyVisibility', async (global, actions, payload) => {
} = global.settings;
if (!settings) {
return undefined;
return;
}
const rules = buildInputPrivacyRules(global, {
@ -395,12 +401,12 @@ addActionHandler('setPrivacyVisibility', async (global, actions, payload) => {
const result = await callApi('setPrivacySettings', privacyKey, rules);
if (!result) {
return undefined;
return;
}
global = getGlobal();
return {
setGlobal({
...global,
settings: {
...global.settings,
@ -409,7 +415,7 @@ addActionHandler('setPrivacyVisibility', async (global, actions, payload) => {
[privacyKey]: result,
},
},
};
});
});
addActionHandler('setPrivacySettings', async (global, actions, payload) => {
@ -419,7 +425,7 @@ addActionHandler('setPrivacySettings', async (global, actions, payload) => {
} = global.settings;
if (!settings) {
return undefined;
return;
}
const rules = buildInputPrivacyRules(global, {
@ -430,12 +436,12 @@ addActionHandler('setPrivacySettings', async (global, actions, payload) => {
const result = await callApi('setPrivacySettings', privacyKey, rules);
if (!result) {
return undefined;
return;
}
global = getGlobal();
return {
setGlobal({
...global,
settings: {
...global.settings,
@ -444,7 +450,7 @@ addActionHandler('setPrivacySettings', async (global, actions, payload) => {
[privacyKey]: result,
},
},
};
});
});
function buildInputPrivacyRules(global: GlobalState, {
@ -521,9 +527,9 @@ addActionHandler('updateIsOnline', (global, actions, payload) => {
addActionHandler('loadContentSettings', async () => {
const result = await callApi('fetchContentSettings');
if (!result) return undefined;
if (!result) return;
return replaceSettings(getGlobal(), result);
setGlobal(replaceSettings(getGlobal(), result));
});
addActionHandler('updateContentSettings', async (global, actions, payload) => {
@ -531,10 +537,8 @@ addActionHandler('updateContentSettings', async (global, actions, payload) => {
const result = await callApi('updateContentSettings', payload);
if (!result) {
return replaceSettings(getGlobal(), { isSensitiveEnabled: !payload });
setGlobal(replaceSettings(getGlobal(), { isSensitiveEnabled: !payload }));
}
return undefined;
});
addActionHandler('loadCountryList', async (global, actions, payload = {}) => {
@ -542,12 +546,12 @@ addActionHandler('loadCountryList', async (global, actions, payload = {}) => {
if (!langCode) langCode = global.settings.byKey.language;
const countryList = await callApi('fetchCountryList', { langCode });
if (!countryList) return undefined;
if (!countryList) return;
return {
setGlobal({
...getGlobal(),
countryList,
};
});
});
addActionHandler('ensureTimeFormat', async (global, actions) => {
@ -571,10 +575,10 @@ addActionHandler('ensureTimeFormat', async (global, actions) => {
addActionHandler('loadAppConfig', async () => {
const appConfig = await callApi('fetchAppConfig');
if (!appConfig) return undefined;
if (!appConfig) return;
return {
setGlobal({
...getGlobal(),
appConfig,
};
});
});

View File

@ -1,4 +1,4 @@
import { addActionHandler, getGlobal } from '../../index';
import { addActionHandler, getGlobal, setGlobal } from '../../index';
import { ApiChannelStatistics } from '../../../api/types';
import { callApi } from '../../../api/gramjs';
@ -9,12 +9,12 @@ addActionHandler('loadStatistics', async (global, actions, payload) => {
const { chatId, isGroup } = payload;
const chat = selectChat(global, chatId);
if (!chat?.fullInfo) {
return undefined;
return;
}
const result = await callApi(isGroup ? 'fetchGroupStatistics' : 'fetchChannelStatistics', { chat });
if (!result) {
return undefined;
return;
}
global = getGlobal();
@ -26,9 +26,7 @@ addActionHandler('loadStatistics', async (global, actions, payload) => {
.map((message) => ({ ...message, ...messages[message.msgId] }));
}
global = updateStatistics(global, chatId, result);
return global;
setGlobal(updateStatistics(global, chatId, result));
});
addActionHandler('loadStatisticsAsyncGraph', async (global, actions, payload) => {
@ -37,15 +35,15 @@ addActionHandler('loadStatisticsAsyncGraph', async (global, actions, payload) =>
} = payload;
const chat = selectChat(global, chatId);
if (!chat?.fullInfo) {
return undefined;
return;
}
const dcId = chat.fullInfo!.statisticsDcId;
const result = await callApi('fetchStatisticsAsyncGraph', { token, dcId, isPercentage });
if (!result) {
return undefined;
return;
}
return updateStatisticsGraph(getGlobal(), chatId, name, result);
setGlobal(updateStatisticsGraph(getGlobal(), chatId, name, result));
});

View File

@ -60,12 +60,12 @@ addActionHandler('loadGreetingStickers', async (global) => {
const greeting = await callApi('fetchStickersForEmoji', { emoji: '👋⭐️', hash });
if (!greeting) {
return undefined;
return;
}
global = getGlobal();
return {
setGlobal({
...global,
stickers: {
...global.stickers,
@ -74,7 +74,7 @@ addActionHandler('loadGreetingStickers', async (global) => {
stickers: greeting.stickers.filter((sticker) => sticker.emoji === '👋'),
},
},
};
});
});
addActionHandler('loadFeaturedStickers', (global) => {
@ -112,14 +112,14 @@ addActionHandler('saveGif', async (global, actions, payload) => {
const { gif, shouldUnsave } = payload!;
const result = await callApi('saveGif', { gif, shouldUnsave });
if (!result) {
return undefined;
return;
}
global = getGlobal();
const gifs = global.gifs.saved.gifs?.filter(({ id }) => id !== gif.id) || [];
const newGifs = shouldUnsave ? gifs : [gif, ...gifs];
return {
setGlobal({
...global,
gifs: {
...global.gifs,
@ -128,7 +128,7 @@ addActionHandler('saveGif', async (global, actions, payload) => {
gifs: newGifs,
},
},
};
});
});
addActionHandler('faveSticker', (global, actions, payload) => {
@ -164,7 +164,7 @@ addActionHandler('loadEmojiKeywords', async (global, actions, payload: { languag
let currentEmojiKeywords = global.emojiKeywords[language];
if (currentEmojiKeywords?.isLoading) {
return undefined;
return;
}
setGlobal({
@ -187,7 +187,7 @@ addActionHandler('loadEmojiKeywords', async (global, actions, payload: { languag
currentEmojiKeywords = global.emojiKeywords[language];
if (!emojiKeywords) {
return {
setGlobal({
...global,
emojiKeywords: {
...global.emojiKeywords,
@ -196,10 +196,12 @@ addActionHandler('loadEmojiKeywords', async (global, actions, payload: { languag
isLoading: false,
},
},
};
});
return;
}
return {
setGlobal({
...global,
emojiKeywords: {
...global.emojiKeywords,
@ -212,7 +214,7 @@ addActionHandler('loadEmojiKeywords', async (global, actions, payload: { languag
},
},
},
};
});
});
async function loadStickerSets(hash?: string) {

View File

@ -6,13 +6,13 @@ import { replaceSettings, updateTwoFaSettings } from '../../reducers';
addActionHandler('loadPasswordInfo', async (global) => {
const result = await callApi('getPasswordInfo');
if (!result) {
return undefined;
return;
}
global = getGlobal();
global = replaceSettings(global, { hasPassword: result.hasPassword });
global = updateTwoFaSettings(global, { hint: result.hint });
return global;
setGlobal(global);
});
addActionHandler('checkPassword', async (global, actions, payload) => {

View File

@ -37,25 +37,23 @@ addActionHandler('loadUser', async (global, actions, payload) => {
const { userId } = payload!;
const user = selectUser(global, userId);
if (!user) {
return undefined;
return;
}
const result = await callApi('fetchUsers', { users: [user] });
if (!result) {
return undefined;
return;
}
const { users, userStatusesById } = result;
global = getGlobal();
global = updateUsers(global, buildCollectionByKey(users, 'id'));
global = replaceUserStatuses(global, {
...global.users.statusesById,
...userStatusesById,
});
return global;
setGlobal(global);
});
addActionHandler('loadTopUsers', (global) => {
@ -78,13 +76,13 @@ addActionHandler('loadCommonChats', async (global) => {
const { chatId } = selectCurrentMessageList(global) || {};
const user = chatId ? selectUser(global, chatId) : undefined;
if (!user || isUserBot(user) || user.commonChats?.isFullyLoaded) {
return undefined;
return;
}
const maxId = user.commonChats?.maxId;
const result = await callApi('fetchCommonChats', user.id, user.accessHash!, maxId);
if (!result) {
return undefined;
return;
}
const { chats, chatIds, isFullyLoaded } = result;
@ -101,7 +99,7 @@ addActionHandler('loadCommonChats', async (global) => {
},
});
return global;
setGlobal(global);
});
addActionHandler('updateContact', (global, actions, payload) => {
@ -235,12 +233,12 @@ addActionHandler('loadProfilePhotos', async (global, actions, payload) => {
const user = isPrivate ? selectUser(global, profileId) : undefined;
const chat = !isPrivate ? selectChat(global, profileId) : undefined;
if (!user && !chat) {
return undefined;
return;
}
const result = await callApi('fetchProfilePhotos', user, chat);
if (!result || !result.photos) {
return undefined;
return;
}
global = getGlobal();
@ -252,7 +250,7 @@ addActionHandler('loadProfilePhotos', async (global, actions, payload) => {
global = updateChat(global, profileId, { photos: result.photos });
}
return global;
setGlobal(global);
});
addActionHandler('setUserSearchQuery', (global, actions, payload) => {
@ -269,18 +267,17 @@ addActionHandler('importContact', async (global, actions, payload) => {
const { phoneNumber: phone, firstName, lastName } = payload!;
const result = await callApi('importContact', { phone, firstName, lastName });
if (!result) {
actions.showNotification({
message: langProvider.getTranslation('Contacts.PhoneNumber.NotRegistred'),
});
if (result) {
actions.openChat({ id: result });
return closeNewContactDialog(getGlobal());
return;
}
actions.showNotification({
message: langProvider.getTranslation('Contacts.PhoneNumber.NotRegistred'),
});
actions.openChat({ id: result });
return undefined;
setGlobal(closeNewContactDialog(getGlobal()));
});
addActionHandler('reportSpam', (global, actions, payload) => {

View File

@ -203,11 +203,11 @@ addActionHandler('joinVoiceChatByLink', async (global, actions, payload) => {
});
addActionHandler('joinGroupCall', async (global, actions, payload) => {
if (!ARE_CALLS_SUPPORTED) return undefined;
if (!ARE_CALLS_SUPPORTED) return;
if (global.phoneCall) {
actions.toggleGroupCallPanel();
return undefined;
return;
}
const {
@ -222,19 +222,19 @@ addActionHandler('joinGroupCall', async (global, actions, payload) => {
if (groupCall?.id === activeGroupCallId) {
actions.toggleGroupCallPanel();
return undefined;
return;
}
if (activeGroupCallId) {
actions.leaveGroupCall({
rejoin: payload,
});
return undefined;
return;
}
if (groupCall && activeGroupCallId === groupCall.id) {
actions.toggleGroupCallPanel();
return undefined;
return;
}
if (!groupCall && (!id || !accessHash)) {
@ -244,7 +244,7 @@ addActionHandler('joinGroupCall', async (global, actions, payload) => {
});
}
if (!groupCall) return undefined;
if (!groupCall) return;
global = getGlobal();
global = updateGroupCall(
@ -265,7 +265,7 @@ addActionHandler('joinGroupCall', async (global, actions, payload) => {
},
isCallPanelVisible: false,
};
return global;
setGlobal(global);
});
addActionHandler('playGroupCallSound', (global, actions, payload) => {

View File

@ -29,7 +29,7 @@ type ActionHandler = (
global: GlobalState,
actions: Actions,
payload: any,
) => GlobalState | void | Promise<GlobalState | void>;
) => GlobalState | void | Promise<void>;
type MapStateToProps<OwnProps = undefined> = ((global: GlobalState, ownProps: OwnProps) => AnyLiteral);
@ -81,19 +81,11 @@ export function getActions() {
function handleAction(name: string, payload?: ActionPayload, options?: ActionOptions) {
actionHandlers[name]?.forEach((handler) => {
const response = handler(currentGlobal, actions, payload);
if (!response) {
if (!response || typeof response.then === 'function') {
return;
}
if (typeof response.then === 'function') {
response.then((newGlobal: GlobalState | void) => {
if (newGlobal) {
setGlobal(newGlobal, options);
}
});
} else {
setGlobal(response, options);
}
setGlobal(response, options);
});
}
@ -254,7 +246,7 @@ export function typify<ProjectGlobalState, ActionPayloads, NonTypedActionNames e
global: ProjectGlobalState,
actions: ProjectActions,
payload: ProjectActionTypes[ActionName],
) => ProjectGlobalState | void | Promise<ProjectGlobalState | void>;
) => ProjectGlobalState | void | Promise<void>;
};
return {