Rewritten WS handling, file selections. Minor UI fixes.
This commit is contained in:
		| @@ -1,8 +1,118 @@ | ||||
| function createWebSocket(url: string, eventHandler: (event: MessageEvent) => void) { | ||||
|   const urlObject = new URL(url, location.origin.replace(/^http/, 'ws')) | ||||
|   const webSocket = new WebSocket(urlObject) | ||||
|   webSocket.onmessage = eventHandler | ||||
| import { useDocumentStore } from "@/stores/documents" | ||||
| import type { DirEntry, UpdateEntry, errorEvent } from "./Document" | ||||
|  | ||||
| export const controlUrl = '/api/control' | ||||
| export const uploadUrl = '/api/upload' | ||||
| export const watchUrl = '/api/watch' | ||||
|  | ||||
| let tree = null as DirEntry | null | ||||
| let reconnectDuration = 500 | ||||
| let wsWatch = null as WebSocket | null | ||||
|  | ||||
| export const connect = (path: string, handlers: Partial<Record<keyof WebSocketEventMap, any>>) => { | ||||
|   const webSocket = new WebSocket(new URL(path, location.origin.replace(/^http/, 'ws'))) | ||||
|   for (const [event, handler] of Object.entries(handlers)) webSocket.addEventListener(event, handler) | ||||
|   return webSocket | ||||
| } | ||||
|  | ||||
| export default createWebSocket | ||||
| export const watchConnect = async () => { | ||||
|   wsWatch = connect(watchUrl, { | ||||
|     open() { console.log("Connected to", watchUrl)}, | ||||
|     message: handleWatchMessage, | ||||
|     close: watchReconnect, | ||||
|   }) | ||||
|   await wsWatch | ||||
| } | ||||
|  | ||||
| export const watchDisconnect = () => { | ||||
|   if (!wsWatch) return | ||||
|   wsWatch.close() | ||||
|   wsWatch = null | ||||
| } | ||||
|  | ||||
| const watchReconnect = (event: MessageEvent) => { | ||||
|   const store = useDocumentStore() | ||||
|   if (store.connected) { | ||||
|     console.warn("Disconnected from server", event) | ||||
|     store.connected = false | ||||
|   } | ||||
|   reconnectDuration = Math.min(5000, reconnectDuration + 500) | ||||
|   // The server closes the websocket after errors, so we need to reopen it | ||||
|   setTimeout(() => { | ||||
|     wsWatch = connect(watchUrl, { | ||||
|       message: handleWatchMessage, | ||||
|       close: watchReconnect, | ||||
|     }) | ||||
|     console.log("Attempting to reconnect...") | ||||
|   }, reconnectDuration) | ||||
| } | ||||
|  | ||||
|  | ||||
| const handleWatchMessage = (event: MessageEvent) => { | ||||
|   const store = useDocumentStore() | ||||
|   const msg = JSON.parse(event.data) | ||||
|   if ('error' in msg) { | ||||
|     if (msg.error.code === 401) { | ||||
|       store.user.isLoggedIn = false | ||||
|       store.user.isOpenLoginModal = true | ||||
|     } else { | ||||
|       store.error = msg.error.message | ||||
|     } | ||||
|   } | ||||
|   switch (true) { | ||||
|     case !!msg.root: | ||||
|       handleRootMessage(msg) | ||||
|       break | ||||
|     case !!msg.update: | ||||
|       handleUpdateMessage(msg) | ||||
|       break | ||||
|     case !!msg.space: | ||||
|       console.log('Watch space', msg.space) | ||||
|       break | ||||
|     case !!msg.error: | ||||
|       handleError(msg) | ||||
|       break | ||||
|     default: | ||||
|   } | ||||
| } | ||||
|  | ||||
| function handleRootMessage({ root }: { root: DirEntry }) { | ||||
|   const store = useDocumentStore() | ||||
|   console.log('Watch root', root) | ||||
|   reconnectDuration = 500 | ||||
|   store.connected = true | ||||
|   store.user.isLoggedIn = true | ||||
|   store.updateRoot(root) | ||||
|   tree = root | ||||
| } | ||||
|  | ||||
| function handleUpdateMessage(updateData: { update: UpdateEntry[] }) { | ||||
|   const store = useDocumentStore() | ||||
|   console.log('Watch update', updateData.update) | ||||
|   if (!tree) return console.error('Watch update before root') | ||||
|   let node: DirEntry = tree | ||||
|   for (const elem of updateData.update) { | ||||
|     if (elem.deleted) { | ||||
|       delete node.dir[elem.name] | ||||
|       break // Deleted elements can't have further children | ||||
|     } | ||||
|     if (elem.name !== undefined) { | ||||
|       // @ts-ignore | ||||
|       node = node.dir[elem.name] ||= {} | ||||
|     } | ||||
|     if (elem.key !== undefined) node.key = elem.key | ||||
|     if (elem.size !== undefined) node.size = elem.size | ||||
|     if (elem.mtime !== undefined) node.mtime = elem.mtime | ||||
|     if (elem.dir !== undefined) node.dir = elem.dir | ||||
|   } | ||||
|   store.updateRoot(tree) | ||||
| } | ||||
|  | ||||
| function handleError(msg: errorEvent) { | ||||
|   const store = useDocumentStore() | ||||
|   if (msg.error.code === 401) { | ||||
|     store.user.isOpenLoginModal = true | ||||
|     store.user.isLoggedIn = false | ||||
|     return | ||||
|   } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Leo Vasanko
					Leo Vasanko