Skip to content

Commit a23d9bc

Browse files
committed
feat(run): enhance command flags and config loading
- Refactor flag parsing to support default config bytes input - Add comprehensive CLI flag bindings for server, JWT, database, registry, Kubernetes, and other configurations - Improve configuration loading logic with better error handling - Introduce bytes source for in-memory config loading - Update Dockerfile CMD to include custom config and output paths - Modify cluster endpoint validation in client config generation - Remove unused GlobalEmail field from Bootstrap proto message - Add helper methods for RegistryType enum checks - Adjust default values in server.yaml for cluster settings
1 parent b66b89d commit a23d9bc

File tree

9 files changed

+200
-81
lines changed

9 files changed

+200
-81
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,4 @@ EXPOSE 8080
5656
EXPOSE 9090
5757

5858
# 运行应用
59-
CMD ["rabbit", "run"]
59+
CMD ["rabbit", "run", "-c", "/moon/config", "-o", "~/.rabbit"]

cmd/run/client.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"google.golang.org/protobuf/types/known/durationpb"
1616

1717
"github.com/aide-family/magicbox/load"
18+
"github.com/aide-family/magicbox/strutil"
1819
"github.com/aide-family/magicbox/strutil/cnst"
1920
"github.com/aide-family/rabbit/internal/conf"
2021
"github.com/aide-family/rabbit/internal/server"
@@ -70,7 +71,7 @@ func generateClientConfig(
7071
clientConfig.Kubernetes = bc.GetKubernetes()
7172
}
7273

73-
if clusterConfig != nil {
74+
if clusterConfig != nil && strutil.IsNotEmpty(clusterConfig.GetEndpoints()) {
7475
clientConfig.Cluster = clusterConfig
7576
} else {
7677
// 如果没有配置,使用默认值

cmd/run/flags.go

Lines changed: 74 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/aide-family/magicbox/strutil"
1111
"github.com/aide-family/rabbit/cmd"
1212
"github.com/aide-family/rabbit/internal/conf"
13+
"github.com/aide-family/rabbit/pkg/config"
1314
"github.com/aide-family/rabbit/pkg/enum"
1415
)
1516

@@ -18,76 +19,93 @@ type Flags struct {
1819
configPath string
1920
clientConfigOutputPath string
2021

21-
httpAddress string
22-
httpNetwork string
23-
httpTimeout string
24-
grpcAddress string
25-
grpcNetwork string
26-
grpcTimeout string
27-
environment string
22+
*conf.Bootstrap
23+
environment string
24+
httpTimeout string
25+
grpcTimeout string
26+
jwtExpire string
27+
eventBusTimeout string
28+
registryType string
2829
}
2930

3031
var flags Flags
3132

32-
func (f *Flags) addFlags(c *cobra.Command) {
33-
c.Flags().StringVarP(&f.configPath, "config", "c", "./config", "config file (default is ./config)")
34-
c.Flags().StringVarP(&f.clientConfigOutputPath, "client-config-output", "o", "~/.rabbit/config.yaml", "client config output file (default is ~/.rabbit/config.yaml)")
33+
func (f *Flags) addFlags(c *cobra.Command, bc *conf.Bootstrap) {
34+
f.Bootstrap = bc
35+
c.Flags().StringVarP(&f.configPath, "config", "c", "", `Example: -c=./config/, --config="./config/"`)
36+
c.Flags().StringVarP(&f.clientConfigOutputPath, "client-config-output", "o", "~/.rabbit/", `Example: -o=./client/, --client-config-output="~/.rabbit/"`)
3537

36-
c.Flags().StringVar(&f.httpAddress, "http-address", "0.0.0.0:8080", "http address (default is 0.0.0.0:8080)")
37-
c.Flags().StringVar(&f.httpNetwork, "http-network", "tcp", "http network (default is tcp)")
38-
c.Flags().StringVar(&f.httpTimeout, "http-timeout", "10s", "http timeout (default is 10s)")
39-
c.Flags().StringVar(&f.grpcAddress, "grpc-address", "0.0.0.0:9090", "grpc address (default is 0.0.0.0:9090)")
40-
c.Flags().StringVar(&f.grpcNetwork, "grpc-network", "tcp", "grpc network (default is tcp)")
41-
c.Flags().StringVar(&f.grpcTimeout, "grpc-timeout", "10s", "grpc timeout (default is 10s)")
42-
c.Flags().StringVarP(&f.environment, "environment", "e", "PROD", "environment (DEV, TEST, PREVIEW, PROD)")
38+
c.Flags().StringVar(&f.environment, "environment", f.Environment.String(), `Example: --environment="DEV", --environment="TEST", --environment="PREVIEW", --environment="PROD"`)
39+
c.Flags().StringVar(&f.Server.Http.Address, "http-address", f.Server.Http.Address, `Example: --http-address="0.0.0.0:8080", --http-address=":8080"`)
40+
c.Flags().StringVar(&f.Server.Http.Network, "http-network", f.Server.Http.Network, `Example: --http-network="tcp"`)
41+
c.Flags().StringVar(&f.httpTimeout, "http-timeout", f.Server.Http.Timeout.AsDuration().String(), `Example: --http-timeout="10s", --http-timeout="1m", --http-timeout="1h", --http-timeout="1d"`)
42+
c.Flags().StringVar(&f.Server.Grpc.Address, "grpc-address", f.Server.Grpc.Address, `Example: --grpc-address="0.0.0.0:9090", --grpc-address=":9090"`)
43+
c.Flags().StringVar(&f.Server.Grpc.Network, "grpc-network", f.Server.Grpc.Network, `Example: --grpc-network="tcp"`)
44+
c.Flags().StringVar(&f.grpcTimeout, "grpc-timeout", f.Server.Grpc.Timeout.AsDuration().String(), `Example: --grpc-timeout="10s", --grpc-timeout="1m", --grpc-timeout="1h", --grpc-timeout="1d"`)
45+
c.Flags().StringVar(&f.Jwt.Secret, "jwt-secret", f.Jwt.Secret, `Example: --jwt-secret="xxx"`)
46+
c.Flags().StringVar(&f.jwtExpire, "jwt-expire", f.Jwt.Expire.AsDuration().String(), `Example: --jwt-expire="10s", --jwt-expire="1m", --jwt-expire="1h", --jwt-expire="1d"`)
47+
c.Flags().StringVar(&f.Jwt.Issuer, "jwt-issuer", f.Jwt.Issuer, `Example: --jwt-issuer="xxx"`)
48+
c.Flags().StringVar(&f.Main.Username, "main-username", f.Main.Username, `Example: --main-username="root"`)
49+
c.Flags().StringVar(&f.Main.Password, "main-password", f.Main.Password, `Example: --main-password="123456"`)
50+
c.Flags().StringVar(&f.Main.Host, "main-host", f.Main.Host, `Example: --main-host="localhost"`)
51+
c.Flags().Int32Var(&f.Main.Port, "main-port", f.Main.Port, `Example: --main-port=3306"`)
52+
c.Flags().StringVar(&f.Main.Database, "main-database", f.Main.Database, `Example: --main-database="rabbit"`)
53+
c.Flags().StringVar(&f.Main.Debug, "main-debug", f.Main.Debug, `Example: --main-debug="false"`)
54+
c.Flags().StringVar(&f.Main.UseSystemLogger, "main-use-system-logger", f.Main.UseSystemLogger, `Example: --main-use-system-logger="true"`)
55+
c.Flags().Int32Var(&f.EventBus.WorkerCount, "event-bus-worker-count", f.EventBus.WorkerCount, `Example: --event-bus-worker-count=1"`)
56+
c.Flags().StringVar(&f.eventBusTimeout, "event-bus-timeout", f.EventBus.Timeout.AsDuration().String(), `Example: --event-bus-timeout="10s", --event-bus-timeout="1m", --event-bus-timeout="1h", --event-bus-timeout="1d"`)
57+
c.Flags().StringVar(&f.registryType, "registry-type", f.RegistryType.String(), `Example: --registry-type="etcd"`)
58+
c.Flags().StringVar(&f.Etcd.Endpoints, "etcd-endpoints", f.Etcd.Endpoints, `Example: --etcd-endpoints="127.0.0.1:2379"`)
59+
c.Flags().StringVar(&f.Etcd.Username, "etcd-username", f.Etcd.Username, `Example: --etcd-username="root"`)
60+
c.Flags().StringVar(&f.Etcd.Password, "etcd-password", f.Etcd.Password, `Example: --etcd-password="123456"`)
61+
c.Flags().StringVar(&f.Kubernetes.Namespace, "kubernetes-namespace", f.Kubernetes.Namespace, `Example: --kubernetes-namespace="moon"`)
62+
c.Flags().StringVar(&f.Kubernetes.KubeConfig, "kubernetes-kubeconfig", f.Kubernetes.KubeConfig, `Example: --kubernetes-kubeconfig="~/.kube/config"`)
63+
c.Flags().StringVar(&f.SwaggerBasicAuth.Username, "swagger-basic-auth-username", f.SwaggerBasicAuth.Username, `Example: --swagger-basic-auth-username="root"`)
64+
c.Flags().StringVar(&f.SwaggerBasicAuth.Password, "swagger-basic-auth-password", f.SwaggerBasicAuth.Password, `Example: --swagger-basic-auth-password="123456"`)
65+
c.Flags().StringVar(&f.MetricsBasicAuth.Username, "metrics-basic-auth-username", f.MetricsBasicAuth.Username, `Example: --metrics-basic-auth-username="root"`)
66+
c.Flags().StringVar(&f.MetricsBasicAuth.Password, "metrics-basic-auth-password", f.MetricsBasicAuth.Password, `Example: --metrics-basic-auth-password="123456"`)
67+
c.Flags().StringVar(&f.EnableClientConfig, "enable-client-config", f.EnableClientConfig, `Example: --enable-client-config="true"`)
68+
c.Flags().StringVar(&f.EnableSwagger, "enable-swagger", f.EnableSwagger, `Example: --enable-swagger="true"`)
69+
c.Flags().StringVar(&f.EnableMetrics, "enable-metrics", f.EnableMetrics, `Example: --enable-metrics="true"`)
70+
c.Flags().StringVar(&f.UseDatabase, "use-database", f.UseDatabase, `Example: --use-database="true"`)
71+
c.Flags().StringSliceVar(&f.ConfigPaths, "config-paths", f.ConfigPaths, `Example: --config-paths="./datasource"`)
4372
}
4473

45-
func (f *Flags) applyToBootstrap(bc *conf.Bootstrap) {
46-
if pointer.IsNil(bc.GetServer()) {
47-
bc.Server = &conf.Server{
48-
Http: &conf.Server_HTTPServer{},
49-
Grpc: &conf.Server_GRPCServer{},
50-
}
51-
}
52-
httpConf := bc.GetServer().GetHttp()
53-
if pointer.IsNil(httpConf) {
54-
httpConf = &conf.Server_HTTPServer{}
55-
bc.Server.Http = httpConf
56-
}
57-
if strutil.IsEmpty(httpConf.Address) {
58-
httpConf.Address = f.httpAddress
74+
func (f *Flags) applyToBootstrap() {
75+
metadata := f.Server.Metadata
76+
if pointer.IsNil(metadata) {
77+
metadata = make(map[string]string)
5978
}
60-
if strutil.IsEmpty(httpConf.Network) {
61-
httpConf.Network = f.httpNetwork
62-
}
63-
if httpConf.GetTimeout().AsDuration() <= 0 {
64-
timeout, err := time.ParseDuration(f.httpTimeout)
65-
if pointer.IsNil(err) {
66-
httpConf.Timeout = durationpb.New(timeout)
79+
metadata["repository"] = f.Repo
80+
metadata["author"] = f.Author
81+
metadata["email"] = f.Email
82+
f.Server.Metadata = metadata
83+
if strutil.IsNotEmpty(f.httpTimeout) {
84+
if timeout, err := time.ParseDuration(f.httpTimeout); pointer.IsNil(err) {
85+
f.Server.Http.Timeout = durationpb.New(timeout)
6786
}
6887
}
69-
grpcConf := bc.GetServer().GetGrpc()
70-
if pointer.IsNil(grpcConf) {
71-
grpcConf = &conf.Server_GRPCServer{}
72-
bc.Server.Grpc = grpcConf
73-
}
74-
if strutil.IsEmpty(grpcConf.Address) {
75-
grpcConf.Address = f.grpcAddress
88+
if strutil.IsNotEmpty(f.grpcTimeout) {
89+
if timeout, err := time.ParseDuration(f.grpcTimeout); pointer.IsNil(err) {
90+
f.Server.Grpc.Timeout = durationpb.New(timeout)
91+
}
7692
}
77-
if strutil.IsEmpty(grpcConf.Network) {
78-
grpcConf.Network = f.grpcNetwork
93+
94+
if strutil.IsNotEmpty(f.environment) {
95+
f.Environment = enum.Environment(enum.Environment_value[f.environment])
7996
}
80-
if grpcConf.GetTimeout().AsDuration() <= 0 {
81-
timeout, err := time.ParseDuration(f.grpcTimeout)
82-
if pointer.IsNil(err) {
83-
grpcConf.Timeout = durationpb.New(timeout)
97+
if strutil.IsNotEmpty(f.jwtExpire) {
98+
if expire, err := time.ParseDuration(f.jwtExpire); pointer.IsNil(err) {
99+
f.Jwt.Expire = durationpb.New(expire)
84100
}
85101
}
86-
if bc.Environment.IsUnknown() {
87-
env := enum.Environment_PROD
88-
if strutil.IsNotEmpty(f.environment) {
89-
env = enum.Environment(enum.Environment_value[f.environment])
102+
if strutil.IsNotEmpty(f.eventBusTimeout) {
103+
if timeout, err := time.ParseDuration(f.eventBusTimeout); pointer.IsNil(err) {
104+
f.EventBus.Timeout = durationpb.New(timeout)
90105
}
91-
bc.Environment = env
106+
}
107+
108+
if strutil.IsNotEmpty(f.registryType) {
109+
f.RegistryType = config.RegistryType(config.RegistryType_value[f.registryType])
92110
}
93111
}

cmd/run/run.go

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
"github.com/aide-family/rabbit/internal/server"
1919
)
2020

21-
func NewCmd() *cobra.Command {
21+
func NewCmd(defaultServerConfigBytes []byte) *cobra.Command {
2222
runCmd := &cobra.Command{
2323
Use: "run",
2424
Short: "Run the Rabbit service",
@@ -28,39 +28,53 @@ func NewCmd() *cobra.Command {
2828
},
2929
Run: runServer,
3030
}
31-
flags.addFlags(runCmd)
32-
return runCmd
33-
}
34-
35-
func runServer(_ *cobra.Command, _ []string) {
36-
flags.GlobalFlags = cmd.GetGlobalFlags()
3731
var bc conf.Bootstrap
3832
c := config.New(config.WithSource(
3933
env.NewSource(),
40-
file.NewSource(flags.configPath),
34+
conf.NewBytesSource(defaultServerConfigBytes),
4135
))
4236
if err := c.Load(); err != nil {
4337
flags.Helper.Errorw("msg", "load config failed", "error", err)
44-
return
38+
panic(err)
4539
}
4640

4741
if err := c.Scan(&bc); err != nil {
4842
flags.Helper.Errorw("msg", "scan config failed", "error", err)
49-
return
43+
panic(err)
44+
}
45+
46+
flags.addFlags(runCmd, &bc)
47+
return runCmd
48+
}
49+
50+
func runServer(_ *cobra.Command, _ []string) {
51+
flags.GlobalFlags = cmd.GetGlobalFlags()
52+
var bc conf.Bootstrap
53+
if strutil.IsNotEmpty(flags.configPath) {
54+
c := config.New(config.WithSource(
55+
env.NewSource(),
56+
file.NewSource(flags.configPath),
57+
))
58+
if err := c.Load(); err != nil {
59+
flags.Helper.Errorw("msg", "load config failed", "error", err)
60+
return
61+
}
62+
63+
if err := c.Scan(&bc); err != nil {
64+
flags.Helper.Errorw("msg", "scan config failed", "error", err)
65+
return
66+
}
67+
flags.Bootstrap = &bc
5068
}
5169

52-
flags.applyToBootstrap(&bc)
53-
serverConf := bc.GetServer()
54-
metadata := serverConf.GetMetadata()
55-
metadata["repository"] = "https://github.com/aide-family/rabbit"
56-
metadata["author"] = "Aide Family"
57-
metadata["email"] = "1058165620@qq.com"
70+
flags.applyToBootstrap()
71+
serverConf := flags.GetServer()
5872
envOpts := []hello.Option{
5973
hello.WithVersion(flags.Version),
6074
hello.WithID(flags.Hostname),
6175
hello.WithName(serverConf.GetName()),
62-
hello.WithEnv(bc.GetEnvironment().String()),
63-
hello.WithMetadata(metadata),
76+
hello.WithEnv(flags.Environment.String()),
77+
hello.WithMetadata(serverConf.GetMetadata()),
6478
}
6579
if serverConf.GetUseRandomID() == "true" {
6680
envOpts = append(envOpts, hello.WithID(strutil.RandomID()))
@@ -76,7 +90,7 @@ func runServer(_ *cobra.Command, _ []string) {
7690
"span.id", tracing.SpanID()),
7791
)
7892

79-
app, cleanup, err := wireApp(&bc, helper)
93+
app, cleanup, err := wireApp(flags.Bootstrap, helper)
8094
if err != nil {
8195
flags.Helper.Errorw("msg", "wireApp failed", "error", err)
8296
return

config/server.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ eventBus:
4343
registryType: ${MOON_RABBIT_REGISTRY_TYPE:}
4444

4545
cluster:
46-
name: ${MOON_RABBIT_CLUSTER_NAME:rabbit}
47-
endpoints: ${MOON_RABBIT_CLUSTER_ENDPOINTS:localhost:9090}
46+
name: ${MOON_RABBIT_CLUSTER_NAME:moon.rabbit}
47+
endpoints: ${MOON_RABBIT_CLUSTER_ENDPOINTS:}
4848
protocol: ${MOON_RABBIT_CLUSTER_PROTOCOL:GRPC}
4949
timeout: ${MOON_RABBIT_CLUSTER_TIMEOUT:10s}
5050

internal/conf/conf.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package conf
2+
3+
import (
4+
"context"
5+
"strings"
6+
7+
"github.com/go-kratos/kratos/v2/config"
8+
)
9+
10+
var (
11+
_ config.Source = (*bytesSource)(nil)
12+
_ config.Watcher = (*noOpWatcher)(nil)
13+
)
14+
15+
func NewBytesSource(data []byte) config.Source {
16+
d := bytesSource(data)
17+
return &d
18+
}
19+
20+
type bytesSource []byte
21+
22+
// Load implements config.Source.
23+
func (b *bytesSource) Load() ([]*config.KeyValue, error) {
24+
// Make a copy of the data to avoid external modifications
25+
data := make([]byte, len(*b))
26+
copy(data, *b)
27+
return []*config.KeyValue{
28+
{
29+
Key: "server",
30+
Value: data,
31+
Format: format(*b),
32+
},
33+
}, nil
34+
}
35+
36+
// format detects the format from the data content.
37+
func format(data []byte) string {
38+
content := strings.TrimSpace(string(data))
39+
if strings.HasPrefix(content, "{") || strings.HasPrefix(content, "[") {
40+
return "json"
41+
}
42+
return "yaml"
43+
}
44+
45+
// Watch implements config.Source.
46+
func (b *bytesSource) Watch() (config.Watcher, error) {
47+
return newNoOpWatcher(), nil
48+
}
49+
50+
type noOpWatcher struct {
51+
ctx context.Context
52+
cancel context.CancelFunc
53+
}
54+
55+
func newNoOpWatcher() config.Watcher {
56+
ctx, cancel := context.WithCancel(context.Background())
57+
return &noOpWatcher{
58+
ctx: ctx,
59+
cancel: cancel,
60+
}
61+
}
62+
63+
// Next implements config.Watcher.
64+
func (w *noOpWatcher) Next() ([]*config.KeyValue, error) {
65+
<-w.ctx.Done()
66+
return nil, w.ctx.Err()
67+
}
68+
69+
// Stop implements config.Watcher.
70+
func (w *noOpWatcher) Stop() error {
71+
w.cancel()
72+
return nil
73+
}

internal/conf/conf.proto

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ option go_package = "github.com/aide-family/rabbit/internal/conf;conf";
1111
message Bootstrap {
1212
rabbit.enum.Environment environment = 1;
1313
Server server = 2;
14-
GlobalEmail globalEmail = 3;
14+
// GlobalEmail globalEmail = 3;
1515
JWT jwt = 4;
1616
map<string, rabbit.config.MySQLConfig> biz = 5;
1717
rabbit.config.MySQLConfig main = 6;

main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func main() {
6161
config.NewCmd(defaultServerConfig),
6262
delete.NewCmd(),
6363
get.NewCmd(),
64-
run.NewCmd(),
64+
run.NewCmd(defaultServerConfig),
6565
send.NewCmd(),
6666
version.NewCmd(),
6767
}

pkg/config/config.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package config
2+
3+
func (e RegistryType) IsUnknown() bool {
4+
return e == RegistryType_UNKNOWN
5+
}
6+
7+
func (e RegistryType) IsEtcd() bool {
8+
return e == RegistryType_ETCD
9+
}
10+
11+
func (e RegistryType) IsKubernetes() bool {
12+
return e == RegistryType_KUBERNETES
13+
}

0 commit comments

Comments
 (0)