AT Protocol Jetstream Module for Open Web Desktop
at main 110 lines 3.6 kB view raw
1import { useApplicationManager } from "@owdproject/core/runtime/composables/useApplicationManager" 2import { useDesktopStore } from '@owdproject/core/runtime/stores/storeDesktop' 3import { useRuntimeConfig } from 'nuxt/app' 4 5function getJetstreamUrl(host: string, actorDid: string) { 6 const url = new URL('subscribe', `wss://${host}`) 7 url.searchParams.append('wantedDids', actorDid) 8 url.searchParams.append( 9 'wantedCollections', 10 'org.owdproject.application.desktop' 11 ) 12 url.searchParams.append( 13 'wantedCollections', 14 'org.owdproject.application.windows' 15 ) 16 url.searchParams.append( 17 'wantedCollections', 18 'org.owdproject.application.meta' 19 ) 20 return url.toString() 21} 22 23/** 24 * Load actor desktop 25 * 26 * @param actorDid 27 */ 28export async function startActorDesktopStreamw(actorDid: string) { 29 const applicationManager = useApplicationManager() 30 const runtimeConfig = useRuntimeConfig() 31 32 let ws: WebSocket | null = null 33 34 const handleMessage = (event: MessageEvent) => { 35 try { 36 const data = JSON.parse(event.data) 37 38 let applicationController 39 let atprotoApplicationId 40 41 switch (data.commit.collection) { 42 case 'org.owdproject.desktop': 43 useDesktopStore().$patch(data.commit.record.state) 44 break 45 case 'org.owdproject.application.windows': 46 atprotoApplicationId = data.commit.rkey.split('/').pop() 47 48 // get the application controller by its id 49 applicationController = applicationManager.getAppById(atprotoApplicationId) 50 51 // if the application doesn't exist, exit early 52 if (!applicationController) { 53 return 54 } 55 56 const isApplicationNowRunning = Object.keys(data.commit.record.windows).length > 0 57 58 applicationController.setRunning(isApplicationNowRunning) 59 60 let windowController 61 62 // iterate through all windows in the received remote state 63 for (const windowId in data.commit.record.windows) { 64 // try to find an existing local window controller 65 windowController = applicationController.getWindowById(windowId) 66 67 if (!windowController) { 68 // if the window doesn't exist locally, create it 69 return applicationController.openWindow( 70 data.commit.record.windows[windowId].model, 71 data.commit.record.windows[windowId], 72 { 73 isRestoring: true 74 } 75 ) 76 } else { 77 // if the window exists, update its state with the remote one 78 windowController.setState( 79 data.commit.record.windows[windowId].state 80 ) 81 } 82 } 83 84 // second loop: close any local windows that are not in the remote state anymore 85 for (const windowId of applicationController.windows.keys()) { 86 if (!data.commit.record.windows[windowId]) { 87 // the window is no longer present remotely, so close it locally 88 applicationController.closeWindow(windowId) 89 } 90 } 91 92 break 93 case 'org.owdproject.application.meta': 94 atprotoApplicationId = data.commit.rkey.split('/').pop() 95 96 applicationController.storeMeta.$patch({ 97 ...data.commit.record 98 }) 99 break 100 } 101 } catch (e) { 102 console.warn('Invalid jetstream message', e) 103 } 104 } 105 106 ws = new WebSocket( 107 getJetstreamUrl(runtimeConfig.public.desktop.atprotoJetstream.host, actorDid) 108 ) 109 ws.addEventListener('message', handleMessage) 110}