Skip to content

Commit 381dbf7

Browse files
committed
fix: variable handling operates on debounced
updates changed: restructured variable definitions to include variable paths fix: variable parsing for non-numerics
1 parent 7645d50 commit 381dbf7

24 files changed

+490
-408
lines changed

src/actions/common.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,9 @@ export function createCommonActions(self: InstanceBaseExt<WingConfig>): Companio
9595
const send = self.connection!.sendCommand.bind(self.connection)
9696
const ensureLoaded = self.stateHandler!.ensureLoaded.bind(self.stateHandler)
9797
const state = self.stateHandler?.state
98+
const logger = self.logger
9899
if (!state) {
99-
self.logger!.error('State handler or state is not available for creating common actions')
100+
logger?.error('State handler or state is not available for creating common actions')
100101
throw new Error('State handler or state is not available')
101102
}
102103
const transitions = self.transitions

src/handlers/connection-handler.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
import osc, { OscMessage } from 'osc'
2-
import { ModuleLogger } from './logger.js'
2+
33
import { EventEmitter } from 'events'
44
import { OSCSomeArguments } from '@companion-module/base'
5+
import { ModuleLogger } from './logger.js'
56

67
/**
78
* Handles OSC UDP connection management, message sending, and event emission for the Behringer Wing module.
89
* Emits 'message', 'error', and 'close' events.
910
*/
1011
export class ConnectionHandler extends EventEmitter {
1112
private osc: osc.UDPPort
12-
private logger?: ModuleLogger
1313
private subscriptionTimer?: NodeJS.Timeout
1414
private subscriptionInterval: number = 9000
15+
private logger?: ModuleLogger
1516

1617
/**
1718
* Create a new ConnectionHandler.
@@ -60,7 +61,8 @@ export class ConnectionHandler extends EventEmitter {
6061
})
6162

6263
this.osc.on('message', (msg: OscMessage) => {
63-
this.logger?.debug(`Received ${JSON.stringify(msg)}`)
64+
const stringValue = (msg.args as osc.MetaArgument[])[0].value
65+
this.logger?.debug(`State updated for ${msg.address}: ${stringValue}`)
6466
this.emit('message', msg)
6567
})
6668

@@ -157,8 +159,7 @@ export class ConnectionHandler extends EventEmitter {
157159
args: args,
158160
}
159161
this.osc.send(command)
160-
// this.osc.send({ address: cmd, args: [] }) // a bit ugly, but needed to keep the desk state up to date in companion
161162
if (preventLog) return
162-
this.logger?.debug(`Sending OSC command: ${JSON.stringify(command)}`)
163+
this.logger?.debug(`Sending OSC command: ${command.address} ${argument ?? ''}`)
163164
}
164165
}

src/handlers/device-detector.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import osc from 'osc'
22
import { WingModel } from '../models/types.js'
3-
import { ModuleLogger } from './logger.js'
43
import { EventEmitter } from 'events'
4+
import { ModuleLogger } from './logger.js'
55

66
export interface DeviceInfo {
77
deviceName: string
@@ -25,8 +25,8 @@ export class WingDeviceDetector extends EventEmitter implements WingDeviceDetect
2525
private osc?: osc.UDPPort
2626
private knownDevices = new Map<string, DeviceInfo>()
2727
private queryTimer: NodeJS.Timeout | undefined
28-
private logger?: ModuleLogger
2928
private noDeviceTimeout: NodeJS.Timeout | undefined
29+
private logger?: ModuleLogger
3030

3131
constructor(logger?: ModuleLogger) {
3232
super()

src/handlers/feedback-handler.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import EventEmitter from 'events'
2-
import { ModuleLogger } from './logger.js'
32
import debounceFn from 'debounce-fn'
43
import { FeedbackId } from '../feedbacks.js'
54
import { OscMessage } from 'osc'
65
import { WingSubscriptions } from '../state/index.js'
6+
import { ModuleLogger } from './logger.js'
77

88
/**
99
* Handles feedback updates based on incoming OSC messages and manages feedback subscriptions.
@@ -12,9 +12,9 @@ import { WingSubscriptions } from '../state/index.js'
1212
export class FeedbackHandler extends EventEmitter {
1313
private readonly messageFeedbacks = new Set<FeedbackId>()
1414
private readonly debounceMessageFeedbacks: () => void
15-
private logger?: ModuleLogger
1615
private pollTimeout?: NodeJS.Timeout
1716
private pollInterval: number = 3000
17+
private logger: ModuleLogger | undefined
1818

1919
subscriptions?: WingSubscriptions
2020

@@ -24,8 +24,8 @@ export class FeedbackHandler extends EventEmitter {
2424
*/
2525
constructor(logger?: ModuleLogger) {
2626
super()
27-
this.logger = logger
2827

28+
this.logger = logger
2929
this.subscriptions = new WingSubscriptions()
3030

3131
this.debounceMessageFeedbacks = debounceFn(
@@ -47,16 +47,17 @@ export class FeedbackHandler extends EventEmitter {
4747
* Process an OSC message and trigger feedback checks if needed.
4848
* @param msg OSC message to process.
4949
*/
50-
processMessage(msg: OscMessage): void {
51-
this.logger?.debug(`Processing message for feedbacks: ${msg.address}`)
52-
53-
const toUpdate = this.subscriptions?.getFeedbacks(msg.address)
54-
if (toUpdate === undefined) {
55-
return
56-
}
57-
if (toUpdate.length > 0) {
58-
toUpdate.forEach((f) => this.messageFeedbacks.add(f))
59-
this.debounceMessageFeedbacks()
50+
processMessage(msgs: Set<OscMessage>): void {
51+
this.logger?.debug(`Processing messages for feedbacks`)
52+
for (const msg of msgs) {
53+
const toUpdate = this.subscriptions?.getFeedbacks(msg.address)
54+
if (toUpdate === undefined) {
55+
return
56+
}
57+
if (toUpdate.length > 0) {
58+
toUpdate.forEach((f) => this.messageFeedbacks.add(f))
59+
this.debounceMessageFeedbacks()
60+
}
6061
}
6162
}
6263

src/handlers/logger.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,22 @@ type LoggerFunction = (level: LogLevel, message: string) => void
88
export class ModuleLogger {
99
private moduleName: string
1010
private loggerFn?: LoggerFunction
11+
private enabled: boolean
1112
debugMode: boolean
1213
timestamps: boolean
1314

1415
/**
1516
* Create a new ModuleLogger.
17+
*
1618
* @param moduleName Name to prefix log messages.
1719
* @param loggerFn Optional custom log function.
18-
* @param debugMode Whether to include source location information in logs.
19-
* @param timestamps Whether to include timestamps in logs.
2020
*/
2121
constructor(moduleName: string, loggerFn?: LoggerFunction) {
2222
this.moduleName = moduleName
2323
this.loggerFn = loggerFn
2424
this.debugMode = false
2525
this.timestamps = false
26+
this.enabled = true
2627
}
2728

2829
/**
@@ -38,6 +39,7 @@ export class ModuleLogger {
3839
* @param message Message to log.
3940
*/
4041
debug(message: string): void {
42+
if (!this.enabled) return
4143
const msg = this.formatMessage(message)
4244
if (this.loggerFn) {
4345
this.loggerFn('debug', `[${this.moduleName}] ${msg}`)
@@ -51,6 +53,7 @@ export class ModuleLogger {
5153
* @param message Message to log.
5254
*/
5355
info(message: string): void {
56+
if (!this.enabled) return
5457
const msg = this.formatMessage(message)
5558
if (this.loggerFn) {
5659
this.loggerFn('info', `[${this.moduleName}] ${msg}`)
@@ -64,6 +67,7 @@ export class ModuleLogger {
6467
* @param message Message to log.
6568
*/
6669
error(message: string): void {
70+
if (!this.enabled) return
6771
const msg = this.formatMessage(message)
6872
if (this.loggerFn) {
6973
this.loggerFn('error', `[${this.moduleName}] ${msg}`)
@@ -77,6 +81,7 @@ export class ModuleLogger {
7781
* @param message Message to log.
7882
*/
7983
warn(message: string): void {
84+
if (!this.enabled) return
8085
const msg = this.formatMessage(message)
8186
if (this.loggerFn) {
8287
this.loggerFn('warn', `[${this.moduleName}] ${msg}`)
@@ -85,6 +90,14 @@ export class ModuleLogger {
8590
}
8691
}
8792

93+
enable(): void {
94+
this.enabled = true
95+
}
96+
97+
disable(): void {
98+
this.enabled = false
99+
}
100+
88101
/**
89102
* Format the message with optional timestamp and source location.
90103
* @private

src/handlers/osc-forwarder.ts

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,22 @@ import { ModuleLogger } from './logger.js'
44

55
export class OscForwarder {
66
private port: osc.UDPPort | undefined
7-
private logger: ModuleLogger
7+
private logger: ModuleLogger | undefined
88

9-
constructor(logger: ModuleLogger) {
9+
constructor(logger?: ModuleLogger) {
1010
this.logger = logger
1111
}
1212

13-
setup(enabled: boolean | undefined, host?: string, port?: number): void {
13+
setup(enabled: boolean | undefined, host?: string, port?: number, logger?: ModuleLogger): void {
1414
this.close()
1515

16+
this.logger = logger
17+
1618
if (!enabled || !host || !port) {
1719
return
1820
}
1921

20-
this.logger.info(`Setting up OSC forwarder to ${host}:${port}`)
22+
this.logger?.info(`Setting up OSC forwarder to ${host}:${port}`)
2123
try {
2224
this.port = new osc.UDPPort({
2325
localAddress: '0.0.0.0',
@@ -28,21 +30,21 @@ export class OscForwarder {
2830
})
2931

3032
this.port.on('error', (err: Error): void => {
31-
this.logger.warn(`OSC Forwarder Error: ${err.message}`)
33+
this.logger?.warn(`OSC Forwarder Error: ${err.message}`)
3234
})
3335

3436
this.port.open()
35-
this.logger.info(`OSC forwarding enabled to ${host}:${port}`)
37+
this.logger?.info(`OSC forwarding enabled to ${host}:${port}`)
3638
} catch (err: any) {
37-
this.logger.error(`Failed to setup OSC forwarder: ${err?.message ?? err}`)
39+
this.logger?.error(`Failed to setup OSC forwarder: ${err?.message ?? err}`)
3840
}
3941
}
4042

4143
send(message: OscMessage): void {
4244
try {
4345
this.port?.send(message)
4446
} catch (err: any) {
45-
this.logger.warn(`OSC forward send failed: ${err?.message ?? err}`)
47+
this.logger?.warn(`OSC forward send failed: ${err?.message ?? err}`)
4648
}
4749
}
4850

src/handlers/state-handler.ts

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
import EventEmitter from 'events'
2-
import { ModuleLogger } from './logger.js'
32
import { ModelSpec } from '../models/types.js'
43
import { WingState } from '../state/index.js'
54
import PQueue from 'p-queue'
65
import osc, { OscMessage } from 'osc'
76
import debounceFn from 'debounce-fn'
7+
import { ModuleLogger } from './logger.js'
88

99
/**
1010
* Manages the internal state of the Behringer Wing, processes OSC messages, and emits state updates.
1111
* Handles request queueing and state synchronization.
1212
*/
1313
export class StateHandler extends EventEmitter {
1414
private model: ModelSpec
15+
private logger: ModuleLogger | undefined
1516
state?: WingState
16-
private logger?: ModuleLogger
1717

1818
private inFlightRequests: { [path: string]: () => void } = {}
1919
private readonly requestQueue: PQueue = new PQueue({
@@ -35,8 +35,8 @@ export class StateHandler extends EventEmitter {
3535
constructor(model: ModelSpec, logger?: ModuleLogger) {
3636
super()
3737
this.model = model
38-
this.state = new WingState(model)
3938
this.logger = logger
39+
this.state = new WingState(model)
4040

4141
this.debounceUpdateCompanion = debounceFn(this.updateCompanionWithState.bind(this), {
4242
wait: 200,
@@ -99,22 +99,27 @@ export class StateHandler extends EventEmitter {
9999
* Process an OSC message, update state, and emit events as needed.
100100
* @param msg OSC message to process.
101101
*/
102-
processMessage(msg: OscMessage): void {
103-
const { address, args } = msg
104-
105-
const wasExpected = !!this.inFlightRequests[msg.address]
106-
if (this.inFlightRequests[msg.address]) {
107-
this.logger?.debug(`Received answer for request ${msg.address}`)
108-
this.inFlightRequests[msg.address]()
109-
delete this.inFlightRequests[msg.address]
110-
}
102+
processMessage(msgs: Set<OscMessage>): void {
103+
for (const msg of msgs) {
104+
const { address, args } = msg
105+
106+
const wasExpected = !!this.inFlightRequests[msg.address]
107+
if (this.inFlightRequests[msg.address]) {
108+
this.logger?.debug(`Received answer for request ${msg.address}`)
109+
this.inFlightRequests[msg.address]()
110+
delete this.inFlightRequests[msg.address]
111+
}
111112

112-
this.state?.set(address, args as osc.MetaArgument[])
113-
this.logger?.debug(`State updated for ${address} with args: ${JSON.stringify(args)}`)
113+
const value = args as osc.MetaArgument[]
114+
this.state?.set(address, value)
114115

115-
const hadStructuralChange = this.updateLists(msg)
116-
if (!wasExpected && hadStructuralChange) {
117-
this.requestUpdate()
116+
const stringValue = value[0].value
117+
this.logger?.debug(`State updated for ${address}: ${stringValue}`)
118+
119+
const hadStructuralChange = this.updateLists(msg)
120+
if (!wasExpected && hadStructuralChange) {
121+
this.requestUpdate()
122+
}
118123
}
119124
}
120125

0 commit comments

Comments
 (0)