github.com/annwntech/go-micro/v2@v2.9.5/config/cmd/cmd.go (about) 1 // Package cmd is an interface for parsing the command line 2 package cmd 3 4 import ( 5 "fmt" 6 "math/rand" 7 "strings" 8 "time" 9 10 "github.com/annwntech/go-micro/v2/auth" 11 "github.com/annwntech/go-micro/v2/auth/provider" 12 "github.com/annwntech/go-micro/v2/broker" 13 "github.com/annwntech/go-micro/v2/client" 14 "github.com/annwntech/go-micro/v2/client/grpc" 15 "github.com/annwntech/go-micro/v2/client/selector" 16 "github.com/annwntech/go-micro/v2/config" 17 configSrc "github.com/annwntech/go-micro/v2/config/source" 18 configSrv "github.com/annwntech/go-micro/v2/config/source/service" 19 "github.com/annwntech/go-micro/v2/debug/profile" 20 "github.com/annwntech/go-micro/v2/debug/profile/http" 21 "github.com/annwntech/go-micro/v2/debug/profile/pprof" 22 "github.com/annwntech/go-micro/v2/debug/trace" 23 "github.com/annwntech/go-micro/v2/logger" 24 "github.com/annwntech/go-micro/v2/registry" 25 registrySrv "github.com/annwntech/go-micro/v2/registry/service" 26 "github.com/annwntech/go-micro/v2/runtime" 27 "github.com/annwntech/go-micro/v2/server" 28 "github.com/annwntech/go-micro/v2/store" 29 "github.com/annwntech/go-micro/v2/transport" 30 authutil "github.com/annwntech/go-micro/v2/util/auth" 31 "github.com/annwntech/go-micro/v2/util/wrapper" 32 33 // clients 34 cgrpc "github.com/annwntech/go-micro/v2/client/grpc" 35 cmucp "github.com/annwntech/go-micro/v2/client/mucp" 36 37 // servers 38 "github.com/micro/cli/v2" 39 40 sgrpc "github.com/annwntech/go-micro/v2/server/grpc" 41 smucp "github.com/annwntech/go-micro/v2/server/mucp" 42 43 // brokers 44 brokerHttp "github.com/annwntech/go-micro/v2/broker/http" 45 "github.com/annwntech/go-micro/v2/broker/memory" 46 "github.com/annwntech/go-micro/v2/broker/nats" 47 brokerSrv "github.com/annwntech/go-micro/v2/broker/service" 48 49 // registries 50 "github.com/annwntech/go-micro/v2/registry/etcd" 51 "github.com/annwntech/go-micro/v2/registry/mdns" 52 rmem "github.com/annwntech/go-micro/v2/registry/memory" 53 regSrv "github.com/annwntech/go-micro/v2/registry/service" 54 55 // runtimes 56 kRuntime "github.com/annwntech/go-micro/v2/runtime/kubernetes" 57 lRuntime "github.com/annwntech/go-micro/v2/runtime/local" 58 srvRuntime "github.com/annwntech/go-micro/v2/runtime/service" 59 60 // selectors 61 "github.com/annwntech/go-micro/v2/client/selector/dns" 62 "github.com/annwntech/go-micro/v2/client/selector/router" 63 "github.com/annwntech/go-micro/v2/client/selector/static" 64 65 // transports 66 thttp "github.com/annwntech/go-micro/v2/transport/http" 67 tmem "github.com/annwntech/go-micro/v2/transport/memory" 68 69 // stores 70 memStore "github.com/annwntech/go-micro/v2/store/memory" 71 svcStore "github.com/annwntech/go-micro/v2/store/service" 72 73 // tracers 74 // jTracer "github.com/annwntech/go-micro/v2/debug/trace/jaeger" 75 memTracer "github.com/annwntech/go-micro/v2/debug/trace/memory" 76 77 // auth 78 jwtAuth "github.com/annwntech/go-micro/v2/auth/jwt" 79 svcAuth "github.com/annwntech/go-micro/v2/auth/service" 80 81 // auth providers 82 "github.com/annwntech/go-micro/v2/auth/provider/basic" 83 "github.com/annwntech/go-micro/v2/auth/provider/oauth" 84 ) 85 86 type Cmd interface { 87 // The cli app within this cmd 88 App() *cli.App 89 // Adds options, parses flags and initialise 90 // exits on error 91 Init(opts ...Option) error 92 // Options set within this command 93 Options() Options 94 } 95 96 type cmd struct { 97 opts Options 98 app *cli.App 99 } 100 101 type Option func(o *Options) 102 103 var ( 104 DefaultCmd = newCmd() 105 106 DefaultFlags = []cli.Flag{ 107 &cli.StringFlag{ 108 Name: "client", 109 EnvVars: []string{"MICRO_CLIENT"}, 110 Usage: "Client for go-micro; rpc", 111 }, 112 &cli.StringFlag{ 113 Name: "client_request_timeout", 114 EnvVars: []string{"MICRO_CLIENT_REQUEST_TIMEOUT"}, 115 Usage: "Sets the client request timeout. e.g 500ms, 5s, 1m. Default: 5s", 116 }, 117 &cli.IntFlag{ 118 Name: "client_retries", 119 EnvVars: []string{"MICRO_CLIENT_RETRIES"}, 120 Value: client.DefaultRetries, 121 Usage: "Sets the client retries. Default: 1", 122 }, 123 &cli.IntFlag{ 124 Name: "client_pool_size", 125 EnvVars: []string{"MICRO_CLIENT_POOL_SIZE"}, 126 Usage: "Sets the client connection pool size. Default: 1", 127 }, 128 &cli.StringFlag{ 129 Name: "client_pool_ttl", 130 EnvVars: []string{"MICRO_CLIENT_POOL_TTL"}, 131 Usage: "Sets the client connection pool ttl. e.g 500ms, 5s, 1m. Default: 1m", 132 }, 133 &cli.IntFlag{ 134 Name: "register_ttl", 135 EnvVars: []string{"MICRO_REGISTER_TTL"}, 136 Value: 60, 137 Usage: "Register TTL in seconds", 138 }, 139 &cli.IntFlag{ 140 Name: "register_interval", 141 EnvVars: []string{"MICRO_REGISTER_INTERVAL"}, 142 Value: 30, 143 Usage: "Register interval in seconds", 144 }, 145 &cli.StringFlag{ 146 Name: "server", 147 EnvVars: []string{"MICRO_SERVER"}, 148 Usage: "Server for go-micro; rpc", 149 }, 150 &cli.StringFlag{ 151 Name: "server_name", 152 EnvVars: []string{"MICRO_SERVER_NAME"}, 153 Usage: "Name of the server. go.micro.srv.example", 154 }, 155 &cli.StringFlag{ 156 Name: "server_version", 157 EnvVars: []string{"MICRO_SERVER_VERSION"}, 158 Usage: "Version of the server. 1.1.0", 159 }, 160 &cli.StringFlag{ 161 Name: "server_id", 162 EnvVars: []string{"MICRO_SERVER_ID"}, 163 Usage: "Id of the server. Auto-generated if not specified", 164 }, 165 &cli.StringFlag{ 166 Name: "server_address", 167 EnvVars: []string{"MICRO_SERVER_ADDRESS"}, 168 Usage: "Bind address for the server. 127.0.0.1:8080", 169 }, 170 &cli.StringFlag{ 171 Name: "server_advertise", 172 EnvVars: []string{"MICRO_SERVER_ADVERTISE"}, 173 Usage: "Used instead of the server_address when registering with discovery. 127.0.0.1:8080", 174 }, 175 &cli.StringSliceFlag{ 176 Name: "server_metadata", 177 EnvVars: []string{"MICRO_SERVER_METADATA"}, 178 Value: &cli.StringSlice{}, 179 Usage: "A list of key-value pairs defining metadata. version=1.0.0", 180 }, 181 &cli.StringFlag{ 182 Name: "broker", 183 EnvVars: []string{"MICRO_BROKER"}, 184 Usage: "Broker for pub/sub. http, nats, rabbitmq", 185 }, 186 &cli.StringFlag{ 187 Name: "broker_address", 188 EnvVars: []string{"MICRO_BROKER_ADDRESS"}, 189 Usage: "Comma-separated list of broker addresses", 190 }, 191 &cli.StringFlag{ 192 Name: "profile", 193 Usage: "Debug profiler for cpu and memory stats", 194 EnvVars: []string{"MICRO_DEBUG_PROFILE"}, 195 }, 196 &cli.StringFlag{ 197 Name: "registry", 198 EnvVars: []string{"MICRO_REGISTRY"}, 199 Usage: "Registry for discovery. etcd, mdns", 200 }, 201 &cli.StringFlag{ 202 Name: "registry_address", 203 EnvVars: []string{"MICRO_REGISTRY_ADDRESS"}, 204 Usage: "Comma-separated list of registry addresses", 205 }, 206 &cli.StringFlag{ 207 Name: "runtime", 208 Usage: "Runtime for building and running services e.g local, kubernetes", 209 EnvVars: []string{"MICRO_RUNTIME"}, 210 Value: "local", 211 }, 212 &cli.StringFlag{ 213 Name: "runtime_source", 214 Usage: "Runtime source for building and running services e.g github.com/micro/service", 215 EnvVars: []string{"MICRO_RUNTIME_SOURCE"}, 216 Value: "github.com/micro/services", 217 }, 218 &cli.StringFlag{ 219 Name: "selector", 220 EnvVars: []string{"MICRO_SELECTOR"}, 221 Usage: "Selector used to pick nodes for querying", 222 }, 223 &cli.StringFlag{ 224 Name: "store", 225 EnvVars: []string{"MICRO_STORE"}, 226 Usage: "Store used for key-value storage", 227 }, 228 &cli.StringFlag{ 229 Name: "store_address", 230 EnvVars: []string{"MICRO_STORE_ADDRESS"}, 231 Usage: "Comma-separated list of store addresses", 232 }, 233 &cli.StringFlag{ 234 Name: "store_database", 235 EnvVars: []string{"MICRO_STORE_DATABASE"}, 236 Usage: "Database option for the underlying store", 237 }, 238 &cli.StringFlag{ 239 Name: "store_table", 240 EnvVars: []string{"MICRO_STORE_TABLE"}, 241 Usage: "Table option for the underlying store", 242 }, 243 &cli.StringFlag{ 244 Name: "transport", 245 EnvVars: []string{"MICRO_TRANSPORT"}, 246 Usage: "Transport mechanism used; http", 247 }, 248 &cli.StringFlag{ 249 Name: "transport_address", 250 EnvVars: []string{"MICRO_TRANSPORT_ADDRESS"}, 251 Usage: "Comma-separated list of transport addresses", 252 }, 253 &cli.StringFlag{ 254 Name: "tracer", 255 EnvVars: []string{"MICRO_TRACER"}, 256 Usage: "Tracer for distributed tracing, e.g. memory, jaeger", 257 }, 258 &cli.StringFlag{ 259 Name: "tracer_address", 260 EnvVars: []string{"MICRO_TRACER_ADDRESS"}, 261 Usage: "Comma-separated list of tracer addresses", 262 }, 263 &cli.StringFlag{ 264 Name: "auth", 265 EnvVars: []string{"MICRO_AUTH"}, 266 Usage: "Auth for role based access control, e.g. service", 267 }, 268 &cli.StringFlag{ 269 Name: "auth_id", 270 EnvVars: []string{"MICRO_AUTH_ID"}, 271 Usage: "Account ID used for client authentication", 272 }, 273 &cli.StringFlag{ 274 Name: "auth_secret", 275 EnvVars: []string{"MICRO_AUTH_SECRET"}, 276 Usage: "Account secret used for client authentication", 277 }, 278 &cli.StringFlag{ 279 Name: "auth_namespace", 280 EnvVars: []string{"MICRO_AUTH_NAMESPACE"}, 281 Usage: "Namespace for the services auth account", 282 Value: "go.micro", 283 }, 284 &cli.StringFlag{ 285 Name: "auth_public_key", 286 EnvVars: []string{"MICRO_AUTH_PUBLIC_KEY"}, 287 Usage: "Public key for JWT auth (base64 encoded PEM)", 288 }, 289 &cli.StringFlag{ 290 Name: "auth_private_key", 291 EnvVars: []string{"MICRO_AUTH_PRIVATE_KEY"}, 292 Usage: "Private key for JWT auth (base64 encoded PEM)", 293 }, 294 &cli.StringFlag{ 295 Name: "auth_provider", 296 EnvVars: []string{"MICRO_AUTH_PROVIDER"}, 297 Usage: "Auth provider used to login user", 298 }, 299 &cli.StringFlag{ 300 Name: "auth_provider_client_id", 301 EnvVars: []string{"MICRO_AUTH_PROVIDER_CLIENT_ID"}, 302 Usage: "The client id to be used for oauth", 303 }, 304 &cli.StringFlag{ 305 Name: "auth_provider_client_secret", 306 EnvVars: []string{"MICRO_AUTH_PROVIDER_CLIENT_SECRET"}, 307 Usage: "The client secret to be used for oauth", 308 }, 309 &cli.StringFlag{ 310 Name: "auth_provider_endpoint", 311 EnvVars: []string{"MICRO_AUTH_PROVIDER_ENDPOINT"}, 312 Usage: "The enpoint to be used for oauth", 313 }, 314 &cli.StringFlag{ 315 Name: "auth_provider_redirect", 316 EnvVars: []string{"MICRO_AUTH_PROVIDER_REDIRECT"}, 317 Usage: "The redirect to be used for oauth", 318 }, 319 &cli.StringFlag{ 320 Name: "auth_provider_scope", 321 EnvVars: []string{"MICRO_AUTH_PROVIDER_SCOPE"}, 322 Usage: "The scope to be used for oauth", 323 }, 324 &cli.StringFlag{ 325 Name: "config", 326 EnvVars: []string{"MICRO_CONFIG"}, 327 Usage: "The source of the config to be used to get configuration", 328 }, 329 } 330 331 DefaultBrokers = map[string]func(...broker.Option) broker.Broker{ 332 "service": brokerSrv.NewBroker, 333 "memory": memory.NewBroker, 334 "nats": nats.NewBroker, 335 "http": brokerHttp.NewBroker, 336 } 337 338 DefaultClients = map[string]func(...client.Option) client.Client{ 339 "mucp": cmucp.NewClient, 340 "grpc": cgrpc.NewClient, 341 } 342 343 DefaultRegistries = map[string]func(...registry.Option) registry.Registry{ 344 "service": regSrv.NewRegistry, 345 "etcd": etcd.NewRegistry, 346 "mdns": mdns.NewRegistry, 347 "memory": rmem.NewRegistry, 348 } 349 350 DefaultSelectors = map[string]func(...selector.Option) selector.Selector{ 351 "dns": dns.NewSelector, 352 "router": router.NewSelector, 353 "static": static.NewSelector, 354 } 355 356 DefaultServers = map[string]func(...server.Option) server.Server{ 357 "mucp": smucp.NewServer, 358 "grpc": sgrpc.NewServer, 359 } 360 361 DefaultTransports = map[string]func(...transport.Option) transport.Transport{ 362 "memory": tmem.NewTransport, 363 "http": thttp.NewTransport, 364 } 365 366 DefaultRuntimes = map[string]func(...runtime.Option) runtime.Runtime{ 367 "local": lRuntime.NewRuntime, 368 "service": srvRuntime.NewRuntime, 369 "kubernetes": kRuntime.NewRuntime, 370 } 371 372 DefaultStores = map[string]func(...store.Option) store.Store{ 373 "memory": memStore.NewStore, 374 "service": svcStore.NewStore, 375 } 376 377 DefaultTracers = map[string]func(...trace.Option) trace.Tracer{ 378 "memory": memTracer.NewTracer, 379 // "jaeger": jTracer.NewTracer, 380 } 381 382 DefaultAuths = map[string]func(...auth.Option) auth.Auth{ 383 "service": svcAuth.NewAuth, 384 "jwt": jwtAuth.NewAuth, 385 } 386 387 DefaultAuthProviders = map[string]func(...provider.Option) provider.Provider{ 388 "oauth": oauth.NewProvider, 389 "basic": basic.NewProvider, 390 } 391 392 DefaultProfiles = map[string]func(...profile.Option) profile.Profile{ 393 "http": http.NewProfile, 394 "pprof": pprof.NewProfile, 395 } 396 397 DefaultConfigs = map[string]func(...config.Option) (config.Config, error){ 398 "service": config.NewConfig, 399 } 400 ) 401 402 func init() { 403 rand.Seed(time.Now().Unix()) 404 } 405 406 func newCmd(opts ...Option) Cmd { 407 options := Options{ 408 Auth: &auth.DefaultAuth, 409 Broker: &broker.DefaultBroker, 410 Client: &client.DefaultClient, 411 Registry: ®istry.DefaultRegistry, 412 Server: &server.DefaultServer, 413 Selector: &selector.DefaultSelector, 414 Transport: &transport.DefaultTransport, 415 Runtime: &runtime.DefaultRuntime, 416 Store: &store.DefaultStore, 417 Tracer: &trace.DefaultTracer, 418 Profile: &profile.DefaultProfile, 419 Config: &config.DefaultConfig, 420 421 Brokers: DefaultBrokers, 422 Clients: DefaultClients, 423 Registries: DefaultRegistries, 424 Selectors: DefaultSelectors, 425 Servers: DefaultServers, 426 Transports: DefaultTransports, 427 Runtimes: DefaultRuntimes, 428 Stores: DefaultStores, 429 Tracers: DefaultTracers, 430 Auths: DefaultAuths, 431 Profiles: DefaultProfiles, 432 Configs: DefaultConfigs, 433 } 434 435 for _, o := range opts { 436 o(&options) 437 } 438 439 if len(options.Description) == 0 { 440 options.Description = "a go-micro service" 441 } 442 443 cmd := new(cmd) 444 cmd.opts = options 445 cmd.app = cli.NewApp() 446 cmd.app.Name = cmd.opts.Name 447 cmd.app.Version = cmd.opts.Version 448 cmd.app.Usage = cmd.opts.Description 449 cmd.app.Before = cmd.Before 450 cmd.app.Flags = DefaultFlags 451 cmd.app.Action = func(c *cli.Context) error { 452 return nil 453 } 454 455 if len(options.Version) == 0 { 456 cmd.app.HideVersion = true 457 } 458 459 return cmd 460 } 461 462 func (c *cmd) App() *cli.App { 463 return c.app 464 } 465 466 func (c *cmd) Options() Options { 467 return c.opts 468 } 469 470 func (c *cmd) Before(ctx *cli.Context) error { 471 // If flags are set then use them otherwise do nothing 472 var serverOpts []server.Option 473 var clientOpts []client.Option 474 475 // setup a client to use when calling the runtime. It is important the auth client is wrapped 476 // after the cache client since the wrappers are applied in reverse order and the cache will use 477 // some of the headers set by the auth client. 478 authFn := func() auth.Auth { return *c.opts.Auth } 479 cacheFn := func() *client.Cache { return (*c.opts.Client).Options().Cache } 480 microClient := wrapper.CacheClient(cacheFn, grpc.NewClient()) 481 microClient = wrapper.AuthClient(authFn, microClient) 482 483 // Set the store 484 if name := ctx.String("store"); len(name) > 0 { 485 s, ok := c.opts.Stores[name] 486 if !ok { 487 return fmt.Errorf("Unsupported store: %s", name) 488 } 489 490 *c.opts.Store = s(store.WithClient(microClient)) 491 } 492 493 // Set the runtime 494 if name := ctx.String("runtime"); len(name) > 0 { 495 r, ok := c.opts.Runtimes[name] 496 if !ok { 497 return fmt.Errorf("Unsupported runtime: %s", name) 498 } 499 500 *c.opts.Runtime = r(runtime.WithClient(microClient)) 501 } 502 503 // Set the tracer 504 if name := ctx.String("tracer"); len(name) > 0 { 505 r, ok := c.opts.Tracers[name] 506 if !ok { 507 return fmt.Errorf("Unsupported tracer: %s", name) 508 } 509 510 *c.opts.Tracer = r() 511 } 512 513 // Set the client 514 if name := ctx.String("client"); len(name) > 0 { 515 // only change if we have the client and type differs 516 if cl, ok := c.opts.Clients[name]; ok && (*c.opts.Client).String() != name { 517 *c.opts.Client = cl() 518 } 519 } 520 521 // Set the server 522 if name := ctx.String("server"); len(name) > 0 { 523 // only change if we have the server and type differs 524 if s, ok := c.opts.Servers[name]; ok && (*c.opts.Server).String() != name { 525 *c.opts.Server = s() 526 } 527 } 528 529 // Setup auth 530 authOpts := []auth.Option{} 531 532 if len(ctx.String("auth_id")) > 0 || len(ctx.String("auth_secret")) > 0 { 533 authOpts = append(authOpts, auth.Credentials( 534 ctx.String("auth_id"), ctx.String("auth_secret"), 535 )) 536 } 537 if len(ctx.String("auth_public_key")) > 0 { 538 authOpts = append(authOpts, auth.PublicKey(ctx.String("auth_public_key"))) 539 } 540 if len(ctx.String("auth_private_key")) > 0 { 541 authOpts = append(authOpts, auth.PrivateKey(ctx.String("auth_private_key"))) 542 } 543 if len(ctx.String("auth_namespace")) > 0 { 544 authOpts = append(authOpts, auth.Issuer(ctx.String("auth_namespace"))) 545 } 546 if name := ctx.String("auth_provider"); len(name) > 0 { 547 _, ok := DefaultAuthProviders[name] 548 if !ok { 549 return fmt.Errorf("AuthProvider %s not found", name) 550 } 551 552 var provOpts []provider.Option 553 clientID := ctx.String("auth_provider_client_id") 554 clientSecret := ctx.String("auth_provider_client_secret") 555 if len(clientID) > 0 || len(clientSecret) > 0 { 556 provOpts = append(provOpts, provider.Credentials(clientID, clientSecret)) 557 } 558 if e := ctx.String("auth_provider_endpoint"); len(e) > 0 { 559 provOpts = append(provOpts, provider.Endpoint(e)) 560 } 561 if r := ctx.String("auth_provider_redirect"); len(r) > 0 { 562 provOpts = append(provOpts, provider.Redirect(r)) 563 } 564 if s := ctx.String("auth_provider_scope"); len(s) > 0 { 565 provOpts = append(provOpts, provider.Scope(s)) 566 } 567 568 // authOpts = append(authOpts, auth.WithProvider(p(provOpts...))) 569 } 570 571 // Set the auth 572 if name := ctx.String("auth"); len(name) > 0 { 573 a, ok := c.opts.Auths[name] 574 if !ok { 575 return fmt.Errorf("Unsupported auth: %s", name) 576 } 577 *c.opts.Auth = a(authOpts...) 578 serverOpts = append(serverOpts, server.Auth(*c.opts.Auth)) 579 } else { 580 (*c.opts.Auth).Init(authOpts...) 581 } 582 583 // Set the registry 584 if name := ctx.String("registry"); len(name) > 0 && (*c.opts.Registry).String() != name { 585 r, ok := c.opts.Registries[name] 586 if !ok { 587 return fmt.Errorf("Registry %s not found", name) 588 } 589 590 *c.opts.Registry = r(registrySrv.WithClient(microClient)) 591 serverOpts = append(serverOpts, server.Registry(*c.opts.Registry)) 592 clientOpts = append(clientOpts, client.Registry(*c.opts.Registry)) 593 594 if err := (*c.opts.Selector).Init(selector.Registry(*c.opts.Registry)); err != nil { 595 logger.Fatalf("Error configuring registry: %v", err) 596 } 597 598 clientOpts = append(clientOpts, client.Selector(*c.opts.Selector)) 599 600 if err := (*c.opts.Broker).Init(broker.Registry(*c.opts.Registry)); err != nil { 601 logger.Fatalf("Error configuring broker: %v", err) 602 } 603 } 604 605 // generate the services auth account 606 serverID := (*c.opts.Server).Options().Id 607 if err := authutil.Generate(serverID, c.App().Name, (*c.opts.Auth)); err != nil { 608 return err 609 } 610 611 // Set the profile 612 if name := ctx.String("profile"); len(name) > 0 { 613 p, ok := c.opts.Profiles[name] 614 if !ok { 615 return fmt.Errorf("Unsupported profile: %s", name) 616 } 617 618 *c.opts.Profile = p() 619 } 620 621 // Set the broker 622 if name := ctx.String("broker"); len(name) > 0 && (*c.opts.Broker).String() != name { 623 b, ok := c.opts.Brokers[name] 624 if !ok { 625 return fmt.Errorf("Broker %s not found", name) 626 } 627 628 *c.opts.Broker = b() 629 serverOpts = append(serverOpts, server.Broker(*c.opts.Broker)) 630 clientOpts = append(clientOpts, client.Broker(*c.opts.Broker)) 631 } 632 633 // Set the selector 634 if name := ctx.String("selector"); len(name) > 0 && (*c.opts.Selector).String() != name { 635 s, ok := c.opts.Selectors[name] 636 if !ok { 637 return fmt.Errorf("Selector %s not found", name) 638 } 639 640 *c.opts.Selector = s(selector.Registry(*c.opts.Registry)) 641 642 // No server option here. Should there be? 643 clientOpts = append(clientOpts, client.Selector(*c.opts.Selector)) 644 } 645 646 // Set the transport 647 if name := ctx.String("transport"); len(name) > 0 && (*c.opts.Transport).String() != name { 648 t, ok := c.opts.Transports[name] 649 if !ok { 650 return fmt.Errorf("Transport %s not found", name) 651 } 652 653 *c.opts.Transport = t() 654 serverOpts = append(serverOpts, server.Transport(*c.opts.Transport)) 655 clientOpts = append(clientOpts, client.Transport(*c.opts.Transport)) 656 } 657 658 // Parse the server options 659 metadata := make(map[string]string) 660 for _, d := range ctx.StringSlice("server_metadata") { 661 var key, val string 662 parts := strings.Split(d, "=") 663 key = parts[0] 664 if len(parts) > 1 { 665 val = strings.Join(parts[1:], "=") 666 } 667 metadata[key] = val 668 } 669 670 if len(metadata) > 0 { 671 serverOpts = append(serverOpts, server.Metadata(metadata)) 672 } 673 674 if len(ctx.String("broker_address")) > 0 { 675 if err := (*c.opts.Broker).Init(broker.Addrs(strings.Split(ctx.String("broker_address"), ",")...)); err != nil { 676 logger.Fatalf("Error configuring broker: %v", err) 677 } 678 } 679 680 if len(ctx.String("registry_address")) > 0 { 681 if err := (*c.opts.Registry).Init(registry.Addrs(strings.Split(ctx.String("registry_address"), ",")...)); err != nil { 682 logger.Fatalf("Error configuring registry: %v", err) 683 } 684 } 685 686 if len(ctx.String("transport_address")) > 0 { 687 if err := (*c.opts.Transport).Init(transport.Addrs(strings.Split(ctx.String("transport_address"), ",")...)); err != nil { 688 logger.Fatalf("Error configuring transport: %v", err) 689 } 690 } 691 692 if len(ctx.String("store_address")) > 0 { 693 if err := (*c.opts.Store).Init(store.Nodes(strings.Split(ctx.String("store_address"), ",")...)); err != nil { 694 logger.Fatalf("Error configuring store: %v", err) 695 } 696 } 697 698 if len(ctx.String("store_database")) > 0 { 699 if err := (*c.opts.Store).Init(store.Database(ctx.String("store_database"))); err != nil { 700 logger.Fatalf("Error configuring store database option: %v", err) 701 } 702 } 703 704 if len(ctx.String("store_table")) > 0 { 705 if err := (*c.opts.Store).Init(store.Table(ctx.String("store_table"))); err != nil { 706 logger.Fatalf("Error configuring store table option: %v", err) 707 } 708 } 709 710 if len(ctx.String("server_name")) > 0 { 711 serverOpts = append(serverOpts, server.Name(ctx.String("server_name"))) 712 } 713 714 if len(ctx.String("server_version")) > 0 { 715 serverOpts = append(serverOpts, server.Version(ctx.String("server_version"))) 716 } 717 718 if len(ctx.String("server_id")) > 0 { 719 serverOpts = append(serverOpts, server.Id(ctx.String("server_id"))) 720 } 721 722 if len(ctx.String("server_address")) > 0 { 723 serverOpts = append(serverOpts, server.Address(ctx.String("server_address"))) 724 } 725 726 if len(ctx.String("server_advertise")) > 0 { 727 serverOpts = append(serverOpts, server.Advertise(ctx.String("server_advertise"))) 728 } 729 730 if ttl := time.Duration(ctx.Int("register_ttl")); ttl >= 0 { 731 serverOpts = append(serverOpts, server.RegisterTTL(ttl*time.Second)) 732 } 733 734 if val := time.Duration(ctx.Int("register_interval")); val >= 0 { 735 serverOpts = append(serverOpts, server.RegisterInterval(val*time.Second)) 736 } 737 738 if len(ctx.String("runtime_source")) > 0 { 739 if err := (*c.opts.Runtime).Init(runtime.WithSource(ctx.String("runtime_source"))); err != nil { 740 logger.Fatalf("Error configuring runtime: %v", err) 741 } 742 } 743 744 if ctx.String("config") == "service" { 745 opt := config.WithSource(configSrv.NewSource(configSrc.WithClient(microClient))) 746 if err := (*c.opts.Config).Init(opt); err != nil { 747 logger.Fatalf("Error configuring config: %v", err) 748 } 749 } 750 751 // client opts 752 if r := ctx.Int("client_retries"); r >= 0 { 753 clientOpts = append(clientOpts, client.Retries(r)) 754 } 755 756 if t := ctx.String("client_request_timeout"); len(t) > 0 { 757 d, err := time.ParseDuration(t) 758 if err != nil { 759 return fmt.Errorf("failed to parse client_request_timeout: %v", t) 760 } 761 clientOpts = append(clientOpts, client.RequestTimeout(d)) 762 } 763 764 if r := ctx.Int("client_pool_size"); r > 0 { 765 clientOpts = append(clientOpts, client.PoolSize(r)) 766 } 767 768 if t := ctx.String("client_pool_ttl"); len(t) > 0 { 769 d, err := time.ParseDuration(t) 770 if err != nil { 771 return fmt.Errorf("failed to parse client_pool_ttl: %v", t) 772 } 773 clientOpts = append(clientOpts, client.PoolTTL(d)) 774 } 775 776 // We have some command line opts for the server. 777 // Lets set it up 778 if len(serverOpts) > 0 { 779 if err := (*c.opts.Server).Init(serverOpts...); err != nil { 780 logger.Fatalf("Error configuring server: %v", err) 781 } 782 } 783 784 // Use an init option? 785 if len(clientOpts) > 0 { 786 if err := (*c.opts.Client).Init(clientOpts...); err != nil { 787 logger.Fatalf("Error configuring client: %v", err) 788 } 789 } 790 791 return nil 792 } 793 794 func (c *cmd) Init(opts ...Option) error { 795 for _, o := range opts { 796 o(&c.opts) 797 } 798 if len(c.opts.Name) > 0 { 799 c.app.Name = c.opts.Name 800 } 801 if len(c.opts.Version) > 0 { 802 c.app.Version = c.opts.Version 803 } 804 c.app.HideVersion = len(c.opts.Version) == 0 805 c.app.Usage = c.opts.Description 806 c.app.RunAndExitOnError() 807 return nil 808 } 809 810 func DefaultOptions() Options { 811 return DefaultCmd.Options() 812 } 813 814 func App() *cli.App { 815 return DefaultCmd.App() 816 } 817 818 func Init(opts ...Option) error { 819 return DefaultCmd.Init(opts...) 820 } 821 822 func NewCmd(opts ...Option) Cmd { 823 return newCmd(opts...) 824 }