From 842495f010a0eaf60a4a3a5524a5170513bf1e53 Mon Sep 17 00:00:00 2001 From: Joel Wetzell Date: Mon, 23 Mar 2026 12:11:10 -0500 Subject: [PATCH] generate json-schema dynamically in Go --- api.go | 99 +- go.mod | 1 + go.sum | 2 + internal/config/api.go | 28 + internal/config/config.go | 37 +- internal/config/module.go | 7 + internal/config/processor.go | 6 + internal/config/route.go | 29 + internal/module/db-sqlite.go | 14 +- internal/module/http-server.go | 17 +- internal/module/midi-input.go | 15 +- internal/module/midi-output.go | 15 +- internal/module/module.go | 54 +- internal/module/mqtt-client.go | 23 +- internal/module/nats-client.go | 19 +- internal/module/nats-server.go | 25 +- internal/module/psn-client.go | 3 +- internal/module/redis-client.go | 19 +- internal/module/serial-client.go | 19 +- internal/module/sip-call-server.go | 35 +- internal/module/sip-dtmf-server.go | 41 +- internal/module/tcp-client.go | 26 +- internal/module/tcp-server.go | 28 +- internal/module/time-interval.go | 16 +- internal/module/time-timer.go | 16 +- internal/module/udp-client.go | 21 +- internal/module/udp-multicast.go | 21 +- internal/module/udp-server.go | 21 +- internal/processor/artnet-packet-decode.go | 3 +- internal/processor/artnet-packet-encode.go | 3 +- internal/processor/db-query.go | 3 +- internal/processor/debug-log.go | 3 +- internal/processor/filter-change.go | 3 +- internal/processor/filter-expr.go | 15 +- internal/processor/filter-regex.go | 15 +- internal/processor/float-parse.go | 17 +- internal/processor/float-random.go | 26 +- internal/processor/free-d-create.go | 57 +- internal/processor/free-d-decode.go | 3 +- internal/processor/free-d-encode.go | 3 +- internal/processor/http-request-do.go | 20 +- internal/processor/http-response-create.go | 19 +- internal/processor/int-parse.go | 23 +- internal/processor/int-random.go | 19 +- internal/processor/int-scale.go | 27 +- internal/processor/json-decode.go | 3 +- internal/processor/json-encode.go | 3 +- internal/processor/kv-get.go | 19 +- internal/processor/kv-set.go | 23 +- internal/processor/midi-message-create.go | 101 +- internal/processor/midi-message-decode.go | 3 +- internal/processor/midi-message-encode.go | 3 +- internal/processor/midi-message-unpack.go | 3 +- internal/processor/mqtt-message-create.go | 27 +- internal/processor/nats-message-create.go | 19 +- internal/processor/osc-message-create.go | 26 +- internal/processor/osc-message-decode.go | 3 +- internal/processor/osc-message-encode.go | 3 +- internal/processor/processor.go | 50 +- internal/processor/router-input.go | 16 +- internal/processor/router-output.go | 16 +- internal/processor/script-expr.go | 15 +- internal/processor/script-js.go | 19 +- internal/processor/script-wasm.go | 26 +- .../processor/sip-response-audio-create.go | 22 +- .../processor/sip-response-dtmf-create.go | 22 +- internal/processor/string-create.go | 15 +- internal/processor/string-decode.go | 3 +- internal/processor/string-encode.go | 3 +- internal/processor/string-split.go | 15 +- internal/processor/struct-field-get.go | 14 +- internal/processor/struct-method-get.go | 14 +- internal/processor/time-sleep.go | 15 +- schema/config.schema.json | 29 - schema/modules.schema.json | 586 ----------- schema/processors.schema.json | 926 ------------------ schema/routes.schema.json | 20 - 77 files changed, 1319 insertions(+), 1659 deletions(-) create mode 100644 internal/config/api.go create mode 100644 internal/config/module.go create mode 100644 internal/config/processor.go create mode 100644 internal/config/route.go delete mode 100644 schema/config.schema.json delete mode 100644 schema/modules.schema.json delete mode 100644 schema/processors.schema.json delete mode 100644 schema/routes.schema.json diff --git a/api.go b/api.go index 605c051..a6e34bb 100644 --- a/api.go +++ b/api.go @@ -2,22 +2,18 @@ package showbridge import ( "context" - "embed" _ "embed" "encoding/json" "fmt" - "io/fs" "net/http" "time" "github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/module" + "github.com/jwetzell/showbridge-go/internal/processor" "github.com/jwetzell/showbridge-go/internal/route" ) -//go:embed schema -var schema embed.FS - func (r *Router) startAPIServer(config config.ApiConfig) { if !config.Enabled { r.logger.Warn("API not enabled") @@ -27,8 +23,11 @@ func (r *Router) startAPIServer(config config.ApiConfig) { mux := http.NewServeMux() mux.HandleFunc("/ws", r.handleWebsocket) mux.HandleFunc("/health", r.handleHealthHTTP) - mux.Handle("/schema/{schema}", HandleFS(schema)) mux.HandleFunc("/api/v1/config", r.handleConfigHTTP) + mux.HandleFunc("/schema/config.schema.json", handleConfigSchema) + mux.HandleFunc("/schema/routes.schema.json", handleRoutesSchema) + mux.HandleFunc("/schema/modules.schema.json", handleModulesSchema) + mux.HandleFunc("/schema/processors.schema.json", handleProcessorsSchema) r.apiServerMu.Lock() defer r.apiServerMu.Unlock() @@ -131,14 +130,92 @@ func (r *Router) handleConfigHTTP(w http.ResponseWriter, req *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.WriteHeader(http.StatusMethodNotAllowed) } - } -func HandleFS(fs fs.FS) http.HandlerFunc { - handler := http.FileServerFS(fs) - return func(w http.ResponseWriter, req *http.Request) { +func handleConfigSchema(w http.ResponseWriter, req *http.Request) { + switch req.Method { + case http.MethodGet: + schemaJSON, err := json.Marshal(config.ConfigSchema) + if err != nil { + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Content-Type", "application/json") - handler.ServeHTTP(w, req) + w.Write(schemaJSON) + case http.MethodOptions: + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") + w.WriteHeader(http.StatusOK) + default: + w.Header().Set("Access-Control-Allow-Origin", "*") + w.WriteHeader(http.StatusMethodNotAllowed) + } +} + +func handleRoutesSchema(w http.ResponseWriter, req *http.Request) { + switch req.Method { + case http.MethodGet: + schemaJSON, err := json.Marshal(config.RoutesConfigSchema) + if err != nil { + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Content-Type", "application/json") + w.Write(schemaJSON) + case http.MethodOptions: + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") + w.WriteHeader(http.StatusOK) + default: + w.Header().Set("Access-Control-Allow-Origin", "*") + w.WriteHeader(http.StatusMethodNotAllowed) + } +} + +func handleModulesSchema(w http.ResponseWriter, req *http.Request) { + switch req.Method { + case http.MethodGet: + schemaJSON, err := json.Marshal(module.GetModulesSchema()) + if err != nil { + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Content-Type", "application/json") + w.Write(schemaJSON) + case http.MethodOptions: + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") + w.WriteHeader(http.StatusOK) + default: + w.Header().Set("Access-Control-Allow-Origin", "*") + w.WriteHeader(http.StatusMethodNotAllowed) + } +} + +func handleProcessorsSchema(w http.ResponseWriter, req *http.Request) { + switch req.Method { + case http.MethodGet: + schemaJSON, err := json.Marshal(processor.GetProcessorsSchema()) + if err != nil { + http.Error(w, "Internal server error", http.StatusInternalServerError) + return + } + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Content-Type", "application/json") + w.Write(schemaJSON) + case http.MethodOptions: + w.Header().Set("Access-Control-Allow-Origin", "*") + w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS") + w.Header().Set("Access-Control-Allow-Headers", "Content-Type") + w.WriteHeader(http.StatusOK) + default: + w.Header().Set("Access-Control-Allow-Origin", "*") + w.WriteHeader(http.StatusMethodNotAllowed) } } diff --git a/go.mod b/go.mod index 66ab049..887ab95 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/emiago/sipgo v1.2.1 github.com/expr-lang/expr v1.17.8 github.com/extism/go-sdk v1.7.1 + github.com/google/jsonschema-go v0.4.2 github.com/gorilla/websocket v1.5.3 github.com/jwetzell/artnet-go v0.2.1 github.com/jwetzell/free-d-go v0.1.0 diff --git a/go.sum b/go.sum index 362334e..5173bfa 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,8 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/go-tpm v0.9.8 h1:slArAR9Ft+1ybZu0lBwpSmpwhRXaa85hWtMinMyRAWo= github.com/google/go-tpm v0.9.8/go.mod h1:h9jEsEECg7gtLis0upRBQU+GhYVH6jMjrFxI8u6bVUY= +github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbcqoRA8= +github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e h1:ijClszYn+mADRFY17kjQEVQ1XRhq2/JR1M3sGqeJoxs= github.com/google/pprof v0.0.0-20250317173921-a4b03ec1a45e/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= diff --git a/internal/config/api.go b/internal/config/api.go new file mode 100644 index 0000000..43714f7 --- /dev/null +++ b/internal/config/api.go @@ -0,0 +1,28 @@ +package config + +import ( + "encoding/json" + + "github.com/google/jsonschema-go/jsonschema" +) + +type ApiConfig struct { + Enabled bool `json:"enabled"` + Port int `json:"port"` +} + +var ApiConfigSchema = jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "enabled": { + Type: "boolean", + Description: "Whether the API server is enabled", + Default: json.RawMessage(`false`), + }, + "port": { + Type: "integer", + Description: "Port for the API server to listen on", + }, + }, + Required: []string{"port"}, +} diff --git a/internal/config/config.go b/internal/config/config.go index 7e705a2..552078a 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1,27 +1,28 @@ package config +import ( + "github.com/google/jsonschema-go/jsonschema" +) + type Config struct { Api ApiConfig `json:"api"` Modules []ModuleConfig `json:"modules"` Routes []RouteConfig `json:"routes"` } -type ApiConfig struct { - Enabled bool `json:"enabled"` - Port int `json:"port"` -} -type ModuleConfig struct { - Id string `json:"id"` - Type string `json:"type"` - Params Params `json:"params,omitempty"` -} - -type RouteConfig struct { - Input string `json:"input"` - Processors []ProcessorConfig `json:"processors"` -} - -type ProcessorConfig struct { - Type string `json:"type"` - Params Params `json:"params,omitempty"` +var ConfigSchema = jsonschema.Schema{ + Schema: "https://json-schema.org/draft/2020-12/schema", + ID: "https://showbridge.io/config.schema.json", + Title: "Config", + Description: "showbridge configuration", + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "api": &ApiConfigSchema, + "modules": { + Ref: "https://showbridge.io/modules.schema.json", + }, + "routes": { + Ref: "https://showbridge.io/routes.schema.json", + }, + }, } diff --git a/internal/config/module.go b/internal/config/module.go new file mode 100644 index 0000000..ae750e2 --- /dev/null +++ b/internal/config/module.go @@ -0,0 +1,7 @@ +package config + +type ModuleConfig struct { + Id string `json:"id"` + Type string `json:"type"` + Params Params `json:"params,omitempty"` +} diff --git a/internal/config/processor.go b/internal/config/processor.go new file mode 100644 index 0000000..ea75310 --- /dev/null +++ b/internal/config/processor.go @@ -0,0 +1,6 @@ +package config + +type ProcessorConfig struct { + Type string `json:"type"` + Params Params `json:"params,omitempty"` +} diff --git a/internal/config/route.go b/internal/config/route.go new file mode 100644 index 0000000..beaab5a --- /dev/null +++ b/internal/config/route.go @@ -0,0 +1,29 @@ +package config + +import "github.com/google/jsonschema-go/jsonschema" + +type RouteConfig struct { + Input string `json:"input"` + Processors []ProcessorConfig `json:"processors"` +} + +var RoutesConfigSchema = jsonschema.Schema{ + Schema: "https://json-schema.org/draft/2020-12/schema", + ID: "https://showbridge.io/routes.schema.json", + Title: "Routes", + Description: "route configurations", + Type: "array", + Items: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "input": { + Type: "string", + MinLength: jsonschema.Ptr(1), + }, + "processors": { + Ref: "https://showbridge.io/processors.schema.json", + }, + }, + Required: []string{"input"}, + }, +} diff --git a/internal/module/db-sqlite.go b/internal/module/db-sqlite.go index 07f5adb..1be8beb 100644 --- a/internal/module/db-sqlite.go +++ b/internal/module/db-sqlite.go @@ -7,6 +7,7 @@ import ( "fmt" "log/slog" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" @@ -24,7 +25,18 @@ type DbSqlite struct { func init() { RegisterModule(ModuleRegistration{ - Type: "db.sqlite", + Type: "db.sqlite", + Title: "SQLite Database", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "dsn": { + Type: "string", + MinLength: jsonschema.Ptr(1), + }, + }, + Required: []string{"dsn"}, + }, New: func(config config.ModuleConfig) (common.Module, error) { params := config.Params diff --git a/internal/module/http-server.go b/internal/module/http-server.go index 75c20ba..ddb3d36 100644 --- a/internal/module/http-server.go +++ b/internal/module/http-server.go @@ -9,6 +9,7 @@ import ( "net" "net/http" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/processor" @@ -55,7 +56,21 @@ func (hsrw *HTTPServerResponseWriter) Write(data []byte) (int, error) { func init() { RegisterModule(ModuleRegistration{ - Type: "http.server", + Type: "http.server", + Title: "HTTP Server", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "port": { + Title: "Port", + Type: "integer", + Minimum: jsonschema.Ptr[float64](1024), + Maximum: jsonschema.Ptr[float64](65535), + }, + }, + Required: []string{"port"}, + AdditionalProperties: nil, + }, New: func(config config.ModuleConfig) (common.Module, error) { params := config.Params portNum, err := params.GetInt("port") diff --git a/internal/module/midi-input.go b/internal/module/midi-input.go index 5591e20..c875998 100644 --- a/internal/module/midi-input.go +++ b/internal/module/midi-input.go @@ -8,6 +8,7 @@ import ( "fmt" "log/slog" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "gitlab.com/gomidi/midi/v2" @@ -26,7 +27,19 @@ type MIDIInput struct { func init() { RegisterModule(ModuleRegistration{ - Type: "midi.input", + Type: "midi.input", + Title: "MIDI Input", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "port": { + Title: "Port", + Type: "string", + }, + }, + Required: []string{"port"}, + AdditionalProperties: nil, + }, New: func(config config.ModuleConfig) (common.Module, error) { params := config.Params portString, err := params.GetString("port") diff --git a/internal/module/midi-output.go b/internal/module/midi-output.go index 35ec41d..58973e0 100644 --- a/internal/module/midi-output.go +++ b/internal/module/midi-output.go @@ -8,6 +8,7 @@ import ( "fmt" "log/slog" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "gitlab.com/gomidi/midi/v2" @@ -26,7 +27,19 @@ type MIDIOutput struct { func init() { RegisterModule(ModuleRegistration{ - Type: "midi.output", + Type: "midi.output", + Title: "MIDI Output", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "port": { + Title: "Port", + Type: "string", + }, + }, + Required: []string{"port"}, + AdditionalProperties: nil, + }, New: func(config config.ModuleConfig) (common.Module, error) { params := config.Params diff --git a/internal/module/module.go b/internal/module/module.go index 5ed9571..fe6d8e5 100644 --- a/internal/module/module.go +++ b/internal/module/module.go @@ -5,6 +5,7 @@ import ( "log/slog" "sync" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -16,8 +17,11 @@ type ModuleError struct { } type ModuleRegistration struct { - Type string `json:"type"` - New func(config.ModuleConfig) (common.Module, error) + Type string `json:"type"` + Title string `json:"title,omitempty"` + Description string `json:"description,omitempty"` + ParamsSchema *jsonschema.Schema `json:"paramsSchema,omitempty"` + New func(config.ModuleConfig) (common.Module, error) } func RegisterModule(mod ModuleRegistration) { @@ -46,3 +50,49 @@ var ( func CreateLogger(config config.ModuleConfig) *slog.Logger { return slog.Default().With("component", "module", "id", config.Id, "type", config.Type) } + +func GetModulesSchema() *jsonschema.Schema { + moduleRegistryMu.RLock() + defer moduleRegistryMu.RUnlock() + + schema := &jsonschema.Schema{ + Schema: "https://json-schema.org/draft/2020-12/schema", + ID: "https://showbridge.io/modules.schema.json", + Title: "Modules", + Description: "module configurations", + Type: "array", + } + + moduleDefinitionSchemas := []*jsonschema.Schema{} + for _, mod := range ModuleRegistry { + moduleSchema := &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "id": { + Type: "string", + MinLength: jsonschema.Ptr(1), + }, + "type": { + Const: jsonschema.Ptr[any](mod.Type), + }, + }, + Required: []string{"id", "type"}, + AdditionalProperties: nil, + } + if mod.Title != "" { + moduleSchema.Title = mod.Title + } + if mod.Description != "" { + moduleSchema.Description = mod.Description + } + if mod.ParamsSchema != nil { + moduleSchema.Properties["params"] = mod.ParamsSchema + moduleSchema.Required = append(moduleSchema.Required, "params") + } + moduleDefinitionSchemas = append(moduleDefinitionSchemas, moduleSchema) + } + schema.Items = &jsonschema.Schema{ + OneOf: moduleDefinitionSchemas, + } + return schema +} diff --git a/internal/module/mqtt-client.go b/internal/module/mqtt-client.go index 7d373a1..31b8c5e 100644 --- a/internal/module/mqtt-client.go +++ b/internal/module/mqtt-client.go @@ -7,6 +7,7 @@ import ( "log/slog" mqtt "github.com/eclipse/paho.mqtt.golang" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -25,7 +26,27 @@ type MQTTClient struct { func init() { RegisterModule(ModuleRegistration{ - Type: "mqtt.client", + Type: "mqtt.client", + Title: "MQTT Client", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "broker": { + Title: "Broker URL", + Type: "string", + }, + "topic": { + Title: "Topic", + Type: "string", + }, + "clientId": { + Title: "Client ID", + Type: "string", + }, + }, + Required: []string{"broker", "topic", "clientId"}, + AdditionalProperties: nil, + }, New: func(config config.ModuleConfig) (common.Module, error) { params := config.Params brokerString, err := params.GetString("broker") diff --git a/internal/module/nats-client.go b/internal/module/nats-client.go index 3d38367..20e869b 100644 --- a/internal/module/nats-client.go +++ b/internal/module/nats-client.go @@ -5,6 +5,7 @@ import ( "errors" "log/slog" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/processor" @@ -24,7 +25,23 @@ type NATSClient struct { func init() { RegisterModule(ModuleRegistration{ - Type: "nats.client", + Type: "nats.client", + Title: "NATS Client", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "url": { + Title: "NATS Server URL", + Type: "string", + }, + "subject": { + Title: "Subject", + Type: "string", + }, + }, + Required: []string{"url", "subject"}, + AdditionalProperties: nil, + }, New: func(config config.ModuleConfig) (common.Module, error) { params := config.Params urlString, err := params.GetString("url") diff --git a/internal/module/nats-server.go b/internal/module/nats-server.go index 76e0573..d1b714a 100644 --- a/internal/module/nats-server.go +++ b/internal/module/nats-server.go @@ -2,12 +2,14 @@ package module import ( "context" + "encoding/json" "errors" "fmt" "log/slog" "net" "time" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "github.com/nats-io/nats-server/v2/server" @@ -26,7 +28,28 @@ type NATSServer struct { func init() { RegisterModule(ModuleRegistration{ - Type: "nats.server", + Type: "nats.server", + Title: "NATS Server", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "ip": { + Title: "IP", + Type: "string", + Default: json.RawMessage(`"0.0.0.0"`), + }, + "port": { + Title: "Port", + Type: "integer", + Minimum: jsonschema.Ptr[float64](1024), + Maximum: jsonschema.Ptr[float64](65535), + Default: json.RawMessage(`4222`), + }, + }, + Required: []string{}, + + AdditionalProperties: nil, + }, New: func(moduleConfig config.ModuleConfig) (common.Module, error) { params := moduleConfig.Params portNum, err := params.GetInt("port") diff --git a/internal/module/psn-client.go b/internal/module/psn-client.go index 918b64c..ebcec91 100644 --- a/internal/module/psn-client.go +++ b/internal/module/psn-client.go @@ -24,7 +24,8 @@ type PSNClient struct { func init() { RegisterModule(ModuleRegistration{ - Type: "psn.client", + Type: "psn.client", + Title: "PosiStageNet Client", New: func(config config.ModuleConfig) (common.Module, error) { return &PSNClient{config: config, decoder: psn.NewDecoder(), logger: CreateLogger(config)}, nil diff --git a/internal/module/redis-client.go b/internal/module/redis-client.go index 05aee07..54013e6 100644 --- a/internal/module/redis-client.go +++ b/internal/module/redis-client.go @@ -6,6 +6,7 @@ import ( "fmt" "log/slog" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "github.com/redis/go-redis/v9" @@ -24,7 +25,23 @@ type RedisClient struct { func init() { RegisterModule(ModuleRegistration{ - Type: "redis.client", + Type: "redis.client", + Title: "Redis Client", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "host": { + Type: "string", + }, + "port": { + Type: "integer", + Minimum: jsonschema.Ptr[float64](1), + Maximum: jsonschema.Ptr[float64](65535), + }, + }, + Required: []string{"host", "port"}, + AdditionalProperties: nil, + }, New: func(config config.ModuleConfig) (common.Module, error) { params := config.Params hostString, err := params.GetString("host") diff --git a/internal/module/serial-client.go b/internal/module/serial-client.go index ab3b84b..9802fe0 100644 --- a/internal/module/serial-client.go +++ b/internal/module/serial-client.go @@ -9,6 +9,7 @@ import ( "log/slog" "time" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/framer" @@ -29,7 +30,23 @@ type SerialClient struct { func init() { RegisterModule(ModuleRegistration{ - Type: "serial.client", + Type: "serial.client", + Title: "Serial Client", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "port": { + Title: "Port", + Type: "string", + }, + "baudRate": { + Title: "Baud Rate", + Type: "integer", + }, + }, + Required: []string{"port", "baudRate"}, + AdditionalProperties: nil, + }, New: func(config config.ModuleConfig) (common.Module, error) { params := config.Params portString, err := params.GetString("port") diff --git a/internal/module/sip-call-server.go b/internal/module/sip-call-server.go index 1b9ea1d..5c93aaf 100644 --- a/internal/module/sip-call-server.go +++ b/internal/module/sip-call-server.go @@ -2,6 +2,7 @@ package module import ( "context" + "encoding/json" "errors" "fmt" "io" @@ -14,6 +15,7 @@ import ( "github.com/emiago/diago/media" "github.com/emiago/sipgo" "github.com/emiago/sipgo/sip" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/processor" @@ -45,7 +47,38 @@ type sipCallContextKey string func init() { RegisterModule(ModuleRegistration{ - Type: "sip.call.server", + Type: "sip.call.server", + Title: "SIP Call Server", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "ip": { + Title: "IP", + Type: "string", + Default: json.RawMessage(`"0.0.0.0"`), + }, + "port": { + Title: "Port", + Type: "integer", + Minimum: jsonschema.Ptr[float64](1024), + Maximum: jsonschema.Ptr[float64](65535), + Default: json.RawMessage(`5060`), + }, + "transport": { + Title: "Transport", + Type: "string", + Enum: []any{"udp", "tcp", "ws", "udp4", "tcp4"}, + Default: json.RawMessage(`"udp"`), + }, + "userAgent": { + Title: "User Agent", + Type: "string", + Default: json.RawMessage(`"showbridge"`), + }, + }, + Required: []string{}, + AdditionalProperties: nil, + }, New: func(moduleConfig config.ModuleConfig) (common.Module, error) { params := moduleConfig.Params portNum, err := params.GetInt("port") diff --git a/internal/module/sip-dtmf-server.go b/internal/module/sip-dtmf-server.go index 41d6b2d..e562d3f 100644 --- a/internal/module/sip-dtmf-server.go +++ b/internal/module/sip-dtmf-server.go @@ -2,6 +2,7 @@ package module import ( "context" + "encoding/json" "errors" "fmt" "io" @@ -15,6 +16,7 @@ import ( "github.com/emiago/diago/media" "github.com/emiago/sipgo" "github.com/emiago/sipgo/sip" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/processor" @@ -45,7 +47,44 @@ type SIPDTMFCall struct { func init() { RegisterModule(ModuleRegistration{ - Type: "sip.dtmf.server", + Type: "sip.dtmf.server", + Title: "SIP DTMF Server", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "ip": { + Title: "IP", + Type: "string", + Default: json.RawMessage(`"0.0.0.0"`), + }, + "port": { + Title: "Port", + Type: "integer", + Minimum: jsonschema.Ptr[float64](1024), + Maximum: jsonschema.Ptr[float64](65535), + Default: json.RawMessage(`5060`), + }, + "transport": { + Title: "Transport", + Type: "string", + Enum: []any{"udp", "tcp", "ws", "udp4", "tcp4"}, + Default: json.RawMessage(`"udp"`), + }, + "userAgent": { + Title: "User Agent", + Type: "string", + Default: json.RawMessage(`"showbridge"`), + }, + "separator": { + Title: "DTMF Separator", + Type: "string", + MinLength: jsonschema.Ptr(1), + MaxLength: jsonschema.Ptr(1), + }, + }, + Required: []string{"separator"}, + AdditionalProperties: nil, + }, New: func(moduleConfig config.ModuleConfig) (common.Module, error) { params := moduleConfig.Params diff --git a/internal/module/tcp-client.go b/internal/module/tcp-client.go index 6421248..4e759fd 100644 --- a/internal/module/tcp-client.go +++ b/internal/module/tcp-client.go @@ -8,6 +8,7 @@ import ( "net" "time" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/framer" @@ -26,7 +27,30 @@ type TCPClient struct { func init() { RegisterModule(ModuleRegistration{ - Type: "net.tcp.client", + Type: "net.tcp.client", + Title: "TCP Client", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "host": { + Title: "Host", + Type: "string", + }, + "port": { + Title: "Port", + Type: "integer", + Minimum: jsonschema.Ptr[float64](1), + Maximum: jsonschema.Ptr[float64](65535), + }, + "framing": { + Title: "Framing Method", + Type: "string", + Enum: []any{"LF", "CR", "CRLF", "SLIP", "RAW"}, + }, + }, + Required: []string{"host", "port", "framing"}, + AdditionalProperties: nil, + }, New: func(config config.ModuleConfig) (common.Module, error) { params := config.Params hostString, err := params.GetString("host") diff --git a/internal/module/tcp-server.go b/internal/module/tcp-server.go index 2e1e1db..a3e40a7 100644 --- a/internal/module/tcp-server.go +++ b/internal/module/tcp-server.go @@ -2,6 +2,7 @@ package module import ( "context" + "encoding/json" "errors" "fmt" "log/slog" @@ -11,6 +12,7 @@ import ( "syscall" "time" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "github.com/jwetzell/showbridge-go/internal/framer" @@ -32,7 +34,31 @@ type TCPServer struct { func init() { RegisterModule(ModuleRegistration{ - Type: "net.tcp.server", + Type: "net.tcp.server", + Title: "TCP Server", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "ip": { + Title: "IP", + Type: "string", + Default: json.RawMessage(`"0.0.0.0"`), + }, + "port": { + Title: "Port", + Type: "integer", + Minimum: jsonschema.Ptr[float64](1024), + Maximum: jsonschema.Ptr[float64](65535), + }, + "framing": { + Title: "Framing Method", + Type: "string", + Enum: []any{"LF", "CR", "CRLF", "SLIP", "RAW"}, + }, + }, + Required: []string{"port", "framing"}, + AdditionalProperties: nil, + }, New: func(moduleConfig config.ModuleConfig) (common.Module, error) { params := moduleConfig.Params portNum, err := params.GetInt("port") diff --git a/internal/module/time-interval.go b/internal/module/time-interval.go index e79efc5..d531e52 100644 --- a/internal/module/time-interval.go +++ b/internal/module/time-interval.go @@ -7,6 +7,7 @@ import ( "log/slog" "time" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -23,7 +24,20 @@ type TimeInterval struct { func init() { RegisterModule(ModuleRegistration{ - Type: "time.interval", + Type: "time.interval", + Title: "Interval", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "duration": { + Title: "Duration", + Type: "integer", + Description: "Interval duration in milliseconds", + }, + }, + Required: []string{"duration"}, + AdditionalProperties: nil, + }, New: func(config config.ModuleConfig) (common.Module, error) { params := config.Params diff --git a/internal/module/time-timer.go b/internal/module/time-timer.go index 7161e1d..f765013 100644 --- a/internal/module/time-timer.go +++ b/internal/module/time-timer.go @@ -7,6 +7,7 @@ import ( "log/slog" "time" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -23,7 +24,20 @@ type TimeTimer struct { func init() { RegisterModule(ModuleRegistration{ - Type: "time.timer", + Type: "time.timer", + Title: "Timer", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "duration": { + Title: "Duration", + Type: "integer", + Description: "Interval duration in milliseconds", + }, + }, + Required: []string{"duration"}, + AdditionalProperties: nil, + }, New: func(config config.ModuleConfig) (common.Module, error) { params := config.Params diff --git a/internal/module/udp-client.go b/internal/module/udp-client.go index 6fd7185..29e4bd9 100644 --- a/internal/module/udp-client.go +++ b/internal/module/udp-client.go @@ -7,6 +7,7 @@ import ( "log/slog" "net" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -24,7 +25,25 @@ type UDPClient struct { func init() { RegisterModule(ModuleRegistration{ - Type: "net.udp.client", + Type: "net.udp.client", + Title: "UDP Client", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "host": { + Title: "Host", + Type: "string", + }, + "port": { + Title: "Port", + Type: "integer", + Minimum: jsonschema.Ptr[float64](1), + Maximum: jsonschema.Ptr[float64](65535), + }, + }, + Required: []string{"host", "port"}, + AdditionalProperties: nil, + }, New: func(config config.ModuleConfig) (common.Module, error) { params := config.Params hostString, err := params.GetString("host") diff --git a/internal/module/udp-multicast.go b/internal/module/udp-multicast.go index 2aa703b..0353ce0 100644 --- a/internal/module/udp-multicast.go +++ b/internal/module/udp-multicast.go @@ -8,6 +8,7 @@ import ( "net" "time" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -24,7 +25,25 @@ type UDPMulticast struct { func init() { RegisterModule(ModuleRegistration{ - Type: "net.udp.multicast", + Type: "net.udp.multicast", + Title: "UDP Multicast", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "ip": { + Title: "IP", + Type: "string", + }, + "port": { + Title: "Port", + Type: "integer", + Minimum: jsonschema.Ptr[float64](1024), + Maximum: jsonschema.Ptr[float64](65535), + }, + }, + Required: []string{"ip", "port"}, + AdditionalProperties: nil, + }, New: func(moduleConfig config.ModuleConfig) (common.Module, error) { params := moduleConfig.Params ipString, err := params.GetString("ip") diff --git a/internal/module/udp-server.go b/internal/module/udp-server.go index 35888f3..0bea9b9 100644 --- a/internal/module/udp-server.go +++ b/internal/module/udp-server.go @@ -8,6 +8,7 @@ import ( "net" "time" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -24,7 +25,25 @@ type UDPServer struct { func init() { RegisterModule(ModuleRegistration{ - Type: "net.udp.server", + Type: "net.udp.server", + Title: "UDP Server", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "ip": { + Title: "IP", + Type: "string", + }, + "port": { + Title: "Port", + Type: "integer", + Minimum: jsonschema.Ptr[float64](1024), + Maximum: jsonschema.Ptr[float64](65535), + }, + }, + Required: []string{"ip", "port"}, + AdditionalProperties: nil, + }, New: func(moduleConfig config.ModuleConfig) (common.Module, error) { params := moduleConfig.Params portNum, err := params.GetInt("port") diff --git a/internal/processor/artnet-packet-decode.go b/internal/processor/artnet-packet-decode.go index b15990d..692f422 100644 --- a/internal/processor/artnet-packet-decode.go +++ b/internal/processor/artnet-packet-decode.go @@ -40,7 +40,8 @@ func (apd *ArtNetPacketDecode) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "artnet.packet.decode", + Type: "artnet.packet.decode", + Title: "Decode ArtNet Packet", New: func(config config.ProcessorConfig) (Processor, error) { return &ArtNetPacketDecode{config: config}, nil }, diff --git a/internal/processor/artnet-packet-encode.go b/internal/processor/artnet-packet-encode.go index 4bff064..1a22ce7 100644 --- a/internal/processor/artnet-packet-encode.go +++ b/internal/processor/artnet-packet-encode.go @@ -39,7 +39,8 @@ func (ape *ArtNetPacketEncode) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "artnet.packet.encode", + Type: "artnet.packet.encode", + Title: "Encode ArtNet Packet", New: func(config config.ProcessorConfig) (Processor, error) { return &ArtNetPacketEncode{config: config}, nil }, diff --git a/internal/processor/db-query.go b/internal/processor/db-query.go index c29da62..76f01cc 100644 --- a/internal/processor/db-query.go +++ b/internal/processor/db-query.go @@ -104,7 +104,8 @@ func (dq *DbQuery) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "db.query", + Type: "db.query", + Title: "Query Database", New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/debug-log.go b/internal/processor/debug-log.go index 10c442e..9297543 100644 --- a/internal/processor/debug-log.go +++ b/internal/processor/debug-log.go @@ -28,7 +28,8 @@ func (dl *DebugLog) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "debug.log", + Type: "debug.log", + Title: "Debug Log", New: func(config config.ProcessorConfig) (Processor, error) { return &DebugLog{config: config, logger: slog.Default().With("component", "processor", "type", config.Type)}, nil }, diff --git a/internal/processor/filter-change.go b/internal/processor/filter-change.go index 8e36896..9843ce3 100644 --- a/internal/processor/filter-change.go +++ b/internal/processor/filter-change.go @@ -31,7 +31,8 @@ func (fc *FilterChange) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "filter.change", + Type: "filter.change", + Title: "Filter On Change", New: func(config config.ProcessorConfig) (Processor, error) { return &FilterChange{config: config}, nil }, diff --git a/internal/processor/filter-expr.go b/internal/processor/filter-expr.go index 4ccb0de..7b90a37 100644 --- a/internal/processor/filter-expr.go +++ b/internal/processor/filter-expr.go @@ -6,6 +6,7 @@ import ( "github.com/expr-lang/expr" "github.com/expr-lang/expr/vm" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -47,7 +48,19 @@ func (fe *FilterExpr) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "filter.expr", + Type: "filter.expr", + Title: "Filter by Expr expression", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "expression": { + Title: "Expression", + Type: "string", + }, + }, + Required: []string{"expression"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/filter-regex.go b/internal/processor/filter-regex.go index 71018c7..e281242 100644 --- a/internal/processor/filter-regex.go +++ b/internal/processor/filter-regex.go @@ -6,6 +6,7 @@ import ( "fmt" "regexp" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -39,7 +40,19 @@ func (fr *FilterRegex) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "filter.regex", + Type: "filter.regex", + Title: "Filter by Regex", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "pattern": { + Title: "Pattern", + Type: "string", + }, + }, + Required: []string{"pattern"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/float-parse.go b/internal/processor/float-parse.go index b911660..dd3f428 100644 --- a/internal/processor/float-parse.go +++ b/internal/processor/float-parse.go @@ -2,10 +2,12 @@ package processor import ( "context" + "encoding/json" "errors" "fmt" "strconv" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -39,7 +41,20 @@ func (fp *FloatParse) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "float.parse", + Type: "float.parse", + Title: "Parse Float", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "bitSize": { + Title: "Bit Size", + Type: "integer", + Enum: []any{32, 64}, + Default: json.RawMessage("64"), + }, + }, + AdditionalProperties: nil, + }, New: func(moduleConfig config.ProcessorConfig) (Processor, error) { params := moduleConfig.Params diff --git a/internal/processor/float-random.go b/internal/processor/float-random.go index cf43854..ec06d6b 100644 --- a/internal/processor/float-random.go +++ b/internal/processor/float-random.go @@ -2,10 +2,12 @@ package processor import ( "context" + "encoding/json" "errors" "fmt" "math/rand/v2" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -38,7 +40,29 @@ func (fr *FloatRandom) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "float.random", + Type: "float.random", + Title: "Random Float", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "bitSize": { + Title: "Bit Size", + Type: "integer", + Enum: []any{32, 64}, + Default: json.RawMessage("32"), + }, + "min": { + Title: "Minimum", + Type: "number", + }, + "max": { + Title: "Maximum", + Type: "number", + }, + }, + Required: []string{"min", "max"}, + AdditionalProperties: nil, + }, New: func(processorConfig config.ProcessorConfig) (Processor, error) { params := processorConfig.Params diff --git a/internal/processor/free-d-create.go b/internal/processor/free-d-create.go index 619bc2e..90669ff 100644 --- a/internal/processor/free-d-create.go +++ b/internal/processor/free-d-create.go @@ -7,6 +7,7 @@ import ( "strconv" "text/template" + "github.com/google/jsonschema-go/jsonschema" freeD "github.com/jwetzell/free-d-go" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" @@ -205,7 +206,61 @@ func (fc *FreeDCreate) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "freed.create", + Type: "freed.create", + Title: "Create FreeD", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "id": { + Title: "Camera ID", + Type: "string", + }, + "pan": { + Title: "Pan", + Type: "string", + }, + "tilt": { + Title: "Tilt", + Type: "string", + }, + "roll": { + Title: "Roll", + Type: "string", + }, + "posX": { + Title: "Position X", + Type: "string", + }, + "posY": { + Title: "Position Y", + Type: "string", + }, + "posZ": { + Title: "Position Z", + Type: "string", + }, + "zoom": { + Title: "Zoom", + Type: "string", + }, + "focus": { + Title: "Focus", + Type: "string", + }, + }, + Required: []string{ + "id", + "pan", + "tilt", + "roll", + "posX", + "posY", + "posZ", + "zoom", + "focus", + }, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { // TODO(jwetzell): make some params optional diff --git a/internal/processor/free-d-decode.go b/internal/processor/free-d-decode.go index 5c4d8b1..92d4b15 100644 --- a/internal/processor/free-d-decode.go +++ b/internal/processor/free-d-decode.go @@ -37,7 +37,8 @@ func (fd *FreeDDecode) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "freed.decode", + Type: "freed.decode", + Title: "Decode FreeD", New: func(config config.ProcessorConfig) (Processor, error) { return &FreeDDecode{config: config}, nil }, diff --git a/internal/processor/free-d-encode.go b/internal/processor/free-d-encode.go index 994ceed..a0ae34f 100644 --- a/internal/processor/free-d-encode.go +++ b/internal/processor/free-d-encode.go @@ -34,7 +34,8 @@ func (fe *FreeDEncode) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "freed.encode", + Type: "freed.encode", + Title: "Encode FreeD", New: func(config config.ProcessorConfig) (Processor, error) { return &FreeDEncode{config: config}, nil }, diff --git a/internal/processor/http-request-do.go b/internal/processor/http-request-do.go index 9ce0c11..6262390 100644 --- a/internal/processor/http-request-do.go +++ b/internal/processor/http-request-do.go @@ -9,6 +9,7 @@ import ( "text/template" "time" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -70,7 +71,24 @@ func (hrd *HTTPRequestDo) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "http.request.do", + Type: "http.request.do", + Title: "Do HTTP Request", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "method": { + Title: "HTTP Method", + Type: "string", + Enum: []any{"GET", "POST"}, + }, + "url": { + Title: "URL", + Type: "string", + }, + }, + Required: []string{"method", "url"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/http-response-create.go b/internal/processor/http-response-create.go index c01c9b9..2a720f8 100644 --- a/internal/processor/http-response-create.go +++ b/internal/processor/http-response-create.go @@ -6,6 +6,7 @@ import ( "fmt" "text/template" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -44,7 +45,23 @@ func (hrc *HTTPResponseCreate) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "http.response.create", + Type: "http.response.create", + Title: "Create HTTP Response", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "status": { + Title: "Status Code", + Type: "integer", + }, + "body": { + Title: "Body", + Type: "string", + }, + }, + Required: []string{"status", "body"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/int-parse.go b/internal/processor/int-parse.go index 9c5e865..d91a4af 100644 --- a/internal/processor/int-parse.go +++ b/internal/processor/int-parse.go @@ -2,10 +2,12 @@ package processor import ( "context" + "encoding/json" "errors" "fmt" "strconv" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -40,7 +42,26 @@ func (ip *IntParse) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "int.parse", + Type: "int.parse", + Title: "Parse Int", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "base": { + Title: "Base", + Type: "integer", + Enum: []any{0, 2, 8, 10, 16}, + Default: json.RawMessage("10"), + }, + "bitSize": { + Title: "Bit Size", + Type: "integer", + Enum: []any{0, 8, 16, 32, 64}, + Default: json.RawMessage("64"), + }, + }, + AdditionalProperties: nil, + }, New: func(moduleConfig config.ProcessorConfig) (Processor, error) { params := moduleConfig.Params diff --git a/internal/processor/int-random.go b/internal/processor/int-random.go index c324c5b..55825f6 100644 --- a/internal/processor/int-random.go +++ b/internal/processor/int-random.go @@ -6,6 +6,7 @@ import ( "fmt" "math/rand/v2" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -28,7 +29,23 @@ func (ir *IntRandom) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "int.random", + Type: "int.random", + Title: "Random Int", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "min": { + Title: "Minimum", + Type: "integer", + }, + "max": { + Title: "Maximum", + Type: "integer", + }, + }, + Required: []string{"min", "max"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/int-scale.go b/internal/processor/int-scale.go index 1d30ae2..85d3b39 100644 --- a/internal/processor/int-scale.go +++ b/internal/processor/int-scale.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -36,7 +37,31 @@ func (ir *IntScale) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "int.scale", + Type: "int.scale", + Title: "Scale Int", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "inMin": { + Title: "Input Minimum", + Type: "integer", + }, + "inMax": { + Title: "Input Maximum", + Type: "integer", + }, + "outMin": { + Title: "Output Minimum", + Type: "integer", + }, + "outMax": { + Title: "Output Maximum", + Type: "integer", + }, + }, + Required: []string{"inMin", "inMax", "outMin", "outMax"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/json-decode.go b/internal/processor/json-decode.go index 8930537..30c7c46 100644 --- a/internal/processor/json-decode.go +++ b/internal/processor/json-decode.go @@ -46,7 +46,8 @@ func (jd *JsonDecode) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "json.decode", + Type: "json.decode", + Title: "Decode JSON", New: func(config config.ProcessorConfig) (Processor, error) { return &JsonDecode{config: config}, nil }, diff --git a/internal/processor/json-encode.go b/internal/processor/json-encode.go index 696a5d8..56e001d 100644 --- a/internal/processor/json-encode.go +++ b/internal/processor/json-encode.go @@ -38,7 +38,8 @@ func (je *JsonEncode) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "json.encode", + Type: "json.encode", + Title: "Encode JSON", New: func(config config.ProcessorConfig) (Processor, error) { return &JsonEncode{config: config}, nil }, diff --git a/internal/processor/kv-get.go b/internal/processor/kv-get.go index 3ac4d64..fa48576 100644 --- a/internal/processor/kv-get.go +++ b/internal/processor/kv-get.go @@ -6,6 +6,7 @@ import ( "fmt" "log/slog" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -51,7 +52,23 @@ func (kvg *KVGet) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "kv.get", + Type: "kv.get", + Title: "Get Key", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "module": { + Title: "Module ID", + Type: "string", + }, + "key": { + Title: "Key", + Type: "string", + }, + }, + Required: []string{"module", "key"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/kv-set.go b/internal/processor/kv-set.go index 7d77ba1..52e6faf 100644 --- a/internal/processor/kv-set.go +++ b/internal/processor/kv-set.go @@ -8,6 +8,7 @@ import ( "html/template" "log/slog" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -62,7 +63,27 @@ func (kvs *KVSet) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "kv.set", + Type: "kv.set", + Title: "Set Key", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "module": { + Title: "Module ID", + Type: "string", + }, + "key": { + Title: "Key", + Type: "string", + }, + "value": { + Title: "Value", + Type: "string", + }, + }, + Required: []string{"module", "key", "value"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/midi-message-create.go b/internal/processor/midi-message-create.go index 560a21d..a4291be 100644 --- a/internal/processor/midi-message-create.go +++ b/internal/processor/midi-message-create.go @@ -9,6 +9,7 @@ import ( "strconv" "text/template" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "gitlab.com/gomidi/midi/v2" @@ -314,7 +315,105 @@ func newMidiProgramChangeCreate(config config.ProcessorConfig) (Processor, error func init() { RegisterProcessor(ProcessorRegistration{ - Type: "midi.message.create", + Type: "midi.message.create", + Title: "Create MIDI Message", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + OneOf: []*jsonschema.Schema{ + { + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "type": { + Title: "MIDI Message Type", + Type: "string", + Enum: []any{"NoteOn", "noteon", "note_on"}, + }, + "channel": { + Title: "Channel", + Type: "string", + }, + "note": { + Title: "Note", + Type: "string", + }, + "velocity": { + Title: "Velocity", + Type: "string", + }, + }, + Required: []string{"type", "channel", "note", "velocity"}, + AdditionalProperties: nil, + }, + { + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "type": { + Title: "MIDI Message Type", + Type: "string", + Enum: []any{"NoteOff", "noteoff", "note_off"}, + }, + "channel": { + Title: "Channel", + Type: "string", + }, + "note": { + Title: "Note", + Type: "string", + }, + "velocity": { + Title: "Velocity", + Type: "string", + }, + }, + Required: []string{"type", "channel", "note", "velocity"}, + AdditionalProperties: nil, + }, + { + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "type": { + Title: "MIDI Message Type", + Type: "string", + Enum: []any{"ControlChange", "controlchange", "control_change"}, + }, + "channel": { + Title: "Channel", + Type: "string", + }, + "control": { + Title: "Control", + Type: "string", + }, + "value": { + Title: "Value", + Type: "string", + }, + }, + Required: []string{"type", "channel", "control", "value"}, + AdditionalProperties: nil, + }, + { + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "type": { + Title: "MIDI Message Type", + Type: "string", + Enum: []any{"ProgramChange", "programchange", "program_change"}, + }, + "channel": { + Title: "Channel", + Type: "string", + }, + "program": { + Title: "Program", + Type: "string", + }, + }, + Required: []string{"type", "channel", "program"}, + AdditionalProperties: nil, + }, + }, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/midi-message-decode.go b/internal/processor/midi-message-decode.go index fbbd546..a0f87be 100644 --- a/internal/processor/midi-message-decode.go +++ b/internal/processor/midi-message-decode.go @@ -36,7 +36,8 @@ func (mmd *MIDIMessageDecode) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "midi.message.decode", + Type: "midi.message.decode", + Title: "Decode MIDI Message", New: func(config config.ProcessorConfig) (Processor, error) { return &MIDIMessageDecode{config: config}, nil }, diff --git a/internal/processor/midi-message-encode.go b/internal/processor/midi-message-encode.go index 95d0203..3dea40a 100644 --- a/internal/processor/midi-message-encode.go +++ b/internal/processor/midi-message-encode.go @@ -34,7 +34,8 @@ func (mme *MIDIMessageEncode) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "midi.message.encode", + Type: "midi.message.encode", + Title: "Encode MIDI Message", New: func(config config.ProcessorConfig) (Processor, error) { return &MIDIMessageEncode{config: config}, nil }, diff --git a/internal/processor/midi-message-unpack.go b/internal/processor/midi-message-unpack.go index a844e0b..0087303 100644 --- a/internal/processor/midi-message-unpack.go +++ b/internal/processor/midi-message-unpack.go @@ -92,7 +92,8 @@ func (mmu *MIDIMessageUnpack) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "midi.message.unpack", + Type: "midi.message.unpack", + Title: "Unpack MIDI Message", New: func(config config.ProcessorConfig) (Processor, error) { return &MIDIMessageUnpack{config: config}, nil }, diff --git a/internal/processor/mqtt-message-create.go b/internal/processor/mqtt-message-create.go index 5ebb461..b0bf7cf 100644 --- a/internal/processor/mqtt-message-create.go +++ b/internal/processor/mqtt-message-create.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -80,7 +81,31 @@ func (mmc *MQTTMessageCreate) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "mqtt.message.create", + Type: "mqtt.message.create", + Title: "Create MQTT Message", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "topic": { + Title: "Topic", + Type: "string", + }, + "qos": { + Title: "QoS", + Type: "number", + }, + "retained": { + Title: "Retained", + Type: "boolean", + }, + "payload": { + Title: "Payload", + Type: "string", + }, + }, + Required: []string{"topic", "qos", "retained", "payload"}, + AdditionalProperties: nil, + }, New: func(processorConfig config.ProcessorConfig) (Processor, error) { params := processorConfig.Params topicString, err := params.GetString("topic") diff --git a/internal/processor/nats-message-create.go b/internal/processor/nats-message-create.go index 0296405..c7210ae 100644 --- a/internal/processor/nats-message-create.go +++ b/internal/processor/nats-message-create.go @@ -6,6 +6,7 @@ import ( "fmt" "text/template" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -59,7 +60,23 @@ func (nmc *NATSMessageCreate) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "nats.message.create", + Type: "nats.message.create", + Title: "Create NATS Message", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "subject": { + Title: "Subject", + Type: "string", + }, + "payload": { + Title: "Payload", + Type: "string", + }, + }, + Required: []string{"subject", "payload"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params subjectString, err := params.GetString("subject") diff --git a/internal/processor/osc-message-create.go b/internal/processor/osc-message-create.go index 57fb65d..719fbe4 100644 --- a/internal/processor/osc-message-create.go +++ b/internal/processor/osc-message-create.go @@ -9,6 +9,7 @@ import ( "strconv" "text/template" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/osc-go" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" @@ -86,7 +87,30 @@ func (omc *OSCMessageCreate) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "osc.message.create", + Type: "osc.message.create", + Title: "Create OSC Message", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "address": { + Title: "Address", + Type: "string", + }, + "args": { + Title: "Arguments", + Type: "array", + Items: &jsonschema.Schema{ + Type: "string", + }, + }, + "types": { + Title: "Argument Types", + Type: "string", + }, + }, + Required: []string{"address"}, + AdditionalProperties: nil, + }, New: func(processorConfig config.ProcessorConfig) (Processor, error) { params := processorConfig.Params addressString, err := params.GetString("address") diff --git a/internal/processor/osc-message-decode.go b/internal/processor/osc-message-decode.go index f41e8da..3469444 100644 --- a/internal/processor/osc-message-decode.go +++ b/internal/processor/osc-message-decode.go @@ -48,7 +48,8 @@ func (omd *OSCMessageDecode) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "osc.message.decode", + Type: "osc.message.decode", + Title: "Decode OSC Message", New: func(config config.ProcessorConfig) (Processor, error) { return &OSCMessageDecode{config: config}, nil }, diff --git a/internal/processor/osc-message-encode.go b/internal/processor/osc-message-encode.go index 1585d8b..3e57b2d 100644 --- a/internal/processor/osc-message-encode.go +++ b/internal/processor/osc-message-encode.go @@ -32,7 +32,8 @@ func (ome *OSCMessageEncode) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "osc.message.encode", + Type: "osc.message.encode", + Title: "Encode OSC Message", New: func(config config.ProcessorConfig) (Processor, error) { return &OSCMessageEncode{config: config}, nil }, diff --git a/internal/processor/processor.go b/internal/processor/processor.go index 0b15a5d..a4d0562 100644 --- a/internal/processor/processor.go +++ b/internal/processor/processor.go @@ -5,6 +5,7 @@ import ( "fmt" "sync" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -15,8 +16,11 @@ type Processor interface { } type ProcessorRegistration struct { - Type string `json:"type"` - New func(config.ProcessorConfig) (Processor, error) + Type string `json:"type"` + Title string `json:"title,omitempty"` + Description string `json:"description,omitempty"` + ParamsSchema *jsonschema.Schema `json:"paramsSchema,omitempty"` + New func(config.ProcessorConfig) (Processor, error) } func RegisterProcessor(processor ProcessorRegistration) { @@ -41,3 +45,45 @@ var ( processorRegistryMu sync.RWMutex ProcessorRegistry = make(map[string]ProcessorRegistration) ) + +func GetProcessorsSchema() *jsonschema.Schema { + processorRegistryMu.RLock() + defer processorRegistryMu.RUnlock() + + schema := &jsonschema.Schema{ + Schema: "https://json-schema.org/draft/2020-12/schema", + ID: "https://showbridge.io/processors.schema.json", + Title: "Processors", + Description: "processor configurations", + Type: "array", + } + + processorDefinitionSchemas := []*jsonschema.Schema{} + for _, proc := range ProcessorRegistry { + processorSchema := &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "type": { + Const: jsonschema.Ptr[any](proc.Type), + }, + }, + Required: []string{"type"}, + AdditionalProperties: nil, + } + if proc.Title != "" { + processorSchema.Title = proc.Title + } + if proc.Description != "" { + processorSchema.Description = proc.Description + } + if proc.ParamsSchema != nil { + processorSchema.Properties["params"] = proc.ParamsSchema + processorSchema.Required = append(processorSchema.Required, "params") + } + processorDefinitionSchemas = append(processorDefinitionSchemas, processorSchema) + } + schema.Items = &jsonschema.Schema{ + OneOf: processorDefinitionSchemas, + } + return schema +} diff --git a/internal/processor/router-input.go b/internal/processor/router-input.go index 1a86d3d..280a77c 100644 --- a/internal/processor/router-input.go +++ b/internal/processor/router-input.go @@ -6,6 +6,7 @@ import ( "fmt" "log/slog" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -44,7 +45,20 @@ func (ro *RouterInput) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "router.input", + Type: "router.input", + Title: "Router Input", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "source": { + Title: "Source", + Type: "string", + Description: "source to report as to the router", + }, + }, + Required: []string{"source"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/router-output.go b/internal/processor/router-output.go index 3bb4899..c760b23 100644 --- a/internal/processor/router-output.go +++ b/internal/processor/router-output.go @@ -6,6 +6,7 @@ import ( "fmt" "log/slog" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -40,7 +41,20 @@ func (ro *RouterOutput) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "router.output", + Type: "router.output", + Title: "Router Output", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "module": { + Title: "Module ID", + Type: "string", + Description: "ID of module to send output to", + }, + }, + Required: []string{"module"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/script-expr.go b/internal/processor/script-expr.go index 183bf6b..2497913 100644 --- a/internal/processor/script-expr.go +++ b/internal/processor/script-expr.go @@ -6,6 +6,7 @@ import ( "github.com/expr-lang/expr" "github.com/expr-lang/expr/vm" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -36,7 +37,19 @@ func (se *ScriptExpr) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "script.expr", + Type: "script.expr", + Title: "Evaluate Expr Expression", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "expression": { + Title: "Expression", + Type: "string", + }, + }, + Required: []string{"expression"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/script-js.go b/internal/processor/script-js.go index e3ed939..bbd35f1 100644 --- a/internal/processor/script-js.go +++ b/internal/processor/script-js.go @@ -4,6 +4,7 @@ import ( "context" "fmt" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" "modernc.org/quickjs" @@ -21,9 +22,9 @@ func (sj *ScriptJS) Process(ctx context.Context, wrappedPayload common.WrappedPa //NOTE(jwetzell): some weird conversion going on with these types _, isUint8Slice := common.GetAnyAs[[]uint8](wrappedPayload.Payload) - _, isbyteSlice := common.GetAnyAs[[]byte](wrappedPayload.Payload) + _, isByteSlice := common.GetAnyAs[[]byte](wrappedPayload.Payload) - if isUint8Slice || isbyteSlice { + if isUint8Slice || isByteSlice { intSlice, ok := common.GetAnyAsIntSlice(wrappedPayload.Payload) if ok { @@ -93,7 +94,19 @@ func (sj *ScriptJS) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "script.js", + Type: "script.js", + Title: "Run JavaScript", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "program": { + Title: "Program", + Type: "string", + }, + }, + Required: []string{"program"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/script-wasm.go b/internal/processor/script-wasm.go index 4bf48c0..daaa76f 100644 --- a/internal/processor/script-wasm.go +++ b/internal/processor/script-wasm.go @@ -2,10 +2,12 @@ package processor import ( "context" + "encoding/json" "errors" "fmt" extism "github.com/extism/go-sdk" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -50,7 +52,29 @@ func (sw *ScriptWASM) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "script.wasm", + Type: "script.wasm", + Title: "Run WASM Plugin", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "path": { + Title: "Path", + Type: "string", + }, + "function": { + Title: "Function", + Type: "string", + Default: json.RawMessage(`"process"`), + }, + "enableWasi": { + Title: "Enable WASI", + Type: "boolean", + Default: json.RawMessage("false"), + }, + }, + Required: []string{"path"}, + AdditionalProperties: nil, + }, New: func(processorConfig config.ProcessorConfig) (Processor, error) { params := processorConfig.Params diff --git a/internal/processor/sip-response-audio-create.go b/internal/processor/sip-response-audio-create.go index ad883de..91c1dd6 100644 --- a/internal/processor/sip-response-audio-create.go +++ b/internal/processor/sip-response-audio-create.go @@ -6,6 +6,7 @@ import ( "fmt" "text/template" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -51,7 +52,26 @@ func (srac *SipResponseAudioCreate) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "sip.response.audio.create", + Type: "sip.response.audio.create", + Title: "Create SIP Audio Response", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "preWait": { + Title: "Pre Wait (ms)", + Type: "integer", + }, + "postWait": { + Title: "Post Wait (ms)", + Type: "integer", + }, + "audioFile": { + Type: "string", + }, + }, + Required: []string{"preWait", "postWait", "audioFile"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/sip-response-dtmf-create.go b/internal/processor/sip-response-dtmf-create.go index 6d63cbc..a836bf3 100644 --- a/internal/processor/sip-response-dtmf-create.go +++ b/internal/processor/sip-response-dtmf-create.go @@ -8,6 +8,7 @@ import ( "regexp" "text/template" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -59,7 +60,26 @@ func (srdc *SipResponseDTMFCreate) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "sip.response.dtmf.create", + Type: "sip.response.dtmf.create", + Title: "Create SIP DTMF Response", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "preWait": { + Title: "Pre Wait (ms)", + Type: "integer", + }, + "postWait": { + Title: "Post Wait (ms)", + Type: "integer", + }, + "digits": { + Type: "string", + }, + }, + Required: []string{"preWait", "postWait", "digits"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/string-create.go b/internal/processor/string-create.go index 0beddaf..bda5b5f 100644 --- a/internal/processor/string-create.go +++ b/internal/processor/string-create.go @@ -6,6 +6,7 @@ import ( "fmt" "text/template" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -37,7 +38,19 @@ func (sc *StringCreate) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "string.create", + Type: "string.create", + Title: "Create String", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "template": { + Title: "Template", + Type: "string", + }, + }, + Required: []string{"template"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params templateString, err := params.GetString("template") diff --git a/internal/processor/string-decode.go b/internal/processor/string-decode.go index 79bac96..029a309 100644 --- a/internal/processor/string-decode.go +++ b/internal/processor/string-decode.go @@ -33,7 +33,8 @@ func (sd *StringDecode) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "string.decode", + Type: "string.decode", + Title: "Decode String", New: func(config config.ProcessorConfig) (Processor, error) { return &StringDecode{config: config}, nil }, diff --git a/internal/processor/string-encode.go b/internal/processor/string-encode.go index f9b9a56..622e656 100644 --- a/internal/processor/string-encode.go +++ b/internal/processor/string-encode.go @@ -32,7 +32,8 @@ func (se *StringEncode) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "string.encode", + Type: "string.encode", + Title: "Encode String", New: func(config config.ProcessorConfig) (Processor, error) { return &StringEncode{config: config}, nil }, diff --git a/internal/processor/string-split.go b/internal/processor/string-split.go index 96da0a7..5da69a2 100644 --- a/internal/processor/string-split.go +++ b/internal/processor/string-split.go @@ -6,6 +6,7 @@ import ( "fmt" "strings" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -35,7 +36,19 @@ func (ss *StringSplit) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "string.split", + Type: "string.split", + Title: "Split String", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "separator": { + Title: "Separator", + Type: "string", + }, + }, + Required: []string{"separator"}, + AdditionalProperties: nil, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/internal/processor/struct-field-get.go b/internal/processor/struct-field-get.go index b108d25..5052338 100644 --- a/internal/processor/struct-field-get.go +++ b/internal/processor/struct-field-get.go @@ -6,6 +6,7 @@ import ( "fmt" "reflect" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -44,7 +45,18 @@ func (sf *StructFieldGet) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "struct.field.get", + Type: "struct.field.get", + Title: "Get Struct Field", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "name": { + Title: "Field Name", + Type: "string", + }, + }, + Required: []string{"name"}, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params nameString, err := params.GetString("name") diff --git a/internal/processor/struct-method-get.go b/internal/processor/struct-method-get.go index a7be3ba..374d042 100644 --- a/internal/processor/struct-method-get.go +++ b/internal/processor/struct-method-get.go @@ -6,6 +6,7 @@ import ( "fmt" "reflect" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -63,7 +64,18 @@ func (sm *StructMethodGet) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "struct.method.get", + Type: "struct.method.get", + Title: "Get Struct Method", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "name": { + Title: "Method Name", + Type: "string", + }, + }, + Required: []string{"name"}, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params nameString, err := params.GetString("name") diff --git a/internal/processor/time-sleep.go b/internal/processor/time-sleep.go index 4157c5f..4e25377 100644 --- a/internal/processor/time-sleep.go +++ b/internal/processor/time-sleep.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/google/jsonschema-go/jsonschema" "github.com/jwetzell/showbridge-go/internal/common" "github.com/jwetzell/showbridge-go/internal/config" ) @@ -25,7 +26,19 @@ func (ts *TimeSleep) Type() string { func init() { RegisterProcessor(ProcessorRegistration{ - Type: "time.sleep", + Type: "time.sleep", + Title: "Sleep", + ParamsSchema: &jsonschema.Schema{ + Type: "object", + Properties: map[string]*jsonschema.Schema{ + "duration": { + Title: "Duration", + Type: "integer", + Description: "Duration to sleep in milliseconds", + }, + }, + Required: []string{"duration"}, + }, New: func(config config.ProcessorConfig) (Processor, error) { params := config.Params diff --git a/schema/config.schema.json b/schema/config.schema.json deleted file mode 100644 index 74b9c32..0000000 --- a/schema/config.schema.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://showbridge.io/config.schema.json", - "title": "Config", - "description": "showbridge configuration", - "type": "object", - "properties": { - "api": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Whether the API server is enabled" - }, - "port": { - "type": "integer", - "description": "Port for the API server to listen on" - } - }, - "required": ["port"] - }, - "modules": { - "$ref": "https://showbridge.io/modules.schema.json" - }, - "routes": { - "$ref": "https://showbridge.io/routes.schema.json" - } - } -} diff --git a/schema/modules.schema.json b/schema/modules.schema.json deleted file mode 100644 index 38e2b2a..0000000 --- a/schema/modules.schema.json +++ /dev/null @@ -1,586 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://showbridge.io/modules.schema.json", - "title": "Modules", - "description": "module configurations", - "type": "array", - "items": { - "oneOf": [ - { - "type": "object", - "title": "HTTP Server", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "http.server" - }, - "params": { - "type": "object", - "properties": { - "port": { - "title": "Port", - "type": "integer", - "minimum": 1024, - "maximum": 65535 - } - }, - "required": ["port"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Interval", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "time.interval" - }, - "params": { - "type": "object", - "properties": { - "duration": { - "title": "Duration", - "type": "integer", - "description": "Interval duration in milliseconds" - } - }, - "required": ["duration"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Timer", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "time.timer" - }, - "params": { - "type": "object", - "properties": { - "duration": { - "title": "Duration", - "type": "integer", - "description": "Timer duration in milliseconds" - } - }, - "required": ["duration"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "MIDI Input", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "midi.input" - }, - "params": { - "type": "object", - "properties": { - "port": { - "title": "Port", - "type": "string" - } - }, - "required": ["port"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "MIDI Output", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "midi.output" - }, - "params": { - "type": "object", - "properties": { - "port": { - "title": "Port", - "type": "string" - } - }, - "required": ["port"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "MQTT Client", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "mqtt.client" - }, - "params": { - "type": "object", - "properties": { - "broker": { - "title": "Broker URL", - "type": "string" - }, - "topic": { - "title": "Topic", - "type": "string" - }, - "clientId": { - "title": "Client ID", - "type": "string" - } - }, - "required": ["broker", "topic", "clientId"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "NATS Client", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "nats.client" - }, - "params": { - "type": "object", - "properties": { - "url": { - "title": "NATS Server URL", - "type": "string" - }, - "subject": { - "title": "Subject", - "type": "string" - } - }, - "required": ["url", "subject"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "NATS Server", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "nats.server" - }, - "params": { - "type": "object", - "properties": { - "ip": { - "title": "IP", - "type": "string", - "default": "0.0.0.0" - }, - "port": { - "title": "Port", - "type": "integer", - "minimum": 1024, - "maximum": 65535, - "default": 4222 - } - }, - "required": [], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "PSN Client", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "psn.client" - } - }, - "required": ["id", "type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "RedisClientModule", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "redis.client" - }, - "params": { - "type": "object", - "properties": { - "host": { - "type": "string" - }, - "port": { - "type": "integer", - "minimum": 1, - "maximum": 65535 - } - }, - "required": ["host", "port"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Serial Client", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "serial.client" - }, - "params": { - "type": "object", - "properties": { - "port": { - "title": "Port", - "type": "string" - }, - "baudRate": { - "title": "Baud Rate", - "type": "integer" - } - }, - "required": ["port", "baudRate"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "SIP Call Server", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "sip.call.server" - }, - "params": { - "type": "object", - "properties": { - "ip": { - "title": "IP", - "type": "string", - "default": "0.0.0.0" - }, - "port": { - "title": "Port", - "type": "integer", - "minimum": 1024, - "maximum": 65535, - "default": 5060 - }, - "transport": { - "title": "Transport", - "type": "string", - "enum": ["udp", "tcp", "ws", "udp4", "tcp4"], - "default": "udp" - }, - "userAgent": { - "title": "User Agent", - "type": "string", - "default": "showbridge" - } - }, - "required": [], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "SIP DTMF Server", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "sip.dtmf.server" - }, - "params": { - "type": "object", - "properties": { - "ip": { - "title": "IP", - "type": "string", - "default": "0.0.0.0" - }, - "port": { - "title": "Port", - "type": "integer", - "minimum": 1024, - "maximum": 65535, - "default": 5060 - }, - "transport": { - "title": "Transport", - "type": "string", - "enum": ["udp", "tcp", "ws", "udp4", "tcp4"], - "default": "udp" - }, - "userAgent": { - "title": "User Agent", - "type": "string", - "default": "showbridge" - }, - "separator": { - "title": "DTMF Separator", - "type": "string", - "minLength": 1, - "maxLength": 1 - } - }, - "required": ["separator"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "TCP Client", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "net.tcp.client" - }, - "params": { - "type": "object", - "properties": { - "host": { - "title": "Host", - "type": "string" - }, - "port": { - "title": "Port", - "type": "integer", - "minimum": 1, - "maximum": 65535 - }, - "framing": { - "title": "Framing Method", - "type": "string", - "enum": ["LF", "CR", "CRLF", "SLIP", "RAW"] - } - }, - "required": ["host", "port", "framing"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "TCP Server", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "net.tcp.server" - }, - "params": { - "type": "object", - "properties": { - "ip": { - "title": "IP", - "type": "string", - "default": "0.0.0.0" - }, - "port": { - "title": "Port", - "type": "integer", - "minimum": 1024, - "maximum": 65535 - }, - "framing": { - "title": "Framing Method", - "type": "string", - "enum": ["LF", "CR", "CRLF", "SLIP", "RAW"] - } - }, - "required": ["port", "framing"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "UDP Client", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "net.udp.client" - }, - "params": { - "type": "object", - "properties": { - "host": { - "title": "Host", - "type": "string" - }, - "port": { - "title": "Port", - "type": "integer", - "minimum": 1, - "maximum": 65535 - } - }, - "required": ["host", "port"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "UDP Multicast", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "net.udp.multicast" - }, - "params": { - "type": "object", - "properties": { - "ip": { - "title": "IP", - "type": "string" - }, - "port": { - "title": "Port", - "type": "integer", - "minimum": 1024, - "maximum": 65535 - } - }, - "required": ["ip", "port"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "UDP Server", - "properties": { - "id": { - "type": "string", - "minLength": 1 - }, - "type": { - "const": "net.udp.server" - }, - "params": { - "type": "object", - "properties": { - "ip": { - "title": "IP", - "type": "string", - "default": "0.0.0.0" - }, - "port": { - "title": "Port", - "type": "integer", - "minimum": 1024, - "maximum": 65535 - } - }, - "required": ["port"], - "additionalProperties": false - } - }, - "required": ["id", "type", "params"], - "additionalProperties": false - } - ] - } -} diff --git a/schema/processors.schema.json b/schema/processors.schema.json deleted file mode 100644 index 4faee11..0000000 --- a/schema/processors.schema.json +++ /dev/null @@ -1,926 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://showbridge.io/processors.schema.json", - "title": "Processors", - "description": "processor configurations", - "type": "array", - "items": { - "oneOf": [ - { - "type": "object", - "title": "Decode ArtNet Packet", - "properties": { - "type": { - "type": "string", - "const": "artnet.packet.decode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Encode ArtNet Packet", - "properties": { - "type": { - "type": "string", - "const": "artnet.packet.encode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Debug Log", - "properties": { - "type": { - "type": "string", - "const": "debug.log" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Filter by Expr expression", - "properties": { - "type": { - "type": "string", - "const": "filter.expr" - }, - "params": { - "type": "object", - "properties": { - "expression": { - "title": "Expression", - "type": "string" - } - }, - "required": ["expression"], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Filter by Regex", - "properties": { - "type": { - "type": "string", - "const": "filter.regex" - }, - "params": { - "type": "object", - "properties": { - "pattern": { - "title": "Pattern", - "type": "string" - } - }, - "required": ["pattern"], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Filter Unique Values", - "properties": { - "type": { - "type": "string", - "const": "filter.unique" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Parse Float", - "properties": { - "type": { - "type": "string", - "const": "float.parse" - }, - "params": { - "type": "object", - "properties": { - "bitSize": { - "title": "Bit Size", - "type": "integer", - "enum": [32, 64], - "default": 64 - } - }, - "additionalProperties": false - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Create FreeD", - "properties": { - "type": { - "type": "string", - "const": "freed.create" - }, - "params": { - "type": "object", - "properties": { - "id": { - "title": "Camera ID", - "type": "string" - }, - "pan": { - "title": "Pan", - "type": "string" - }, - "tilt": { - "title": "Tilt", - "type": "string" - }, - "roll": { - "title": "Roll", - "type": "string" - }, - "posX": { - "title": "Position X", - "type": "string" - }, - "posY": { - "title": "Position Y", - "type": "string" - }, - "posZ": { - "title": "Position Z", - "type": "string" - }, - "zoom": { - "title": "Zoom", - "type": "string" - }, - "focus": { - "title": "Focus", - "type": "string" - } - }, - "required": [ - "id", - "pan", - "tilt", - "roll", - "posX", - "posY", - "posZ", - "zoom", - "focus" - ], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Decode FreeD", - "properties": { - "type": { - "type": "string", - "const": "freed.decode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Encode FreeD", - "properties": { - "type": { - "type": "string", - "const": "freed.encode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Do HTTP Request", - "properties": { - "type": { - "type": "string", - "const": "http.request.do" - }, - "params": { - "type": "object", - "properties": { - "method": { - "title": "HTTP Method", - "type": "string", - "enum": ["GET", "POST"] - }, - "url": { - "title": "URL", - "type": "string" - } - }, - "required": ["method", "url"], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Create HTTP Response", - "properties": { - "type": { - "type": "string", - "const": "http.response.create" - }, - "params": { - "type": "object", - "properties": { - "status": { - "title": "Status Code", - "type": "integer" - }, - "body": { - "title": "Body", - "type": "string" - } - }, - "required": ["status", "body"], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Parse Int", - "properties": { - "type": { - "type": "string", - "const": "int.parse" - }, - "params": { - "type": "object", - "properties": { - "base": { - "title": "Base", - "type": "integer", - "enum": [0, 2, 8, 10, 16], - "default": 10 - }, - "bitSize": { - "title": "Bit Size", - "type": "integer", - "enum": [0, 8, 16, 32, 64], - "default": 64 - } - }, - "additionalProperties": false - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Random Int", - "properties": { - "type": { - "type": "string", - "const": "int.random" - }, - "params": { - "type": "object", - "properties": { - "min": { - "title": "Minimum", - "type": "integer" - }, - "max": { - "title": "Maximum", - "type": "integer" - } - }, - "required": ["min", "max"], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Scale Int", - "properties": { - "type": { - "type": "string", - "const": "int.scale" - }, - "params": { - "type": "object", - "properties": { - "inMin": { - "title": "Input Minimum", - "type": "integer" - }, - "inMax": { - "title": "Input Maximum", - "type": "integer" - }, - "outMin": { - "title": "Output Minimum", - "type": "integer" - }, - "outMax": { - "title": "Output Maximum", - "type": "integer" - } - }, - "required": ["inMin", "inMax", "outMin", "outMax"], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Decode JSON", - "properties": { - "type": { - "type": "string", - "const": "json.decode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Encode JSON", - "properties": { - "type": { - "type": "string", - "const": "json.encode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Create MIDI Message", - "properties": { - "type": { - "type": "string", - "const": "midi.message.create" - }, - "params": { - "type": "object", - "oneOf": [ - { - "type": "object", - "properties": { - "type": { - "title": "MIDI Message Type", - "type": "string", - "enum": ["NoteOn", "noteon", "note_on"] - }, - "channel": { - "title": "Channel", - "type": "string" - }, - "note": { - "title": "Note", - "type": "string" - }, - "velocity": { - "title": "Velocity", - "type": "string" - } - }, - "required": ["type", "channel", "note", "velocity"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "title": "MIDI Message Type", - "type": "string", - "enum": ["NoteOff", "noteoff", "note_off"] - }, - "channel": { - "title": "Channel", - "type": "string" - }, - "note": { - "title": "Note", - "type": "string" - }, - "velocity": { - "title": "Velocity", - "type": "string" - } - }, - "required": ["type", "channel", "note", "velocity"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "title": "MIDI Message Type", - "type": "string", - "enum": ["ControlChange", "controlchange", "control_change"] - }, - "channel": { - "title": "Channel", - "type": "string" - }, - "control": { - "title": "Control", - "type": "string" - }, - "value": { - "title": "Value", - "type": "string" - } - }, - "required": ["type", "channel", "control", "value"], - "additionalProperties": false - }, - { - "type": "object", - "properties": { - "type": { - "title": "MIDI Message Type", - "type": "string", - "enum": ["ProgramChange", "programchange", "program_change"] - }, - "channel": { - "title": "Channel", - "type": "string" - }, - "program": { - "title": "Program", - "type": "string" - } - }, - "required": ["type", "channel", "program"], - "additionalProperties": false - } - ] - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Decode MIDI Message", - "properties": { - "type": { - "type": "string", - "const": "midi.message.decode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Encode MIDI Message", - "properties": { - "type": { - "type": "string", - "const": "midi.message.encode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Unpack MIDI Message", - "properties": { - "type": { - "type": "string", - "const": "midi.message.unpack" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Create MQTT Message", - "properties": { - "type": { - "type": "string", - "const": "mqtt.message.create" - }, - "params": { - "type": "object", - "properties": { - "topic": { - "title": "Topic", - "type": "string" - }, - "qos": { - "title": "QoS", - "type": "number" - }, - "retained": { - "title": "Retained", - "type": "boolean" - }, - "payload": { - "title": "Payload", - "type": "string" - } - }, - "required": ["topic", "qos", "retained", "payload"], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Encode MQTT Message", - "properties": { - "type": { - "type": "string", - "const": "mqtt.message.encode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Create NATS Message", - "properties": { - "type": { - "type": "string", - "const": "nats.message.create" - }, - "params": { - "type": "object", - "properties": { - "subject": { - "title": "Subject", - "type": "string" - }, - "payload": { - "title": "Payload", - "type": "string" - } - }, - "required": ["subject", "payload"], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Create OSC Message", - "properties": { - "type": { - "type": "string", - "const": "osc.message.create" - }, - "params": { - "type": "object", - "properties": { - "address": { - "title": "Address", - "type": "string" - }, - "args": { - "title": "Arguments", - "type": "array", - "items": { - "type": "string" - } - }, - "types": { - "title": "Argument Types", - "type": "string" - } - }, - "required": ["address"], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Decode OSC Message", - "properties": { - "type": { - "type": "string", - "const": "osc.message.decode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Encode OSC Message", - "properties": { - "type": { - "type": "string", - "const": "osc.message.encode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Router Input", - "properties": { - "type": { - "type": "string", - "const": "router.input" - }, - "params": { - "type": "object", - "properties": { - "source": { - "title": "Source", - "type": "string", - "description": "source to report as to the router" - } - }, - "required": ["source"] - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Router Output", - "properties": { - "type": { - "type": "string", - "const": "router.output" - }, - "params": { - "type": "object", - "properties": { - "module": { - "title": "Module ID", - "type": "string", - "description": "ID of module to send output to" - } - }, - "required": ["module"] - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Evaluate Expr expression", - "properties": { - "type": { - "type": "string", - "const": "script.expr" - }, - "params": { - "type": "object", - "properties": { - "expression": { - "title": "Expression", - "type": "string" - } - }, - "required": ["expression"], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Run JavaScript", - "properties": { - "type": { - "type": "string", - "const": "script.js" - }, - "params": { - "type": "object", - "properties": { - "program": { - "title": "Program", - "type": "string" - } - }, - "required": ["program"], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Run WASM Plugin", - "properties": { - "type": { - "type": "string", - "const": "script.wasm" - }, - "params": { - "type": "object", - "properties": { - "path": { - "title": "Path", - "type": "string" - }, - "function": { - "title": "Function", - "type": "string", - "default": "process" - }, - "enableWasi": { - "title": "Enable WASI", - "type": "boolean", - "default": false - } - }, - "required": ["path"], - "additionalProperties": false - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Create String", - "properties": { - "type": { - "type": "string", - "const": "string.create" - }, - "params": { - "type": "object", - "properties": { - "template": { - "title": "Template", - "type": "string" - } - }, - "required": ["template"] - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Decode String", - "properties": { - "type": { - "type": "string", - "const": "string.decode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Encode String", - "properties": { - "type": { - "type": "string", - "const": "string.encode" - } - }, - "required": ["type"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Split String", - "properties": { - "type": { - "type": "string", - "const": "string.split" - }, - "params": { - "type": "object", - "properties": { - "separator": { - "title": "Separator", - "type": "string" - } - }, - "required": ["separator"] - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Get Struct Field", - "properties": { - "type": { - "type": "string", - "const": "struct.field.get" - }, - "params": { - "type": "object", - "properties": { - "name": { - "title": "Field Name", - "type": "string" - } - }, - "required": ["name"] - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Get Struct Method", - "properties": { - "type": { - "type": "string", - "const": "struct.method.get" - }, - "params": { - "type": "object", - "properties": { - "name": { - "title": "Method Name", - "type": "string" - } - }, - "required": ["name"] - } - }, - "required": ["type", "params"], - "additionalProperties": false - }, - { - "type": "object", - "title": "Sleep", - "properties": { - "type": { - "type": "string", - "const": "time.sleep" - }, - "params": { - "type": "object", - "properties": { - "duration": { - "title": "Duration", - "type": "integer", - "description": "Duration to sleep in milliseconds" - } - }, - "required": ["duration"] - } - }, - "required": ["type", "params"], - "additionalProperties": false - } - ] - } -} diff --git a/schema/routes.schema.json b/schema/routes.schema.json deleted file mode 100644 index 2625090..0000000 --- a/schema/routes.schema.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://showbridge.io/routes.schema.json", - "title": "Routes", - "description": "route configurations", - "type": "array", - "items": { - "type": "object", - "properties": { - "input": { - "type": "string", - "minLength": 1 - }, - "processors": { - "$ref": "https://showbridge.io/processors.schema.json" - } - }, - "required": ["input"] - } -}