diff --git a/src/backend/src/helpers.js b/src/backend/src/helpers.js index 7c4a1cc64..991e1b56a 100644 --- a/src/backend/src/helpers.js +++ b/src/backend/src/helpers.js @@ -23,8 +23,8 @@ import { contentType as _contentType } from 'mime-types'; import { resolve as _resolve, extname } from 'path'; import { v4 } from 'uuid'; import APIError from './api/APIError.js'; -import { redisClient } from './clients/redis/redisSingleton.js'; import { setRedisCacheValue } from './clients/redis/cacheUpdate.js'; +import { redisClient } from './clients/redis/redisSingleton.js'; import config from './config.js'; import { APP_ICONS_SUBDOMAIN } from './consts/app-icons.js'; import { NodeUIDSelector } from './filesystem/node/selectors.js'; @@ -145,7 +145,7 @@ const isBase64AppIcon = (app) => { return isRawBase64ImageString(trimmed); }; -const buildAppIconUrl = (app_uid, size = DEFAULT_APP_ICON_SIZE) => { +const buildAppIconSubdomainUrl = (app_uid, size = DEFAULT_APP_ICON_SIZE) => { if ( ! app_uid ) return null; const normalized_uid = normalizeAppUid(app_uid); const iconSize = Number.isFinite(Number(size)) ? Number(size) : DEFAULT_APP_ICON_SIZE; @@ -176,16 +176,6 @@ const buildAppIconEndpointUrl = (app_uid, size = DEFAULT_APP_ICON_SIZE) => { return `${apiBaseUrl}/app-icon/${normalized_uid}/${iconSize}`; }; -const withAppIconUrl = (app) => { - if ( ! app ) return app; - const iconIsBase64 = isBase64AppIcon(app); - const icon_url = iconIsBase64 - ? buildAppIconEndpointUrl(app.uid ?? app.uuid) - : buildAppIconUrl(app.uid ?? app.uuid); - if ( ! icon_url ) return { ...app }; - return { ...app, icon: icon_url, icon_is_base64: iconIsBase64 }; -}; - export async function is_empty (dir_uuid) { /** @type BaseDatabaseAccessService */ const db = servicesContainer.services.get('database').get(DB_READ, 'filesystem'); @@ -521,6 +511,15 @@ export async function get_app (options) { return app; } +const get_app_icon_url = (app, size) => { + const iconIsBase64 = isBase64AppIcon(app); + const svc_appIcon = servicesContainer.services.get('app-icon'); + console.log('THIS SHOULD BE TRUE', svc_appIcon.config.no_subdomain); + return (iconIsBase64 || svc_appIcon.config.no_subdomain) + ? buildAppIconEndpointUrl(app.uid ?? app.uuid, size) + : buildAppIconSubdomainUrl(app.uid ?? app.uuid, size); +}; + /** * Get multiple apps by uid/name/id, aligned to the input order. * @@ -533,7 +532,12 @@ export const get_apps = spanify('get_apps', async (specifiers, options = {}) => specifiers = [specifiers]; } - const decorateApp = (app) => (withAppIconUrl(app)); + const decorateApp = (app) => { + if ( ! app ) return app; + const icon_url = get_app_icon_url(app.uid ?? app.uuid); + if ( ! icon_url ) return { ...app }; + return { ...app, icon: icon_url }; + }; const normalizeAppForCache = (app) => { if ( ! app ) return app; const normalized = { ...app }; @@ -2113,13 +2117,7 @@ export async function get_taskbar_items (user, { if ( no_icons ) { delete item.icon; } else { - const svc_appIcon = servicesContainer.services.get('app-icon'); - const iconUrl = svc_appIcon.getSizedIconUrl({ - appUid: item.uid, - size: iconSize, - }); - - item.icon = iconUrl;; + item.icon = get_app_icon_url(item, iconSize); } // add to final object diff --git a/src/backend/src/modules/apps/AppIconService.js b/src/backend/src/modules/apps/AppIconService.js index 02ed4fc1e..09ecfb40d 100644 --- a/src/backend/src/modules/apps/AppIconService.js +++ b/src/backend/src/modules/apps/AppIconService.js @@ -25,11 +25,11 @@ import { LLMkdir } from '../../filesystem/ll_operations/ll_mkdir.js'; import { LLRead } from '../../filesystem/ll_operations/ll_read.js'; import { NodePathSelector } from '../../filesystem/node/selectors.js'; import { get_app, get_user } from '../../helpers.js'; -import { AppRedisCacheSpace } from './AppRedisCacheSpace.js'; import BaseService from '../../services/BaseService.js'; import { DB_READ, DB_WRITE } from '../../services/database/consts.js'; import { Endpoint } from '../../util/expressutil.js'; import { buffer_to_stream, stream_to_buffer } from '../../util/streamutil.js'; +import { AppRedisCacheSpace } from './AppRedisCacheSpace.js'; import DEFAULT_APP_ICON from './default-app-icon.js'; const require = createRequire(import.meta.url); @@ -91,7 +91,7 @@ export class AppIconService extends BaseService { } = await this.#getIconStream({ appUid, size: resolvedSize, - allowRedirect: true, + allowRedirect: !this.config.no_subdomain, }); if ( redirectUrl ) { diff --git a/src/backend/src/modules/apps/AppIconService.test.js b/src/backend/src/modules/apps/AppIconService.test.js index 0bbc058c6..0e927cf36 100644 --- a/src/backend/src/modules/apps/AppIconService.test.js +++ b/src/backend/src/modules/apps/AppIconService.test.js @@ -1,4 +1,4 @@ -import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import config from '../../config.js'; import { AppIconService } from './AppIconService.js'; @@ -15,6 +15,9 @@ describe('AppIconService', () => { describe('URL helpers', () => { it('extracts a puter subdomain from a static hosting URL', () => { const service = Object.create(AppIconService.prototype); + // TODO: We might need a better way to do this. A service with no + // initialization is difficult to test. + service.config = {}; const domain = 'site.puter.localhost:4100'; config.load_config({ static_hosting_domain: domain,