go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/logdog/client/cmd/logdog_butler/subcommand_serve.go (about)

     1  // Copyright 2015 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"strings"
    19  
    20  	log "go.chromium.org/luci/common/logging"
    21  	"go.chromium.org/luci/logdog/client/butler"
    22  	"go.chromium.org/luci/logdog/client/butler/streamserver"
    23  
    24  	"github.com/maruel/subcommands"
    25  )
    26  
    27  var subcommandServe = &subcommands.Command{
    28  	UsageLine: "serve",
    29  	ShortDesc: "Instantiates a stream server.",
    30  	LongDesc:  "Instantiates a stream server, accepting connections and forwarding them to output.",
    31  	CommandRun: func() subcommands.CommandRun {
    32  		cmd := &serveCommandRun{}
    33  		cmd.Flags.StringVar(&cmd.uri, "streamserver-uri", "",
    34  			`The stream server Unix socket to bind to "unix:<absolute path>" `+
    35  				`(the default is to pick a unique path).`)
    36  		return cmd
    37  	},
    38  }
    39  
    40  type serveCommandRun struct {
    41  	subcommands.CommandRunBase
    42  
    43  	uri string
    44  }
    45  
    46  func (cmd *serveCommandRun) Run(app subcommands.Application, args []string, _ subcommands.Env) int {
    47  	a := app.(*application)
    48  
    49  	// HACK: -streamserver-uri is only really used on Linux, so we recognize only
    50  	// Unix sockets (not Windows named pipes).
    51  	if cmd.uri != "" {
    52  		if !strings.HasPrefix(cmd.uri, "unix:") {
    53  			log.Errorf(a, "Only unix stream server URI are supported, got %q", cmd.uri)
    54  			return runtimeErrorReturnCode
    55  		}
    56  		cmd.uri = strings.TrimPrefix(cmd.uri, "unix:")
    57  	}
    58  
    59  	streamServer, err := streamserver.New(a, cmd.uri)
    60  	if err != nil {
    61  		log.WithError(err).Errorf(a, "Failed to make the stream server.")
    62  		return runtimeErrorReturnCode
    63  	}
    64  
    65  	if err := streamServer.Listen(); err != nil {
    66  		log.WithError(err).Errorf(a, "Failed to connect to stream server.")
    67  		return runtimeErrorReturnCode
    68  	}
    69  	log.Infof(a, "listening on %q", streamServer.Address())
    70  
    71  	// We think everything will work. Configure our Output instance.
    72  	of, err := a.getOutputFactory()
    73  	if err != nil {
    74  		log.WithError(err).Errorf(a, "Failed to get output factory instance.")
    75  		return runtimeErrorReturnCode
    76  	}
    77  	output, err := of.configOutput(a)
    78  	if err != nil {
    79  		log.WithError(err).Errorf(a, "Failed to create output instance.")
    80  		return runtimeErrorReturnCode
    81  	}
    82  	defer output.Close()
    83  
    84  	err = a.runWithButler(output, func(b *butler.Butler) error {
    85  		b.AddStreamServer(streamServer)
    86  		return b.Wait()
    87  	})
    88  	if err != nil {
    89  		logAnnotatedErr(a, err, "Failed to serve.")
    90  		return runtimeErrorReturnCode
    91  	}
    92  
    93  	return 0
    94  }