2023-01-15 16:38:02 +08:00
import type { Pausable } from '@vueuse/core'
2024-01-09 09:56:15 +01:00
import type { mastodon } from 'masto'
2023-01-15 16:38:02 +08:00
import type { Ref } from 'vue'
import type { ElkInstance } from '../users'
import type { UserLogin } from '~/types'
2025-02-06 17:56:43 +01:00
import { createRestAPIClient , createStreamingAPIClient , MastoHttpError } from 'masto'
2023-01-15 16:38:02 +08:00
2023-03-30 19:01:24 +00:00
export function createMasto() {
2023-01-15 16:38:02 +08:00
return {
2024-01-09 09:56:15 +01:00
client : shallowRef < mastodon.rest.Client > ( undefined as never ) ,
streamingClient : shallowRef < mastodon.streaming.Client | undefined > ( ) ,
2023-01-15 16:38:02 +08:00
}
}
export type ElkMasto = ReturnType < typeof createMasto >
2023-01-07 02:40:15 +08:00
2023-03-30 19:01:24 +00:00
export function useMasto() {
return useNuxtApp ( ) . $masto as ElkMasto
}
export function useMastoClient() {
return useMasto ( ) . client . value
}
2023-01-15 16:38:02 +08:00
export function mastoLogin ( masto : ElkMasto , user : Pick < UserLogin , 'server' | 'token' > ) {
const server = user . server
const url = ` https:// ${ server } `
2023-01-15 17:44:36 +08:00
const instance : ElkInstance = reactive ( getInstanceCache ( server ) || { uri : server , accountDomain : server } )
2024-01-09 09:56:15 +01:00
const accessToken = user . token
2023-01-15 16:38:02 +08:00
2024-01-09 09:56:15 +01:00
const createStreamingClient = ( streamingApiUrl : string | undefined ) = > {
return streamingApiUrl ? createStreamingAPIClient ( { streamingApiUrl , accessToken , implementation : globalThis.WebSocket } ) : undefined
}
2025-02-06 17:56:43 +01:00
const streamingApiUrl = instance ? . configuration ? . urls ? . streaming
2024-01-09 09:56:15 +01:00
masto . client . value = createRestAPIClient ( { url , accessToken } )
masto . streamingClient . value = createStreamingClient ( streamingApiUrl )
// Refetch instance info in the background on login
2025-02-06 17:56:43 +01:00
masto . client . value . v2 . instance . fetch ( ) . catch ( error = > new Promise < mastodon.v2.Instance > ( ( resolve , reject ) = > {
if ( error instanceof MastoHttpError && error . statusCode === 404 ) {
return masto . client . value . v1 . instance . fetch ( ) . then ( ( newInstance ) = > {
console . warn ( ` Instance ${ server } on version ${ newInstance . version } does not support "GET /api/v2/instance" API, try converting to v2 instance... expect some errors ` )
const v2Instance = {
. . . newInstance ,
domain : newInstance.uri ,
sourceUrl : '' ,
usage : {
users : {
activeMonth : 0 ,
} ,
} ,
icon : [ ] ,
apiVersions : {
mastodon : newInstance.version ,
} ,
contact : {
email : newInstance.email ,
} ,
configuration : {
. . . ( newInstance . configuration ? ? { } ) ,
urls : {
streaming : newInstance.urls.streamingApi ,
} ,
} ,
} as unknown as mastodon . v2 . Instance
return resolve ( v2Instance )
} ) . catch ( reject )
}
return reject ( error )
} ) ) . then ( ( newInstance ) = > {
2023-01-15 16:38:02 +08:00
Object . assign ( instance , newInstance )
2025-02-06 17:56:43 +01:00
if ( newInstance . configuration . urls . streaming !== streamingApiUrl )
masto . streamingClient . value = createStreamingClient ( newInstance . configuration . urls . streaming )
2024-01-09 09:56:15 +01:00
2023-01-30 11:58:18 +01:00
instanceStorage . value [ server ] = newInstance
2023-01-15 16:38:02 +08:00
} )
return instance
}
interface UseStreamingOptions < Controls extends boolean > {
/ * *
* Expose more controls
*
* @default false
* /
controls? : Controls
/ * *
* Connect on calling
*
* @default true
* /
immediate? : boolean
}
export function useStreaming (
2024-01-09 09:56:15 +01:00
cb : ( client : mastodon.streaming.Client ) = > mastodon . streaming . Subscription ,
2023-01-15 16:38:02 +08:00
options : UseStreamingOptions < true > ,
2024-01-09 09:56:15 +01:00
) : { stream : Ref < mastodon.streaming.Subscription | undefined > } & Pausable
2023-01-15 16:38:02 +08:00
export function useStreaming (
2024-01-09 09:56:15 +01:00
cb : ( client : mastodon.streaming.Client ) = > mastodon . streaming . Subscription ,
2023-01-15 16:38:02 +08:00
options? : UseStreamingOptions < false > ,
2024-01-09 09:56:15 +01:00
) : Ref < mastodon.streaming.Subscription | undefined >
2023-01-15 16:38:02 +08:00
export function useStreaming (
2024-01-09 09:56:15 +01:00
cb : ( client : mastodon.streaming.Client ) = > mastodon . streaming . Subscription ,
2023-01-15 16:38:02 +08:00
{ immediate = true , controls } : UseStreamingOptions < boolean > = { } ,
2024-01-09 09:56:15 +01:00
) : ( { stream : Ref < mastodon.streaming.Subscription | undefined > } & Pausable ) | Ref < mastodon.streaming.Subscription | undefined > {
const { streamingClient } = useMasto ( )
2023-01-15 16:38:02 +08:00
const isActive = ref ( immediate )
2024-01-09 09:56:15 +01:00
const stream = ref < mastodon.streaming.Subscription > ( )
2023-01-15 16:38:02 +08:00
function pause() {
isActive . value = false
}
function resume() {
isActive . value = true
}
function cleanup() {
if ( stream . value ) {
2024-01-09 09:56:15 +01:00
stream . value . unsubscribe ( )
2023-01-15 16:38:02 +08:00
stream . value = undefined
}
}
watchEffect ( ( ) = > {
cleanup ( )
2024-01-09 09:56:15 +01:00
if ( streamingClient . value && isActive . value )
stream . value = cb ( streamingClient . value )
2023-01-15 16:38:02 +08:00
} )
2023-01-07 02:40:15 +08:00
2024-02-24 17:46:14 +01:00
if ( import . meta . client && ! process . test )
2023-02-06 23:22:56 +01:00
useNuxtApp ( ) . $pageLifecycle . addFrozenListener ( cleanup )
2023-01-15 16:38:02 +08:00
tryOnBeforeUnmount ( ( ) = > isActive . value = false )
2023-01-07 02:40:15 +08:00
2023-01-15 16:38:02 +08:00
if ( controls )
return { stream , isActive , pause , resume }
else
return stream
2023-01-07 02:40:15 +08:00
}