160 lines
3.8 KiB
TypeScript
160 lines
3.8 KiB
TypeScript
import type { DocumentStore } from '@/stores/documents'
|
|
import { useDocumentStore } from '@/stores/documents'
|
|
import createWebSocket from './WS'
|
|
|
|
export type FUID = string
|
|
|
|
type BaseDocument = {
|
|
name: string
|
|
key: FUID
|
|
}
|
|
|
|
export type FolderDocument = BaseDocument & {
|
|
type: 'folder' | 'file'
|
|
size: number
|
|
sizedisp: string
|
|
mtime: number
|
|
modified: string
|
|
}
|
|
|
|
export type Document = FolderDocument
|
|
|
|
export type errorEvent = {
|
|
error: {
|
|
code: number
|
|
message: string
|
|
redirect: string
|
|
}
|
|
}
|
|
|
|
// Raw types the backend /api/watch sends us
|
|
|
|
export type FileEntry = {
|
|
id: FUID
|
|
size: number
|
|
mtime: number
|
|
}
|
|
|
|
export type DirEntry = {
|
|
id: FUID
|
|
size: number
|
|
mtime: number
|
|
dir: DirList
|
|
}
|
|
|
|
export type DirList = Record<string, FileEntry | DirEntry>
|
|
|
|
export type UpdateEntry = {
|
|
name: string
|
|
deleted?: boolean
|
|
id?: FUID
|
|
size?: number
|
|
mtime?: number
|
|
dir?: DirList
|
|
}
|
|
|
|
// Helper structure for selections
|
|
export interface SelectedItems {
|
|
selected: Set<FUID>
|
|
missing: Set<FUID>
|
|
rootdir: DirList
|
|
entries: Record<FUID, FileEntry | DirEntry>
|
|
fullpath: Record<FUID, string>
|
|
relpath: Record<FUID, string>
|
|
url: Record<FUID, string>
|
|
ids: FUID[]
|
|
}
|
|
|
|
export const url_document_watch_ws = '/api/watch'
|
|
export const url_document_upload_ws = '/api/upload'
|
|
export const url_document_get = '/files'
|
|
|
|
export class DocumentHandler {
|
|
constructor(private store: DocumentStore = useDocumentStore()) {
|
|
this.handleWebSocketMessage = this.handleWebSocketMessage.bind(this)
|
|
}
|
|
|
|
handleWebSocketMessage(event: MessageEvent) {
|
|
const msg = JSON.parse(event.data)
|
|
if ('error' in msg) {
|
|
if (msg.error.code === 401) {
|
|
this.store.user.isLoggedIn = false
|
|
this.store.user.isOpenLoginModal = true
|
|
} else {
|
|
this.store.error = msg.error.message
|
|
}
|
|
// The server closes the websocket after errors, so we need to reopen it
|
|
setTimeout(() => {
|
|
this.store.wsWatch = createWebSocket(
|
|
url_document_watch_ws,
|
|
this.handleWebSocketMessage
|
|
)
|
|
}, 1000)
|
|
}
|
|
switch (true) {
|
|
case !!msg.root:
|
|
this.handleRootMessage(msg)
|
|
break
|
|
case !!msg.update:
|
|
this.handleUpdateMessage(msg)
|
|
break
|
|
case !!msg.error:
|
|
this.handleError(msg)
|
|
break
|
|
default:
|
|
}
|
|
}
|
|
|
|
private handleRootMessage({ root }: { root: DirEntry }) {
|
|
if (this.store && this.store.root) {
|
|
this.store.user.isLoggedIn = true
|
|
this.store.root = root
|
|
}
|
|
}
|
|
private handleUpdateMessage(updateData: { update: UpdateEntry[] }) {
|
|
let node: DirEntry = this.store.root
|
|
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.id !== undefined) node.id = elem.id
|
|
if (elem.size !== undefined) node.size = elem.size
|
|
if (elem.mtime !== undefined) node.mtime = elem.mtime
|
|
if (elem.dir !== undefined) node.dir = elem.dir
|
|
}
|
|
}
|
|
private handleError(msg: errorEvent) {
|
|
if (msg.error.code === 401) {
|
|
this.store.user.isOpenLoginModal = true
|
|
this.store.user.isLoggedIn = false
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
export class DocumentUploadHandler {
|
|
constructor(private store: DocumentStore = useDocumentStore()) {
|
|
this.handleWebSocketMessage = this.handleWebSocketMessage.bind(this)
|
|
}
|
|
|
|
handleWebSocketMessage(event: MessageEvent) {
|
|
const msg = JSON.parse(event.data)
|
|
switch (true) {
|
|
case !!msg.written:
|
|
this.handleWrittenMessage(msg)
|
|
break
|
|
default:
|
|
}
|
|
}
|
|
|
|
private handleWrittenMessage(msg: { written: number }) {
|
|
// if (this.store && this.store.root) this.store.root = root;
|
|
console.log('Written message', msg.written)
|
|
}
|
|
}
|