Skip to content

Commit

Permalink
Add sse item renamed event (#10567)
Browse files Browse the repository at this point in the history
* Add sse item renamed event
AlexAndBear authored Mar 8, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent befe172 commit a6a9c29
Showing 4 changed files with 195 additions and 89 deletions.
3 changes: 2 additions & 1 deletion packages/web-client/src/sse.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,8 @@ import { fetchEventSource, FetchEventSourceInit } from '@microsoft/fetch-event-s

export enum MESSAGE_TYPE {
NOTIFICATION = 'userlog-notification',
POSTPROCESSING_FINISHED = 'postprocessing-finished'
POSTPROCESSING_FINISHED = 'postprocessing-finished',
ITEM_RENAMED = 'item-renamed'
}

export class RetriableError extends Error {
102 changes: 15 additions & 87 deletions packages/web-runtime/src/container/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -27,8 +27,7 @@ import {
useSharesStore,
useResourcesStore,
ResourcesStore,
SpacesStore,
ImageDimension
SpacesStore
} from '@ownclouders/web-pkg'
import { authService } from '../services/auth'
import {
@@ -49,15 +48,14 @@ import {
} from '@ownclouders/web-pkg'
import { MESSAGE_TYPE } from '@ownclouders/web-client/src/sse'
import { getQueryParam } from '../helpers/url'
import { z } from 'zod'
import PQueue from 'p-queue'
import { extractNodeId, extractStorageId } from '@ownclouders/web-client/src/helpers'
import { storeToRefs } from 'pinia'
import { getExtensionNavItems } from '../helpers/navItems'
import {
RawConfigSchema,
SentryConfig
} from '@ownclouders/web-pkg/src/composables/piniaStores/config/types'
import { onSSEItemRenamedEvent, onSSEProcessingFinishedEvent } from './sse'

const getEmbedConfigFromQuery = (
doesEmbedEnabledOptionExists: boolean
@@ -641,100 +639,20 @@ export const announceCustomStyles = ({ configStore }: { configStore?: ConfigStor
})
}

const fileReadyEventSchema = z.object({
itemid: z.string(),
parentitemid: z.string()
})

const onSSEProcessingFinishedEvent = async ({
resourcesStore,
spacesStore,
msg,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
clientService,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
resourceQueue,
previewService
}: {
resourcesStore: ResourcesStore
spacesStore: SpacesStore
msg: MessageEvent
clientService: ClientService
resourceQueue: PQueue
previewService: PreviewService
}) => {
try {
const postProcessingData = fileReadyEventSchema.parse(JSON.parse(msg.data))
const currentFolder = resourcesStore.currentFolder
if (!currentFolder) {
return
}

// UPDATE_RESOURCE_FIELD only handles files in the currentFolder, so we can shortcut here for now
if (!extractNodeId(currentFolder.id)) {
// if we don't have a nodeId here, we have a space (root) as current folder and can only check against the storageId
if (currentFolder.id !== extractStorageId(postProcessingData.parentitemid)) {
return
}
} else {
if (currentFolder.id !== postProcessingData.parentitemid) {
return
}
}

const resource = resourcesStore.resources.find((f) => f.id === postProcessingData.itemid)
const matchingSpace = spacesStore.spaces.find((s) => s.id === resource.storageId)
const isFileLoaded = !!resource
if (isFileLoaded) {
resourcesStore.updateResourceField({
id: postProcessingData.itemid,
field: 'processing',
value: false
})

if (matchingSpace) {
const preview = await previewService.loadPreview({
resource,
space: matchingSpace,
dimensions: ImageDimension.Thumbnail
})

if (preview) {
resourcesStore.updateResourceField({
id: postProcessingData.itemid,
field: 'thumbnail',
value: preview
})
}
}
} else {
// FIXME: we currently cannot do this, we need to block this for ongoing uploads and copy operations
// when fixing revert the changelog removal
// resourceQueue.add(async () => {
// const { resource } = await clientService.webdav.listFilesById({
// fileId: postProcessingData.itemid
// })
// resource.path = urlJoin(currentFolder.path, resource.name)
// resourcesStore.upsertResource(resource)
// })
}
} catch (e) {
console.error('Unable to parse sse postprocessing data', e)
}
}

export const registerSSEEventListeners = ({
resourcesStore,
spacesStore,
clientService,
previewService,
configStore
configStore,
router
}: {
resourcesStore: ResourcesStore
spacesStore: SpacesStore
clientService: ClientService
previewService: PreviewService
configStore: ConfigStore
router: Router
}): void => {
const resourceQueue = new PQueue({
concurrency: configStore.options.concurrentRequests.sse
@@ -747,6 +665,16 @@ export const registerSSEEventListeners = ({
}
)

clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.ITEM_RENAMED, (msg) =>
onSSEItemRenamedEvent({
resourcesStore,
spacesStore,
msg,
clientService,
router
})
)

clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.POSTPROCESSING_FINISHED, (msg) =>
onSSEProcessingFinishedEvent({
resourcesStore,
176 changes: 176 additions & 0 deletions packages/web-runtime/src/container/sse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import {
ClientService,
createFileRouteOptions,
ImageDimension,
PreviewService,
ResourcesStore,
SpacesStore
} from '@ownclouders/web-pkg'
import PQueue from 'p-queue'
import { extractNodeId, extractStorageId } from '@ownclouders/web-client/src/helpers'
import { z } from 'zod'
import { Router } from 'vue-router'

const fileReadyEventSchema = z.object({
itemid: z.string(),
parentitemid: z.string()
})

type SSEMessageData = {
itemid?: string
parentitemid?: string
}

const itemInCurrentFolder = ({
resourcesStore,
sseData
}: {
resourcesStore: ResourcesStore
sseData: SSEMessageData
}) => {
const currentFolder = resourcesStore.currentFolder
if (!currentFolder) {
return false
}

if (!extractNodeId(currentFolder.id)) {
// if we don't have a nodeId here, we have a space (root) as current folder and can only check against the storageId
if (currentFolder.id !== extractStorageId(sseData.parentitemid)) {
return false
}
} else {
if (currentFolder.id !== sseData.parentitemid) {
return false
}
}

return true
}

export const onSSEItemRenamedEvent = async ({
resourcesStore,
spacesStore,
msg,
clientService,
router
}: {
resourcesStore: ResourcesStore
spacesStore: SpacesStore
msg: MessageEvent
clientService: ClientService
router: Router
}) => {
try {
const sseData = fileReadyEventSchema.parse(JSON.parse(msg.data))

const currentFolder = resourcesStore.currentFolder
const resourceIsCurrentFolder = currentFolder.id === sseData.itemid

if (!resourceIsCurrentFolder && !itemInCurrentFolder({ resourcesStore, sseData })) {
return false
}

const resource = resourceIsCurrentFolder
? currentFolder
: resourcesStore.resources.find((f) => f.id === sseData.itemid)

const space = spacesStore.spaces.find((s) => s.id === resource.storageId)

if (!resource || !space) {
return
}

const updatedResource = await clientService.webdav.getFileInfo(space, {
fileId: sseData.itemid
})

if (resourceIsCurrentFolder) {
resourcesStore.setCurrentFolder(updatedResource)
return router.push(
createFileRouteOptions(space, {
path: updatedResource.path,
fileId: updatedResource.fileId
})
)
}

resourcesStore.updateResourceField({
id: sseData.itemid,
field: 'name',
value: updatedResource.name
})

resourcesStore.updateResourceField({
id: sseData.itemid,
field: 'path',
value: updatedResource.path
})
} catch (e) {
console.error('Unable to parse sse event item renamed data', e)
}
}
export const onSSEProcessingFinishedEvent = async ({
resourcesStore,
spacesStore,
msg,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
clientService,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
resourceQueue,
previewService
}: {
resourcesStore: ResourcesStore
spacesStore: SpacesStore
msg: MessageEvent
clientService: ClientService
resourceQueue: PQueue
previewService: PreviewService
}) => {
try {
const sseData = fileReadyEventSchema.parse(JSON.parse(msg.data))

if (!itemInCurrentFolder({ resourcesStore, sseData })) {
return false
}

const resource = resourcesStore.resources.find((f) => f.id === sseData.itemid)
const space = spacesStore.spaces.find((s) => s.id === resource.storageId)
const isFileLoaded = !!resource

if (isFileLoaded) {
resourcesStore.updateResourceField({
id: sseData.itemid,
field: 'processing',
value: false
})

if (space) {
const preview = await previewService.loadPreview({
resource,
space,
dimensions: ImageDimension.Thumbnail
})

if (preview) {
resourcesStore.updateResourceField({
id: sseData.itemid,
field: 'thumbnail',
value: preview
})
}
}
} else {
// FIXME: we currently cannot do this, we need to block this for ongoing uploads and copy operations
// when fixing revert the changelog removal
// resourceQueue.add(async () => {
// const { resource } = await clientService.webdav.listFilesById({
// fileId: sseData.itemid
// })
// resource.path = urlJoin(currentFolder.path, resource.name)
// resourcesStore.upsertResource(resource)
// })
}
} catch (e) {
console.error('Unable to parse sse event postprocessing-finished data', e)
}
}
3 changes: 2 additions & 1 deletion packages/web-runtime/src/index.ts
Original file line number Diff line number Diff line change
@@ -196,7 +196,8 @@ export const bootstrapApp = async (configurationPath: string): Promise<void> =>
spacesStore,
clientService,
previewService,
configStore
configStore,
router
})
}

0 comments on commit a6a9c29

Please sign in to comment.