github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/cmd/service/service.go (about)

     1  // Package service provides micro service commands
     2  package service
     3  
     4  import (
     5  	"fmt"
     6  	"os"
     7  	"strings"
     8  
     9  	"github.com/tickoalcantara12/micro/v3/cmd"
    10  	"github.com/tickoalcantara12/micro/v3/plugin"
    11  	"github.com/tickoalcantara12/micro/v3/service"
    12  	"github.com/tickoalcantara12/micro/v3/service/logger"
    13  	prox "github.com/tickoalcantara12/micro/v3/service/proxy"
    14  	"github.com/tickoalcantara12/micro/v3/service/proxy/grpc"
    15  	"github.com/tickoalcantara12/micro/v3/service/proxy/http"
    16  	"github.com/tickoalcantara12/micro/v3/service/proxy/mucp"
    17  	rt "github.com/tickoalcantara12/micro/v3/service/runtime"
    18  	"github.com/tickoalcantara12/micro/v3/service/server"
    19  	ccli "github.com/urfave/cli/v2"
    20  
    21  	// services
    22  	api "github.com/tickoalcantara12/micro/v3/service/api/server"
    23  	auth "github.com/tickoalcantara12/micro/v3/service/auth/server"
    24  	broker "github.com/tickoalcantara12/micro/v3/service/broker/server"
    25  	config "github.com/tickoalcantara12/micro/v3/service/config/server"
    26  	events "github.com/tickoalcantara12/micro/v3/service/events/server"
    27  	network "github.com/tickoalcantara12/micro/v3/service/network/server"
    28  	proxy "github.com/tickoalcantara12/micro/v3/service/proxy/server"
    29  	registry "github.com/tickoalcantara12/micro/v3/service/registry/server"
    30  	runtime "github.com/tickoalcantara12/micro/v3/service/runtime/server"
    31  	store "github.com/tickoalcantara12/micro/v3/service/store/server"
    32  
    33  	// misc commands
    34  	"github.com/tickoalcantara12/micro/v3/cmd/service/handler/exec"
    35  	"github.com/tickoalcantara12/micro/v3/cmd/service/handler/file"
    36  )
    37  
    38  // Run starts a micro service sidecar to encapsulate any app
    39  func Run(ctx *ccli.Context) {
    40  	name := ctx.String("name")
    41  	address := ctx.String("address")
    42  	endpoint := ctx.String("endpoint")
    43  
    44  	metadata := make(map[string]string)
    45  	for _, md := range ctx.StringSlice("metadata") {
    46  		parts := strings.Split(md, "=")
    47  		if len(parts) < 2 {
    48  			continue
    49  		}
    50  
    51  		key := parts[0]
    52  		val := strings.Join(parts[1:], "=")
    53  
    54  		// set the key/val
    55  		metadata[key] = val
    56  	}
    57  
    58  	var opts []service.Option
    59  	if len(metadata) > 0 {
    60  		opts = append(opts, service.Metadata(metadata))
    61  	}
    62  	if len(name) > 0 {
    63  		opts = append(opts, service.Name(name))
    64  	}
    65  	if len(address) > 0 {
    66  		opts = append(opts, service.Address(address))
    67  	}
    68  
    69  	if len(endpoint) == 0 {
    70  		endpoint = prox.DefaultEndpoint
    71  	}
    72  
    73  	var p prox.Proxy
    74  
    75  	switch {
    76  	case strings.HasPrefix(endpoint, "grpc"):
    77  		endpoint = strings.TrimPrefix(endpoint, "grpc://")
    78  		p = grpc.NewProxy(prox.WithEndpoint(endpoint))
    79  	case strings.HasPrefix(endpoint, "http"):
    80  		p = http.NewProxy(prox.WithEndpoint(endpoint))
    81  	case strings.HasPrefix(endpoint, "file"):
    82  		endpoint = strings.TrimPrefix(endpoint, "file://")
    83  		p = file.NewProxy(prox.WithEndpoint(endpoint))
    84  	case strings.HasPrefix(endpoint, "exec"):
    85  		endpoint = strings.TrimPrefix(endpoint, "exec://")
    86  		p = exec.NewProxy(prox.WithEndpoint(endpoint))
    87  	default:
    88  		p = mucp.NewProxy(prox.WithEndpoint(endpoint))
    89  	}
    90  
    91  	// run the service if asked to
    92  	if ctx.Args().Len() > 0 {
    93  		args := []rt.CreateOption{
    94  			rt.WithCommand(ctx.Args().Slice()...),
    95  			rt.WithOutput(os.Stdout),
    96  		}
    97  
    98  		// create new local runtime
    99  		r := rt.DefaultRuntime
   100  
   101  		// start the runtime
   102  		r.Start()
   103  
   104  		// register the service
   105  		r.Create(&rt.Service{
   106  			Name: name,
   107  		}, args...)
   108  
   109  		// stop the runtime
   110  		defer func() {
   111  			r.Delete(&rt.Service{
   112  				Name: name,
   113  			})
   114  			r.Stop()
   115  		}()
   116  	}
   117  
   118  	logger.Infof("Service [%s] Serving %s at endpoint %s\n", p.String(), name, endpoint)
   119  
   120  	// new service
   121  	srv := service.New(opts...)
   122  
   123  	// create new muxer
   124  	//	muxer := mux.New(name, p)
   125  
   126  	// set the router
   127  	srv.Server().Init(
   128  		server.WithRouter(p),
   129  	)
   130  
   131  	// run service
   132  	srv.Run()
   133  }
   134  
   135  type srvCommand struct {
   136  	Name    string
   137  	Command ccli.ActionFunc
   138  	Flags   []ccli.Flag
   139  }
   140  
   141  var srvCommands = []srvCommand{
   142  	{
   143  		Name:    "api",
   144  		Command: api.Run,
   145  		Flags:   api.Flags,
   146  	},
   147  	{
   148  		Name:    "auth",
   149  		Command: auth.Run,
   150  		Flags:   auth.Flags,
   151  	},
   152  	{
   153  		Name:    "broker",
   154  		Command: broker.Run,
   155  	},
   156  	{
   157  		Name:    "config",
   158  		Command: config.Run,
   159  		Flags:   config.Flags,
   160  	},
   161  	{
   162  		Name:    "events",
   163  		Command: events.Run,
   164  	},
   165  	{
   166  		Name:    "network",
   167  		Command: network.Run,
   168  		Flags:   network.Flags,
   169  	},
   170  	{
   171  		Name:    "proxy",
   172  		Command: proxy.Run,
   173  		Flags:   proxy.Flags,
   174  	},
   175  	{
   176  		Name:    "registry",
   177  		Command: registry.Run,
   178  	},
   179  	{
   180  		Name:    "runtime",
   181  		Command: runtime.Run,
   182  		Flags:   runtime.Flags,
   183  	},
   184  	{
   185  		Name:    "store",
   186  		Command: store.Run,
   187  	},
   188  }
   189  
   190  func init() {
   191  	// move newAction outside the loop and pass c as an arg to
   192  	// set the scope of the variable
   193  	newAction := func(c srvCommand) func(ctx *ccli.Context) error {
   194  		return func(ctx *ccli.Context) error {
   195  			// configure the loggerger
   196  			logger.DefaultLogger.Init(logger.WithFields(map[string]interface{}{"service": c.Name}))
   197  
   198  			// run the service
   199  			c.Command(ctx)
   200  			return nil
   201  		}
   202  	}
   203  
   204  	subcommands := make([]*ccli.Command, len(srvCommands))
   205  	for i, c := range srvCommands {
   206  		// construct the command
   207  		command := &ccli.Command{
   208  			Name:   c.Name,
   209  			Flags:  c.Flags,
   210  			Usage:  fmt.Sprintf("Run micro %v", c.Name),
   211  			Action: newAction(c),
   212  		}
   213  
   214  		// setup the plugins
   215  		for _, p := range plugin.Plugins(plugin.Module(c.Name)) {
   216  			if cmds := p.Commands(); len(cmds) > 0 {
   217  				command.Subcommands = append(command.Subcommands, cmds...)
   218  			}
   219  
   220  			if flags := p.Flags(); len(flags) > 0 {
   221  				command.Flags = append(command.Flags, flags...)
   222  			}
   223  		}
   224  
   225  		// set the command
   226  		subcommands[i] = command
   227  	}
   228  
   229  	command := &ccli.Command{
   230  		Name:  "service",
   231  		Usage: "Run a micro service",
   232  		Action: func(ctx *ccli.Context) error {
   233  			Run(ctx)
   234  			return nil
   235  		},
   236  		Flags: []ccli.Flag{
   237  			&ccli.StringFlag{
   238  				Name:    "name",
   239  				Usage:   "Name of the service",
   240  				EnvVars: []string{"MICRO_SERVICE_NAME"},
   241  				Value:   "service",
   242  			},
   243  			&ccli.StringFlag{
   244  				Name:    "address",
   245  				Usage:   "Address of the service",
   246  				EnvVars: []string{"MICRO_SERVICE_ADDRESS"},
   247  			},
   248  			&ccli.StringFlag{
   249  				Name:    "endpoint",
   250  				Usage:   "The local service endpoint (Defaults to localhost:9090); {http, grpc, file, exec}://path-or-address e.g http://localhost:9090",
   251  				EnvVars: []string{"MICRO_SERVICE_ENDPOINT"},
   252  			},
   253  			&ccli.StringSliceFlag{
   254  				Name:    "metadata",
   255  				Usage:   "Add metadata as key-value pairs describing the service e.g owner=john@example.com",
   256  				EnvVars: []string{"MICRO_SERVICE_METADATA"},
   257  			},
   258  		},
   259  		Subcommands: subcommands,
   260  	}
   261  
   262  	// register global plugins and flags
   263  	for _, p := range plugin.Plugins() {
   264  		if cmds := p.Commands(); len(cmds) > 0 {
   265  			command.Subcommands = append(command.Subcommands, cmds...)
   266  		}
   267  
   268  		if flags := p.Flags(); len(flags) > 0 {
   269  			command.Flags = append(command.Flags, flags...)
   270  		}
   271  	}
   272  
   273  	cmd.Register(command)
   274  }