Skip to content

Commit

Permalink
refactor (#341)
Browse files Browse the repository at this point in the history
  • Loading branch information
Roy Razon authored Nov 12, 2023
1 parent 8989b0d commit 6f5d017
Show file tree
Hide file tree
Showing 18 changed files with 320 additions and 264 deletions.
4 changes: 2 additions & 2 deletions packages/cli/src/commands/up.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export default class Up extends MachineCreationDriverCommand<typeof Up> {

this.logger.debug('expectedServiceUrls: %j', expectedServiceUrls)

const injectLivecycleScript = flags['enable-widget']
const injectWidgetScript = flags['enable-widget']
? editUrl(flags['livecycle-widget-url'], { queryParams: { profile: thumbprint, env: envId } }).toString()
: undefined

Expand All @@ -135,7 +135,7 @@ export default class Up extends MachineCreationDriverCommand<typeof Up> {
userSpecifiedProjectName: flags.project,
composeFiles: this.config.composeFiles,
envId,
injectLivecycleScript,
scriptInjections: injectWidgetScript ? { 'livecycle-widget': { src: injectWidgetScript } } : undefined,
tunnelOpts,
log: this.logger,
dataDir: this.config.dataDir,
Expand Down
10 changes: 8 additions & 2 deletions packages/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ export { Logger } from './src/log'
export { requiredEnv, numberFromEnv } from './src/env'
export { tunnelNameResolver, TunnelNameResolver } from './src/tunnel-name'
export { editUrl } from './src/url'
export * from './src/compose-tunnel-agent'
export * from './src/compose-utils'
export {
ScriptInjection,
parseScriptInjectionLabels,
scriptInjectionsToLabels,
COMPOSE_TUNNEL_AGENT_PORT,
COMPOSE_TUNNEL_AGENT_SERVICE_LABELS,
COMPOSE_TUNNEL_AGENT_SERVICE_NAME,
} from './src/compose-tunnel-agent'
export { MachineStatusCommand, DockerMachineStatusCommandRecipe } from './src/machine-status-command'
export { ProcessOutputBuffers, orderedOutput, OrderedOutput } from './src/process-output-buffers'
3 changes: 1 addition & 2 deletions packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,9 @@
},
"scripts": {
"test": "yarn jest",
"start": "node dist/main.js",
"dev": "tsx watch ./main.ts",
"lint": "eslint . --ext .ts,.tsx --cache",
"build": "tsc -b",
"clean": "shx rm -rf dist tsconfig.tsbuildinfo",
"prepack": "yarn build",
"bump-to": "yarn version --no-commit-hooks --no-git-tag-version --new-version"
}
Expand Down
74 changes: 0 additions & 74 deletions packages/common/src/compose-tunnel-agent.test.ts

This file was deleted.

51 changes: 0 additions & 51 deletions packages/common/src/compose-tunnel-agent.ts

This file was deleted.

5 changes: 5 additions & 0 deletions packages/common/src/compose-tunnel-agent/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { COMPOSE_TUNNEL_AGENT_SERVICE_LABELS } from './labels'
export { ScriptInjection, parseScriptInjectionLabels, scriptInjectionsToLabels } from './script-injection'

export const COMPOSE_TUNNEL_AGENT_SERVICE_NAME = 'preevy_proxy'
export const COMPOSE_TUNNEL_AGENT_PORT = 3000
8 changes: 8 additions & 0 deletions packages/common/src/compose-tunnel-agent/labels.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const COMPOSE_TUNNEL_AGENT_SERVICE_LABELS = {
PROFILE_THUMBPRINT: 'preevy.profile_thumbprint',
PRIVATE_MODE: 'preevy.private_mode',
ENV_ID: 'preevy.env_id',
ACCESS: 'preevy.access',
EXPOSE: 'preevy.expose',
INJECT_SCRIPT_PREFIX: 'preevy.inject_script',
} as const
100 changes: 100 additions & 0 deletions packages/common/src/compose-tunnel-agent/script-injection.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { describe, test, expect, it } from '@jest/globals'
import { ScriptInjection, parseScriptInjectionLabels, scriptInjectionsToLabels } from './script-injection'

describe('script injection labels', () => {
describe('parseScriptInjectionLabels', () => {
test('should parse correctly a single label group', () => {
const labels = {
'preevy.inject_script.widget.src': 'https://my-script',
'preevy.inject_script.widget.defer': 'true',
'preevy.inject_script.widget.async': 'false',
'preevy.inject_script.widget.path_regex': 't.*t',
}

const [scripts, errors] = parseScriptInjectionLabels(labels)
expect(errors).toHaveLength(0)
expect(scripts).toHaveLength(1)
expect(scripts[0]).toMatchObject({
src: 'https://my-script',
defer: true,
async: false,
pathRegex: expect.any(RegExp),
})
expect(scripts[0].pathRegex?.source).toBe('t.*t')
})

test('should ignore scripts with invalid regex', () => {
const labels = {
'preevy.inject_script.widget.src': 'https://my-script',
'preevy.inject_script.widget.path_regex': '[',
}
const [scripts, errors] = parseScriptInjectionLabels(labels)
expect(scripts).toHaveLength(0)
expect(errors).toHaveLength(1)
})

test('should drop scripts without src', () => {
const labels = {
'preevy.inject_script.widget.defer': 'true',
}
const [scripts, errors] = parseScriptInjectionLabels(labels)
expect(scripts).toHaveLength(0)
expect(errors).toHaveLength(1)
})

test('should support multiple scripts', () => {
const labels = {
'preevy.inject_script.widget.src': 'https://my-script',
'preevy.inject_script.widget.defer': '1',
'preevy.inject_script.widget2.src': 'https://my-script2',
'preevy.inject_script.widget2.defer': 'false',
'preevy.inject_script.widget3.src': 'https://my-script3',
'preevy.inject_script.widget3.defer': '0',
}
const [scripts, errors] = parseScriptInjectionLabels(labels)
expect(errors).toHaveLength(0)
expect(scripts).toHaveLength(3)
expect(scripts).toContainEqual(
{
src: 'https://my-script',
defer: true,
},
)
expect(scripts).toContainEqual(
{
src: 'https://my-script2',
defer: false,
},
)
expect(scripts).toContainEqual(
{
src: 'https://my-script3',
defer: false,
},
)
})
})

describe('scriptInjectionsToLabels', () => {
const injections: Record<string, ScriptInjection> = {
script1: {
src: 'https://my-script',
defer: true,
async: false,
pathRegex: /^aaa/,
},
script2: {
src: 'https://my-script2',
},
}

it('should convert to labels', () => {
expect(scriptInjectionsToLabels(injections)).toMatchObject({
'preevy.inject_script.script1.src': 'https://my-script',
'preevy.inject_script.script1.defer': 'true',
'preevy.inject_script.script1.path_regex': '^aaa',
'preevy.inject_script.script2.src': 'https://my-script2',
})
})
})
})
76 changes: 76 additions & 0 deletions packages/common/src/compose-tunnel-agent/script-injection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { groupBy, mapKeys, partition } from 'lodash'
import { inspect } from 'util'
import { COMPOSE_TUNNEL_AGENT_SERVICE_LABELS } from './labels'

export type ScriptInjection = {
pathRegex?: RegExp
src: string
defer?: boolean
async?: boolean
}

const parseBooleanLabelValue = (s:string) => s === 'true' || s === '1'

const parseScriptInjection = (o: Record<string, string>): ScriptInjection | Error => {
// eslint-disable-next-line camelcase
const { src, defer, async, path_regex } = o
try {
if (!src) {
throw new Error('missing src')
}
return {
// eslint-disable-next-line camelcase
...path_regex && { pathRegex: new RegExp(path_regex) },
...defer && { defer: parseBooleanLabelValue(defer) },
...async && { async: parseBooleanLabelValue(async) },
src,
}
} catch (e) {
return new Error(`error parsing script injection ${inspect(o)}: ${e}`, { cause: e })
}
}

const scriptInjectionToLabels = (
id: string,
{ src, async, defer, pathRegex }: ScriptInjection,
): Record<string, string> => mapKeys<Record<string, string>>({
src,
...async && { async: 'true' },
...defer && { defer: 'true' },
...pathRegex && { path_regex: pathRegex.source },
}, (_value, key) => [COMPOSE_TUNNEL_AGENT_SERVICE_LABELS.INJECT_SCRIPT_PREFIX, id, key].join('.'))

export const scriptInjectionsToLabels = (
injections: Record<string, ScriptInjection>
) => Object.fromEntries(
Object.entries(injections).flatMap(([id, injection]) => Object.entries(scriptInjectionToLabels(id, injection)))
)

const groupedLabelsRe = /^(?<prefix>[^\s]+)\.(?<id>[^.\s]+)\.(?<key>[^.\s]+)$/
type ParsedGroupedLabelKey = { prefix: string; id: string; key: string }
const parseGroupedLabelKey = (key: string) => {
const match = groupedLabelsRe.exec(key)
return match && match.groups as ParsedGroupedLabelKey
}

const parseLabelsWithPrefixAndId = (
labels: Record<string, string>,
prefix: string,
): Record<string, string>[] => {
const split: [ParsedGroupedLabelKey | null, string][] = Object.entries(labels)
.map(([k, v]) => [parseGroupedLabelKey(k), v])
const filteredForPrefix = split.filter(([k]) => k?.prefix === prefix) as [ParsedGroupedLabelKey, string][]
const grouped = groupBy(filteredForPrefix, ([{ id }]) => id)
return Object.values(grouped).map(group => Object.fromEntries(group.map(([{ key }, value]) => [key, value])))
}

export const parseScriptInjectionLabels = (
labels: Record<string, string>,
): [ScriptInjection[], Error[]] => {
const stringifiedInjections = parseLabelsWithPrefixAndId(
labels,
COMPOSE_TUNNEL_AGENT_SERVICE_LABELS.INJECT_SCRIPT_PREFIX,
)
const injectionOrErrors = stringifiedInjections.map(parseScriptInjection)
return partition(injectionOrErrors, x => !(x instanceof Error)) as [ScriptInjection[], Error[]]
}
23 changes: 0 additions & 23 deletions packages/common/src/compose-utils.ts

This file was deleted.

Loading

0 comments on commit 6f5d017

Please sign in to comment.