Skip to content

Commit

Permalink
refactor: Use JS regular expression syntax, not path-to-regexp, in …
Browse files Browse the repository at this point in the history
…`RegexRouter`.
  • Loading branch information
jswalden committed Dec 8, 2024
1 parent 7e37f6f commit 47c4b91
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 66 deletions.
33 changes: 17 additions & 16 deletions companion/lib/Service/OscApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { CoreBase } from '../Core/Base.js'
import { parseColorToNumber, rgb } from '../Resources/Util.js'
import { formatLocation } from '@companion-app/shared/ControlId.js'
import { RegexRouter } from './RegexRouter.js'
import { Bank, Location, Page, VariableName } from './RoutePatterns.js'
import type { Registry } from '../Registry.js'
import type { OscReceivedMessage } from 'osc'
import type { ControlLocation } from '@companion-app/shared/Model/Common.js'
Expand Down Expand Up @@ -50,7 +51,7 @@ export class ServiceOscApi extends CoreBase {
}

#setupLegacyOscRoutes(): void {
this.#router.addPath('/press/bank/:page/:bank', (match: Record<string, string>, message: OscReceivedMessage) => {
this.#router.addRoute(`/press/bank/${Page}/${Bank}`, (match: Record<string, string>, message: OscReceivedMessage) => {
if (!this.#isLegacyRouteAllowed()) return

const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
Expand All @@ -73,7 +74,7 @@ export class ServiceOscApi extends CoreBase {
}
})

this.#router.addPath('/style/bgcolor/:page/:bank', (match: Record<string, string>, message: OscReceivedMessage) => {
this.#router.addRoute(`/style/bgcolor/${Page}/${Bank}`, (match: Record<string, string>, message: OscReceivedMessage) => {
if (!this.#isLegacyRouteAllowed()) return

if (message.args.length > 2) {
Expand All @@ -95,7 +96,7 @@ export class ServiceOscApi extends CoreBase {
}
})

this.#router.addPath('/style/color/:page/:bank', (match: Record<string, string>, message: OscReceivedMessage) => {
this.#router.addRoute(`/style/color/${Page}/${Bank}`, (match: Record<string, string>, message: OscReceivedMessage) => {
if (!this.#isLegacyRouteAllowed()) return

if (message.args.length > 2) {
Expand All @@ -117,7 +118,7 @@ export class ServiceOscApi extends CoreBase {
}
})

this.#router.addPath('/style/text/:page/:bank', (match: Record<string, string>, message: OscReceivedMessage) => {
this.#router.addRoute(`/style/text/${Page}/${Bank}`, (match: Record<string, string>, message: OscReceivedMessage) => {
if (!this.#isLegacyRouteAllowed()) return

if (message.args.length > 0) {
Expand All @@ -137,7 +138,7 @@ export class ServiceOscApi extends CoreBase {
}
})

this.#router.addPath('/rescan', (_match: Record<string, string>, _message: OscReceivedMessage) => {
this.#router.addRoute('/rescan', (_match: Record<string, string>, _message: OscReceivedMessage) => {
if (!this.#isLegacyRouteAllowed()) return

this.logger.info('Got /rescan 1')
Expand All @@ -149,22 +150,22 @@ export class ServiceOscApi extends CoreBase {

#setupNewOscRoutes() {
// controls by location
this.#router.addPath('/location/:page/:row/:column/press', this.#locationPress)
this.#router.addPath('/location/:page/:row/:column/down', this.#locationDown)
this.#router.addPath('/location/:page/:row/:column/up', this.#locationUp)
this.#router.addPath('/location/:page/:row/:column/rotate-left', this.#locationRotateLeft)
this.#router.addPath('/location/:page/:row/:column/rotate-right', this.#locationRotateRight)
this.#router.addPath('/location/:page/:row/:column/step', this.#locationStep)
this.#router.addRoute(`/location/${Location}/press`, this.#locationPress)
this.#router.addRoute(`/location/${Location}/down`, this.#locationDown)
this.#router.addRoute(`/location/${Location}/up`, this.#locationUp)
this.#router.addRoute(`/location/${Location}/rotate-left`, this.#locationRotateLeft)
this.#router.addRoute(`/location/${Location}/rotate-right`, this.#locationRotateRight)
this.#router.addRoute(`/location/${Location}/step`, this.#locationStep)

this.#router.addPath('/location/:page/:row/:column/style/text', this.#locationSetStyleText)
this.#router.addPath('/location/:page/:row/:column/style/color', this.#locationSetStyleColor)
this.#router.addPath('/location/:page/:row/:column/style/bgcolor', this.#locationSetStyleBgcolor)
this.#router.addRoute(`/location/${Location}/style/text`, this.#locationSetStyleText)
this.#router.addRoute(`/location/${Location}/style/color`, this.#locationSetStyleColor)
this.#router.addRoute(`/location/${Location}/style/bgcolor`, this.#locationSetStyleBgcolor)

// custom variables
this.#router.addPath('/custom-variable/:name/value', this.#customVariableSetValue)
this.#router.addRoute(`/custom-variable/${VariableName}/value`, this.#customVariableSetValue)

// surfaces
this.#router.addPath('/surfaces/rescan', this.#surfacesRescan)
this.#router.addRoute('/surfaces/rescan', this.#surfacesRescan)
}

/**
Expand Down
25 changes: 4 additions & 21 deletions companion/lib/Service/RegexRouter.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { pathToRegexp } from 'path-to-regexp'

/**
* A regex based route
*/
Expand Down Expand Up @@ -51,25 +49,10 @@ export class RegexRouter {
/**
* Add a route to the router
*/
addRegex(regexp: RegExp, handler: RouteHandler): void {
if (!regexp || !handler) throw new Error('Invalid route parameters')
this.#routes.push({ regexp, handler })
}

/**
* Add a route to the router, using the express style path syntax
*/
addPath(path: string, handler: PathRouteHandler): void {
const { regexp, keys } = pathToRegexp(path)

this.addRegex(regexp, (match, ...args) => {
const values: Record<string, string> = {}
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
values[key.name] = values[key.name] ?? match[i + 1]
}

return handler(values, ...args)
addRoute(route: string, handler: PathRouteHandler): void {
this.#routes.push({
regexp: new RegExp(`^${route}$`, 'i'),
handler: (match, ...args) => handler(match.groups ?? {}, ...args),
})
}
}
11 changes: 11 additions & 0 deletions companion/lib/Service/RoutePatterns.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Historic parsing behavior mapped variables to non-'/'-delimiter characters.
// Continue to do so even if matching something more precise would be more
// sensible.
export const Element = '[^/]+?'

export const Page = `(?<page>${Element})`
export const Location = `${Page}/(?<row>${Element})/(?<column>${Element})`

export const Bank = `(?<bank>${Element})`

export const VariableName = `(?<name>${Element})`
65 changes: 39 additions & 26 deletions companion/lib/Service/TcpUdpApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,23 @@ import { CoreBase } from '../Core/Base.js'
import { parseColorToNumber } from '../Resources/Util.js'
import { formatLocation } from '@companion-app/shared/ControlId.js'
import { RegexRouter } from './RegexRouter.js'
import { Bank, Element, Location, Page, VariableName } from './RoutePatterns.js'
import type { ControlLocation } from '@companion-app/shared/Model/Common.js'
import type { Registry } from '../Registry.js'
import type { UserConfigModel } from '@companion-app/shared/Model/UserConfigModel.js'

const SurfaceId = `(?<surfaceId>${Element})`
const Step = `(?<step>${Element})`

const MatchAnyCharactersIfSpacePrecedes = '(?<= ).*'
const MatchZeroCharactersIfNoSpacePrecedes = '(?<! )'
const TextRequiringPrecedingSpace =
`(?<text>${MatchAnyCharactersIfSpacePrecedes}|${MatchZeroCharactersIfNoSpacePrecedes})`

const VariableValue = `(?<value>.*)`

const Color = `(?<color>${Element})`

/**
* Common API command processing for {@link ServiceTcp} and {@link ServiceUdp}.
*
Expand Down Expand Up @@ -71,7 +84,7 @@ export class ServiceTcpUdpApi extends CoreBase {
}

#setupLegacyRoutes() {
this.#router.addPath('page-set :page :surfaceId', (match) => {
this.#router.addRoute(`page-set ${Page} ${SurfaceId}`, (match) => {
this.#checkLegacyRouteAllowed()

const page = Number(match.page)
Expand All @@ -85,7 +98,7 @@ export class ServiceTcpUdpApi extends CoreBase {
return `If ${surfaceId} is connected`
})

this.#router.addPath('page-up :surfaceId', (match) => {
this.#router.addRoute(`page-up ${SurfaceId}`, (match) => {
this.#checkLegacyRouteAllowed()

const surfaceId = match.surfaceId
Expand All @@ -95,7 +108,7 @@ export class ServiceTcpUdpApi extends CoreBase {
return `If ${surfaceId} is connected`
})

this.#router.addPath('page-down :surfaceId', (match) => {
this.#router.addRoute(`page-down ${SurfaceId}`, (match) => {
this.#checkLegacyRouteAllowed()

const surfaceId = match.surfaceId
Expand All @@ -105,7 +118,7 @@ export class ServiceTcpUdpApi extends CoreBase {
return `If ${surfaceId} is connected`
})

this.#router.addPath('bank-press :page :bank', (match) => {
this.#router.addRoute(`bank-press ${Page} ${Bank}`, (match) => {
this.#checkLegacyRouteAllowed()

const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
Expand All @@ -123,7 +136,7 @@ export class ServiceTcpUdpApi extends CoreBase {
}, 20)
})

this.#router.addPath('bank-down :page :bank', (match) => {
this.#router.addRoute(`bank-down ${Page} ${Bank}`, (match) => {
this.#checkLegacyRouteAllowed()

const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
Expand All @@ -136,7 +149,7 @@ export class ServiceTcpUdpApi extends CoreBase {
}
})

this.#router.addPath('bank-up :page :bank', (match) => {
this.#router.addRoute(`bank-up ${Page} ${Bank}`, (match) => {
this.#checkLegacyRouteAllowed()

const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
Expand All @@ -149,7 +162,7 @@ export class ServiceTcpUdpApi extends CoreBase {
}
})

this.#router.addPath('bank-step :page :bank :step', (match) => {
this.#router.addRoute(`bank-step ${Page} ${Bank} ${Step}`, (match) => {
this.#checkLegacyRouteAllowed()

const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
Expand All @@ -167,7 +180,7 @@ export class ServiceTcpUdpApi extends CoreBase {
if (!control.stepMakeCurrent(step)) throw new ApiMessageError('Step out of range')
})

this.#router.addPath('style bank :page :bank text{ *text}', (match) => {
this.#router.addRoute(`style bank ${Page} ${Bank} text ?${TextRequiringPrecedingSpace}`, (match) => {
this.#checkLegacyRouteAllowed()

const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
Expand All @@ -184,7 +197,7 @@ export class ServiceTcpUdpApi extends CoreBase {
}
})

this.#router.addPath('style bank :page :bank bgcolor #:color', (match) => {
this.#router.addRoute(`style bank ${Page} ${Bank} bgcolor #${Color}`, (match) => {
this.#checkLegacyRouteAllowed()

const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
Expand All @@ -202,7 +215,7 @@ export class ServiceTcpUdpApi extends CoreBase {
}
})

this.#router.addPath('style bank :page :bank color #:color', (match) => {
this.#router.addRoute(`style bank ${Page} ${Bank} color #${Color}`, (match) => {
this.#checkLegacyRouteAllowed()

const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
Expand All @@ -220,7 +233,7 @@ export class ServiceTcpUdpApi extends CoreBase {
}
})

this.#router.addPath('rescan', async () => {
this.#router.addRoute('rescan', async () => {
this.#checkLegacyRouteAllowed()

this.logger.debug('Rescanning USB')
Expand All @@ -235,27 +248,27 @@ export class ServiceTcpUdpApi extends CoreBase {

#setupNewRoutes() {
// surface pages
this.#router.addPath('surface :surfaceId page-set :page', this.#surfaceSetPage)
this.#router.addPath('surface :surfaceId page-up', this.#surfacePageUp)
this.#router.addPath('surface :surfaceId page-down', this.#surfacePageDown)
this.#router.addRoute(`surface ${SurfaceId} page-set ${Page}`, this.#surfaceSetPage)
this.#router.addRoute(`surface ${SurfaceId} page-up`, this.#surfacePageUp)
this.#router.addRoute(`surface ${SurfaceId} page-down`, this.#surfacePageDown)

// control by location
this.#router.addPath('location :page/:row/:column press', this.#locationPress)
this.#router.addPath('location :page/:row/:column down', this.#locationDown)
this.#router.addPath('location :page/:row/:column up', this.#locationUp)
this.#router.addPath('location :page/:row/:column rotate-left', this.#locationRotateLeft)
this.#router.addPath('location :page/:row/:column rotate-right', this.#locationRotateRight)
this.#router.addPath('location :page/:row/:column set-step :step', this.#locationSetStep)
this.#router.addRoute(`location ${Location} press`, this.#locationPress)
this.#router.addRoute(`location ${Location} down`, this.#locationDown)
this.#router.addRoute(`location ${Location} up`, this.#locationUp)
this.#router.addRoute(`location ${Location} rotate-left`, this.#locationRotateLeft)
this.#router.addRoute(`location ${Location} rotate-right`, this.#locationRotateRight)
this.#router.addRoute(`location ${Location} set-step ${Step}`, this.#locationSetStep)

this.#router.addPath('location :page/:row/:column style text{ *text}', this.#locationStyleText)
this.#router.addPath('location :page/:row/:column style color :color', this.#locationStyleColor)
this.#router.addPath('location :page/:row/:column style bgcolor :bgcolor', this.#locationStyleBgcolor)
this.#router.addRoute(`location ${Location} style text ?${TextRequiringPrecedingSpace}`, this.#locationStyleText)
this.#router.addRoute(`location ${Location} style color ${Color}`, this.#locationStyleColor)
this.#router.addRoute(`location ${Location} style bgcolor ${Color}`, this.#locationStyleBgcolor)

// surfaces
this.#router.addPath('surfaces rescan', this.#surfacesRescan)
this.#router.addRoute('surfaces rescan', this.#surfacesRescan)

// custom variables
this.#router.addPath('custom-variable :name set-value {*value}', this.#customVariableSetValue)
this.#router.addRoute(`custom-variable ${VariableName} set-value ${VariableValue}`, this.#customVariableSetValue)
}

/**
Expand Down Expand Up @@ -440,7 +453,7 @@ export class ServiceTcpUdpApi extends CoreBase {

const control = this.controls.getControl(controlId)
if (control && control.supportsStyle) {
const color = parseColorToNumber(match.bgcolor)
const color = parseColorToNumber(match.color)

control.styleSetFields({ bgcolor: color })
} else {
Expand Down
1 change: 0 additions & 1 deletion companion/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@
"osc": "2.4.5",
"p-debounce": "^4.0.0",
"p-queue": "^8.0.1",
"path-to-regexp": "^8.2.0",
"selfsigned": "^2.4.1",
"semver": "^7.6.3",
"shuttle-control-usb": "^1.5.0",
Expand Down
Loading

0 comments on commit 47c4b91

Please sign in to comment.