Compare commits
	
		
			No commits in common. "main" and "v0.2" have entirely different histories.
		
	
	
		
	
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,2 @@ | |||||||
| config.yaml | config.yaml | ||||||
| midi-request-trigger | midi-request-trigger | ||||||
| midi-request-trigger.log |  | ||||||
							
								
								
									
										16
									
								
								Dockerfile
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								Dockerfile
									
									
									
									
									
								
							| @ -1,16 +0,0 @@ | |||||||
| FROM golang:1.20 |  | ||||||
| 
 |  | ||||||
| # Build app |  | ||||||
| WORKDIR /app |  | ||||||
| COPY go.mod go.sum ./ |  | ||||||
| RUN go mod download |  | ||||||
| COPY *.go ./ |  | ||||||
| RUN go build -o /midi-request-trigger |  | ||||||
| WORKDIR /app |  | ||||||
| RUN rm -Rf /app; mkdir /etc/midi-request-trigger |  | ||||||
| 
 |  | ||||||
| # Configuration volume |  | ||||||
| VOLUME ["/etc/midi-request-trigger"] |  | ||||||
| 
 |  | ||||||
| # Command |  | ||||||
| CMD ["/midi-request-trigger"] |  | ||||||
							
								
								
									
										94
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										94
									
								
								README.md
									
									
									
									
									
								
							| @ -70,11 +70,7 @@ On MacOS, you can setup a Launch Agent in `~/Library/LaunchAgents/com.mrgeckosme | |||||||
|     <false/> |     <false/> | ||||||
| </dict> | </dict> | ||||||
| </plist> | </plist> | ||||||
| ``` |  | ||||||
| 
 | 
 | ||||||
| For local network connection, you need to code sign your build. |  | ||||||
| ```bash |  | ||||||
| codesign -s - --force --deep /path/to/bin/midi-request-trigger |  | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Start with: | Start with: | ||||||
| @ -114,7 +110,7 @@ On MacOS, there is an IAC Driver that can be enabled in Audio MIDI Setup. | |||||||
| midi_routers: | midi_routers: | ||||||
|   - name: service_notifications |   - name: service_notifications | ||||||
|     device: IAC Driver Bus 1 |     device: IAC Driver Bus 1 | ||||||
|     log_level: 2 |     debug_listener: true | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ### Example note trigger configuration | ### Example note trigger configuration | ||||||
| @ -124,7 +120,7 @@ midi_routers: | |||||||
| midi_routers: | midi_routers: | ||||||
|   - name: service_notifications |   - name: service_notifications | ||||||
|     device: IAC Driver Bus 1 |     device: IAC Driver Bus 1 | ||||||
|     log_level: 2 |     debug_listener: true | ||||||
|     note_triggers: |     note_triggers: | ||||||
|       - channel: 0 |       - channel: 0 | ||||||
|         note: 0 |         note: 0 | ||||||
| @ -140,7 +136,7 @@ midi_routers: | |||||||
| midi_routers: | midi_routers: | ||||||
|   - name: service_notifications |   - name: service_notifications | ||||||
|     device: IAC Driver Bus 1 |     device: IAC Driver Bus 1 | ||||||
|     log_level: 2 |     debug_listener: true | ||||||
|     request_triggers: |     request_triggers: | ||||||
|       - channel: 0 |       - channel: 0 | ||||||
|         note: 0 |         note: 0 | ||||||
| @ -156,7 +152,7 @@ midi_routers: | |||||||
| midi_routers: | midi_routers: | ||||||
|   - name: service_notifications |   - name: service_notifications | ||||||
|     device: IAC Driver Bus 1 |     device: IAC Driver Bus 1 | ||||||
|     log_level: 3 |     debug_listener: true | ||||||
|     note_triggers: |     note_triggers: | ||||||
|       - channel: 0 |       - channel: 0 | ||||||
|         note: 0 |         note: 0 | ||||||
| @ -178,85 +174,5 @@ midi_routers: | |||||||
|         headers: |         headers: | ||||||
|           Content-Type: |           Content-Type: | ||||||
|             - multipart/form-data; boundary=---------------------------888832887744 |             - multipart/form-data; boundary=---------------------------888832887744 | ||||||
| ``` |         debug_request: true | ||||||
| 
 |  | ||||||
| ### Example mqtt config |  | ||||||
| 
 |  | ||||||
| ```yaml |  | ||||||
| --- |  | ||||||
| midi_routers: |  | ||||||
|     - name: Wing Midi Signals |  | ||||||
|       device: WING Port 4 |  | ||||||
|       mqtt: |  | ||||||
|         host: 10.0.0.2 |  | ||||||
|         port: 1883 |  | ||||||
|         client_id: midi_mqtt_bridge |  | ||||||
|         user: mqtt |  | ||||||
|         password: password |  | ||||||
|         topic: midi/behringer_wing |  | ||||||
|       log_level: 4 |  | ||||||
|       note_triggers: |  | ||||||
|         - channel: 0 |  | ||||||
|           note: 1 |  | ||||||
|           match_all_velocities: true |  | ||||||
|           mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val |  | ||||||
|           mqtt_payload: |  | ||||||
|             - "1" |  | ||||||
|         - channel: 0 |  | ||||||
|           note: 2 |  | ||||||
|           match_all_velocities: true |  | ||||||
|           mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val |  | ||||||
|           mqtt_payload: |  | ||||||
|             - "2" |  | ||||||
|         - channel: 0 |  | ||||||
|           note: 3 |  | ||||||
|           match_all_velocities: true |  | ||||||
|           mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val |  | ||||||
|           mqtt_payload: |  | ||||||
|             - "3" |  | ||||||
|         - channel: 0 |  | ||||||
|           note: 4 |  | ||||||
|           match_all_velocities: true |  | ||||||
|           mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val |  | ||||||
|           mqtt_payload: |  | ||||||
|             - "4" |  | ||||||
|         - channel: 0 |  | ||||||
|           note: 5 |  | ||||||
|           match_all_velocities: true |  | ||||||
|           mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val |  | ||||||
|           mqtt_payload: |  | ||||||
|             - "5" |  | ||||||
|         - channel: 0 |  | ||||||
|           note: 6 |  | ||||||
|           match_all_velocities: true |  | ||||||
|           mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val |  | ||||||
|           mqtt_payload: |  | ||||||
|             - "6" |  | ||||||
|         - channel: 0 |  | ||||||
|           note: 7 |  | ||||||
|           match_all_velocities: true |  | ||||||
|           mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val |  | ||||||
|           mqtt_payload: |  | ||||||
|             - "7" |  | ||||||
|         - channel: 0 |  | ||||||
|           note: 8 |  | ||||||
|           match_all_velocities: true |  | ||||||
|           mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/enc/val |  | ||||||
|           mqtt_payload: |  | ||||||
|             - "8" |  | ||||||
|         - channel: 0 |  | ||||||
|           match_all_notes: true |  | ||||||
|           match_all_velocities: true |  | ||||||
|           delay_before: 200ms |  | ||||||
|           mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/bu/val |  | ||||||
|           mqtt_payload: |  | ||||||
|             - "1" |  | ||||||
|         - channel: 0 |  | ||||||
|           match_all_notes: true |  | ||||||
|           match_all_velocities: true |  | ||||||
|           delay_before: 200ms |  | ||||||
|           mqtt_topic: osc/behringer_wing/send/$ctl/user/2/2/bu/val |  | ||||||
|           mqtt_payload: |  | ||||||
|             - "0" |  | ||||||
|           delay_after: 200ms |  | ||||||
| ``` | ``` | ||||||
|  | |||||||
							
								
								
									
										131
									
								
								config.go
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								config.go
									
									
									
									
									
								
							| @ -1,17 +1,13 @@ | |||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"fmt" | 	"log" | ||||||
| 	"io" |  | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/user" | 	"os/user" | ||||||
| 	"path" | 	"path" | ||||||
| 	"path/filepath" | 	"path/filepath" | ||||||
| 	"runtime" |  | ||||||
| 
 | 
 | ||||||
| 	"github.com/kkyr/fig" | 	"github.com/kkyr/fig" | ||||||
| 	log "github.com/sirupsen/logrus" |  | ||||||
| 	"gopkg.in/natefinch/lumberjack.v2" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Configurations relating to HTTP server. | // Configurations relating to HTTP server. | ||||||
| @ -23,127 +19,9 @@ type HTTPConfig struct { | |||||||
| 	Enabled  bool   `fig:"enabled"` | 	Enabled  bool   `fig:"enabled"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Configuration for logging. |  | ||||||
| type LogConfig struct { |  | ||||||
| 	// Limit the log output by the log level. |  | ||||||
| 	Level string `fig:"level" yaml:"level" enum:"debug,info,warn,error" default:"info"` |  | ||||||
| 	// How should the log output be formatted. |  | ||||||
| 	Type string `fig:"type" yaml:"type" enum:"json,console" default:"console"` |  | ||||||
| 	// The outputs that the log should go to. Output of `console` will |  | ||||||
| 	// go to the stderr. An file path, will log to the file. Using `default-file` |  | ||||||
| 	// it'll either save to `/var/log/name.log`, or to the same directory as the |  | ||||||
| 	// executable if the path is not writable, or on Windows. |  | ||||||
| 	Outputs []string `fig:"outputs" yaml:"outputs" default:"console,default-file"` |  | ||||||
| 	// Maximum size of the log file in megabytes before it gets rotated. |  | ||||||
| 	MaxSize int `fig:"max_size" yaml:"max_size" default:"1"` |  | ||||||
| 	// Maximum number of backups to save. |  | ||||||
| 	MaxBackups int `fig:"max_backups" yaml:"max_backups" default:"3"` |  | ||||||
| 	// Maximum number of days to retain old log files. |  | ||||||
| 	MaxAge int `fig:"max_age" yaml:"max_age" default:"0"` |  | ||||||
| 	// Use the logal system time instead of UTC for file names of rotated backups. |  | ||||||
| 	LocalTime *bool `fig:"local_time" yaml:"local_time" default:"true"` |  | ||||||
| 	// Should the rotated logs be compressed. |  | ||||||
| 	Compress *bool `fig:"compress" yaml:"compress" default:"true"` |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Apply log config. |  | ||||||
| func (l *LogConfig) Apply() { |  | ||||||
| 	// Apply level. |  | ||||||
| 	switch l.Level { |  | ||||||
| 	case "debug": |  | ||||||
| 		log.SetLevel(log.DebugLevel) |  | ||||||
| 	case "info": |  | ||||||
| 		log.SetLevel(log.InfoLevel) |  | ||||||
| 	case "warn": |  | ||||||
| 		log.SetLevel(log.WarnLevel) |  | ||||||
| 	default: |  | ||||||
| 		log.SetLevel(log.ErrorLevel) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Apply type. |  | ||||||
| 	switch l.Type { |  | ||||||
| 	case "json": |  | ||||||
| 		log.SetFormatter(&log.JSONFormatter{}) |  | ||||||
| 	default: |  | ||||||
| 		log.SetFormatter(&log.TextFormatter{}) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// Change the outputs. |  | ||||||
| 	var outputs []io.Writer |  | ||||||
| 	for _, output := range l.Outputs { |  | ||||||
| 		// If output is console, add stderr and continue. |  | ||||||
| 		if output == "console" { |  | ||||||
| 			outputs = append(outputs, os.Stderr) |  | ||||||
| 			continue |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// If default-file defined, find the default file. |  | ||||||
| 		if output == "default-file" { |  | ||||||
| 			var f *os.File |  | ||||||
| 			var err error |  | ||||||
| 			var logDir, logPath string |  | ||||||
| 			logName := fmt.Sprintf("%s.log", serviceName) |  | ||||||
| 
 |  | ||||||
| 			// On *nix, `/var/log/` should be default if writable. |  | ||||||
| 			if runtime.GOOS != "windows" { |  | ||||||
| 				logDir = "/var/log" |  | ||||||
| 				logPath = filepath.Join(logDir, logName) |  | ||||||
| 
 |  | ||||||
| 				// Verify we can write to log file. |  | ||||||
| 				f, err = os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			// If we could not open the file, then we should try the executable path. |  | ||||||
| 			if err != nil || f == nil { |  | ||||||
| 				exe, err := os.Executable() |  | ||||||
| 				if err != nil { |  | ||||||
| 					log.Println("Unable to find an writable log path to save log to.") |  | ||||||
| 					continue |  | ||||||
| 				} else { |  | ||||||
| 					logDir = filepath.Dir(exe) |  | ||||||
| 					logPath = filepath.Join(logDir, logName) |  | ||||||
| 
 |  | ||||||
| 					// Verify we can write to log file. |  | ||||||
| 					f, err = os.OpenFile(logPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) |  | ||||||
| 					if err != nil { |  | ||||||
| 						log.Println("Unable to find an writable log path to save log to.") |  | ||||||
| 						continue |  | ||||||
| 					} else { |  | ||||||
| 						f.Close() |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 			} else { |  | ||||||
| 				// Close file. |  | ||||||
| 				f.Close() |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			// Update the config log path. |  | ||||||
| 			output = logPath |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// Setup lumberjack log rotate for the output, and add to the list. |  | ||||||
| 		logFile := &lumberjack.Logger{ |  | ||||||
| 			Filename:   output, |  | ||||||
| 			MaxSize:    l.MaxSize, |  | ||||||
| 			MaxBackups: l.MaxBackups, |  | ||||||
| 			MaxAge:     l.MaxAge, |  | ||||||
| 			LocalTime:  *l.LocalTime, |  | ||||||
| 			Compress:   *l.Compress, |  | ||||||
| 		} |  | ||||||
| 		outputs = append(outputs, logFile) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// If there are outputs, set the outputs. |  | ||||||
| 	if len(outputs) != 0 { |  | ||||||
| 		mw := io.MultiWriter(outputs...) |  | ||||||
| 		log.SetOutput(mw) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Configuration Structure. | // Configuration Structure. | ||||||
| type Config struct { | type Config struct { | ||||||
| 	HTTP        HTTPConfig    `fig:"http"` | 	HTTP        HTTPConfig    `fig:"http"` | ||||||
| 	Log         *LogConfig    `fig:"log" yaml:"log"` |  | ||||||
| 	MidiRouters []*MidiRouter `fig:"midi_routers"` | 	MidiRouters []*MidiRouter `fig:"midi_routers"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -170,7 +48,7 @@ func (a *App) ReadConfig() { | |||||||
| 	} else if _, err := os.Stat(etcConfig); err == nil { | 	} else if _, err := os.Stat(etcConfig); err == nil { | ||||||
| 		configFile = etcConfig | 		configFile = etcConfig | ||||||
| 	} else { | 	} else { | ||||||
| 		log.Println("Unable to find a configuration file.") | 		log.Fatal("Unable to find a configuration file.") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Load the configuration file. | 	// Load the configuration file. | ||||||
| @ -181,7 +59,6 @@ func (a *App) ReadConfig() { | |||||||
| 			Debug:    true, | 			Debug:    true, | ||||||
| 			Enabled:  false, | 			Enabled:  false, | ||||||
| 		}, | 		}, | ||||||
| 		Log: &LogConfig{}, |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Load configuration. | 	// Load configuration. | ||||||
| @ -191,7 +68,6 @@ func (a *App) ReadConfig() { | |||||||
| 		fig.Dirs(filePath), | 		fig.Dirs(filePath), | ||||||
| 	) | 	) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		app.config = config |  | ||||||
| 		log.Printf("Error parsing configuration: %s\n", err) | 		log.Printf("Error parsing configuration: %s\n", err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| @ -204,9 +80,6 @@ func (a *App) ReadConfig() { | |||||||
| 		config.HTTP.Port = app.flags.HTTPPort | 		config.HTTP.Port = app.flags.HTTPPort | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Apply log configs. |  | ||||||
| 	config.Log.Apply() |  | ||||||
| 
 |  | ||||||
| 	// Set global config structure. | 	// Set global config structure. | ||||||
| 	app.config = config | 	app.config = config | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										26
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								go.mod
									
									
									
									
									
								
							| @ -1,27 +1,21 @@ | |||||||
| module github.com/GRMrGecko/midi-request-trigger | module github.com/GRMrGecko/midi-request-trigger | ||||||
| 
 | 
 | ||||||
| go 1.24.2 | go 1.20 | ||||||
| 
 |  | ||||||
| toolchain go1.24.4 |  | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	github.com/eclipse/paho.mqtt.golang v1.5.0 | 	github.com/eclipse/paho.mqtt.golang v1.5.0 | ||||||
| 	github.com/gorilla/handlers v1.5.2 | 	github.com/gorilla/handlers v1.5.1 | ||||||
| 	github.com/gorilla/mux v1.8.1 | 	github.com/gorilla/mux v1.8.0 | ||||||
| 	github.com/kkyr/fig v0.5.0 | 	github.com/kkyr/fig v0.3.2 | ||||||
| 	github.com/sirupsen/logrus v1.9.3 | 	gitlab.com/gomidi/midi/v2 v2.0.30 | ||||||
| 	gitlab.com/gomidi/midi/v2 v2.3.14 |  | ||||||
| 	gopkg.in/natefinch/lumberjack.v2 v2.2.1 |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	github.com/felixge/httpsnoop v1.0.4 // indirect | 	github.com/felixge/httpsnoop v1.0.1 // indirect | ||||||
| 	github.com/gorilla/websocket v1.5.3 // indirect | 	github.com/gorilla/websocket v1.5.3 // indirect | ||||||
| 	github.com/mitchellh/mapstructure v1.5.0 // indirect | 	github.com/mitchellh/mapstructure v1.4.1 // indirect | ||||||
| 	github.com/pelletier/go-toml v1.9.5 // indirect | 	github.com/pelletier/go-toml v1.9.3 // indirect | ||||||
| 	github.com/pelletier/go-toml/v2 v2.2.4 // indirect | 	golang.org/x/net v0.27.0 // indirect | ||||||
| 	golang.org/x/net v0.41.0 // indirect | 	golang.org/x/sync v0.7.0 // indirect | ||||||
| 	golang.org/x/sync v0.15.0 // indirect |  | ||||||
| 	golang.org/x/sys v0.33.0 // indirect |  | ||||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||||
| ) | ) | ||||||
|  | |||||||
							
								
								
									
										38
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								go.sum
									
									
									
									
									
								
							| @ -1,64 +1,26 @@ | |||||||
| github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |  | ||||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= |  | ||||||
| github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |  | ||||||
| github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o= | github.com/eclipse/paho.mqtt.golang v1.5.0 h1:EH+bUVJNgttidWFkLLVKaQPGmkTUfQQqjOsyvMGvD6o= | ||||||
| github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk= | github.com/eclipse/paho.mqtt.golang v1.5.0/go.mod h1:du/2qNQVqJf/Sqs4MEL77kR8QTqANF7XU7Fk0aOTAgk= | ||||||
| github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= | github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ= | ||||||
| github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= | github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= | ||||||
| github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= |  | ||||||
| github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= |  | ||||||
| github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= | github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= | ||||||
| github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= | github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= | ||||||
| github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= |  | ||||||
| github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= |  | ||||||
| github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= | github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= | ||||||
| github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= | github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= | ||||||
| github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= |  | ||||||
| github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= |  | ||||||
| github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= | github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= | ||||||
| github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | ||||||
| github.com/kkyr/fig v0.3.2 h1:+vMj52FL6RJUxeKOBB6JXIMyyi1/2j1ERDrZXjoBjzM= | github.com/kkyr/fig v0.3.2 h1:+vMj52FL6RJUxeKOBB6JXIMyyi1/2j1ERDrZXjoBjzM= | ||||||
| github.com/kkyr/fig v0.3.2/go.mod h1:ItUILF8IIzgZOMhx5xpJ1W/bviQsWRKOwKXfE/tqUoA= | github.com/kkyr/fig v0.3.2/go.mod h1:ItUILF8IIzgZOMhx5xpJ1W/bviQsWRKOwKXfE/tqUoA= | ||||||
| github.com/kkyr/fig v0.5.0 h1:D4ym5MYYScOSgqyx1HYQaqFn9dXKzIuSz8N6SZ4rzqM= |  | ||||||
| github.com/kkyr/fig v0.5.0/go.mod h1:U4Rq/5eUNJ8o5UvOEc9DiXtNf41srOLn2r/BfCyuc58= |  | ||||||
| github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= | github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= | ||||||
| github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= | ||||||
| github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= |  | ||||||
| github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= |  | ||||||
| github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= | github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ= | ||||||
| github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= | github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= | ||||||
| github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= |  | ||||||
| github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= |  | ||||||
| github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4= |  | ||||||
| github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY= |  | ||||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= |  | ||||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |  | ||||||
| github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= |  | ||||||
| github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= |  | ||||||
| github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |  | ||||||
| github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= |  | ||||||
| github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= |  | ||||||
| gitlab.com/gomidi/midi/v2 v2.0.30 h1:RgRYbQeQSab5ZaP1lqRcCTnTSBQroE3CE6V9HgMmOAc= | gitlab.com/gomidi/midi/v2 v2.0.30 h1:RgRYbQeQSab5ZaP1lqRcCTnTSBQroE3CE6V9HgMmOAc= | ||||||
| gitlab.com/gomidi/midi/v2 v2.0.30/go.mod h1:Y6IFFyABN415AYsFMPJb0/43TRIuVYDpGKp2gDYLTLI= | gitlab.com/gomidi/midi/v2 v2.0.30/go.mod h1:Y6IFFyABN415AYsFMPJb0/43TRIuVYDpGKp2gDYLTLI= | ||||||
| gitlab.com/gomidi/midi/v2 v2.3.14 h1:BbTDExFlg0zm90AtyGDdO87jdKjn+eYqeSlSGGpFPzQ= |  | ||||||
| gitlab.com/gomidi/midi/v2 v2.3.14/go.mod h1:jDpP4O4skYi+7iVwt6Zyp18bd2M4hkjtMuw2cmgKgfw= |  | ||||||
| golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= | golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= | ||||||
| golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= | golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= | ||||||
| golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= |  | ||||||
| golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= |  | ||||||
| golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= | golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= | ||||||
| golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= | golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= | ||||||
| golang.org/x/sync v0.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= |  | ||||||
| golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= |  | ||||||
| golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= |  | ||||||
| golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= |  | ||||||
| golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= |  | ||||||
| golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= |  | ||||||
| golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= |  | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||||||
| gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||||||
| gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= |  | ||||||
| gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= |  | ||||||
| gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |  | ||||||
| gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||||||
| gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | ||||||
|  | |||||||
							
								
								
									
										2
									
								
								http.go
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								http.go
									
									
									
									
									
								
							| @ -4,13 +4,13 @@ import ( | |||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
|  | 	"log" | ||||||
| 	"net" | 	"net" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"os" | 	"os" | ||||||
| 
 | 
 | ||||||
| 	"github.com/gorilla/handlers" | 	"github.com/gorilla/handlers" | ||||||
| 	"github.com/gorilla/mux" | 	"github.com/gorilla/mux" | ||||||
| 	log "github.com/sirupsen/logrus" |  | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Basic HTTP server structure. | // Basic HTTP server structure. | ||||||
|  | |||||||
							
								
								
									
										4
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								main.go
									
									
									
									
									
								
							| @ -3,11 +3,11 @@ package main | |||||||
| import ( | import ( | ||||||
| 	"context" | 	"context" | ||||||
| 	"fmt" | 	"fmt" | ||||||
|  | 	"log" | ||||||
| 	"os" | 	"os" | ||||||
| 	"os/signal" | 	"os/signal" | ||||||
| 	"syscall" | 	"syscall" | ||||||
| 
 | 
 | ||||||
| 	log "github.com/sirupsen/logrus" |  | ||||||
| 	"gitlab.com/gomidi/midi/v2" | 	"gitlab.com/gomidi/midi/v2" | ||||||
| 	_ "gitlab.com/gomidi/midi/v2/drivers/rtmididrv" | 	_ "gitlab.com/gomidi/midi/v2/drivers/rtmididrv" | ||||||
| ) | ) | ||||||
| @ -15,7 +15,7 @@ import ( | |||||||
| const ( | const ( | ||||||
| 	serviceName        = "midi-request-trigger" | 	serviceName        = "midi-request-trigger" | ||||||
| 	serviceDescription = "Takes trigger MIDI messages by HTTP or MQTT requests and trigger HTTP or MQTT requests by MIDI messages" | 	serviceDescription = "Takes trigger MIDI messages by HTTP or MQTT requests and trigger HTTP or MQTT requests by MIDI messages" | ||||||
| 	serviceVersion     = "0.4.1" | 	serviceVersion     = "0.2" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // App is the global application structure for communicating between servers and storing information. | // App is the global application structure for communicating between servers and storing information. | ||||||
|  | |||||||
							
								
								
									
										141
									
								
								midiRouter.go
									
									
									
									
									
								
							
							
						
						
									
										141
									
								
								midiRouter.go
									
									
									
									
									
								
							| @ -5,15 +5,14 @@ import ( | |||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
|  | 	"log" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"net/url" | 	"net/url" | ||||||
| 	"regexp" | 	"regexp" | ||||||
| 	"strconv" | 	"strconv" | ||||||
| 	"strings" | 	"strings" | ||||||
| 	"time" |  | ||||||
| 
 | 
 | ||||||
| 	mqtt "github.com/eclipse/paho.mqtt.golang" | 	mqtt "github.com/eclipse/paho.mqtt.golang" | ||||||
| 	log "github.com/sirupsen/logrus" |  | ||||||
| 	"gitlab.com/gomidi/midi/v2" | 	"gitlab.com/gomidi/midi/v2" | ||||||
| 	"gitlab.com/gomidi/midi/v2/drivers" | 	"gitlab.com/gomidi/midi/v2/drivers" | ||||||
| ) | ) | ||||||
| @ -22,10 +21,8 @@ import ( | |||||||
| type LogLevel int | type LogLevel int | ||||||
| 
 | 
 | ||||||
| const ( | const ( | ||||||
| 	// Logs info messages. | 	// Logs only errors. | ||||||
| 	InfoLog LogLevel = iota | 	ErrorLog LogLevel = iota | ||||||
| 	// Log only errors. |  | ||||||
| 	ErrorLog |  | ||||||
| 	// MQTT, HTTP, and MIDI receive logging. | 	// MQTT, HTTP, and MIDI receive logging. | ||||||
| 	ReceiveLog | 	ReceiveLog | ||||||
| 	// MQTT, HTTP, and MIDI send logging. | 	// MQTT, HTTP, and MIDI send logging. | ||||||
| @ -36,7 +33,7 @@ const ( | |||||||
| 
 | 
 | ||||||
| // Provides a string value for a log level. | // Provides a string value for a log level. | ||||||
| func (l LogLevel) String() string { | func (l LogLevel) String() string { | ||||||
| 	return [...]string{"Info", "Error", "Receive", "Send", "Debug"}[l] | 	return [...]string{"Error", "Receive", "Send", "Debug"}[l] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Configurations relating to MQTT connection. | // Configurations relating to MQTT connection. | ||||||
| @ -73,25 +70,20 @@ type MQTTPayload struct { | |||||||
| 
 | 
 | ||||||
| // Triggers that occur from MIDI messages received. | // Triggers that occur from MIDI messages received. | ||||||
| type NoteTrigger struct { | type NoteTrigger struct { | ||||||
|  | 	// If set, every note played will be matched. | ||||||
|  | 	MatchAllNotes bool `fig:"match_all_notes"` | ||||||
| 	// Channel to match. | 	// Channel to match. | ||||||
| 	Channel uint8 `fig:"channel"` | 	Channel uint8 `fig:"channel"` | ||||||
| 	// If we should match all channel values. |  | ||||||
| 	MatchAllChannels bool `fig:"match_all_channels"` |  | ||||||
| 	// Note to match. | 	// Note to match. | ||||||
| 	Note uint8 `fig:"note"` | 	Note uint8 `fig:"note"` | ||||||
| 	// If we should match all note values. |  | ||||||
| 	MatchAllNotes bool `fig:"match_all_notes"` |  | ||||||
| 	// Velocity to match. | 	// Velocity to match. | ||||||
| 	Velocity uint8 `fig:"velocity"` | 	Velocity uint8 `fig:"velocity"` | ||||||
| 	// If we should match all velocity values. | 	// If we should match all velocity values. | ||||||
| 	MatchAllVelocities bool `fig:"match_all_velocities"` | 	MatchAllVelocities bool `fig:"match_all_velocities"` | ||||||
| 	// Allow delaying the request. |  | ||||||
| 	DelayBefore time.Duration `fig:"delay_before"` |  | ||||||
| 	DelayAfter  time.Duration `fig:"deplay_after"` |  | ||||||
| 	// Custom MQTT message. Do not set to ignore MQTT. | 	// Custom MQTT message. Do not set to ignore MQTT. | ||||||
| 	MqttTopic string `fig:"mqtt_topic"` | 	MqttTopic string `fig:"mqtt_topic"` | ||||||
| 	// Nil payload will generate a payload with midi info. | 	// Nil payload will generate a payload with midi info. | ||||||
| 	MqttPayload interface{} `fig:"mqtt_payload"` | 	MqttPayload []interface{} `fig:"mqtt_payload"` | ||||||
| 	// If the HTTP request should includ midi info. | 	// If the HTTP request should includ midi info. | ||||||
| 	MidiInfoInRequest bool `fig:"midi_info_in_request"` | 	MidiInfoInRequest bool `fig:"midi_info_in_request"` | ||||||
| 	// Should SSL requests require a valid certificate. | 	// Should SSL requests require a valid certificate. | ||||||
| @ -128,7 +120,7 @@ type RequestTrigger struct { | |||||||
| type MidiRouter struct { | type MidiRouter struct { | ||||||
| 	// Used for human readable config. | 	// Used for human readable config. | ||||||
| 	Name string `fig:"name"` | 	Name string `fig:"name"` | ||||||
| 	// Midi device to connect, accepts regular expression. | 	// Midi device to connect. | ||||||
| 	Device string `fig:"device"` | 	Device string `fig:"device"` | ||||||
| 	// MQTT Connection if you are to integrate with MQTT. | 	// MQTT Connection if you are to integrate with MQTT. | ||||||
| 	MQTT MQTTConfig `fig:"mqtt"` | 	MQTT MQTTConfig `fig:"mqtt"` | ||||||
| @ -140,19 +132,18 @@ type MidiRouter struct { | |||||||
| 	RequestTriggers []RequestTrigger `fig:"request_triggers"` | 	RequestTriggers []RequestTrigger `fig:"request_triggers"` | ||||||
| 
 | 
 | ||||||
| 	// How much logging. | 	// How much logging. | ||||||
| 	// 0 - Info | 	// 0 - Errors | ||||||
| 	// 1 - Errors | 	// 1 - MQTT and OSC receive logging. | ||||||
| 	// 2 - MQTT, HTTP, and MIDI receive logging. | 	// 2 - MQTT and OSC send logging. | ||||||
| 	// 3 - MQTT, HTTP, and MIDI send logging. | 	// 3 - Debug | ||||||
| 	// 4 - Debug | 	LogLevel LogLevel `yaml:"log_level" json:"log_level"` | ||||||
| 	LogLevel LogLevel `fig:"log_level"` |  | ||||||
| 
 | 
 | ||||||
| 	// Connection to MIDI device. | 	// Connection to MIDI device. | ||||||
| 	MidiOut drivers.Out `fig:"-"` | 	MidiOut drivers.Out `fig:"-"` | ||||||
| 	// Function to stop listening to MIDI device. | 	// Function to stop listening to MIDI device. | ||||||
| 	ListenerStop func() `fig:"-"` | 	ListenerStop func() `fig:"-"` | ||||||
| 	// The client connection to MQTT. | 	// The client connection to MQTT. | ||||||
| 	MqttClient mqtt.Client `fig:"-"` | 	MqttClient mqtt.Client `yaml:"-" json:"-"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Logging function to allow log levels. | // Logging function to allow log levels. | ||||||
| @ -165,7 +156,7 @@ func (r *MidiRouter) Log(level LogLevel, format string, args ...interface{}) { | |||||||
| // When a MIDI message occurs, send the HTTP request. | // When a MIDI message occurs, send the HTTP request. | ||||||
| func (r *MidiRouter) sendRequest(channel, note, velocity uint8) { | func (r *MidiRouter) sendRequest(channel, note, velocity uint8) { | ||||||
| 	// If MQTT firehose not disabled, send to general cmd topic. | 	// If MQTT firehose not disabled, send to general cmd topic. | ||||||
| 	if r.MqttClient != nil && !r.MQTT.DisableMidiFirehose { | 	if r.MQTT.Host != "" && r.MQTT.Port != 0 && !r.MQTT.DisableMidiFirehose { | ||||||
| 		payload := MQTTPayload{ | 		payload := MQTTPayload{ | ||||||
| 			Channel:  channel, | 			Channel:  channel, | ||||||
| 			Note:     note, | 			Note:     note, | ||||||
| @ -177,7 +168,7 @@ func (r *MidiRouter) sendRequest(channel, note, velocity uint8) { | |||||||
| 		} else { | 		} else { | ||||||
| 			topic := r.MQTT.Topic + "/cmd" | 			topic := r.MQTT.Topic + "/cmd" | ||||||
| 			r.MqttClient.Publish(topic, 0, true, data) | 			r.MqttClient.Publish(topic, 0, true, data) | ||||||
| 			r.Log(SendLog, "-> [MQTT] %s: %s", topic, string(data)) | 			r.Log(SendLog, "-> [MQTT] %s", topic) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -186,26 +177,15 @@ func (r *MidiRouter) sendRequest(channel, note, velocity uint8) { | |||||||
| 		// If match all notes, process this request. | 		// If match all notes, process this request. | ||||||
| 		// If not, check if channel, note, and velocity matches. | 		// If not, check if channel, note, and velocity matches. | ||||||
| 		// The velocity may be defined to accept all. | 		// The velocity may be defined to accept all. | ||||||
| 		if (trig.Channel == channel || trig.MatchAllChannels) && (trig.Note == note || trig.MatchAllNotes) && (trig.Velocity == velocity || trig.MatchAllVelocities) { | 		if trig.MatchAllNotes || (trig.Channel == channel && trig.Note == note && (trig.Velocity == velocity || trig.MatchAllVelocities)) { | ||||||
| 			// For all logging, we want to print the message so setup a common string to print. | 			// For all logging, we want to print the message so setup a common string to print. | ||||||
| 			logInfo := fmt.Sprintf("note %s(%d) on channel %v with velocity %v", midi.Note(note), note, channel, velocity) | 			logInfo := fmt.Sprintf("note %s(%d) on channel %v with velocity %v", midi.Note(note), note, channel, velocity) | ||||||
| 
 | 
 | ||||||
| 			// Delay before. | 			if trig.MqttTopic != "" { | ||||||
| 			time.Sleep(trig.DelayBefore) |  | ||||||
| 
 |  | ||||||
| 			// If MQTT trigger, send the MQTT request. |  | ||||||
| 			if trig.MqttTopic != "" && r.MqttClient != nil { |  | ||||||
| 				// If payload provided, send the defined payload. |  | ||||||
| 				if trig.MqttPayload != nil { | 				if trig.MqttPayload != nil { | ||||||
| 					data, err := json.Marshal(trig.MqttPayload) | 					r.MqttClient.Publish(trig.MqttTopic, 0, true, trig.MqttPayload) | ||||||
| 					if err != nil { | 					r.Log(SendLog, "-> [MQTT] %s", trig.MqttTopic) | ||||||
| 						r.Log(ErrorLog, "Json Encode: %s", err) |  | ||||||
| 				} else { | 				} else { | ||||||
| 						r.MqttClient.Publish(trig.MqttTopic, 0, true, data) |  | ||||||
| 						r.Log(SendLog, "-> [MQTT] %s: %s", trig.MqttTopic, string(data)) |  | ||||||
| 					} |  | ||||||
| 				} else { |  | ||||||
| 					// If no payload provided, send the note information as JSON. |  | ||||||
| 					payload := MQTTPayload{ | 					payload := MQTTPayload{ | ||||||
| 						Channel:  channel, | 						Channel:  channel, | ||||||
| 						Note:     note, | 						Note:     note, | ||||||
| @ -216,12 +196,11 @@ func (r *MidiRouter) sendRequest(channel, note, velocity uint8) { | |||||||
| 						r.Log(ErrorLog, "Json Encode: %s", err) | 						r.Log(ErrorLog, "Json Encode: %s", err) | ||||||
| 					} else { | 					} else { | ||||||
| 						r.MqttClient.Publish(trig.MqttTopic, 0, true, data) | 						r.MqttClient.Publish(trig.MqttTopic, 0, true, data) | ||||||
| 						r.Log(SendLog, "-> [MQTT] %s: %s", trig.MqttTopic, string(data)) | 						r.Log(SendLog, "-> [MQTT] %s", trig.MqttTopic) | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			// If URL trigger defined, perform a HTTP request. |  | ||||||
| 			if trig.URL != "" { | 			if trig.URL != "" { | ||||||
| 				// Default method to GET if nothing is defined. | 				// Default method to GET if nothing is defined. | ||||||
| 				if trig.Method == "" { | 				if trig.Method == "" { | ||||||
| @ -290,9 +269,6 @@ func (r *MidiRouter) sendRequest(channel, note, velocity uint8) { | |||||||
| 					r.Log(DebugLog, "Trigger response: %s\n%s", logInfo, string(body)) | 					r.Log(DebugLog, "Trigger response: %s\n%s", logInfo, string(body)) | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 
 |  | ||||||
| 			// Delay after. |  | ||||||
| 			time.Sleep(trig.DelayAfter) |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -479,60 +455,24 @@ func (r *MidiRouter) MqttSubscribe(topic string) { | |||||||
| func (r *MidiRouter) Connect() { | func (r *MidiRouter) Connect() { | ||||||
| 	// If request triggers defined, find the out port. | 	// If request triggers defined, find the out port. | ||||||
| 	if len(r.RequestTriggers) != 0 { | 	if len(r.RequestTriggers) != 0 { | ||||||
| 		go func() { | 		out, err := midi.FindOutPort(r.Device) | ||||||
| 			deviceRx, err := regexp.Compile(r.Device) |  | ||||||
| 		if err != nil { | 		if err != nil { | ||||||
| 				log.Printf("Failed to compile regexp of '%s': %v", r.Device, err) | 			log.Println("Can't find output device:", r.Device) | ||||||
| 			} |  | ||||||
| 			for { |  | ||||||
| 				var out drivers.Out |  | ||||||
| 				for _, device := range midi.GetOutPorts() { |  | ||||||
| 					if deviceRx.MatchString(device.String()) { |  | ||||||
| 						err = device.Open() |  | ||||||
| 						out = device |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				if out == nil { |  | ||||||
| 					err = fmt.Errorf("unable to find matching device") |  | ||||||
| 				} |  | ||||||
| 				if err != nil { |  | ||||||
| 					r.Log(ErrorLog, "Failed to find output device '%s': %v", r.Device, err) |  | ||||||
| 		} else { | 		} else { | ||||||
| 			r.MidiOut = out | 			r.MidiOut = out | ||||||
| 					break |  | ||||||
| 		} | 		} | ||||||
| 
 |  | ||||||
| 				r.Log(ErrorLog, "Retrying in 1 minute.") |  | ||||||
| 				time.Sleep(time.Minute) |  | ||||||
| 	} | 	} | ||||||
| 		}() |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// If listener is disabled, stop here. | 	// If listener is disabled, stop here. | ||||||
| 	if !r.DisableListener { | 	if r.DisableListener { | ||||||
| 		go func() { | 		return | ||||||
| 			deviceRx, err := regexp.Compile(r.Device) |  | ||||||
| 			if err != nil { |  | ||||||
| 				log.Printf("Failed to compile regexp of '%s': %v", r.Device, err) |  | ||||||
| 	} | 	} | ||||||
| 			for { | 
 | ||||||
| 	// Try finding input port. | 	// Try finding input port. | ||||||
| 				r.Log(InfoLog, "Connecting to input device: %s", r.Device) | 	log.Println("Connecting to device:", r.Device) | ||||||
| 				var in drivers.In | 	in, err := midi.FindInPort(r.Device) | ||||||
| 				for _, device := range midi.GetInPorts() { |  | ||||||
| 					if deviceRx.MatchString(device.String()) { |  | ||||||
| 						err = device.Open() |  | ||||||
| 						in = device |  | ||||||
| 					} |  | ||||||
| 				} |  | ||||||
| 				if in == nil { |  | ||||||
| 					err = fmt.Errorf("unable to find matching device") |  | ||||||
| 				} |  | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 					r.Log(ErrorLog, "Can't find input device '%s': %v", r.Device, err) | 		log.Println("Can't find device:", r.Device) | ||||||
| 					r.Log(ErrorLog, "Retrying in 1 minute.") | 		return | ||||||
| 					time.Sleep(time.Minute) |  | ||||||
| 					continue |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Start listening to MIDI messages. | 	// Start listening to MIDI messages. | ||||||
| @ -556,22 +496,13 @@ func (r *MidiRouter) Connect() { | |||||||
| 	}) | 	}) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		r.Log(ErrorLog, "Error listening to device: %s", err) | 		r.Log(ErrorLog, "Error listening to device: %s", err) | ||||||
| 					r.Log(ErrorLog, "Retrying in 1 minute.") | 		return | ||||||
| 					time.Sleep(time.Minute) |  | ||||||
| 					continue |  | ||||||
| 	} | 	} | ||||||
| 				r.Log(InfoLog, "Connected to input device: %s", r.Device) |  | ||||||
| 
 | 
 | ||||||
| 	// Update stop function for disconnects. | 	// Update stop function for disconnects. | ||||||
| 	r.ListenerStop = stop | 	r.ListenerStop = stop | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		}() |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	if r.MQTT.Host != "" && r.MQTT.Port != 0 { | 	if r.MQTT.Host != "" && r.MQTT.Port != 0 { | ||||||
| 		go func() { |  | ||||||
| 			for { |  | ||||||
| 		// Connect to MQTT. | 		// Connect to MQTT. | ||||||
| 		mqtt_opts := mqtt.NewClientOptions() | 		mqtt_opts := mqtt.NewClientOptions() | ||||||
| 		mqtt_opts.AddBroker(fmt.Sprintf("tcp://%s:%d", r.MQTT.Host, r.MQTT.Port)) | 		mqtt_opts.AddBroker(fmt.Sprintf("tcp://%s:%d", r.MQTT.Host, r.MQTT.Port)) | ||||||
| @ -584,9 +515,7 @@ func (r *MidiRouter) Connect() { | |||||||
| 		r.Log(DebugLog, "Connecting to MQTT") | 		r.Log(DebugLog, "Connecting to MQTT") | ||||||
| 		if t := r.MqttClient.Connect(); t.Wait() && t.Error() != nil { | 		if t := r.MqttClient.Connect(); t.Wait() && t.Error() != nil { | ||||||
| 			log.Fatalf("MQTT error: %s", t.Error()) | 			log.Fatalf("MQTT error: %s", t.Error()) | ||||||
| 					r.Log(ErrorLog, "Retrying in 1 minute.") | 			return | ||||||
| 					time.Sleep(time.Minute) |  | ||||||
| 					continue |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		// Subscribe to MQTT topics. | 		// Subscribe to MQTT topics. | ||||||
| @ -601,9 +530,6 @@ func (r *MidiRouter) Connect() { | |||||||
| 				r.MqttSubscribe(r.MQTT.Topic + "/" + trig.MqttSubTopic) | 				r.MqttSubscribe(r.MQTT.Topic + "/" + trig.MqttSubTopic) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 		}() |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -613,7 +539,4 @@ func (r *MidiRouter) Disconnect() { | |||||||
| 	if r.ListenerStop != nil { | 	if r.ListenerStop != nil { | ||||||
| 		r.ListenerStop() | 		r.ListenerStop() | ||||||
| 	} | 	} | ||||||
| 	if r.MqttClient != nil { |  | ||||||
| 		r.MqttClient.Disconnect(0) |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user