Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: reduce network load on token renewal #11077

Merged
merged 1 commit into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Reduce network load on token renewal

We've reduced the network load on token renewal, resulting in better overall performance of the Web client and less token renewal failures on slow network connections.

https://github.com/owncloud/web/pull/11077
https://github.com/owncloud/web/issues/11069
3 changes: 2 additions & 1 deletion packages/design-system/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { getSizeClass } from './utils/sizeClasses'
import './utils/webFontLoader'
import { App } from 'vue'

import * as components from './components'
Expand All @@ -20,6 +19,8 @@ export const applyCustomProp = (key: string, value: string | undefined) => {

export default {
install(app: App, options: any = {}) {
import('./utils/webFontLoader')

const themeOptions = options.tokens
initializeCustomProps(themeOptions?.breakpoints, 'breakpoint-')
initializeCustomProps(themeOptions?.colorPalette, 'color-')
Expand Down
37 changes: 35 additions & 2 deletions packages/web-runtime/src/container/bootstrap.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { registerClient } from '../services/clientRegistration'
import { buildApplication, NextApplication } from './application'
import { RouteLocationRaw, Router, RouteRecordNormalized } from 'vue-router'
import { App, watch } from 'vue'
import { App, computed, watch } from 'vue'
import { loadTheme } from '../helpers/theme'
import { createGettext, GetTextOptions, Language, Translations } from 'vue3-gettext'
import { getBackendVersion, getWebVersion } from './versions'
Expand All @@ -28,7 +28,8 @@ import {
ResourcesStore,
SpacesStore,
MessageStore,
SharesStore
SharesStore,
ArchiverService
} from '@ownclouders/web-pkg'
import { authService } from '../services/auth'
import {
Expand Down Expand Up @@ -75,6 +76,7 @@ import {
} from './sse'
import { useWebWorkersStore, WebWorkersStore } from '@ownclouders/web-pkg'
import { loadAppTranslations } from '../helpers/language'
import { urlJoin } from '@ownclouders/web-client'

const getEmbedConfigFromQuery = (
doesEmbedEnabledOptionExists: boolean
Expand Down Expand Up @@ -410,6 +412,37 @@ export const announceClientService = ({
app.provide('$clientService', clientService)
}

export const announceArchiverService = ({
app,
configStore,
userStore,
capabilityStore
}: {
app: App
configStore: ConfigStore
userStore: UserStore
capabilityStore: CapabilityStore
}): void => {
app.config.globalProperties.$archiverService = new ArchiverService(
app.config.globalProperties.$clientService,
userStore,
configStore.serverUrl,
computed(
() =>
capabilityStore.filesArchivers || [
{
enabled: true,
version: '1.0.0',
formats: ['tar', 'zip'],
archiver_url: urlJoin(configStore.serverUrl, 'index.php/apps/files/ajax/download.php')
}
]
)
)

app.provide('$archiverService', app.config.globalProperties.$archiverService)
}

/**
* @param vue
*/
Expand Down
18 changes: 13 additions & 5 deletions packages/web-runtime/src/defaults/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import merge from 'lodash-es/merge'
import App from '../App.vue'
import TokenRenewal from '../pages/tokenRenewal.vue'
import missingOrInvalidConfigPage from '../pages/missingOrInvalidConfig.vue'

// fontawesome-free attributions console message
import '@fortawesome/fontawesome-free/attribution'

export { default as DesignSystem } from 'design-system'
export * from './languages'

export const pages = { success: App, failure: missingOrInvalidConfigPage }
export const pages = {
success: App,
failure: missingOrInvalidConfigPage,
tokenRenewal: TokenRenewal
}

export const loadTranslations = async () => {
const { coreTranslations, clientTranslations, pkgTranslations, odsTranslations } = await import(
Expand All @@ -17,3 +18,10 @@ export const loadTranslations = async () => {

return merge({}, coreTranslations, clientTranslations, pkgTranslations, odsTranslations)
}

export const loadDesignSystem = async () => {
// fontawesome-free attributions console message
import('@fortawesome/fontawesome-free/attribution')

return (await import('design-system')).default
}
1 change: 1 addition & 0 deletions packages/web-runtime/src/helpers/silentRedirect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const isSilentRedirectRoute = () => window.location.pathname === '/web-oidc-silent-redirect'
122 changes: 56 additions & 66 deletions packages/web-runtime/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
import {
DesignSystem as designSystem,
pages,
loadTranslations,
supportedLanguages
} from './defaults'
import { loadDesignSystem, pages, loadTranslations, supportedLanguages } from './defaults'
import { router } from './router'
import { PortalTarget } from '@ownclouders/web-pkg'
import { createHead } from '@vueuse/head'
Expand Down Expand Up @@ -31,7 +26,8 @@ import {
announcePasswordPolicyService,
registerSSEEventListeners,
setViewOptions,
announceGettext
announceGettext,
announceArchiverService
} from './container/bootstrap'
import { applicationStore } from './container/store'
import {
Expand All @@ -41,18 +37,20 @@ import {
PublicSpaceResource
} from '@ownclouders/web-client'
import { loadCustomTranslations } from 'web-runtime/src/helpers/customTranslations'
import { computed, createApp, watch } from 'vue'
import { createApp, watch } from 'vue'
import PortalVue, { createWormhole } from 'portal-vue'
import { createPinia } from 'pinia'
import Avatar from './components/Avatar.vue'
import focusMixin from './mixins/focusMixin'
import { ArchiverService } from '@ownclouders/web-pkg'
import { UnifiedRoleDefinition } from '@ownclouders/web-client/graph/generated'
import { extensionPoints } from './extensionPoints'
import { isSilentRedirectRoute } from './helpers/silentRedirect'

export const bootstrapApp = async (configurationPath: string, appsReadyCallback: () => void) => {
const isSilentRedirect = isSilentRedirectRoute()

const pinia = createPinia()
const app = createApp(pages.success)
const app = createApp(isSilentRedirect ? pages.tokenRenewal : pages.success)
app.use(pinia)

const {
Expand All @@ -74,65 +72,12 @@ export const bootstrapApp = async (configurationPath: string, appsReadyCallback:
app.provide('$router', router)

await announceConfiguration({ path: configurationPath, configStore })
startSentry(configStore, app)

app.use(abilitiesPlugin, createMongoAbility([]), { useGlobalProperties: true })

const gettext = announceGettext({ app, availableLanguages: supportedLanguages })

announceUppyService({ app })
announceClientService({ app, configStore, authStore })

// TODO: move to announceArchiverService function
app.config.globalProperties.$archiverService = new ArchiverService(
app.config.globalProperties.$clientService,
userStore,
configStore.serverUrl,
computed(
() =>
capabilityStore.filesArchivers || [
{
enabled: true,
version: '1.0.0',
formats: ['tar', 'zip'],
archiver_url: `${configStore.serverUrl}index.php/apps/files/ajax/download.php`
}
]
)
)
app.provide('$archiverService', app.config.globalProperties.$archiverService)
announceLoadingService({ app })
announcePreviewService({
app,
configStore,
userStore,
authStore,
capabilityStore
})
announcePasswordPolicyService({ app })
await announceClient(configStore)

app.config.globalProperties.$wormhole = createWormhole()
app.use(PortalVue, {
wormhole: app.config.globalProperties.$wormhole,
// do not register portal-target component so we can register our own wrapper
portalTargetName: false
})
app.component('PortalTarget', PortalTarget)

const applicationsPromise = initializeApplications({ app, configStore, router })
const translationsPromise = loadTranslations()
const customTranslationsPromise = loadCustomTranslations({ configStore })
const themePromise = announceTheme({ app, designSystem, configStore })
const [coreTranslations, customTranslations] = await Promise.all([
translationsPromise,
customTranslationsPromise,
applicationsPromise,
themePromise
])

announceTranslations({ appsStore, gettext, coreTranslations, customTranslations })

announceAuthService({
app,
configStore,
Expand All @@ -142,9 +87,49 @@ export const bootstrapApp = async (configurationPath: string, appsReadyCallback:
capabilityStore,
webWorkersStore
})
announceCustomStyles({ configStore })
announceCustomScripts({ configStore })
announceDefaults({ appsStore, router, extensionRegistry, configStore })

if (!isSilentRedirect) {
const designSystem = await loadDesignSystem()

announceUppyService({ app })
startSentry(configStore, app)
announceArchiverService({ app, configStore, userStore, capabilityStore })
announceLoadingService({ app })
announcePreviewService({
app,
configStore,
userStore,
authStore,
capabilityStore
})
announcePasswordPolicyService({ app })
await announceClient(configStore)

app.config.globalProperties.$wormhole = createWormhole()
app.use(PortalVue, {
wormhole: app.config.globalProperties.$wormhole,
// do not register portal-target component so we can register our own wrapper
portalTargetName: false
})
app.component('PortalTarget', PortalTarget)

const applicationsPromise = initializeApplications({ app, configStore, router })
const translationsPromise = loadTranslations()
const customTranslationsPromise = loadCustomTranslations({ configStore })
const themePromise = announceTheme({ app, designSystem, configStore })
const [coreTranslations, customTranslations] = await Promise.all([
translationsPromise,
customTranslationsPromise,
applicationsPromise,
themePromise
])

announceTranslations({ appsStore, gettext, coreTranslations, customTranslations })

announceCustomStyles({ configStore })
announceCustomScripts({ configStore })
announceDefaults({ appsStore, router, extensionRegistry, configStore })
}

app.use(router)
app.use(createHead())
Expand All @@ -154,6 +139,10 @@ export const bootstrapApp = async (configurationPath: string, appsReadyCallback:

app.mount('#owncloud')

if (isSilentRedirect) {
return
}

setViewOptions({ resourcesStore })

const applications = Array.from(applicationStore.values())
Expand Down Expand Up @@ -273,6 +262,7 @@ export const bootstrapErrorApp = async (err: Error): Promise<void> => {
const { capabilityStore, configStore } = announcePiniaStores()
announceVersions({ capabilityStore })
const app = createApp(pages.failure)
const designSystem = await loadDesignSystem()
await announceTheme({ app, designSystem, configStore })
console.error(err)
const translations = await loadTranslations()
Expand Down
4 changes: 2 additions & 2 deletions packages/web-runtime/src/pages/oidcCallback.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ export default defineComponent({
const error = ref(false)
const footerSlogan = computed(() => currentTheme.value.common.slogan)
const logoImg = computed(() => currentTheme.value.logo.login)
const footerSlogan = computed(() => unref(currentTheme)?.common.slogan)
const logoImg = computed(() => unref(currentTheme)?.logo.login)
const route = useRoute()
Expand Down
13 changes: 13 additions & 0 deletions packages/web-runtime/src/pages/tokenRenewal.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<template>
<router-view />
</template>
<script lang="ts">
import { defineComponent } from 'vue'
/**
* This page gets rendered in the iFrame for the silent token renewal to take place.
*/
export default defineComponent({
name: 'TokenRenewal'
})
</script>
5 changes: 4 additions & 1 deletion packages/web-runtime/src/services/auth/authService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { Ability } from '@ownclouders/web-client'
import { Language } from 'vue3-gettext'
import { PublicLinkType } from '@ownclouders/web-client'
import { WebWorkersStore } from '@ownclouders/web-pkg'
import { isSilentRedirectRoute } from '../../helpers/silentRedirect'

export class AuthService implements AuthServiceInterface {
private clientService: ClientService
Expand Down Expand Up @@ -109,7 +110,9 @@ export class AuthService implements AuthServiceInterface {
accessTokenExpiryThreshold: this.accessTokenExpiryThreshold
})

if (!this.tokenTimerWorker) {
// don't load worker in the silent redirect iframe
const isSilentRedirect = isSilentRedirectRoute()
if (!this.tokenTimerWorker && !isSilentRedirect) {
const { options } = this.configStore

if (!options.embed?.enabled || !options.embed?.delegateAuthentication) {
Expand Down