bigbuffet-rw/app/soapbox/actions/streaming.ts

195 lines
6.5 KiB
TypeScript
Raw Normal View History

import { getSettings } from 'soapbox/actions/settings';
import messages from 'soapbox/locales/messages';
2022-09-21 15:52:20 -07:00
import { normalizeChat } from 'soapbox/normalizers';
2022-08-25 12:56:53 -07:00
import { queryClient } from 'soapbox/queries/client';
import { play, soundCache } from 'soapbox/utils/sounds';
import { connectStream } from '../stream';
import {
deleteAnnouncement,
fetchAnnouncements,
updateAnnouncements,
updateReaction as updateAnnouncementsReaction,
} from './announcements';
import { updateConversations } from './conversations';
import { fetchFilters } from './filters';
import { MARKER_FETCH_SUCCESS } from './markers';
import { updateNotificationsQueue, expandNotifications } from './notifications';
import { updateStatus } from './statuses';
import {
// deleteFromTimelines,
expandHomeTimeline,
connectTimeline,
disconnectTimeline,
processTimelineUpdate,
} from './timelines';
2022-09-21 15:52:20 -07:00
import type { InfiniteData, UseInfiniteQueryResult } from '@tanstack/react-query';
import type { AppDispatch, RootState } from 'soapbox/store';
2022-09-21 15:52:20 -07:00
import type { APIEntity, Chat, ChatMessage } from 'soapbox/types/entities';
const STREAMING_CHAT_UPDATE = 'STREAMING_CHAT_UPDATE';
const STREAMING_FOLLOW_RELATIONSHIPS_UPDATE = 'STREAMING_FOLLOW_RELATIONSHIPS_UPDATE';
const validLocale = (locale: string) => Object.keys(messages).includes(locale);
const getLocale = (state: RootState) => {
const locale = getSettings(state).get('locale') as string;
return validLocale(locale) ? locale : 'en';
};
const updateFollowRelationships = (relationships: APIEntity) =>
(dispatch: AppDispatch, getState: () => RootState) => {
const me = getState().me;
return dispatch({
type: STREAMING_FOLLOW_RELATIONSHIPS_UPDATE,
me,
...relationships,
});
};
2022-09-21 15:52:20 -07:00
interface ChatPayload extends Omit<Chat, 'last_message'> {
last_message: ChatMessage | null,
}
interface ChatPage {
result: Chat[],
hasMore: boolean,
link?: string,
}
const updateChat = (payload: ChatPayload) => {
queryClient.setQueriesData<InfiniteData<ChatPage>>(['chats', 'search'], (data) => {
if (data) {
const pages = data.pages.map(page => {
const result = page.result.map(chat => chat.id === payload.id ? payload as any : chat);
return { ...page, result };
});
return { ...data, pages };
}
});
// if (payload.last_message) {
// queryClient.setQueryData<UseInfiniteQueryResult<ChatMessage[]>>(['chats', 'messages', payload.id], (data) => {
// if (data) {
// const pages = [...data.pages];
// pages[0]?.push(payload.last_message);
// return { ...result, pages };
// }
// });
// }
};
const connectTimelineStream = (
timelineId: string,
path: string,
pollingRefresh: ((dispatch: AppDispatch, done?: () => void) => void) | null = null,
accept: ((status: APIEntity) => boolean) | null = null,
) => connectStream(path, pollingRefresh, (dispatch: AppDispatch, getState: () => RootState) => {
const locale = getLocale(getState());
return {
onConnect() {
dispatch(connectTimeline(timelineId));
},
onDisconnect() {
dispatch(disconnectTimeline(timelineId));
},
onReceive(data: any) {
switch (data.event) {
case 'update':
dispatch(processTimelineUpdate(timelineId, JSON.parse(data.payload), accept));
break;
case 'status.update':
dispatch(updateStatus(JSON.parse(data.payload)));
break;
2022-06-23 12:58:38 -07:00
// FIXME: We think delete & redraft is causing jumpy timelines.
// Fix that in ScrollableList then re-enable this!
//
// case 'delete':
// dispatch(deleteFromTimelines(data.payload));
// break;
case 'notification':
messages[locale]().then(messages => {
dispatch(updateNotificationsQueue(JSON.parse(data.payload), messages, locale, window.location.pathname));
}).catch(error => {
console.error(error);
});
break;
case 'conversation':
dispatch(updateConversations(JSON.parse(data.payload)));
break;
case 'filters_changed':
dispatch(fetchFilters());
break;
case 'pleroma:chat_update':
2022-09-21 15:52:20 -07:00
case 'chat_message': // TruthSocial
updateChat(JSON.parse(data.payload));
play(soundCache.chat);
break;
case 'pleroma:follow_relationships_update':
dispatch(updateFollowRelationships(JSON.parse(data.payload)));
break;
case 'announcement':
dispatch(updateAnnouncements(JSON.parse(data.payload)));
break;
case 'announcement.reaction':
dispatch(updateAnnouncementsReaction(JSON.parse(data.payload)));
break;
case 'announcement.delete':
dispatch(deleteAnnouncement(data.payload));
break;
case 'marker':
dispatch({ type: MARKER_FETCH_SUCCESS, marker: JSON.parse(data.payload) });
break;
}
},
};
});
const refreshHomeTimelineAndNotification = (dispatch: AppDispatch, done?: () => void) =>
dispatch(expandHomeTimeline({}, () =>
dispatch(expandNotifications({}, () =>
dispatch(fetchAnnouncements(done))))));
const connectUserStream = () =>
connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification);
const connectCommunityStream = ({ onlyMedia }: Record<string, any> = {}) =>
connectTimelineStream(`community${onlyMedia ? ':media' : ''}`, `public:local${onlyMedia ? ':media' : ''}`);
const connectPublicStream = ({ onlyMedia }: Record<string, any> = {}) =>
connectTimelineStream(`public${onlyMedia ? ':media' : ''}`, `public${onlyMedia ? ':media' : ''}`);
const connectRemoteStream = (instance: string, { onlyMedia }: Record<string, any> = {}) =>
connectTimelineStream(`remote${onlyMedia ? ':media' : ''}:${instance}`, `public:remote${onlyMedia ? ':media' : ''}&instance=${instance}`);
const connectHashtagStream = (id: string, tag: string, accept: (status: APIEntity) => boolean) =>
connectTimelineStream(`hashtag:${id}`, `hashtag&tag=${tag}`, null, accept);
const connectDirectStream = () =>
connectTimelineStream('direct', 'direct');
const connectListStream = (id: string) =>
connectTimelineStream(`list:${id}`, `list&list=${id}`);
const connectGroupStream = (id: string) =>
connectTimelineStream(`group:${id}`, `group&group=${id}`);
export {
STREAMING_CHAT_UPDATE,
STREAMING_FOLLOW_RELATIONSHIPS_UPDATE,
connectTimelineStream,
connectUserStream,
connectCommunityStream,
connectPublicStream,
connectRemoteStream,
connectHashtagStream,
connectDirectStream,
connectListStream,
connectGroupStream,
};