Add Streaming hooks
This commit is contained in:
parent
bea4707743
commit
77f0f4d377
6 changed files with 88 additions and 44 deletions
|
@ -73,8 +73,9 @@ const updateChatQuery = (chat: IChat) => {
|
|||
queryClient.setQueryData<Chat>(ChatKeys.chat(chat.id), newChat as any);
|
||||
};
|
||||
|
||||
interface StreamOpts {
|
||||
interface TimelineStreamOpts {
|
||||
statContext?: IStatContext
|
||||
enabled?: boolean
|
||||
}
|
||||
|
||||
const connectTimelineStream = (
|
||||
|
@ -82,7 +83,7 @@ const connectTimelineStream = (
|
|||
path: string,
|
||||
pollingRefresh: ((dispatch: AppDispatch, done?: () => void) => void) | null = null,
|
||||
accept: ((status: APIEntity) => boolean) | null = null,
|
||||
opts?: StreamOpts,
|
||||
opts?: TimelineStreamOpts,
|
||||
) => connectStream(path, pollingRefresh, (dispatch: AppDispatch, getState: () => RootState) => {
|
||||
const locale = getLocale(getState());
|
||||
|
||||
|
@ -196,7 +197,7 @@ const refreshHomeTimelineAndNotification = (dispatch: AppDispatch, done?: () =>
|
|||
dispatch(expandNotifications({}, () =>
|
||||
dispatch(fetchAnnouncements(done))))));
|
||||
|
||||
const connectUserStream = (opts?: StreamOpts) =>
|
||||
const connectUserStream = (opts?: TimelineStreamOpts) =>
|
||||
connectTimelineStream('home', 'user', refreshHomeTimelineAndNotification, null, opts);
|
||||
|
||||
const connectCommunityStream = ({ onlyMedia }: Record<string, any> = {}) =>
|
||||
|
@ -236,4 +237,5 @@ export {
|
|||
connectListStream,
|
||||
connectGroupStream,
|
||||
connectNostrStream,
|
||||
type TimelineStreamOpts,
|
||||
};
|
||||
|
|
|
@ -43,3 +43,7 @@ export { useSuggestedGroups } from './groups/useSuggestedGroups';
|
|||
export { useUnmuteGroup } from './groups/useUnmuteGroup';
|
||||
export { useUpdateGroup } from './groups/useUpdateGroup';
|
||||
export { useUpdateGroupTag } from './groups/useUpdateGroupTag';
|
||||
|
||||
// Streaming
|
||||
export { useUserStream } from './streaming/useUserStream';
|
||||
export { useNostrStream } from './streaming/useNostrStream';
|
11
app/soapbox/api/hooks/streaming/useNostrStream.ts
Normal file
11
app/soapbox/api/hooks/streaming/useNostrStream.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { useFeatures } from 'soapbox/hooks';
|
||||
|
||||
import { useTimelineStream } from './useTimelineStream';
|
||||
|
||||
function useNostrStream() {
|
||||
const features = useFeatures();
|
||||
const enabled = features.nostrSign && Boolean(window.nostr);
|
||||
return useTimelineStream('nostr', 'nostr', null, null, { enabled });
|
||||
}
|
||||
|
||||
export { useNostrStream };
|
41
app/soapbox/api/hooks/streaming/useTimelineStream.ts
Normal file
41
app/soapbox/api/hooks/streaming/useTimelineStream.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import { useEffect, useRef } from 'react';
|
||||
|
||||
import { connectTimelineStream } from 'soapbox/actions/streaming';
|
||||
import { useAppDispatch, useAppSelector, useInstance } from 'soapbox/hooks';
|
||||
import { getAccessToken } from 'soapbox/utils/auth';
|
||||
|
||||
function useTimelineStream(...args: Parameters<typeof connectTimelineStream>) {
|
||||
// TODO: get rid of streaming.ts and move the actual opts here.
|
||||
const { enabled = true } = args[4] ?? {};
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const instance = useInstance();
|
||||
const stream = useRef<(() => void) | null>(null);
|
||||
|
||||
const accessToken = useAppSelector(getAccessToken);
|
||||
const streamingUrl = instance.urls.get('streaming_api');
|
||||
|
||||
const connect = () => {
|
||||
if (enabled && accessToken && streamingUrl && !stream.current) {
|
||||
stream.current = dispatch(connectTimelineStream(...args));
|
||||
}
|
||||
};
|
||||
|
||||
const disconnect = () => {
|
||||
if (stream.current) {
|
||||
stream.current();
|
||||
stream.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
connect();
|
||||
return disconnect;
|
||||
}, [accessToken, streamingUrl, enabled]);
|
||||
|
||||
return {
|
||||
disconnect,
|
||||
};
|
||||
}
|
||||
|
||||
export { useTimelineStream };
|
22
app/soapbox/api/hooks/streaming/useUserStream.ts
Normal file
22
app/soapbox/api/hooks/streaming/useUserStream.ts
Normal file
|
@ -0,0 +1,22 @@
|
|||
import { fetchAnnouncements } from 'soapbox/actions/announcements';
|
||||
import { expandNotifications } from 'soapbox/actions/notifications';
|
||||
import { expandHomeTimeline } from 'soapbox/actions/timelines';
|
||||
import { useStatContext } from 'soapbox/contexts/stat-context';
|
||||
|
||||
import { useTimelineStream } from './useTimelineStream';
|
||||
|
||||
import type { AppDispatch } from 'soapbox/store';
|
||||
|
||||
function useUserStream() {
|
||||
const statContext = useStatContext();
|
||||
return useTimelineStream('home', 'user', refresh, null, { statContext });
|
||||
}
|
||||
|
||||
/** Refresh home timeline and notifications. */
|
||||
function refresh(dispatch: AppDispatch, done?: () => void) {
|
||||
return dispatch(expandHomeTimeline({}, () =>
|
||||
dispatch(expandNotifications({}, () =>
|
||||
dispatch(fetchAnnouncements(done))))));
|
||||
}
|
||||
|
||||
export { useUserStream };
|
|
@ -14,16 +14,15 @@ import { openModal } from 'soapbox/actions/modals';
|
|||
import { expandNotifications } from 'soapbox/actions/notifications';
|
||||
import { register as registerPushNotifications } from 'soapbox/actions/push-notifications';
|
||||
import { fetchScheduledStatuses } from 'soapbox/actions/scheduled-statuses';
|
||||
import { connectNostrStream, connectUserStream } from 'soapbox/actions/streaming';
|
||||
import { fetchSuggestionsForTimeline } from 'soapbox/actions/suggestions';
|
||||
import { expandHomeTimeline } from 'soapbox/actions/timelines';
|
||||
import { useNostrStream, useUserStream } from 'soapbox/api/hooks';
|
||||
import GroupLookupHoc from 'soapbox/components/hoc/group-lookup-hoc';
|
||||
import withHoc from 'soapbox/components/hoc/with-hoc';
|
||||
import SidebarNavigation from 'soapbox/components/sidebar-navigation';
|
||||
import ThumbNavigation from 'soapbox/components/thumb-navigation';
|
||||
import { Layout } from 'soapbox/components/ui';
|
||||
import { useStatContext } from 'soapbox/contexts/stat-context';
|
||||
import { useAppDispatch, useAppSelector, useOwnAccount, useSoapboxConfig, useFeatures, useInstance, useDraggedFiles } from 'soapbox/hooks';
|
||||
import { useAppDispatch, useAppSelector, useOwnAccount, useSoapboxConfig, useFeatures, useDraggedFiles } from 'soapbox/hooks';
|
||||
import AdminPage from 'soapbox/pages/admin-page';
|
||||
import ChatsPage from 'soapbox/pages/chats-page';
|
||||
import DefaultPage from 'soapbox/pages/default-page';
|
||||
|
@ -39,7 +38,7 @@ import RemoteInstancePage from 'soapbox/pages/remote-instance-page';
|
|||
import SearchPage from 'soapbox/pages/search-page';
|
||||
import StatusPage from 'soapbox/pages/status-page';
|
||||
import { usePendingPolicy } from 'soapbox/queries/policies';
|
||||
import { getAccessToken, getVapidKey } from 'soapbox/utils/auth';
|
||||
import { getVapidKey } from 'soapbox/utils/auth';
|
||||
import { isStandalone } from 'soapbox/utils/state';
|
||||
|
||||
import BackgroundShapes from './components/background-shapes';
|
||||
|
@ -363,21 +362,13 @@ const UI: React.FC<IUI> = ({ children }) => {
|
|||
const history = useHistory();
|
||||
const dispatch = useAppDispatch();
|
||||
const { data: pendingPolicy } = usePendingPolicy();
|
||||
const instance = useInstance();
|
||||
const statContext = useStatContext();
|
||||
|
||||
const userStream = useRef<any>(null);
|
||||
const nostrStream = useRef<any>(null);
|
||||
const node = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const me = useAppSelector(state => state.me);
|
||||
const { account } = useOwnAccount();
|
||||
const features = useFeatures();
|
||||
const vapidKey = useAppSelector(state => getVapidKey(state));
|
||||
|
||||
const dropdownMenuIsOpen = useAppSelector(state => state.dropdown_menu.isOpen);
|
||||
const accessToken = useAppSelector(state => getAccessToken(state));
|
||||
const streamingUrl = instance.urls.get('streaming_api');
|
||||
const standalone = useAppSelector(isStandalone);
|
||||
|
||||
const { isDragging } = useDraggedFiles(node);
|
||||
|
@ -390,28 +381,6 @@ const UI: React.FC<IUI> = ({ children }) => {
|
|||
}
|
||||
};
|
||||
|
||||
const connectStreaming = () => {
|
||||
if (accessToken && streamingUrl) {
|
||||
if (!userStream.current) {
|
||||
userStream.current = dispatch(connectUserStream({ statContext }));
|
||||
}
|
||||
if (!nostrStream.current && features.nostrSign && window.nostr) {
|
||||
nostrStream.current = dispatch(connectNostrStream());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const disconnectStreaming = () => {
|
||||
if (userStream.current) {
|
||||
userStream.current();
|
||||
userStream.current = null;
|
||||
}
|
||||
if (nostrStream.current) {
|
||||
nostrStream.current();
|
||||
nostrStream.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
const handleDragEnter = (e: DragEvent) => e.preventDefault();
|
||||
const handleDragLeave = (e: DragEvent) => e.preventDefault();
|
||||
const handleDragOver = (e: DragEvent) => e.preventDefault();
|
||||
|
@ -458,10 +427,6 @@ const UI: React.FC<IUI> = ({ children }) => {
|
|||
if (window.Notification?.permission === 'default') {
|
||||
window.setTimeout(() => Notification.requestPermission(), 120 * 1000);
|
||||
}
|
||||
|
||||
return () => {
|
||||
disconnectStreaming();
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -477,9 +442,8 @@ const UI: React.FC<IUI> = ({ children }) => {
|
|||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
connectStreaming();
|
||||
}, [accessToken, streamingUrl]);
|
||||
useUserStream();
|
||||
useNostrStream();
|
||||
|
||||
// The user has logged in
|
||||
useEffect(() => {
|
||||
|
|
Loading…
Reference in a new issue