Skip to content

Commit 3320600

Browse files
committed
refactor: Use JS regular expression syntax, not path-to-regexp, in RegexRouter.
1 parent 1d7f2e0 commit 3320600

File tree

7 files changed

+235
-137
lines changed

7 files changed

+235
-137
lines changed

companion/lib/Service/OscApi.ts

+100-87
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { CoreBase } from '../Core/Base.js'
22
import { parseColorToNumber, rgb } from '../Resources/Util.js'
33
import { formatLocation } from '@companion-app/shared/ControlId.js'
44
import { RegexRouter } from './RegexRouter.js'
5+
import { Bank, Location, Page, VariableName } from './RoutePatterns.js'
56
import type { Registry } from '../Registry.js'
67
import type { OscReceivedMessage } from 'osc'
78
import type { ControlLocation } from '@companion-app/shared/Model/Common.js'
@@ -50,94 +51,106 @@ export class ServiceOscApi extends CoreBase {
5051
}
5152

5253
#setupLegacyOscRoutes(): void {
53-
this.#router.addPath('/press/bank/:page/:bank', (match: Record<string, string>, message: OscReceivedMessage) => {
54-
if (!this.#isLegacyRouteAllowed()) return
55-
56-
const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
57-
if (!controlId) return
58-
59-
if (message.args.length > 0 && message.args[0].type == 'i' && message.args[0].value == 1) {
60-
this.logger.info(`Got /press/bank/ (press) for ${controlId}`)
61-
this.controls.pressControl(controlId, true, undefined)
62-
} else if (message.args.length > 0 && message.args[0].type == 'i' && message.args[0].value == 0) {
63-
this.logger.info(`Got /press/bank/ (release) for ${controlId}`)
64-
this.controls.pressControl(controlId, false, undefined)
65-
} else {
66-
this.logger.info(`Got /press/bank/ (trigger)${controlId}`)
67-
this.controls.pressControl(controlId, true, undefined)
68-
69-
setTimeout(() => {
70-
this.logger.info(`Auto releasing /press/bank/ (trigger)${controlId}`)
54+
this.#router.addRoute(
55+
`/press/bank/${Page}/${Bank}`,
56+
(match: Record<string, string>, message: OscReceivedMessage) => {
57+
if (!this.#isLegacyRouteAllowed()) return
58+
59+
const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
60+
if (!controlId) return
61+
62+
if (message.args.length > 0 && message.args[0].type == 'i' && message.args[0].value == 1) {
63+
this.logger.info(`Got /press/bank/ (press) for ${controlId}`)
64+
this.controls.pressControl(controlId, true, undefined)
65+
} else if (message.args.length > 0 && message.args[0].type == 'i' && message.args[0].value == 0) {
66+
this.logger.info(`Got /press/bank/ (release) for ${controlId}`)
7167
this.controls.pressControl(controlId, false, undefined)
72-
}, 20)
68+
} else {
69+
this.logger.info(`Got /press/bank/ (trigger)${controlId}`)
70+
this.controls.pressControl(controlId, true, undefined)
71+
72+
setTimeout(() => {
73+
this.logger.info(`Auto releasing /press/bank/ (trigger)${controlId}`)
74+
this.controls.pressControl(controlId, false, undefined)
75+
}, 20)
76+
}
7377
}
74-
})
75-
76-
this.#router.addPath('/style/bgcolor/:page/:bank', (match: Record<string, string>, message: OscReceivedMessage) => {
77-
if (!this.#isLegacyRouteAllowed()) return
78-
79-
if (message.args.length > 2) {
80-
const r = message.args[0].value
81-
const g = message.args[1].value
82-
const b = message.args[2].value
83-
if (typeof r === 'number' && typeof g === 'number' && typeof b === 'number') {
84-
const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
85-
if (!controlId) return
86-
87-
const control = this.controls.getControl(controlId)
88-
if (control && control.supportsStyle) {
89-
this.logger.info(`Got /style/bgcolor for ${controlId}`)
90-
control.styleSetFields({ bgcolor: rgb(r, g, b) })
91-
} else {
92-
this.logger.info(`Got /style/bgcolor for unknown control: ${controlId}`)
78+
)
79+
80+
this.#router.addRoute(
81+
`/style/bgcolor/${Page}/${Bank}`,
82+
(match: Record<string, string>, message: OscReceivedMessage) => {
83+
if (!this.#isLegacyRouteAllowed()) return
84+
85+
if (message.args.length > 2) {
86+
const r = message.args[0].value
87+
const g = message.args[1].value
88+
const b = message.args[2].value
89+
if (typeof r === 'number' && typeof g === 'number' && typeof b === 'number') {
90+
const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
91+
if (!controlId) return
92+
93+
const control = this.controls.getControl(controlId)
94+
if (control && control.supportsStyle) {
95+
this.logger.info(`Got /style/bgcolor for ${controlId}`)
96+
control.styleSetFields({ bgcolor: rgb(r, g, b) })
97+
} else {
98+
this.logger.info(`Got /style/bgcolor for unknown control: ${controlId}`)
99+
}
93100
}
94101
}
95102
}
96-
})
97-
98-
this.#router.addPath('/style/color/:page/:bank', (match: Record<string, string>, message: OscReceivedMessage) => {
99-
if (!this.#isLegacyRouteAllowed()) return
100-
101-
if (message.args.length > 2) {
102-
const r = message.args[0].value
103-
const g = message.args[1].value
104-
const b = message.args[2].value
105-
if (typeof r === 'number' && typeof g === 'number' && typeof b === 'number') {
106-
const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
107-
if (!controlId) return
108-
109-
const control = this.controls.getControl(controlId)
110-
if (control && control.supportsStyle) {
111-
this.logger.info(`Got /style/color for ${controlId}`)
112-
control.styleSetFields({ color: rgb(r, g, b) })
113-
} else {
114-
this.logger.info(`Got /style/color for unknown control: ${controlId}`)
103+
)
104+
105+
this.#router.addRoute(
106+
`/style/color/${Page}/${Bank}`,
107+
(match: Record<string, string>, message: OscReceivedMessage) => {
108+
if (!this.#isLegacyRouteAllowed()) return
109+
110+
if (message.args.length > 2) {
111+
const r = message.args[0].value
112+
const g = message.args[1].value
113+
const b = message.args[2].value
114+
if (typeof r === 'number' && typeof g === 'number' && typeof b === 'number') {
115+
const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
116+
if (!controlId) return
117+
118+
const control = this.controls.getControl(controlId)
119+
if (control && control.supportsStyle) {
120+
this.logger.info(`Got /style/color for ${controlId}`)
121+
control.styleSetFields({ color: rgb(r, g, b) })
122+
} else {
123+
this.logger.info(`Got /style/color for unknown control: ${controlId}`)
124+
}
115125
}
116126
}
117127
}
118-
})
119-
120-
this.#router.addPath('/style/text/:page/:bank', (match: Record<string, string>, message: OscReceivedMessage) => {
121-
if (!this.#isLegacyRouteAllowed()) return
122-
123-
if (message.args.length > 0) {
124-
const text = message.args[0].value
125-
if (typeof text === 'string') {
126-
const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
127-
if (!controlId) return
128-
129-
const control = this.controls.getControl(controlId)
130-
if (control && control.supportsStyle) {
131-
this.logger.info(`Got /style/text for ${controlId}`)
132-
control.styleSetFields({ text: text })
133-
} else {
134-
this.logger.info(`Got /style/color for unknown control: ${controlId}`)
128+
)
129+
130+
this.#router.addRoute(
131+
`/style/text/${Page}/${Bank}`,
132+
(match: Record<string, string>, message: OscReceivedMessage) => {
133+
if (!this.#isLegacyRouteAllowed()) return
134+
135+
if (message.args.length > 0) {
136+
const text = message.args[0].value
137+
if (typeof text === 'string') {
138+
const controlId = this.page.getControlIdAtOldBankIndex(Number(match.page), Number(match.bank))
139+
if (!controlId) return
140+
141+
const control = this.controls.getControl(controlId)
142+
if (control && control.supportsStyle) {
143+
this.logger.info(`Got /style/text for ${controlId}`)
144+
control.styleSetFields({ text: text })
145+
} else {
146+
this.logger.info(`Got /style/color for unknown control: ${controlId}`)
147+
}
135148
}
136149
}
137150
}
138-
})
151+
)
139152

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

143156
this.logger.info('Got /rescan 1')
@@ -149,22 +162,22 @@ export class ServiceOscApi extends CoreBase {
149162

150163
#setupNewOscRoutes() {
151164
// controls by location
152-
this.#router.addPath('/location/:page/:row/:column/press', this.#locationPress)
153-
this.#router.addPath('/location/:page/:row/:column/down', this.#locationDown)
154-
this.#router.addPath('/location/:page/:row/:column/up', this.#locationUp)
155-
this.#router.addPath('/location/:page/:row/:column/rotate-left', this.#locationRotateLeft)
156-
this.#router.addPath('/location/:page/:row/:column/rotate-right', this.#locationRotateRight)
157-
this.#router.addPath('/location/:page/:row/:column/step', this.#locationStep)
165+
this.#router.addRoute(`/location/${Location}/press`, this.#locationPress)
166+
this.#router.addRoute(`/location/${Location}/down`, this.#locationDown)
167+
this.#router.addRoute(`/location/${Location}/up`, this.#locationUp)
168+
this.#router.addRoute(`/location/${Location}/rotate-left`, this.#locationRotateLeft)
169+
this.#router.addRoute(`/location/${Location}/rotate-right`, this.#locationRotateRight)
170+
this.#router.addRoute(`/location/${Location}/step`, this.#locationStep)
158171

159-
this.#router.addPath('/location/:page/:row/:column/style/text', this.#locationSetStyleText)
160-
this.#router.addPath('/location/:page/:row/:column/style/color', this.#locationSetStyleColor)
161-
this.#router.addPath('/location/:page/:row/:column/style/bgcolor', this.#locationSetStyleBgcolor)
172+
this.#router.addRoute(`/location/${Location}/style/text`, this.#locationSetStyleText)
173+
this.#router.addRoute(`/location/${Location}/style/color`, this.#locationSetStyleColor)
174+
this.#router.addRoute(`/location/${Location}/style/bgcolor`, this.#locationSetStyleBgcolor)
162175

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

166179
// surfaces
167-
this.#router.addPath('/surfaces/rescan', this.#surfacesRescan)
180+
this.#router.addRoute('/surfaces/rescan', this.#surfacesRescan)
168181
}
169182

170183
/**

companion/lib/Service/RegexRouter.ts

+4-21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { pathToRegexp } from 'path-to-regexp'
2-
31
/**
42
* A regex based route
53
*/
@@ -51,25 +49,10 @@ export class RegexRouter {
5149
/**
5250
* Add a route to the router
5351
*/
54-
addRegex(regexp: RegExp, handler: RouteHandler): void {
55-
if (!regexp || !handler) throw new Error('Invalid route parameters')
56-
this.#routes.push({ regexp, handler })
57-
}
58-
59-
/**
60-
* Add a route to the router, using the express style path syntax
61-
*/
62-
addPath(path: string, handler: PathRouteHandler): void {
63-
const { regexp, keys } = pathToRegexp(path)
64-
65-
this.addRegex(regexp, (match, ...args) => {
66-
const values: Record<string, string> = {}
67-
for (let i = 0; i < keys.length; i++) {
68-
const key = keys[i]
69-
values[key.name] = values[key.name] ?? match[i + 1]
70-
}
71-
72-
return handler(values, ...args)
52+
addRoute(route: string, handler: PathRouteHandler): void {
53+
this.#routes.push({
54+
regexp: new RegExp(`^${route}$`, 'i'),
55+
handler: (match, ...args) => handler(match.groups ?? {}, ...args),
7356
})
7457
}
7558
}
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Historic parsing behavior mapped variables to non-'/'-delimiter characters.
2+
// Continue to do so even if matching something more precise would be more
3+
// sensible.
4+
export const Element = '[^/]+?'
5+
6+
export const Page = `(?<page>${Element})`
7+
export const Location = `${Page}/(?<row>${Element})/(?<column>${Element})`
8+
9+
export const Bank = `(?<bank>${Element})`
10+
11+
export const VariableName = `(?<name>${Element})`

0 commit comments

Comments
 (0)