/
config.go
190 lines (171 loc) · 6.6 KB
/
config.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
181
182
183
184
185
186
187
188
189
190
package main
import (
"errors"
"os"
"path/filepath"
"time"
"github.com/jessevdk/go-flags"
"google.golang.org/grpc/grpclog"
"gopkg.in/yaml.v3"
)
// CfgCmdLine is command line arguments representation for YAML settings.
type CfgCmdLine struct {
ConfigPath string `json:"-" yaml:"-" env:"CONFIGPATH" short:"c" long:"cfgpath" description:"Configuration path. Can be full path to config folder, or relative from executable destination."`
NoConfig bool `json:"-" yaml:"-" long:"nocfg" description:"Specifies do not load settings from YAML-settings file, keeps default."`
DataFile string `json:"data-file" yaml:"data-file" short:"d" long:"data" default:"ports.json" description:"Name of file with database."`
}
// CfgWebServ is web server settings.
type CfgWebServ struct {
PortHTTP []string `json:"port-http" yaml:"port-http" short:"w" long:"porthttp" description:"List of address:port values for non-encrypted connections. Address is skipped in most common cases, port only remains."`
ReadTimeout time.Duration `json:"read-timeout" yaml:"read-timeout" long:"rt" description:"Maximum duration for reading the entire request, including the body."`
ReadHeaderTimeout time.Duration `json:"read-header-timeout" yaml:"read-header-timeout" long:"rht" description:"Amount of time allowed to read request headers."`
WriteTimeout time.Duration `json:"write-timeout" yaml:"write-timeout" long:"wt" description:"Maximum duration before timing out writes of the response."`
IdleTimeout time.Duration `json:"idle-timeout" yaml:"idle-timeout" long:"it" description:"Maximum amount of time to wait for the next request when keep-alives are enabled."`
MaxHeaderBytes int `json:"max-header-bytes" yaml:"max-header-bytes" long:"mhb" description:"Controls the maximum number of bytes the server will read parsing the request header's keys and values, including the request line, in bytes."`
// Maximum duration to wait for graceful shutdown.
ShutdownTimeout time.Duration `json:"shutdown-timeout" yaml:"shutdown-timeout" long:"st" description:"Maximum duration to wait for graceful shutdown."`
}
type CfgRpcServ struct {
AddrGRPC string `json:"addr-grpc" yaml:"addr-grpc" env:"SERVERURL" short:"u" long:"url" description:"List of URL or IP-addresses with gRPC- services hosts."`
PortGRPC string `json:"port-grpc" yaml:"port-grpc" env:"PORTGRPC" env-delim:";" short:"p" long:"portgrpc" description:"List of ports of gRPC-services."`
SchemeGRPC string `json:"scheme-grpc" yaml:"scheme-grpc" long:"scheme" description:"gRPC scheme name."`
ApiTimeout time.Duration `json:"api-timeout" yaml:"api-timeout"`
}
// Config is common service settings.
type Config struct {
CfgCmdLine `json:"command-line" yaml:"command-line" group:"Data Parameters"`
CfgWebServ `json:"webserver" yaml:"webserver" group:"Web Server"`
CfgRpcServ `json:"grpcserver" yaml:"grpcserver" group:"gRPC Server"`
}
// Instance of common service settings.
var cfg = Config{ // inits default values:
CfgCmdLine: CfgCmdLine{
DataFile: "ports.json",
},
CfgWebServ: CfgWebServ{
PortHTTP: []string{":8008"},
ReadTimeout: time.Duration(15) * time.Second,
ReadHeaderTimeout: time.Duration(15) * time.Second,
WriteTimeout: time.Duration(15) * time.Second,
IdleTimeout: time.Duration(60) * time.Second,
MaxHeaderBytes: 1 << 20,
ShutdownTimeout: time.Duration(15) * time.Second,
},
CfgRpcServ: CfgRpcServ{
AddrGRPC: "localhost",
PortGRPC: ":50051;:50052",
SchemeGRPC: "pds",
ApiTimeout: 2 * time.Second,
},
}
func init() {
if _, err := flags.Parse(&cfg); err != nil {
os.Exit(1)
}
}
const (
gitname = "pds"
gitpath = "github.com/schwarzlichtbezirk/" + gitname
cfgbase = gitname + "-config"
cfgfile = "client.yaml"
)
// ConfigPath determines configuration path, depended on what directory is exist.
var ConfigPath string
// ErrNoCongig is "no configuration path was found" error message.
var ErrNoCongig = errors.New("no configuration path was found")
// DetectConfigPath finds configuration path with existing configuration file at least.
func DetectConfigPath() (retpath string, err error) {
var ok bool
var path string
var exepath = filepath.Dir(os.Args[0])
// try to get from environment setting
if cfg.ConfigPath != "" {
path = envfmt(cfg.ConfigPath)
// try to get access to full path
if ok, _ = pathexists(filepath.Join(path, cfgfile)); ok {
retpath = path
return
}
// try to find relative from executable path
path = filepath.Join(exepath, path)
if ok, _ = pathexists(filepath.Join(path, cfgfile)); ok {
retpath = path
return
}
grpclog.Warningf("no access to pointed configuration path '%s'\n", cfg.ConfigPath)
}
// try to get from config subdirectory on executable path
path = filepath.Join(exepath, cfgbase)
if ok, _ = pathexists(filepath.Join(path, cfgfile)); ok {
retpath = path
return
}
// try to find in executable path
if ok, _ = pathexists(filepath.Join(exepath, cfgfile)); ok {
retpath = exepath
return
}
// try to find in config subdirectory of current path
if ok, _ = pathexists(filepath.Join(cfgbase, cfgfile)); ok {
retpath = cfgbase
return
}
// try to find in current path
if ok, _ = pathexists(cfgfile); ok {
retpath = "."
return
}
// check up current path is the git root path
if ok, _ = pathexists(filepath.Join("config", cfgfile)); ok {
retpath = "config"
return
}
// check up running in devcontainer workspace
path = filepath.Join("/workspaces", gitname, "config")
if ok, _ = pathexists(filepath.Join(path, cfgfile)); ok {
retpath = path
return
}
// check up git source path
var prefix string
if prefix, ok = os.LookupEnv("GOPATH"); ok {
path = filepath.Join(prefix, "src", gitpath, "config")
if ok, _ = pathexists(filepath.Join(path, cfgfile)); ok {
retpath = path
return
}
}
// if GOBIN or GOPATH is present
if prefix, ok = os.LookupEnv("GOBIN"); !ok {
if prefix, ok = os.LookupEnv("GOPATH"); ok {
prefix = filepath.Join(prefix, "bin")
}
}
if ok {
// try to get from go bin config
path = filepath.Join(prefix, cfgbase)
if ok, _ = pathexists(filepath.Join(path, cfgfile)); ok {
retpath = path
return
}
// try to get from go bin root
if ok, _ = pathexists(filepath.Join(prefix, cfgfile)); ok {
retpath = prefix
return
}
}
// no config was found
err = ErrNoCongig
return
}
// ReadYaml reads "data" object from YAML-file with given file path.
func ReadYaml(fname string, data interface{}) (err error) {
var body []byte
if body, err = os.ReadFile(filepath.Join(ConfigPath, fname)); err != nil {
return
}
if err = yaml.Unmarshal(body, data); err != nil {
return
}
return
}