Live video on the AT Protocol
79
fork

Configure Feed

Select the types of activity you want to include in your feed.

at eli/version-label 89 lines 3.0 kB view raw
1import { SessionManager } from "@atproto/api/dist/session-manager"; 2import { useContext } from "react"; 3import { PlaceStreamChatProfile, PlaceStreamLivestream } from "streamplace"; 4import { createStore, StoreApi, useStore } from "zustand"; 5import { StreamplaceContext } from "../streamplace-provider/context"; 6 7// there are three categories of XRPC that we need to handle: 8// 1. Public (probably) OAuth XRPC to the users' PDS for apps that use this API. 9// 2. Confidental OAuth to the Streamplace server for doing things that require 10// server-side authentication. This isn't very much stuff yet, but you need 11// to log into Streamplace to do things like have Streamplace update your 12// activity status. 13// 3. Anonymous XRPC to the Streamplace server for stuff like `getLiveUsers`. This 14// is easy to handle internal to this library. 15// For the Streamplace app itself, all three are the same. For apps that aren't 16// doing OAuth through the Streamplace node, we need to expose an interface that 17// allows them to use atcute or whatever for 1. 18 19export interface StreamplaceState { 20 url: string; 21 liveUsers: PlaceStreamLivestream.LivestreamView[] | null; 22 setLiveUsers: (opts: { 23 liveUsers?: PlaceStreamLivestream.LivestreamView[]; 24 liveUsersLoading?: boolean; 25 liveUsersError?: string | null; 26 liveUsersRefresh?: number; 27 }) => void; 28 liveUsersRefresh: number; 29 liveUsersLoading: boolean; 30 liveUsersError: string | null; 31 oauthSession: SessionManager | null; 32 handle: string | null; 33 chatProfile: PlaceStreamChatProfile.Record | null; 34} 35 36export type StreamplaceStore = StoreApi<StreamplaceState>; 37 38export const makeStreamplaceStore = ({ 39 url, 40}: { 41 url: string; 42}): StoreApi<StreamplaceState> => { 43 return createStore<StreamplaceState>()((set) => ({ 44 url, 45 liveUsers: null, 46 setLiveUsers: (opts: { 47 liveUsers?: PlaceStreamLivestream.LivestreamView[]; 48 liveUsersLoading?: boolean; 49 liveUsersError?: string | null; 50 liveUsersRefresh?: number; 51 }) => { 52 set({ 53 ...opts, 54 }); 55 }, 56 liveUsersRefresh: 0, 57 liveUsersLoading: true, 58 liveUsersError: null, 59 oauthSession: null, 60 handle: null, 61 chatProfile: null, 62 })); 63}; 64 65export function getStreamplaceStoreFromContext(): StreamplaceStore { 66 const context = useContext(StreamplaceContext); 67 if (!context) { 68 throw new Error( 69 "useStreamplaceStore must be used within a StreamplaceProvider", 70 ); 71 } 72 return context.store; 73} 74 75export function useStreamplaceStore<U>( 76 selector: (state: StreamplaceState) => U, 77): U { 78 return useStore(getStreamplaceStoreFromContext(), selector); 79} 80 81export const useUrl = () => useStreamplaceStore((x) => x.url); 82 83export const useDID = () => useStreamplaceStore((x) => x.oauthSession?.did); 84 85export const useHandle = () => useStreamplaceStore((x) => x.handle); 86export const useSetHandle = (): ((handle: string) => void) => { 87 const store = getStreamplaceStoreFromContext(); 88 return (handle: string) => store.setState({ handle }); 89};