You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@plc4x.apache.org by sr...@apache.org on 2022/08/05 10:30:11 UTC

[plc4x] 03/03: feat(plc4xbrowser): auto register option for drivers

This is an automated email from the ASF dual-hosted git repository.

sruehl pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/plc4x.git

commit 34d70f7414aa583afe31f0372bb3dbc0efa0690f
Author: Sebastian Rühl <sr...@apache.org>
AuthorDate: Fri Aug 5 12:30:00 2022 +0200

    feat(plc4xbrowser): auto register option for drivers
---
 plc4go/tools/plc4xbrowser/actions.go  |  48 +++++++-
 plc4go/tools/plc4xbrowser/commands.go | 223 +++++++++++++++++++---------------
 plc4go/tools/plc4xbrowser/common.go   |  31 +++++
 plc4go/tools/plc4xbrowser/config.go   |  43 ++++++-
 plc4go/tools/plc4xbrowser/main.go     |   2 +
 plc4go/tools/plc4xbrowser/ui.go       |   4 -
 6 files changed, 246 insertions(+), 105 deletions(-)

diff --git a/plc4go/tools/plc4xbrowser/actions.go b/plc4go/tools/plc4xbrowser/actions.go
index 549661b1b..f22953831 100644
--- a/plc4go/tools/plc4xbrowser/actions.go
+++ b/plc4go/tools/plc4xbrowser/actions.go
@@ -21,15 +21,19 @@ package main
 
 import (
 	"fmt"
+	"github.com/apache/plc4x/plc4go/internal/ads"
+	"github.com/apache/plc4x/plc4go/internal/bacnetip"
+	"github.com/apache/plc4x/plc4go/internal/cbus"
+	"github.com/apache/plc4x/plc4go/internal/s7"
 	plc4go "github.com/apache/plc4x/plc4go/pkg/api"
+	"github.com/apache/plc4x/plc4go/pkg/api/transports"
+	"github.com/pkg/errors"
 	"github.com/rivo/tview"
 	"github.com/rs/zerolog"
 	"github.com/rs/zerolog/log"
 )
 
 func initSubsystem() {
-	driverManager = plc4go.NewPlcDriverManager()
-
 	logLevel := zerolog.InfoLevel
 	if configuredLevel := config.LogLevel; configuredLevel != "" {
 		if parsedLevel, err := zerolog.ParseLevel(configuredLevel); err != nil {
@@ -38,6 +42,7 @@ func initSubsystem() {
 			logLevel = parsedLevel
 		}
 	}
+	driverManager = plc4go.NewPlcDriverManager()
 
 	log.Logger = log.
 		//// Enable below if you want to see the filenames
@@ -48,6 +53,15 @@ func initSubsystem() {
 	// We offset the commands executed with the last commands
 	commandsExecuted = len(config.History.Last10Commands)
 	outputCommandHistory()
+
+	for _, driver := range config.AutoRegisterDrivers {
+		log.Info().Msgf("Auto register driver %s")
+		if err := validateDriverParam(driver); err != nil {
+			log.Err(err).Msgf("Invalid configuration")
+			continue
+		}
+		_ = registerDriver(driver)
+	}
 }
 
 func outputCommandHistory() {
@@ -56,3 +70,33 @@ func outputCommandHistory() {
 		_, _ = fmt.Fprintf(commandOutput, "   [#00ff00]%d[white]: [\"%d\"]%s[\"\"]\n", i, i, command)
 	}
 }
+
+func validateDriverParam(driver string) error {
+	for _, protocol := range protocolList {
+		if protocol == driver {
+			return nil
+		}
+	}
+	return errors.Errorf("protocol %s not found", driver)
+}
+
+func registerDriver(driver string) error {
+	switch driver {
+	case "ads":
+		driverManager.RegisterDriver(ads.NewDriver())
+		transports.RegisterTcpTransport(driverManager)
+	case "bacnetip":
+		driverManager.RegisterDriver(bacnetip.NewDriver())
+		transports.RegisterUdpTransport(driverManager)
+	case "c-bus":
+		driverManager.RegisterDriver(cbus.NewDriver())
+		transports.RegisterTcpTransport(driverManager)
+	case "s7":
+		driverManager.RegisterDriver(s7.NewDriver())
+		transports.RegisterTcpTransport(driverManager)
+	default:
+		return errors.Errorf("Unknown driver %s", driver)
+	}
+	go driverAdded(driver)
+	return nil
+}
diff --git a/plc4go/tools/plc4xbrowser/commands.go b/plc4go/tools/plc4xbrowser/commands.go
index 930cdcab7..6a77134b4 100644
--- a/plc4go/tools/plc4xbrowser/commands.go
+++ b/plc4go/tools/plc4xbrowser/commands.go
@@ -21,13 +21,8 @@ package main
 
 import (
 	"fmt"
-	"github.com/apache/plc4x/plc4go/internal/ads"
-	"github.com/apache/plc4x/plc4go/internal/bacnetip"
-	"github.com/apache/plc4x/plc4go/internal/cbus"
-	"github.com/apache/plc4x/plc4go/internal/s7"
 	plc4x_config "github.com/apache/plc4x/plc4go/pkg/api/config"
 	"github.com/apache/plc4x/plc4go/pkg/api/model"
-	"github.com/apache/plc4x/plc4go/pkg/api/transports"
 	"github.com/pkg/errors"
 	"github.com/rivo/tview"
 	"github.com/rs/zerolog"
@@ -36,14 +31,8 @@ import (
 	"strings"
 )
 
-var plc4xBrowserLog = zerolog.Nop()
-
 const rootCommandIndicator = "rootCommand"
 
-const protocols = "ads,bacnetip,c-bus,s7"
-
-var protocolsSuggestions = strings.Split(protocols, ",")
-
 var commands = map[inputMode]Command{
 	normalMode:        rootCommand,
 	subscribeEditMode: rootCommand,
@@ -61,7 +50,7 @@ var rootCommand = Command{
 				if err != nil {
 					return errors.Wrapf(err, "can't parse connection url %s", connectionString)
 				}
-				addHost(connectionUrl.Host)
+				addHostHistoryEntry(connectionUrl.Host)
 				connectionId := fmt.Sprintf("%s://%s", connectionUrl.Scheme, connectionUrl.Host)
 				if _, ok := connections[connectionId]; ok {
 					return errors.Errorf("%s already connected", connectionId)
@@ -76,7 +65,7 @@ var rootCommand = Command{
 				return nil
 			},
 			parameterSuggestions: func(currentText string) (entries []string) {
-				for _, protocol := range protocolsSuggestions {
+				for _, protocol := range protocolList {
 					if strings.HasPrefix(currentText, protocol) {
 						for _, host := range config.History.Last10Hosts {
 							entries = append(entries, protocol+"://"+host)
@@ -122,28 +111,11 @@ var rootCommand = Command{
 		{
 			Name:        "register",
 			Description: "register a driver in the subsystem",
-			action: func(_ Command, protocol string) error {
-				switch protocol {
-				case "ads":
-					driverManager.RegisterDriver(ads.NewDriver())
-					transports.RegisterTcpTransport(driverManager)
-				case "bacnetip":
-					driverManager.RegisterDriver(bacnetip.NewDriver())
-					transports.RegisterUdpTransport(driverManager)
-				case "c-bus":
-					driverManager.RegisterDriver(cbus.NewDriver())
-					transports.RegisterTcpTransport(driverManager)
-				case "s7":
-					driverManager.RegisterDriver(s7.NewDriver())
-					transports.RegisterTcpTransport(driverManager)
-				default:
-					return errors.Errorf("Unknown protocol %s", protocol)
-				}
-				driverAdded(protocol)
-				return nil
+			action: func(_ Command, driver string) error {
+				return registerDriver(driver)
 			},
 			parameterSuggestions: func(currentText string) (entries []string) {
-				for _, protocol := range protocolsSuggestions {
+				for _, protocol := range protocolList {
 					if strings.HasPrefix(protocol, currentText) {
 						entries = append(entries, protocol)
 					}
@@ -265,75 +237,132 @@ var rootCommand = Command{
 			Description: "plc4x related settings",
 			subCommands: []Command{
 				{
-					Name: "TraceTransactionManagerWorkers",
-					action: func(_ Command, argument string) error {
-						switch argument {
-						case "on":
-							plc4x_config.TraceTransactionManagerWorkers = true
-						case "off":
-							plc4x_config.TraceTransactionManagerWorkers = false
-						default:
-							return errors.Errorf("illegal argument %s", argument)
-						}
-						return nil
-					},
-					parameterSuggestions: func(currentText string) (entries []string) {
-						entries = append(entries, "on", "off")
-						return
+					Name:        "TraceTransactionManagerWorkers",
+					Description: "print information about transaction manager workers",
+					subCommands: []Command{
+						{
+							Name:        "on",
+							Description: "trace on",
+							action: func(_ Command, _ string) error {
+								plc4x_config.TraceTransactionManagerWorkers = true
+								return nil
+							},
+						},
+						{
+							Name:        "off",
+							Description: "trace off",
+							action: func(_ Command, _ string) error {
+								plc4x_config.TraceTransactionManagerWorkers = false
+								return nil
+							},
+						},
 					},
 				},
 				{
-					Name: "TraceTransactionManagerTransactions",
-					action: func(_ Command, argument string) error {
-						switch argument {
-						case "on":
-							plc4x_config.TraceTransactionManagerTransactions = true
-						case "off":
-							plc4x_config.TraceTransactionManagerTransactions = false
-						default:
-							return errors.Errorf("illegal argument %s", argument)
-						}
-						return nil
-					},
-					parameterSuggestions: func(currentText string) (entries []string) {
-						entries = append(entries, "on", "off")
-						return
+					Name:        "TraceTransactionManagerTransactions",
+					Description: "print information about transaction manager transactions",
+					subCommands: []Command{
+						{
+							Name:        "on",
+							Description: "trace on",
+							action: func(_ Command, _ string) error {
+								plc4x_config.TraceTransactionManagerTransactions = true
+								return nil
+							},
+						},
+						{
+							Name:        "off",
+							Description: "trace off",
+							action: func(_ Command, _ string) error {
+								plc4x_config.TraceTransactionManagerTransactions = false
+								return nil
+							},
+						},
 					},
 				},
 				{
-					Name: "TraceDefaultMessageCodecWorker",
-					action: func(_ Command, argument string) error {
-						switch argument {
-						case "on":
-							plc4x_config.TraceDefaultMessageCodecWorker = true
-						case "off":
-							plc4x_config.TraceDefaultMessageCodecWorker = false
-						default:
-							return errors.Errorf("illegal argument %s", argument)
-						}
-						return nil
-					},
-					parameterSuggestions: func(currentText string) (entries []string) {
-						entries = append(entries, "on", "off")
-						return
+					Name:        "TraceDefaultMessageCodecWorker",
+					Description: "print information about message codec workers",
+					subCommands: []Command{
+						{
+							Name:        "on",
+							Description: "trace on",
+							action: func(_ Command, _ string) error {
+								plc4x_config.TraceDefaultMessageCodecWorker = true
+								return nil
+							},
+						},
+						{
+							Name:        "off",
+							Description: "trace off",
+							action: func(_ Command, _ string) error {
+								plc4x_config.TraceDefaultMessageCodecWorker = false
+								return nil
+							},
+						},
 					},
 				},
 				{
-					Name: "plc4xbrowser-debug",
-					action: func(_ Command, argument string) error {
-						switch argument {
-						case "on":
-							plc4xBrowserLog = zerolog.New(zerolog.ConsoleWriter{Out: tview.ANSIWriter(consoleOutput)})
-						case "off":
-							plc4xBrowserLog = zerolog.Nop()
-						default:
-							return errors.Errorf("illegal argument %s", argument)
-						}
-						return nil
+					Name:        "plc4xbrowser-debug",
+					Description: "Prints out debug information of the browser itself",
+					subCommands: []Command{
+						{
+							Name:        "on",
+							Description: "debug on",
+							action: func(_ Command, _ string) error {
+								plc4xBrowserLog = zerolog.New(zerolog.ConsoleWriter{Out: tview.ANSIWriter(consoleOutput)})
+								return nil
+							},
+						},
+						{
+							Name:        "off",
+							Description: "debug off",
+							action: func(_ Command, _ string) error {
+								plc4xBrowserLog = zerolog.Nop()
+								return nil
+							},
+						},
 					},
-					parameterSuggestions: func(currentText string) (entries []string) {
-						entries = append(entries, "on", "off")
-						return
+				},
+				{
+					Name:        "auto-register",
+					Description: "autoregister driver at startup",
+					subCommands: []Command{
+						{
+							Name: "list",
+							action: func(currentCommand Command, argument string) error {
+								_, _ = fmt.Fprintf(commandOutput, "Auto-register enabled drivers:\n  %s\n", strings.Join(config.AutoRegisterDrivers, "\n  "))
+								return nil
+							},
+						},
+						{
+							Name: "enable",
+							action: func(_ Command, argument string) error {
+								return enableAutoRegister(argument)
+							},
+							parameterSuggestions: func(currentText string) (entries []string) {
+								for _, protocol := range protocolList {
+									if strings.HasPrefix(protocol, currentText) {
+										entries = append(entries, protocol)
+									}
+								}
+								return
+							},
+						},
+						{
+							Name: "disable",
+							action: func(_ Command, argument string) error {
+								return disableAutoRegister(argument)
+							},
+							parameterSuggestions: func(currentText string) (entries []string) {
+								for _, protocol := range protocolList {
+									if strings.HasPrefix(protocol, currentText) {
+										entries = append(entries, protocol)
+									}
+								}
+								return
+							},
+						},
 					},
 				},
 			},
@@ -368,7 +397,11 @@ func init() {
 			_, _ = fmt.Fprintf(commandOutput, "[#0000ff]Available commands[white]\n")
 			rootCommand.visit(0, func(currentIndent int, command Command) {
 				indentString := strings.Repeat("  ", currentIndent)
-				_, _ = fmt.Fprintf(commandOutput, "%s [#00ff00]%s[white]: %s\n", indentString, command.Name, command.Description)
+				description := command.Description
+				if description == "" {
+					description = command.Name + "s"
+				}
+				_, _ = fmt.Fprintf(commandOutput, "%s [#00ff00]%s[white]: %s\n", indentString, command.Name, description)
 			})
 			return nil
 		},
@@ -460,7 +493,7 @@ func (c Command) hasDirectExecution() bool {
 func Execute(commandText string) error {
 	err := rootCommand.Execute(commandText)
 	if err == nil {
-		addCommand(commandText)
+		addCommandHistoryEntry(commandText)
 	}
 	return err
 }
@@ -492,7 +525,7 @@ func (c Command) Execute(commandText string) error {
 func (c Command) visit(i int, f func(currentIndent int, command Command)) {
 	f(i, c)
 	for _, subCommand := range c.subCommands {
-		f(i+1, subCommand)
+		subCommand.visit(i+1, f)
 	}
 }
 
diff --git a/plc4go/tools/plc4xbrowser/common.go b/plc4go/tools/plc4xbrowser/common.go
new file mode 100644
index 000000000..b42f76a1b
--- /dev/null
+++ b/plc4go/tools/plc4xbrowser/common.go
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package main
+
+import (
+	"github.com/rs/zerolog"
+	"strings"
+)
+
+const protocols = "ads,bacnetip,c-bus,s7"
+
+var protocolList = strings.Split(protocols, ",")
+
+var plc4xBrowserLog = zerolog.Nop()
diff --git a/plc4go/tools/plc4xbrowser/config.go b/plc4go/tools/plc4xbrowser/config.go
index aba7a12d9..13313402f 100644
--- a/plc4go/tools/plc4xbrowser/config.go
+++ b/plc4go/tools/plc4xbrowser/config.go
@@ -20,6 +20,7 @@
 package main
 
 import (
+	"github.com/pkg/errors"
 	"github.com/rs/zerolog"
 	"github.com/rs/zerolog/log"
 	"gopkg.in/yaml.v3"
@@ -37,8 +38,9 @@ type Config struct {
 		Last10Hosts    []string `yaml:"last_hosts"`
 		Last10Commands []string `yaml:"last_commands"`
 	}
-	LastUpdated time.Time `yaml:"last_updated"`
-	LogLevel    string    `yaml:"log_level"`
+	AutoRegisterDrivers []string  `yaml:"auto_register_driver"`
+	LastUpdated         time.Time `yaml:"last_updated"`
+	LogLevel            string    `yaml:"log_level"`
 }
 
 func init() {
@@ -96,7 +98,7 @@ func saveConfig() {
 	}
 }
 
-func addHost(host string) {
+func addHostHistoryEntry(host string) {
 	existingIndex := -1
 	for i, lastHost := range config.History.Last10Hosts {
 		if lastHost == host {
@@ -113,7 +115,7 @@ func addHost(host string) {
 	config.History.Last10Hosts = append(config.History.Last10Hosts, host)
 }
 
-func addCommand(command string) {
+func addCommandHistoryEntry(command string) {
 	switch command {
 	case "clear":
 		return
@@ -139,3 +141,36 @@ func addCommand(command string) {
 func setLevel(level zerolog.Level) {
 	config.LogLevel = level.String()
 }
+
+func enableAutoRegister(driver string) error {
+	if err := validateDriverParam(driver); err != nil {
+		return err
+	}
+	for _, autoRegisterDriver := range config.AutoRegisterDrivers {
+		if autoRegisterDriver == driver {
+			return errors.Errorf("%s already registered for auto register", driver)
+		}
+	}
+	config.AutoRegisterDrivers = append(config.AutoRegisterDrivers, driver)
+	log.Info().Msgf("Auto register enabled for %s", driver)
+	return nil
+}
+
+func disableAutoRegister(driver string) error {
+	if err := validateDriverParam(driver); err != nil {
+		return err
+	}
+	index := -1
+	for i, autoRegisterDriver := range config.AutoRegisterDrivers {
+		if autoRegisterDriver == driver {
+			index = i
+			break
+		}
+	}
+	if index < 0 {
+		return errors.Errorf("%s not registered for auto register", driver)
+	}
+	config.AutoRegisterDrivers = append(config.AutoRegisterDrivers[:index], config.AutoRegisterDrivers[index+1:]...)
+	log.Info().Msgf("Auto register disabled for %s", driver)
+	return nil
+}
diff --git a/plc4go/tools/plc4xbrowser/main.go b/plc4go/tools/plc4xbrowser/main.go
index c0793b0b9..9cc64d20e 100644
--- a/plc4go/tools/plc4xbrowser/main.go
+++ b/plc4go/tools/plc4xbrowser/main.go
@@ -71,7 +71,9 @@ func shutdown() {
 }
 
 func main() {
+	loadConfig()
 	application := setupApplication()
+	initSubsystem()
 
 	if err := application.Run(); err != nil {
 		panic(err)
diff --git a/plc4go/tools/plc4xbrowser/ui.go b/plc4go/tools/plc4xbrowser/ui.go
index 139bb56c1..39ac34fdf 100644
--- a/plc4go/tools/plc4xbrowser/ui.go
+++ b/plc4go/tools/plc4xbrowser/ui.go
@@ -60,10 +60,6 @@ func setupApplication() *tview.Application {
 
 	application.SetRoot(grid, true).EnableMouse(true)
 
-	loadConfig()
-
-	initSubsystem()
-
 	application.SetInputCapture(func(event *tcell.EventKey) *tcell.EventKey {
 		switch event.Key() {
 		case tcell.KeyCtrlC: