| // Copyright 2024 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Package server provides functionality for running a gRPC server that serves |
| // the BtpeerManagementService. |
| package server |
| |
| import ( |
| "context" |
| "fmt" |
| "log/slog" |
| "net" |
| |
| "go.chromium.org/chromiumos/config/go/test/lab/api/btpeerd" |
| "go.chromium.org/chromiumos/platform/btpeerd/core/exec" |
| "google.golang.org/grpc" |
| ) |
| |
| // RunGRPCServer starts a gRPC server on the specified system port. |
| // The server is stopped if the context expires. Will only return if the server |
| // has stopped. Returns a non-nil error if the server stopped on its own. |
| func RunGRPCServer(ctx context.Context, port int) error { |
| // Configure server. |
| var serverOpts []grpc.ServerOption |
| server := grpc.NewServer(serverOpts...) |
| runner := &exec.SystemCmdRunner{} |
| btpeerd.RegisterBtpeerManagementServiceServer(server, NewBtpeerManagementServiceServer(runner)) |
| |
| // Start server, stopping it if the ctx expires. |
| listenAddr := fmt.Sprintf("localhost:%d", port) |
| slog.Info("Starting gRPC server", "listenAddr", listenAddr) |
| lis, err := net.Listen("tcp", listenAddr) |
| if err != nil { |
| return fmt.Errorf("failed to listen on tcp port %d: %w", port, err) |
| } |
| slog.Debug("gRPC service info", "serviceInfo", server.GetServiceInfo()) |
| serverChannel := make(chan error, 1) |
| go func() { |
| serverChannel <- server.Serve(lis) |
| }() |
| select { |
| case err := <-serverChannel: |
| return fmt.Errorf("grpc server error: %w", err) |
| case <-ctx.Done(): |
| slog.Info("Stopping gRPC server gracefully") |
| server.GracefulStop() |
| return nil |
| } |
| } |