Skip to content

Commit dc206b4

Browse files
Add daemon command and gRPC list support
1 parent e8af622 commit dc206b4

File tree

15 files changed

+654
-15
lines changed

15 files changed

+654
-15
lines changed

Taskfile.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,3 +126,19 @@ tasks:
126126
general:prepare-deps:
127127
desc: Prepare project dependencies for license check
128128
# No preparation is needed for Go module-based projects.
129+
130+
protoc:compile:
131+
desc: Compile protobuf definitions
132+
cmds:
133+
- buf dep update
134+
- buf generate
135+
136+
protoc:check:
137+
desc: Perform linting of the protobuf definitions
138+
cmds:
139+
- buf lint
140+
141+
protoc:format:
142+
desc: Perform formatting of the protobuf definitions
143+
cmds:
144+
- buf format --write

buf.gen.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
version: v2
2+
plugins:
3+
# Use protoc-gen-go
4+
- remote: buf.build/protocolbuffers/go:v1.34.2
5+
out: ./rpc
6+
opt:
7+
- paths=source_relative
8+
# Use of protoc-gen-go-grpc
9+
- remote: buf.build/grpc/go:v1.5.1
10+
out: ./rpc
11+
opt:
12+
- paths=source_relative
13+
inputs:
14+
- directory: ./rpc
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package daemon
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"net"
8+
"os"
9+
"strings"
10+
"syscall"
11+
12+
"github.com/arduino/arduino-flasher-cli/cmd/feedback"
13+
"github.com/arduino/arduino-flasher-cli/cmd/i18n"
14+
"github.com/spf13/cobra"
15+
"google.golang.org/grpc"
16+
17+
rpc "github.com/arduino/arduino-flasher-cli/rpc/cc/arduino/flasher/cli/commands/v1"
18+
)
19+
20+
func NewDaemonCommand(srv rpc.ArduinoCoreServiceServer) *cobra.Command {
21+
var daemonPort string
22+
var maxGRPCRecvMsgSize int
23+
daemonCommand := &cobra.Command{
24+
Use: "daemon",
25+
Short: i18n.Tr("Run the Arduino Flasher CLI as a gRPC daemon."),
26+
Example: " " + os.Args[0] + " daemon",
27+
Args: cobra.NoArgs,
28+
Run: func(cmd *cobra.Command, args []string) {
29+
runDaemonCommand(srv, daemonPort, maxGRPCRecvMsgSize)
30+
},
31+
}
32+
33+
daemonCommand.Flags().StringVar(&daemonPort,
34+
"port", "50051",
35+
i18n.Tr("The TCP port the daemon will listen to"))
36+
37+
daemonCommand.Flags().IntVar(&maxGRPCRecvMsgSize,
38+
"max-grpc-recv-message-size", 16*1024*1024,
39+
i18n.Tr("Sets the maximum message size in bytes the daemon can receive"))
40+
41+
return daemonCommand
42+
}
43+
44+
func runDaemonCommand(srv rpc.ArduinoCoreServiceServer, daemonPort string, maxGRPCRecvMsgSize int) {
45+
gRPCOptions := []grpc.ServerOption{}
46+
gRPCOptions = append(gRPCOptions, grpc.MaxRecvMsgSize(maxGRPCRecvMsgSize))
47+
s := grpc.NewServer(gRPCOptions...)
48+
49+
// register the commands service
50+
rpc.RegisterArduinoCoreServiceServer(s, srv)
51+
52+
daemonIP := "127.0.0.1"
53+
lis, err := net.Listen("tcp", fmt.Sprintf("%s:%s", daemonIP, daemonPort))
54+
if err != nil {
55+
// Invalid port, such as "Foo"
56+
var dnsError *net.DNSError
57+
if errors.As(err, &dnsError) {
58+
feedback.Fatal(i18n.Tr("Failed to listen on TCP port: %[1]s. %[2]s is unknown name.", daemonPort, dnsError.Name), feedback.ErrBadTCPPortArgument)
59+
}
60+
// Invalid port number, such as -1
61+
var addrError *net.AddrError
62+
if errors.As(err, &addrError) {
63+
feedback.Fatal(i18n.Tr("Failed to listen on TCP port: %[1]s. %[2]s is an invalid port.", daemonPort, addrError.Addr), feedback.ErrBadTCPPortArgument)
64+
}
65+
// Port is already in use
66+
var syscallErr *os.SyscallError
67+
if errors.As(err, &syscallErr) && errors.Is(syscallErr.Err, syscall.EADDRINUSE) {
68+
feedback.Fatal(i18n.Tr("Failed to listen on TCP port: %s. Address already in use.", daemonPort), feedback.ErrFailedToListenToTCPPort)
69+
}
70+
feedback.Fatal(i18n.Tr("Failed to listen on TCP port: %[1]s. Unexpected error: %[2]v", daemonPort, err), feedback.ErrFailedToListenToTCPPort)
71+
}
72+
73+
// We need to retrieve the port used only if the user did not specify it
74+
// and let the OS choose it randomly, in all other cases we already know
75+
// which port is used.
76+
if daemonPort == "0" {
77+
address := lis.Addr()
78+
split := strings.Split(address.String(), ":")
79+
80+
if len(split) <= 1 {
81+
feedback.Fatal(i18n.Tr("Invalid TCP address: port is missing"), feedback.ErrBadTCPPortArgument)
82+
}
83+
84+
daemonPort = split[1]
85+
}
86+
87+
feedback.PrintResult(daemonResult{
88+
IP: daemonIP,
89+
Port: daemonPort,
90+
})
91+
92+
if err := s.Serve(lis); err != nil {
93+
feedback.Fatal(fmt.Sprintf("Failed to serve: %v", err), feedback.ErrFailedToListenToTCPPort)
94+
}
95+
}
96+
97+
type daemonResult struct {
98+
IP string
99+
Port string
100+
}
101+
102+
func (r daemonResult) Data() interface{} {
103+
return r
104+
}
105+
106+
func (r daemonResult) String() string {
107+
j, _ := json.Marshal(r)
108+
return fmt.Sprintln(i18n.Tr("Daemon is now listening on %s:%s", r.IP, r.Port)) + fmt.Sprintln(string(j))
109+
}

cmd/arduino-flasher-cli/main.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,24 @@ import (
2323
"github.com/spf13/cobra"
2424
"go.bug.st/cleanup"
2525

26+
"github.com/arduino/arduino-flasher-cli/cmd/arduino-flasher-cli/daemon"
2627
"github.com/arduino/arduino-flasher-cli/cmd/arduino-flasher-cli/download"
2728
"github.com/arduino/arduino-flasher-cli/cmd/arduino-flasher-cli/drivers"
2829
"github.com/arduino/arduino-flasher-cli/cmd/arduino-flasher-cli/flash"
2930
"github.com/arduino/arduino-flasher-cli/cmd/arduino-flasher-cli/list"
3031
"github.com/arduino/arduino-flasher-cli/cmd/arduino-flasher-cli/version"
3132
"github.com/arduino/arduino-flasher-cli/cmd/feedback"
3233
"github.com/arduino/arduino-flasher-cli/cmd/i18n"
34+
"github.com/arduino/arduino-flasher-cli/commands"
3335
)
3436

3537
// Version will be set a build time with -ldflags
3638
var Version string = "0.0.0-dev"
3739
var format string
3840

3941
func main() {
42+
srv := commands.NewArduinoCoreServer()
43+
4044
rootCmd := &cobra.Command{
4145
Use: "arduino-flasher-cli",
4246
Short: "A CLI to update your Arduino UNO Q board, by downloading and flashing the latest Arduino Linux image",
@@ -61,6 +65,7 @@ func main() {
6165
list.NewListCmd(),
6266
download.NewDownloadCmd(),
6367
version.NewVersionCmd(Version),
68+
daemon.NewDaemonCommand(srv),
6469
)
6570

6671
ctx := context.Background()

commands/service.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package commands
2+
3+
import rpc "github.com/arduino/arduino-flasher-cli/rpc/cc/arduino/flasher/cli/commands/v1"
4+
5+
type arduinoCoreServerImpl struct {
6+
rpc.UnsafeArduinoCoreServiceServer // Force compile error for unimplemented methods
7+
}
8+
9+
func NewArduinoCoreServer() rpc.ArduinoCoreServiceServer {
10+
return &arduinoCoreServerImpl{}
11+
}

commands/service_list.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package commands
2+
3+
import (
4+
"context"
5+
6+
"github.com/arduino/arduino-flasher-cli/internal/updater"
7+
rpc "github.com/arduino/arduino-flasher-cli/rpc/cc/arduino/flasher/cli/commands/v1"
8+
)
9+
10+
func (s *arduinoCoreServerImpl) List(ctx context.Context, req *rpc.ListRequest) (*rpc.ListResponse, error) {
11+
client := updater.NewClient()
12+
13+
manifest, err := client.GetInfoManifest(ctx)
14+
if err != nil {
15+
return nil, err
16+
}
17+
18+
resp := &rpc.ListResponse{}
19+
resp.Latest = manifest.Latest.Version
20+
for _, r := range manifest.Releases {
21+
resp.Releases = append(resp.Releases, &rpc.Release{BuildId: r.Version})
22+
}
23+
24+
return resp, nil
25+
}

go.mod

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ require (
1616
go.bug.st/cleanup v1.0.0
1717
go.bug.st/f v0.4.0
1818
go.bug.st/relaxed-semver v0.15.0
19+
google.golang.org/grpc v1.77.0
20+
google.golang.org/protobuf v1.36.10
1921
)
2022

2123
require (
@@ -71,12 +73,13 @@ require (
7173
github.com/xanzy/ssh-agent v0.3.3 // indirect
7274
github.com/yusufpapurcu/wmi v1.2.4 // indirect
7375
github.com/zeebo/xxh3 v1.0.2 // indirect
74-
golang.org/x/crypto v0.37.0 // indirect
75-
golang.org/x/net v0.39.0 // indirect
76-
golang.org/x/sync v0.16.0 // indirect
76+
golang.org/x/crypto v0.43.0 // indirect
77+
golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 // indirect
78+
golang.org/x/sync v0.17.0 // indirect
7779
golang.org/x/sys v0.37.0 // indirect
78-
golang.org/x/term v0.35.0 // indirect
79-
golang.org/x/text v0.24.0 // indirect
80+
golang.org/x/term v0.36.0 // indirect
81+
golang.org/x/text v0.30.0 // indirect
82+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect
8083
gopkg.in/warnings.v0 v0.1.2 // indirect
8184
gopkg.in/yaml.v3 v3.0.1 // indirect
8285
mvdan.cc/sh/v3 v3.12.0 // indirect

go.sum

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,10 @@ github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMj
6565
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
6666
github.com/go-git/go-git/v5 v5.16.2 h1:fT6ZIOjE5iEnkzKyxTHK1W4HGAsPhqEqiSAssSO77hM=
6767
github.com/go-git/go-git/v5 v5.16.2/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
68+
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
69+
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
70+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
71+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
6872
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
6973
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
7074
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
@@ -78,6 +82,8 @@ github.com/go-task/template v0.2.0 h1:xW7ek0o65FUSTbKcSNeg2Vyf/I7wYXFgLUznptvviB
7882
github.com/go-task/template v0.2.0/go.mod h1:dbdoUb6qKnHQi1y6o+IdIrs0J4o/SEhSTA6bbzZmdtc=
7983
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
8084
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
85+
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
86+
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
8187
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
8288
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
8389
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
@@ -181,16 +187,28 @@ go.bug.st/f v0.4.0 h1:Vstqb950nMA+PhAlRxUw8QL1ntHy/gXHNyyzjkQLJ10=
181187
go.bug.st/f v0.4.0/go.mod h1:bMo23205ll7UW63KwO1ut5RdlJ9JK8RyEEr88CmOF5Y=
182188
go.bug.st/relaxed-semver v0.15.0 h1:w37+SYQPxF53RQO7QZZuPIMaPouOifdaP0B1ktst2nA=
183189
go.bug.st/relaxed-semver v0.15.0/go.mod h1:bwHiCtYuD2m716tBk2OnOBjelsbXw9el5EIuyxT/ksU=
190+
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
191+
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
192+
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
193+
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
194+
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
195+
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
196+
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
197+
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
198+
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
199+
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
200+
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
201+
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
184202
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
185-
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
186-
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
203+
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
204+
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
187205
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
188206
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
189207
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
190-
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
191-
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
192-
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
193-
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
208+
golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82 h1:6/3JGEh1C88g7m+qzzTbl3A0FtsLguXieqofVLU/JAo=
209+
golang.org/x/net v0.46.1-0.20251013234738-63d1a5100f82/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
210+
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
211+
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
194212
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
195213
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
196214
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -206,12 +224,20 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
206224
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
207225
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
208226
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
209-
golang.org/x/term v0.35.0 h1:bZBVKBudEyhRcajGcNc3jIfWPqV4y/Kt2XcoigOWtDQ=
210-
golang.org/x/term v0.35.0/go.mod h1:TPGtkTLesOwf2DE8CgVYiZinHAOuy5AYUYT1lENIZnA=
227+
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
228+
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
211229
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
212-
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
213-
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
230+
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
231+
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
214232
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
233+
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
234+
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
235+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk=
236+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
237+
google.golang.org/grpc v1.77.0 h1:wVVY6/8cGA6vvffn+wWK5ToddbgdU3d8MNENr4evgXM=
238+
google.golang.org/grpc v1.77.0/go.mod h1:z0BY1iVj0q8E1uSQCjL9cppRj+gnZjzDnzV0dHhrNig=
239+
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
240+
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
215241
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
216242
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
217243
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=

0 commit comments

Comments
 (0)