Skip to content

Commit

Permalink
feat: shared udp listener bitfocus/companion#2399
Browse files Browse the repository at this point in the history
  • Loading branch information
Julusian committed Feb 17, 2024
1 parent be38363 commit a0022e6
Show file tree
Hide file tree
Showing 5 changed files with 345 additions and 0 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"license": "MIT",
"repository": "https://github.com/bitfocus/companion-module-base",
"scripts": {
"dev": "yarn build:ts --watch",
"build": "yarn build:json-schema && yarn build:ajv-validator && yarn build:ts",
"build:ts": "tsc -p tsconfig.build.json",
"build:json-schema": "json2ts --input assets/manifest.schema.json --output generated/manifest.d.ts",
Expand Down
37 changes: 37 additions & 0 deletions src/host-api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type { CompanionButtonPresetDefinition } from '../module-api/preset.js'
import type { CompanionHTTPRequest, CompanionHTTPResponse } from '../module-api/http.js'
import type { SomeCompanionActionInputField } from '../module-api/action.js'
import type { CompanionVariableValue } from '../module-api/variable.js'
import type { RemoteInfo } from 'dgram'

export interface ModuleToHostEventsV0 {
'log-message': (msg: LogMessageMessage) => never
Expand All @@ -30,6 +31,9 @@ export interface ModuleToHostEventsV0 {
upgradedItems: (msg: UpgradedDataResponseMessage) => void
recordAction: (msg: RecordActionMessage) => never
setCustomVariable: (msg: SetCustomVariableMessage) => never
sharedUdpSocketJoin: (msg: SharedUdpSocketMessageJoin) => string
sharedUdpSocketLeave: (msg: SharedUdpSocketMessageLeave) => void
sharedUdpSocketSend: (msg: SharedUdpSocketMessageSend) => void
}

export interface HostToModuleEventsV0 {
Expand All @@ -47,6 +51,8 @@ export interface HostToModuleEventsV0 {
learnFeedback: (msg: LearnFeedbackMessage) => LearnFeedbackResponseMessage
startStopRecordActions: (msg: StartStopRecordActionsMessage) => void
variablesChanged: (msg: VariablesChangedMessage) => never
sharedUdpSocketMessage: (msg: SharedUdpSocketMessage) => never
sharedUdpSocketError: (msg: SharedUdpSocketError) => never
}

export type EncodeIsVisible<T extends CompanionInputFieldBase> = Omit<T, 'isVisible'> & {
Expand Down Expand Up @@ -273,3 +279,34 @@ export interface SetCustomVariableMessage {
export interface VariablesChangedMessage {
variablesIds: string[]
}

export interface SharedUdpSocketMessageJoin {
family: 'udp4' | 'udp6'
portNumber: number
// TODO - more props?
}
export interface SharedUdpSocketMessageLeave {
handleId: string
}
export interface SharedUdpSocketMessageSend {
handleId: string
message: Buffer

address: string
port: number
}

export interface SharedUdpSocketMessage {
handleId: string
portNumber: number

message: Buffer
source: RemoteInfo
}

export interface SharedUdpSocketError {
handleId: string
portNumber: number

error: Error
}
42 changes: 42 additions & 0 deletions src/module-api/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import type {
SetStatusMessage,
SetVariableDefinitionsMessage,
SetVariableValuesMessage,
SharedUdpSocketError,
SharedUdpSocketMessage,
StartStopRecordActionsMessage,
UpdateActionInstancesMessage,
UpdateConfigAndLabelMessage,
Expand All @@ -43,6 +45,12 @@ import { FeedbackManager } from '../internal/feedback.js'
import type { CompanionHTTPRequest, CompanionHTTPResponse } from './http.js'
import { IpcWrapper } from '../host-api/ipc-wrapper.js'
import { ActionManager } from '../internal/actions.js'
import {
SharedUdpSocket,
SharedUdpSocketImpl,
SharedUdpSocketMessageCallback,
SharedUdpSocketOptions,
} from './shared-udp-socket.js'

export interface InstanceBaseOptions {
/**
Expand All @@ -66,6 +74,7 @@ export abstract class InstanceBase<TConfig> implements InstanceBaseShared<TConfi
readonly #actionManager: ActionManager
readonly #feedbackManager: FeedbackManager

readonly #sharedUdpSocketHandlers = new Map<string, SharedUdpSocketImpl>()
readonly #variableDefinitions = new Map<string, CompanionVariableDefinition>()

readonly #variableValues = new Map<string, CompanionVariableValue>()
Expand Down Expand Up @@ -94,6 +103,8 @@ export abstract class InstanceBase<TConfig> implements InstanceBaseShared<TConfi
`Module instance is being constructed incorrectly. Make sure you aren't trying to do this manually`
)

this.createSharedUdpSocket = this.createSharedUdpSocket.bind(this)

this.#options = {
disableVariableValidation: false,
}
Expand All @@ -113,6 +124,8 @@ export abstract class InstanceBase<TConfig> implements InstanceBaseShared<TConfi
learnFeedback: this._handleLearnFeedback.bind(this),
startStopRecordActions: this._handleStartStopRecordActions.bind(this),
variablesChanged: this._handleVariablesChanged.bind(this),
sharedUdpSocketMessage: this._handleSharedUdpSocketMessage.bind(this),
sharedUdpSocketError: this._handleSharedUdpSocketError.bind(this),
},
(msg) => {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Expand Down Expand Up @@ -321,6 +334,21 @@ export abstract class InstanceBase<TConfig> implements InstanceBaseShared<TConfi
this.#feedbackManager.handleVariablesChanged(msg)
}

private async _handleSharedUdpSocketMessage(msg: SharedUdpSocketMessage): Promise<void> {
for (const socket of this.#sharedUdpSocketHandlers.values()) {
if (socket.handleId === msg.handleId) {
socket.receiveSocketMessage(msg)
}
}
}
private async _handleSharedUdpSocketError(msg: SharedUdpSocketError): Promise<void> {
for (const socket of this.#sharedUdpSocketHandlers.values()) {
if (socket.handleId === msg.handleId) {
socket.receiveSocketError(msg.error)
}
}
}

/**
* Main initialization function called
* once the module is OK to start doing things.
Expand Down Expand Up @@ -661,4 +689,18 @@ export abstract class InstanceBase<TConfig> implements InstanceBaseShared<TConfi
})
)
}

createSharedUdpSocket(options: SharedUdpSocketOptions, callback?: SharedUdpSocketMessageCallback): SharedUdpSocket
createSharedUdpSocket(type: 'udp4' | 'udp6', callback?: SharedUdpSocketMessageCallback): SharedUdpSocket
createSharedUdpSocket(
typeOrOptions: 'udp4' | 'udp6' | SharedUdpSocketOptions,
callback?: SharedUdpSocketMessageCallback
): SharedUdpSocket {
const options: SharedUdpSocketOptions = typeof typeOrOptions === 'string' ? { type: typeOrOptions } : typeOrOptions

const socket = new SharedUdpSocketImpl(this.#ipcWrapper, this.#sharedUdpSocketHandlers, options)
if (callback) socket.on('message', callback)

return socket
}
}
1 change: 1 addition & 0 deletions src/module-api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from './feedback.js'
export * from './http.js'
export * from './input.js'
export * from './preset.js'
export { SharedUdpSocket, SharedUdpSocketEvents } from './shared-udp-socket.js'
export * from './style.js'
export * from './upgrade.js'
export * from './variable.js'
Loading

0 comments on commit a0022e6

Please sign in to comment.