mirror of
https://github.com/stablyai/orca.git
synced 2026-09-29 08:03:20 +00:00
perf(repos): avoid quadratic icon source scans
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { performance } from 'node:perf_hooks'
|
||||
import { extractIconHref } from '../../src/main/repo-icon-source-href.ts'
|
||||
|
||||
// Original production expressions, preserved for the before/after measurement.
|
||||
const html =
|
||||
/<link\b(?=[^>]*\brel=["'](?:icon|shortcut icon)["'])(?=[^>]*\bhref=["']([^"'?]+))[^>]*>/i
|
||||
const object =
|
||||
/(?=[^}]*\brel\s*:\s*["'](?:icon|shortcut icon)["'])(?=[^}]*\bhref\s*:\s*["']([^"'?]+))[^}]*/i
|
||||
const original = (source) => source.match(html)?.[1] ?? source.match(object)?.[1] ?? null
|
||||
|
||||
function measure(fn, source, repetitions) {
|
||||
const samples = []
|
||||
for (let run = 0; run < repetitions; run++) {
|
||||
const started = performance.now()
|
||||
fn(source)
|
||||
samples.push(performance.now() - started)
|
||||
}
|
||||
return samples.sort((a, b) => a - b)[Math.floor(samples.length / 2)]
|
||||
}
|
||||
|
||||
const results = []
|
||||
for (const size of [8192, 16384, 32768]) {
|
||||
for (const shape of ['no icon', 'rel without href']) {
|
||||
const source = 'a'.repeat(size) + (shape === 'rel without href' ? ' rel:"icon"' : '')
|
||||
assert.equal(extractIconHref(source), original(source))
|
||||
const beforeMs = measure(original, source, 3)
|
||||
const afterMs = measure(extractIconHref, source, 15)
|
||||
results.push({
|
||||
shape,
|
||||
bytes: Buffer.byteLength(source),
|
||||
beforeMs,
|
||||
afterMs,
|
||||
speedup: beforeMs / afterMs
|
||||
})
|
||||
}
|
||||
}
|
||||
console.log(JSON.stringify({ node: process.version, platform: process.platform, results }, null, 2))
|
||||
@@ -1,4 +1,6 @@
|
||||
import { readFile, stat } from 'node:fs/promises'
|
||||
import { join } from 'node:path'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { mkdtemp, mkdir, readFile, rm, stat, writeFile } from 'node:fs/promises'
|
||||
import type * as FsPromisesModule from 'node:fs/promises'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import type { ExecutionHostFilesystemRoute } from './providers/execution-host-provider-dispatch'
|
||||
@@ -136,3 +138,55 @@ describe('detectRepoFileIcon connection boundary', () => {
|
||||
expect(stat).toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('declared repo icons through production filesystem routes', () => {
|
||||
it.each([
|
||||
['local', false],
|
||||
['ssh', false],
|
||||
['local', true],
|
||||
['ssh', true]
|
||||
] as const)('preserves declared icon detection on %s (no icon: %s)', async (kind, noIcon) => {
|
||||
const directory = await mkdtemp(join(tmpdir(), 'orca-icon-href-'))
|
||||
const source = noIcon
|
||||
? 'a'.repeat(256 * 1024)
|
||||
: `${'a'.repeat(32768)}{ rel: "icon", href: "/first.png", href: "/chosen.png" }`
|
||||
try {
|
||||
await mkdir(join(directory, 'public'))
|
||||
await writeFile(join(directory, 'index.html'), source)
|
||||
await writeFile(join(directory, 'public', 'chosen.png'), Buffer.from(PNG_BASE64, 'base64'))
|
||||
const provider = remoteFilesystemProvider({
|
||||
stat: async (path) => {
|
||||
const info = await stat(path)
|
||||
return {
|
||||
type: info.isFile() ? 'file' : 'directory',
|
||||
size: info.size,
|
||||
mtime: info.mtimeMs
|
||||
}
|
||||
},
|
||||
readFile: async (path) => {
|
||||
const buffer = await readFile(path)
|
||||
const isBinary = path.endsWith('.png')
|
||||
return {
|
||||
content: buffer.toString(isBinary ? 'base64' : 'utf8'),
|
||||
isBinary,
|
||||
mimeType: isBinary ? 'image/png' : 'text/html'
|
||||
}
|
||||
}
|
||||
})
|
||||
const route: ExecutionHostFilesystemRoute =
|
||||
kind === 'local' ? { kind: 'local', hostId: 'local' } : sshRoute('icon-oracle', provider)
|
||||
await expect(detectRepoFileIcon(directory, route)).resolves.toEqual(
|
||||
noIcon
|
||||
? null
|
||||
: {
|
||||
type: 'image',
|
||||
src: `data:image/png;base64,${PNG_BASE64}`,
|
||||
source: 'file',
|
||||
label: 'public/chosen.png'
|
||||
}
|
||||
)
|
||||
} finally {
|
||||
await rm(directory, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@ import { buildImageDataUri } from '../shared/image-data-uri'
|
||||
import { MAX_REPO_ICON_UPLOAD_BYTES, type RepoIcon } from '../shared/repo-icon'
|
||||
import type { ExecutionHostFilesystemRoute } from './providers/execution-host-provider-dispatch'
|
||||
import type { IFilesystemProvider } from './providers/types'
|
||||
import { extractIconHref } from './repo-icon-source-href'
|
||||
import { iconHrefCandidates } from './repo-icon-href-candidates'
|
||||
import { joinWorktreeRelativePath } from './runtime/runtime-relative-paths'
|
||||
|
||||
@@ -49,11 +50,6 @@ const REPO_ICON_SOURCE_FILE_CANDIDATES = [
|
||||
// not read large app entrypoints just to find a small favicon href.
|
||||
const MAX_REPO_ICON_SOURCE_BYTES = 256 * 1024
|
||||
|
||||
const LINK_ICON_HTML_RE =
|
||||
/<link\b(?=[^>]*\brel=["'](?:icon|shortcut icon)["'])(?=[^>]*\bhref=["']([^"'?]+))[^>]*>/i
|
||||
const LINK_ICON_OBJECT_RE =
|
||||
/(?=[^}]*\brel\s*:\s*["'](?:icon|shortcut icon)["'])(?=[^}]*\bhref\s*:\s*["']([^"'?]+))[^}]*/i
|
||||
|
||||
type DetectedImageFormat = {
|
||||
mimeType: 'image/png' | 'image/webp'
|
||||
}
|
||||
@@ -98,10 +94,6 @@ function detectImageFormat(buffer: Buffer): DetectedImageFormat | null {
|
||||
return null
|
||||
}
|
||||
|
||||
function extractIconHref(source: string): string | null {
|
||||
return source.match(LINK_ICON_HTML_RE)?.[1] ?? source.match(LINK_ICON_OBJECT_RE)?.[1] ?? null
|
||||
}
|
||||
|
||||
function repoIconFromImageBuffer(buffer: Buffer, relativePath: string): RepoIcon | null {
|
||||
const format = detectImageFormat(buffer)
|
||||
if (!format) {
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { extractIconHref } from './repo-icon-source-href'
|
||||
|
||||
// Original production expressions are the compatibility oracle.
|
||||
const HTML_RE =
|
||||
/<link\b(?=[^>]*\brel=["'](?:icon|shortcut icon)["'])(?=[^>]*\bhref=["']([^"'?]+))[^>]*>/i
|
||||
const OBJECT_RE =
|
||||
/(?=[^}]*\brel\s*:\s*["'](?:icon|shortcut icon)["'])(?=[^}]*\bhref\s*:\s*["']([^"'?]+))[^}]*/i
|
||||
|
||||
export function originalIconHref(source: string): string | null {
|
||||
return source.match(HTML_RE)?.[1] ?? source.match(OBJECT_RE)?.[1] ?? null
|
||||
}
|
||||
|
||||
describe('repo icon source href compatibility', () => {
|
||||
it.each([
|
||||
'',
|
||||
'plain source without icon properties',
|
||||
'{ rel: "icon", href: "/first.png", href: "/last.png" }',
|
||||
'{ href: "/first.png", rel: "icon", rel: "stylesheet" }',
|
||||
'{ rel: "icon" } { href: "/unrelated.png" }',
|
||||
'{ rel: "icon", href: "/first.png" } { rel: "icon", href: "/last.png" }',
|
||||
'{ rel: "icon", href: "/object.png" } <link href="/html.png" rel="icon">',
|
||||
'{ rel: "ICON", href: "/UPPER.png" }',
|
||||
'}\n\n{href: "/line.png",\nrel : "shortcut icon"}',
|
||||
'{ rel: "icon", href: "/unterminated}after brace',
|
||||
'{ rel: "icon", href: "?query" }',
|
||||
'{ rel: "icon", href: "/before?query" }',
|
||||
'<link rel="stylesheet" href="/no.png">',
|
||||
'<link rel="icon" href="/yes.png"',
|
||||
'{rel:"icon",href:"/nested{brace}.png"}',
|
||||
'xrel:"icon", xhref:"/no.png"'
|
||||
])('preserves original selection for %s', (source) => {
|
||||
expect(extractIconHref(source)).toBe(originalIconHref(source))
|
||||
})
|
||||
|
||||
it('matches the original across generated malformed property sequences', () => {
|
||||
const tokens = ['}', '{', ' ', 'rel:"icon"', 'href:"a"', 'href:"b"', 'rel:"other"', 'x', '\n']
|
||||
let seed = 97
|
||||
for (let sample = 0; sample < 3000; sample++) {
|
||||
let source = ''
|
||||
for (let token = 0; token < 12; token++) {
|
||||
seed = (Math.imul(seed, 1664525) + 1013904223) >>> 0
|
||||
source += tokens[seed % tokens.length]
|
||||
}
|
||||
expect(extractIconHref(source), source).toBe(originalIconHref(source))
|
||||
}
|
||||
})
|
||||
|
||||
it('handles a maximum-size icon-free entrypoint', () => {
|
||||
expect(extractIconHref('a'.repeat(256 * 1024))).toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,26 @@
|
||||
const LINK_ICON_HTML_RE =
|
||||
/<link\b(?=[^>]*\brel=["'](?:icon|shortcut icon)["'])(?=[^>]*\bhref=["']([^"'?]+))[^>]*>/i
|
||||
const LINK_ICON_OBJECT_RE =
|
||||
/(?=[^}]*\brel\s*:\s*["'](?:icon|shortcut icon)["'])(?=[^}]*\bhref\s*:\s*["']([^"'?]+))[^}]*/iy
|
||||
|
||||
export function extractIconHref(source: string): string | null {
|
||||
const htmlHref = source.match(LINK_ICON_HTML_RE)?.[1]
|
||||
if (htmlHref !== undefined) {
|
||||
return htmlHref
|
||||
}
|
||||
let start = 0
|
||||
while (start <= source.length) {
|
||||
// Every suffix before the next closing brace sees the same candidate properties.
|
||||
LINK_ICON_OBJECT_RE.lastIndex = start
|
||||
const href = LINK_ICON_OBJECT_RE.exec(source)?.[1]
|
||||
if (href !== undefined) {
|
||||
return href
|
||||
}
|
||||
const closingBrace = source.indexOf('}', start)
|
||||
if (closingBrace === -1) {
|
||||
return null
|
||||
}
|
||||
start = closingBrace + 1
|
||||
}
|
||||
return null
|
||||
}
|
||||
Reference in New Issue
Block a user