-
Notifications
You must be signed in to change notification settings - Fork 1
/
root.go
180 lines (151 loc) · 5.26 KB
/
root.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
package cmd
import (
"context"
"fmt"
"io/fs"
"os"
"os/signal"
"syscall"
"github.com/e9ctrl/vd/api"
"github.com/e9ctrl/vd/device"
"github.com/e9ctrl/vd/server"
"github.com/e9ctrl/vd/vdfile"
"github.com/jwalton/gchalk"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
var apiAddr string
var version = "0.0.1"
var longVersion = "0.0.1"
const website = "https://vd.e9controls.com"
// based on https://github.com/labstack/echo/blob/4bc3e475e3137b6402933eec5e6fde641e0d2320/echo.go#L264C5-L264C71
const banner = `
__
_ _____/ /
| |/ / _ /
|___/\_,_/ v%s
Easy to use device simulator
%s
____________________________________O/_______
O\
`
// rootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "vd",
Args: cobra.ExactArgs(1),
Version: longVersion,
Short: "vd is a easy to use device simulator",
Long: `Virtual Device is an open source program that can be used to simulate lab device communication streams.
It is useful for testing and debugging software that communicates with lab devices,
as well as for creating virtual lab environments for education and research.
To run simulator create .toml file with device description and run it using following commands:
vd vdfile.toml
vd vdfile.toml --listenAddr 127.0.0.1:6666
By default, vd is listenning on 127.0.0.1:9999.`,
Run: func(cmd *cobra.Command, args []string) {
fmt.Printf(banner, version, website)
// parse config file
vdfile, err := vdfile.ReadVDFile(args[0])
if err != nil {
fmt.Printf("Config loading failed %v", err)
os.Exit(1)
}
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
defer stop()
// create device instance using loaded vdfile
str, err := device.NewDevice(vdfile)
if err != nil {
fmt.Printf("Device creation failed %v", err)
os.Exit(1)
}
ip := viper.GetString("listenAddr")
if !verifyIPAddr(ip) {
fmt.Println("Wrong TCP address")
os.Exit(1)
}
// create instance of TCP simulator server
srv, err := server.New(str, ip)
if err != nil {
fmt.Printf("TCP server creation failed %v", err)
os.Exit(1)
}
// run TCP simulator server
go srv.Start()
fmt.Println("vd running on ", gchalk.BrightYellow(ip))
addr := viper.GetString("httpListenAddr")
if !verifyIPAddr(addr) {
fmt.Println("Wrong HTTP address")
os.Exit(1)
}
// create instance of HTTP server
a := api.NewHttpApiServer(str)
go func() {
// run HTTP server with REST API
err = a.Serve(ctx, addr)
if err != nil {
fmt.Printf("HTTP server failed %v", err)
os.Exit(1)
}
}()
<-ctx.Done()
srv.Stop()
fmt.Println("vd stopped")
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
// This is the main method that start Cobra CLI.
func Execute(f fs.FS) {
vdTemplate = f
err := RootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
func init() {
cobra.OnInitialize(initConfig)
// Here you will define your flags and configuration settings.
// Cobra supports persistent flags, which, if defined here,
// will be global for your application.
RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.vd.yaml)")
// The default value from here is not used but it is visible in help, that's why it is left here
RootCmd.Flags().StringP("httpListenAddr", "", "127.0.0.1:8080", "Address of the HTTP simulator server")
// Binds viper httpListenAddr flag to cobra httpListenAddr pflag
viper.BindPFlag("httpListenAddr", RootCmd.Flags().Lookup("httpListenAddr"))
// Binds viper apiAddr flag to VD_HTTP_LISTEN_ADDR environment variable
viper.BindEnv("httpListenAddr", "VD_HTTP_LISTEN_ADDR")
// Set default flag in viper cause the default one from cobra is not used
viper.SetDefault("httpListenAddr", "127.0.0.1:8080")
// The default value from here is not used but it is visible in help, that's why it is left here
RootCmd.Flags().StringP("listenAddr", "", "127.0.0.1:9999", "Virtual device address")
// Binds viper listenAddr flag to cobra listenAddr pflag
viper.BindPFlag("listenAddr", RootCmd.Flags().Lookup("listenAddr"))
// Binds viper apiAddr flag to VD_LISTEN_ADDR environment variable
viper.BindEnv("listenAddr", "VD_LISTEN_ADDR")
// Set default flag in viper cause the default one from cobra is not used
viper.SetDefault("listenAddr", "127.0.0.1:9999")
// Cobra also supports local flags, which will only run
// when this action is called directly.
RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := os.UserHomeDir()
cobra.CheckErr(err)
// Search config in home directory with name ".vd" (without extension).
viper.AddConfigPath(home)
viper.SetConfigType("yaml")
viper.SetConfigName(".vd")
}
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed())
}
}