elk/composables/masto/masto.ts

144 lines
4.5 KiB
TypeScript
Raw Permalink Normal View History

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'
import { createRestAPIClient, createStreamingAPIClient, MastoHttpError } from 'masto'
2023-01-15 16:38:02 +08: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
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
}
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
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)
if (newInstance.configuration.urls.streaming !== streamingApiUrl)
masto.streamingClient.value = createStreamingClient(newInstance.configuration.urls.streaming)
2024-01-09 09:56:15 +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)
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
}