diff --git a/.github/golangci.yaml b/.github/golangci.yaml index 91bd454..4be75f8 100644 --- a/.github/golangci.yaml +++ b/.github/golangci.yaml @@ -3,7 +3,7 @@ run: modules-download-mode: readonly output: - formats: github-actions + formats: colored-line-number linters: enable: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 67d6024..4490c38 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -101,11 +101,11 @@ jobs: id: get-next-version - name: Set short sha output id: short-sha - run: echo "::set-output name=short-sha::${GITHUB_SHA::7}" + run: echo "short-sha=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT" - name: Set release version id: release-version run: | - echo "::set-output name=release-version::`echo ${{ steps.get-next-version.outputs.new-release-version }} | sed 's/v//g'`" + echo "release-version=`echo ${{ steps.get-next-version.outputs.new-release-version }} | sed 's/v//g'`" >> "$GITHUB_OUTPUT" outputs: new-release-published: ${{ steps.get-next-version.outputs.new-release-published }} new-release-version: ${{ steps.release-version.outputs.release-version }} diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 435c46c..4664f12 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -9,9 +9,14 @@ concurrency: group: ${{ github.workflow }} cancel-in-progress: false +permissions: + contents: write + pull-requests: write + jobs: go-test: runs-on: ubuntu-latest + timeout-minutes: 10 steps: - name: Checkout uses: actions/checkout@v4 @@ -22,5 +27,31 @@ jobs: check-latest: true - name: Run go build run: go build ./... + - name: Install additional dependencies + run: | + go install github.com/mfridman/tparse@v0.14.0 - name: Run go test - run: go test -race ./... + id: go-test + run: | + make test-coverage + echo 'coverage-report<> $GITHUB_OUTPUT + cat .coverage/test-report.md >> $GITHUB_OUTPUT + echo 'EOF' >> $GITHUB_OUTPUT + echo "coverage-total=$(cat .coverage/coverage.txt)" >> $GITHUB_OUTPUT + - name: Find comment + uses: peter-evans/find-comment@v3 + id: existing-comment + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: Go test coverage + - name: Post comment + uses: peter-evans/create-or-update-comment@v4 + with: + comment-id: ${{ steps.existing-comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body: | + Go test coverage + ${{ steps.go-test.outputs.coverage-report }} + Total coverage: ${{ steps.go-test.outputs.coverage-total }}% + edit-mode: replace diff --git a/.gitignore b/.gitignore index 9856bf1..1f68c6c 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ # Go coverage.txt +.coverage/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..9c4f431 --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +.PHONY: deps +deps: + @go mod tidy + +.PHONY: lint +lint: + @golangci-lint run ./... --config .github/golangci.yaml + +.PHONY: test +test: + @go test -race ./... + +.PHONY: test-coverage +test-coverage: + @mkdir -p .coverage + @go test `go list ./... | grep -Ev "diodepb|examples|internal"` -race -cover -json -coverprofile=.coverage/cover.out.tmp ./... | tparse -format=markdown > .coverage/test-report.md + @cat .coverage/cover.out.tmp > .coverage/cover.out + @go tool cover -func=.coverage/cover.out | grep total | awk '{print substr($$3, 1, length($$3)-1)}' > .coverage/coverage.txt + +.PHONY: codegen +codegen: + @go run internal/cmd/codegen/main.go | gofmt > ./diode/ingester.go diff --git a/README.md b/README.md index 86ed04a..4876448 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,140 @@ -# diode-sdk-go +# Diode SDK Go -TBD +Diode SDK Go is a Go library for interacting with the Diode ingestion service utilizing gRPC. + +Diode is a new [NetBox](https://netboxlabs.com/oss/netbox/) ingestion service that greatly simplifies and enhances the +process to add and update network data +in NetBox, ensuring your network source of truth is always accurate and can be trusted to power your network automation +pipelines. + +More information about Diode can be found +at [https://netboxlabs.com/blog/introducing-diode-streamlining-data-ingestion-in-netbox/](https://netboxlabs.com/blog/introducing-diode-streamlining-data-ingestion-in-netbox/). + +## Installation + +```bash +go install github.com/netboxlabs/diode-sdk-go +``` + +## Usage + +### Environment variables + +* `DIODE_API_KEY` - API key for the Diode service +* `DIODE_SDK_LOG_LEVEL` - Log level for the SDK (default: `INFO`) + +### Example + +* `target` should be the address of the Diode service, e.g. `grpc://localhost:8081` for insecure connection + or `grpcs://example.com` for secure connection. + +```go +package main + +import ( + "context" + "log" + + "github.com/netboxlabs/diode-sdk-go/diode" +) + +func main() { + client, err := diode.NewClient( + "grpc://localhost:8080/diode", + "example-app", + "0.1.0", + diode.WithAPIKey("YOUR_API_KEY"), + ) + if err != nil { + log.Fatal(err) + } + + // Create a device + deviceEntity := &diode.Device{ + Name: diode.String("Device A"), + DeviceType: &diode.DeviceType{ + Model: diode.String("Device Type A"), + Manufacturer: &diode.Manufacturer{ + Name: diode.String("Manufacturer A"), + }, + }, + Platform: &diode.Platform{ + Name: diode.String("Platform A"), + Manufacturer: &diode.Manufacturer{ + Name: diode.String("Manufacturer A"), + }, + }, + Site: &diode.Site{ + Name: diode.String("Site ABC"), + }, + Role: &diode.Role{ + Name: diode.String("Role ABC"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 2"), + }, + }, + }, + Serial: diode.String("123456"), + AssetTag: diode.String("123456"), + Status: diode.String("active"), + Comments: diode.String("Lorem ipsum dolor sit amet"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 3"), + }, + }, + } + + entities := []diode.Entity{ + deviceEntity, + } + + resp, err := client.Ingest(context.Background(), entities) + if err != nil { + log.Fatal(err) + } + if resp != nil && resp.Errors != nil { + log.Printf("Errors: %v\n", resp.Errors) + } else { + log.Printf("Success\n") + } + +} +``` + +See all [examples](./examples/main.go) for reference. + +## Supported entities (object types) + +* Device +* Device Type +* IP Address +* Interface +* Manufacturer +* Platform +* Prefix +* Role +* Site + +#### Linting + +```shell +make list +``` + +#### Testing + +```shell +make test +``` + +## License + +Distributed under the Apache 2.0 License. See [LICENSE.txt](./LICENSE.txt) for more information. diff --git a/diode/client.go b/diode/client.go new file mode 100644 index 0000000..74be37a --- /dev/null +++ b/diode/client.go @@ -0,0 +1,296 @@ +package diode + +import ( + "context" + "crypto/tls" + "crypto/x509" + "errors" + "fmt" + "log/slog" + "net/url" + "os" + "regexp" + "runtime" + "strings" + + "github.com/google/uuid" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "google.golang.org/grpc/credentials/insecure" + "google.golang.org/grpc/metadata" + + "github.com/netboxlabs/diode-sdk-go/diode/v1/diodepb" +) + +const ( + // SDKName is the name of the Diode SDK + SDKName = "diode-sdk-go" + + // SDKVersion is the version of the Diode SDK + SDKVersion = "0.1.0" + + // DiodeAPIKeyEnvVarName is the environment variable name for the Diode API key + DiodeAPIKeyEnvVarName = "DIODE_API_KEY" + + // DiodeSDKLogLevelEnvVarName is the environment variable name for the Diode SDK log level + DiodeSDKLogLevelEnvVarName = "DIODE_SDK_LOG_LEVEL" + + defaultStreamName = "latest" + + authAPIKeyName = "diode-api-key" +) + +var allowedSchemesRe = regexp.MustCompile(`grpc|grpcs`) + +// loadCerts loads the system x509 cert pool +func loadCerts() *x509.CertPool { + certPool, _ := x509.SystemCertPool() + return certPool +} + +// parseTarget parses the target string into authority, path, and tlsVerify +func parseTarget(target string) (string, string, bool, error) { + u, err := url.Parse(target) + if err != nil { + return "", "", false, err + } + + if !allowedSchemesRe.MatchString(u.Scheme) { + return "", "", false, errors.New("target should start with grpc:// or grpcs://") + } + + authority := u.Host + if u.Port() == "" { + authority += ":443" + } + + path := u.Path + if path == "/" { + path = "" + } + + tlsVerify := u.Scheme == "grpcs" + + return authority, path, tlsVerify, nil +} + +// getAPIKey returns the API key either from provided value or environment variable +func getAPIKey(apiKey string) (string, error) { + if apiKey == "" { + apiKey = os.Getenv(DiodeAPIKeyEnvVarName) + } + + if apiKey == "" { + return "", fmt.Errorf("api_key param or %s environment variable required", DiodeAPIKeyEnvVarName) + } + + return apiKey, nil +} + +// Client is an interface that defines the methods available from Diode API +type Client interface { + // Close closes the connection to the API service + Close() error + + // Ingest sends an ingest request to the ingester service + Ingest(context.Context, []Entity) (*diodepb.IngestResponse, error) +} + +// GRPCClient is a gRPC implementation of the ingester service +type GRPCClient struct { + // The logger for the client + logger *slog.Logger + + // gRPC virtual connection + conn *grpc.ClientConn + + // The gRPC API client + client diodepb.IngesterServiceClient + + // Producer's application name + appName string + + // Producer's application version + appVersion string + + // An API key for the Diode API + apiKey string + + // GRPC target + target string + + // GRPC path + path string + + // TLS verify + tlsVerify bool + + // Platform name + platform string + + // Go version + goVersion string + + // Metadata + metadata metadata.MD +} + +// ClientOption is a functional option for the GRPCClient +type ClientOption func(*GRPCClient) + +// WithAPIKey sets the API key for the client +func WithAPIKey(apiKey string) ClientOption { + return func(c *GRPCClient) { + c.apiKey = apiKey + } +} + +// NewClient creates a new diode client based on gRPC +func NewClient(target string, appName string, appVersion string, opts ...ClientOption) (Client, error) { + logger := newLogger() + + if appName == "" { + return nil, fmt.Errorf("app name is required") + } + + if appVersion == "" { + return nil, fmt.Errorf("app version is required") + } + + target, path, tlsVerify, err := parseTarget(target) + if err != nil { + return nil, err + } + + dialOpts := []grpc.DialOption{ + grpc.WithUserAgent(userAgent()), + } + + if path != "" { + logger.Debug("Setting up gRPC interceptor for path", "path", path) + dialOpts = append(dialOpts, methodUnaryInterceptor(path)) + } + + if tlsVerify { + logger.Debug("Setting up gRPC secure channel") + rootCAs := loadCerts() + dialOpts = append(dialOpts, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{RootCAs: rootCAs}))) + } else { + logger.Debug("Setting up gRPC insecure channel") + dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) + } + + conn, err := grpc.NewClient(target, dialOpts...) + if err != nil { + return nil, err + } + + platform := fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) + goVersion := runtime.Version() + + c := &GRPCClient{ + logger: logger, + conn: conn, + client: diodepb.NewIngesterServiceClient(conn), + appName: appName, + appVersion: appVersion, + target: target, + path: path, + tlsVerify: tlsVerify, + platform: platform, + goVersion: goVersion, + } + + var apiKey string + + for _, o := range opts { + o(c) + } + + apiKey, err = getAPIKey(c.apiKey) + if err != nil { + return nil, err + } + + c.apiKey = apiKey + c.metadata = metadata.Pairs(authAPIKeyName, c.apiKey, "platform", platform, "go-version", goVersion) + + return c, nil +} + +// Close closes the connection to the API service +func (g *GRPCClient) Close() error { + if g.conn != nil { + return g.conn.Close() + } + return nil +} + +// Ingest sends an ingest request to the ingester service +func (g *GRPCClient) Ingest(ctx context.Context, entities []Entity) (*diodepb.IngestResponse, error) { + stream := defaultStreamName + + protoEntities := make([]*diodepb.Entity, 0) + for _, entity := range entities { + protoEntities = append(protoEntities, entity.ConvertToProtoEntity()) + } + + req := &diodepb.IngestRequest{ + Id: uuid.NewString(), + Entities: protoEntities, + Stream: stream, + ProducerAppName: g.appName, + ProducerAppVersion: g.appVersion, + SdkName: SDKName, + SdkVersion: SDKVersion, + } + + ctx = metadata.NewOutgoingContext(ctx, g.metadata) + + return g.client.Ingest(ctx, req) +} + +// methodUnaryInterceptor returns a gRPC dial option with a unary interceptor +// +// It's used to intercept the client calls and modify the method details. +// +// Diode's default method generated from Protocol Buffers definition is /diode.v1.IngesterService/Ingest and in order +// to use Diode targets with path (i.e. localhost:8081/this/is/custom/path), this interceptor is used to modify the +// method details, by prepending the generated method name with the path extracted from initial target. +func methodUnaryInterceptor(path string) grpc.DialOption { + return grpc.WithUnaryInterceptor(func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { + method = fmt.Sprintf("%s%s", path, method) + return invoker(ctx, method, req, reply, cc, opts...) + }) +} + +// userAgent returns the user agent string for the SDK +func userAgent() string { + return fmt.Sprintf("%s/%s", SDKName, SDKVersion) +} + +// newLogger creates a new logger for the SDK +func newLogger() *slog.Logger { + level, ok := os.LookupEnv(DiodeSDKLogLevelEnvVarName) + if !ok { + level = "INFO" + } + + var l slog.Level + switch strings.ToUpper(level) { + case "DEBUG": + l = slog.LevelDebug + case "INFO": + l = slog.LevelInfo + case "WARN": + l = slog.LevelWarn + case "ERROR": + l = slog.LevelError + default: + l = slog.LevelDebug + } + + h := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: l, AddSource: false}) + + return slog.New(h) +} diff --git a/diode/client_test.go b/diode/client_test.go new file mode 100644 index 0000000..20ac205 --- /dev/null +++ b/diode/client_test.go @@ -0,0 +1,406 @@ +package diode + +import ( + "context" + "errors" + "fmt" + "log" + "log/slog" + "net" + "net/url" + "os" + "strconv" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + + "github.com/netboxlabs/diode-sdk-go/diode/v1/diodepb" +) + +func TestLoadCerts(t *testing.T) { + certPool := loadCerts() + assert.NotNil(t, certPool) +} + +func TestParseTarget(t *testing.T) { + tests := []struct { + desc string + target string + authority string + path string + tlsVerify bool + wantErr error + }{ + { + desc: "valid target without path and tls verification", + target: "grpc://localhost:8081", + authority: "localhost:8081", + path: "", + tlsVerify: false, + wantErr: nil, + }, + { + desc: "valid target with path", + target: "grpc://localhost:8081/fsfsd", + authority: "localhost:8081", + path: "/fsfsd", + tlsVerify: false, + wantErr: nil, + }, + { + desc: "valid target with tls", + target: "grpcs://localhost:8081", + authority: "localhost:8081", + path: "", + tlsVerify: true, + wantErr: nil, + }, + { + desc: "valid target empty path on grpc://localhost:8081/", + target: "grpc://localhost:8081/", + authority: "localhost:8081", + path: "", + tlsVerify: false, + wantErr: nil, + }, + { + desc: "valid target without port having 443 appended", + target: "grpcs://localhost", + authority: "localhost:443", + path: "", + tlsVerify: true, + wantErr: nil, + }, + { + desc: "invalid scheme in target", + target: "http://localhost:8081", + authority: "", + path: "", + tlsVerify: false, + wantErr: errors.New("target should start with grpc:// or grpcs://"), + }, + { + desc: "invalid target", + target: "grpc://local%host:8081", + authority: "", + path: "", + tlsVerify: false, + wantErr: &url.Error{Op: "parse", URL: "grpc://local%host:8081", Err: url.EscapeError("%ho")}, + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + authority, path, tlsVerify, err := parseTarget(tt.target) + assert.Equal(t, tt.authority, authority) + assert.Equal(t, tt.path, path) + assert.Equal(t, tt.tlsVerify, tlsVerify) + assert.Equal(t, tt.wantErr, err) + }) + } +} + +func TestGetAPIKey(t *testing.T) { + tests := []struct { + desc string + apiKey string + apiKeyEnvVarValue string + wantAPIKey string + wantErr error + }{ + { + desc: "API key provided explicitly", + apiKey: "foobar", + apiKeyEnvVarValue: "", + wantAPIKey: "foobar", + wantErr: nil, + }, + { + desc: "API key provided with environment variable", + apiKey: "", + apiKeyEnvVarValue: "barfoo", + wantAPIKey: "barfoo", + wantErr: nil, + }, + { + desc: "API key not provided either explicitly or with environment variable", + apiKey: "", + apiKeyEnvVarValue: "", + wantAPIKey: "", + wantErr: errors.New("api_key param or DIODE_API_KEY environment variable required"), + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + if tt.apiKeyEnvVarValue != "" { + _ = os.Setenv(DiodeAPIKeyEnvVarName, tt.apiKeyEnvVarValue) + defer func() { + _ = os.Unsetenv(DiodeAPIKeyEnvVarName) + }() + } + apiKey, err := getAPIKey(tt.apiKey) + require.Equal(t, tt.wantAPIKey, apiKey) + require.Equal(t, tt.wantErr, err) + }) + } +} + +func TestNewClient(t *testing.T) { + tests := []struct { + desc string + target string + appName string + appVersion string + apiKey string + apiKeyEnvVarValue string + logLevelEnvVarValue string + wantErr error + }{ + { + desc: "explicit arguments provided", + target: "grpc://localhost:8081", + appName: "my-producer", + appVersion: "0.1.0", + apiKey: "foobar", + apiKeyEnvVarValue: "", + logLevelEnvVarValue: "", + wantErr: nil, + }, + { + desc: "API key provided with environment variable", + target: "grpc://localhost:8081", + appName: "my-producer", + appVersion: "0.1.0", + apiKey: "", + apiKeyEnvVarValue: "foo.bar", + logLevelEnvVarValue: "", + wantErr: nil, + }, + { + desc: "target with path", + target: "grpc://localhost:8081/abcdef", + appName: "my-producer", + appVersion: "0.1.0", + apiKey: "", + apiKeyEnvVarValue: "foo.bar", + logLevelEnvVarValue: "", + wantErr: nil, + }, + { + desc: "target with grpcs scheme", + target: "grpcs://localhost:8081", + appName: "my-producer", + appVersion: "0.1.0", + apiKey: "", + apiKeyEnvVarValue: "foo.bar", + logLevelEnvVarValue: "", + wantErr: nil, + }, + { + desc: "app name not provided", + target: "grpc://localhost:8081", + appName: "", + appVersion: "0.1.0", + apiKey: "foobar", + apiKeyEnvVarValue: "", + logLevelEnvVarValue: "", + wantErr: errors.New("app name is required"), + }, + { + desc: "app version not provided", + target: "grpc://localhost:8081", + appName: "my-producer", + appVersion: "", + apiKey: "foobar", + apiKeyEnvVarValue: "", + logLevelEnvVarValue: "", + wantErr: errors.New("app version is required"), + }, + { + desc: "invalid target", + target: "http://localhost:8081", + appName: "my-producer", + appVersion: "0.1.0", + apiKey: "foobar", + apiKeyEnvVarValue: "", + logLevelEnvVarValue: "", + wantErr: errors.New("target should start with grpc:// or grpcs://"), + }, + { + desc: "missing API key", + target: "grpc://localhost:8081", + appName: "my-producer", + appVersion: "0.1.0", + apiKey: "", + apiKeyEnvVarValue: "", + wantErr: errors.New("api_key param or DIODE_API_KEY environment variable required"), + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + defer func() { + _ = os.Unsetenv(DiodeAPIKeyEnvVarName) + _ = os.Unsetenv(DiodeSDKLogLevelEnvVarName) + }() + + if tt.apiKeyEnvVarValue != "" { + _ = os.Setenv(DiodeAPIKeyEnvVarName, tt.apiKeyEnvVarValue) + } + + opts := []ClientOption{} + if tt.apiKey != "" { + opts = append(opts, WithAPIKey(tt.apiKey)) + } + + client, err := NewClient(tt.target, tt.appName, tt.appVersion, opts...) + require.Equal(t, tt.wantErr, err) + if tt.wantErr == nil { + require.NotNil(t, client) + require.NoError(t, client.Close()) + } + }) + } +} + +func getFreePort() (string, error) { + listener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + return strconv.Itoa(0), err + } + + addr := listener.Addr().(*net.TCPAddr) + + if err = listener.Close(); err != nil { + return strconv.Itoa(0), err + } + return strconv.Itoa(addr.Port), nil +} + +type MockIngesterServiceServer struct { + diodepb.UnimplementedIngesterServiceServer +} + +func (MockIngesterServiceServer) Ingest(_ context.Context, _ *diodepb.IngestRequest) (*diodepb.IngestResponse, error) { + return &diodepb.IngestResponse{Errors: nil}, nil +} + +func startMockServer() (net.Listener, error) { + port, _ := getFreePort() + grpcListener, err := net.Listen("tcp", fmt.Sprintf(":%s", port)) + if err != nil { + return nil, fmt.Errorf("failed to listen on port %s: %v", port, err) + } + + server := grpc.NewServer() + + diodepb.RegisterIngesterServiceServer(server, &MockIngesterServiceServer{}) + + go func() { + if err := server.Serve(grpcListener); err != nil { + log.Fatal(err) + } + }() + + return grpcListener, nil +} + +func TestMethodUnaryInterceptor(t *testing.T) { + tests := []struct { + desc string + path string + wantErr error + }{ + { + desc: "empty path", + path: "", + wantErr: nil, + }, + { + desc: "non-empty path", + path: "foobar", + wantErr: errors.New("rpc error: code = Unimplemented desc = unknown service foobar/diode.v1.IngesterService"), + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + listener, err := startMockServer() + require.NoError(t, err) + + target := fmt.Sprintf("grpc://%s/%s", listener.Addr().String(), tt.path) + appName := "my-producer" + appVersion := "0.1.0" + apiKey := "abcde" + + client, err := NewClient(target, appName, appVersion, WithAPIKey(apiKey)) + require.NoError(t, err) + require.NotNil(t, client) + _, err = client.Ingest(context.Background(), nil) + if tt.wantErr != nil { + require.Equal(t, tt.wantErr.Error(), err.Error()) + } else { + require.NoError(t, err) + } + require.NoError(t, client.Close()) + }) + } +} + +func TestNewLogger(t *testing.T) { + tests := []struct { + desc string + logLevelEnvVarValue string + wantLogLevel slog.Level + }{ + { + desc: "log level not provided", + logLevelEnvVarValue: "", + wantLogLevel: slog.LevelInfo, + }, + { + desc: "debug log level provided", + logLevelEnvVarValue: "debug", + wantLogLevel: slog.LevelDebug, + }, + { + desc: "info log level provided", + logLevelEnvVarValue: "info", + wantLogLevel: slog.LevelInfo, + }, + { + desc: "warn log level provided", + logLevelEnvVarValue: "warn", + wantLogLevel: slog.LevelWarn, + }, + { + desc: "error log level provided", + logLevelEnvVarValue: "error", + wantLogLevel: slog.LevelError, + }, + { + desc: "invalid log level provided", + logLevelEnvVarValue: "invalid", + wantLogLevel: slog.LevelDebug, + }, + } + + for _, tt := range tests { + t.Run(tt.desc, func(t *testing.T) { + defer func() { + _ = os.Unsetenv(DiodeSDKLogLevelEnvVarName) + }() + + if tt.logLevelEnvVarValue != "" { + _ = os.Setenv(DiodeSDKLogLevelEnvVarName, tt.logLevelEnvVarValue) + } + + logger := newLogger() + require.NotNil(t, logger) + assert.True(t, logger.Enabled(context.Background(), tt.wantLogLevel)) + }) + } +} diff --git a/diode/ingester.go b/diode/ingester.go new file mode 100644 index 0000000..51fe9ca --- /dev/null +++ b/diode/ingester.go @@ -0,0 +1,967 @@ +// Code generated by github.com/diode-sdk-go/internal/cmd/codegen. DO NOT EDIT. + +package diode + +import ( + "google.golang.org/protobuf/proto" + + "github.com/netboxlabs/diode-sdk-go/diode/v1/diodepb" +) + +// Entity is an interface that all entities must implement +type Entity interface { + ConvertToProtoMessage() proto.Message + ConvertToProtoEntity() *diodepb.Entity +} + +// Device is based on diodepb.Device +type Device struct { + Name *string + DeviceFqdn *string + DeviceType *DeviceType + Role *Role + Platform *Platform + Serial *string + Site *Site + AssetTag *string + Status *string + Description *string + Comments *string + Tags []*Tag + PrimaryIp4 *IPAddress + PrimaryIp6 *IPAddress +} + +// ConvertToProtoMessageDevice converts a Device to a diodepb.Device +func (e *Device) ConvertToProtoMessage() proto.Message { + return &diodepb.Device{ + Name: e.GetName(), + DeviceFqdn: e.GetDeviceFqdn(), + DeviceType: e.GetDeviceType(), + Role: e.GetRole(), + Platform: e.GetPlatform(), + Serial: e.GetSerial(), + Site: e.GetSite(), + AssetTag: e.GetAssetTag(), + Status: e.GetStatus(), + Description: e.GetDescription(), + Comments: e.GetComments(), + Tags: e.GetTags(), + PrimaryIp4: e.GetPrimaryIp4(), + PrimaryIp6: e.GetPrimaryIp6(), + } +} + +// GetName returns the Name field +func (e *Device) GetName() string { + if e != nil && e.Name != nil { + return *e.Name + } + return "" +} + +// GetDeviceFqdn returns the DeviceFqdn field +func (e *Device) GetDeviceFqdn() *string { + if e != nil && e.DeviceFqdn != nil { + return e.DeviceFqdn + } + return nil +} + +// GetDeviceType returns the DeviceType field +func (e *Device) GetDeviceType() *diodepb.DeviceType { + if e != nil && e.DeviceType != nil { + return e.DeviceType.ConvertToProtoMessage().(*diodepb.DeviceType) + } + return nil +} + +// GetRole returns the Role field +func (e *Device) GetRole() *diodepb.Role { + if e != nil && e.Role != nil { + return e.Role.ConvertToProtoMessage().(*diodepb.Role) + } + return nil +} + +// GetPlatform returns the Platform field +func (e *Device) GetPlatform() *diodepb.Platform { + if e != nil && e.Platform != nil { + return e.Platform.ConvertToProtoMessage().(*diodepb.Platform) + } + return nil +} + +// GetSerial returns the Serial field +func (e *Device) GetSerial() *string { + if e != nil && e.Serial != nil { + return e.Serial + } + return nil +} + +// GetSite returns the Site field +func (e *Device) GetSite() *diodepb.Site { + if e != nil && e.Site != nil { + return e.Site.ConvertToProtoMessage().(*diodepb.Site) + } + return nil +} + +// GetAssetTag returns the AssetTag field +func (e *Device) GetAssetTag() *string { + if e != nil && e.AssetTag != nil { + return e.AssetTag + } + return nil +} + +// GetStatus returns the Status field +func (e *Device) GetStatus() string { + if e != nil && e.Status != nil { + return *e.Status + } + return "" +} + +// GetDescription returns the Description field +func (e *Device) GetDescription() *string { + if e != nil && e.Description != nil { + return e.Description + } + return nil +} + +// GetComments returns the Comments field +func (e *Device) GetComments() *string { + if e != nil && e.Comments != nil { + return e.Comments + } + return nil +} + +// GetTags returns the Tags field +func (e *Device) GetTags() []*diodepb.Tag { + var tags []*diodepb.Tag + for _, el := range e.Tags { + tags = append(tags, el.ConvertToProtoMessage().(*diodepb.Tag)) + } + return tags +} + +// GetPrimaryIp4 returns the PrimaryIp4 field +func (e *Device) GetPrimaryIp4() *diodepb.IPAddress { + if e != nil && e.PrimaryIp4 != nil { + return e.PrimaryIp4.ConvertToProtoMessage().(*diodepb.IPAddress) + } + return nil +} + +// GetPrimaryIp6 returns the PrimaryIp6 field +func (e *Device) GetPrimaryIp6() *diodepb.IPAddress { + if e != nil && e.PrimaryIp6 != nil { + return e.PrimaryIp6.ConvertToProtoMessage().(*diodepb.IPAddress) + } + return nil +} + +// ConvertToProtoEntityDevice converts a Device to a diodepb.Entity +func (e *Device) ConvertToProtoEntity() *diodepb.Entity { + return &diodepb.Entity{ + Entity: &diodepb.Entity_Device{ + Device: e.ConvertToProtoMessage().(*diodepb.Device), + }, + } +} + +// DeviceType is based on diodepb.DeviceType +type DeviceType struct { + Model *string + Slug *string + Manufacturer *Manufacturer + Description *string + Comments *string + PartNumber *string + Tags []*Tag +} + +// ConvertToProtoMessageDeviceType converts a DeviceType to a diodepb.DeviceType +func (e *DeviceType) ConvertToProtoMessage() proto.Message { + return &diodepb.DeviceType{ + Model: e.GetModel(), + Slug: e.GetSlug(), + Manufacturer: e.GetManufacturer(), + Description: e.GetDescription(), + Comments: e.GetComments(), + PartNumber: e.GetPartNumber(), + Tags: e.GetTags(), + } +} + +// GetModel returns the Model field +func (e *DeviceType) GetModel() string { + if e != nil && e.Model != nil { + return *e.Model + } + return "" +} + +// GetSlug returns the Slug field +func (e *DeviceType) GetSlug() string { + if e != nil && e.Slug != nil { + return *e.Slug + } + return "" +} + +// GetManufacturer returns the Manufacturer field +func (e *DeviceType) GetManufacturer() *diodepb.Manufacturer { + if e != nil && e.Manufacturer != nil { + return e.Manufacturer.ConvertToProtoMessage().(*diodepb.Manufacturer) + } + return nil +} + +// GetDescription returns the Description field +func (e *DeviceType) GetDescription() *string { + if e != nil && e.Description != nil { + return e.Description + } + return nil +} + +// GetComments returns the Comments field +func (e *DeviceType) GetComments() *string { + if e != nil && e.Comments != nil { + return e.Comments + } + return nil +} + +// GetPartNumber returns the PartNumber field +func (e *DeviceType) GetPartNumber() *string { + if e != nil && e.PartNumber != nil { + return e.PartNumber + } + return nil +} + +// GetTags returns the Tags field +func (e *DeviceType) GetTags() []*diodepb.Tag { + var tags []*diodepb.Tag + for _, el := range e.Tags { + tags = append(tags, el.ConvertToProtoMessage().(*diodepb.Tag)) + } + return tags +} + +// ConvertToProtoEntityDeviceType converts a DeviceType to a diodepb.Entity +func (e *DeviceType) ConvertToProtoEntity() *diodepb.Entity { + return &diodepb.Entity{ + Entity: &diodepb.Entity_DeviceType{ + DeviceType: e.ConvertToProtoMessage().(*diodepb.DeviceType), + }, + } +} + +// IPAddress is based on diodepb.IPAddress +type IPAddress struct { + Address *string + AssignedObject *Interface + Status *string + Role *string + DnsName *string + Description *string + Comments *string + Tags []*Tag +} + +// ConvertToProtoMessageIPAddress converts a IPAddress to a diodepb.IPAddress +func (e *IPAddress) ConvertToProtoMessage() proto.Message { + return &diodepb.IPAddress{ + Address: e.GetAddress(), + AssignedObject: e.GetAssignedObject(), + Status: e.GetStatus(), + Role: e.GetRole(), + DnsName: e.GetDnsName(), + Description: e.GetDescription(), + Comments: e.GetComments(), + Tags: e.GetTags(), + } +} + +// GetAddress returns the Address field +func (e *IPAddress) GetAddress() string { + if e != nil && e.Address != nil { + return *e.Address + } + return "" +} + +// GetAssignedObject returns the AssignedObject field +func (e *IPAddress) GetAssignedObject() *diodepb.IPAddress_Interface { + if e != nil && e.AssignedObject != nil { + return &diodepb.IPAddress_Interface{ + Interface: e.AssignedObject.ConvertToProtoMessage().(*diodepb.Interface), + } + } + return nil +} + +// GetStatus returns the Status field +func (e *IPAddress) GetStatus() string { + if e != nil && e.Status != nil { + return *e.Status + } + return "" +} + +// GetRole returns the Role field +func (e *IPAddress) GetRole() string { + if e != nil && e.Role != nil { + return *e.Role + } + return "" +} + +// GetDnsName returns the DnsName field +func (e *IPAddress) GetDnsName() *string { + if e != nil && e.DnsName != nil { + return e.DnsName + } + return nil +} + +// GetDescription returns the Description field +func (e *IPAddress) GetDescription() *string { + if e != nil && e.Description != nil { + return e.Description + } + return nil +} + +// GetComments returns the Comments field +func (e *IPAddress) GetComments() *string { + if e != nil && e.Comments != nil { + return e.Comments + } + return nil +} + +// GetTags returns the Tags field +func (e *IPAddress) GetTags() []*diodepb.Tag { + var tags []*diodepb.Tag + for _, el := range e.Tags { + tags = append(tags, el.ConvertToProtoMessage().(*diodepb.Tag)) + } + return tags +} + +// ConvertToProtoEntityIPAddress converts a IPAddress to a diodepb.Entity +func (e *IPAddress) ConvertToProtoEntity() *diodepb.Entity { + return &diodepb.Entity{ + Entity: &diodepb.Entity_IpAddress{ + IpAddress: e.ConvertToProtoMessage().(*diodepb.IPAddress), + }, + } +} + +// Interface is based on diodepb.Interface +type Interface struct { + Device *Device + Name *string + Label *string + Type *string + Enabled *bool + Mtu *int32 + MacAddress *string + Speed *int32 + Wwn *string + MgmtOnly *bool + Description *string + MarkConnected *bool + Mode *string + Tags []*Tag +} + +// ConvertToProtoMessageInterface converts a Interface to a diodepb.Interface +func (e *Interface) ConvertToProtoMessage() proto.Message { + return &diodepb.Interface{ + Device: e.GetDevice(), + Name: e.GetName(), + Label: e.GetLabel(), + Type: e.GetType(), + Enabled: e.GetEnabled(), + Mtu: e.GetMtu(), + MacAddress: e.GetMacAddress(), + Speed: e.GetSpeed(), + Wwn: e.GetWwn(), + MgmtOnly: e.GetMgmtOnly(), + Description: e.GetDescription(), + MarkConnected: e.GetMarkConnected(), + Mode: e.GetMode(), + Tags: e.GetTags(), + } +} + +// GetDevice returns the Device field +func (e *Interface) GetDevice() *diodepb.Device { + if e != nil && e.Device != nil { + return e.Device.ConvertToProtoMessage().(*diodepb.Device) + } + return nil +} + +// GetName returns the Name field +func (e *Interface) GetName() string { + if e != nil && e.Name != nil { + return *e.Name + } + return "" +} + +// GetLabel returns the Label field +func (e *Interface) GetLabel() *string { + if e != nil && e.Label != nil { + return e.Label + } + return nil +} + +// GetType returns the Type field +func (e *Interface) GetType() string { + if e != nil && e.Type != nil { + return *e.Type + } + return "" +} + +// GetEnabled returns the Enabled field +func (e *Interface) GetEnabled() *bool { + if e != nil && e.Enabled != nil { + return e.Enabled + } + return nil +} + +// GetMtu returns the Mtu field +func (e *Interface) GetMtu() *int32 { + if e != nil && e.Mtu != nil { + return e.Mtu + } + return nil +} + +// GetMacAddress returns the MacAddress field +func (e *Interface) GetMacAddress() *string { + if e != nil && e.MacAddress != nil { + return e.MacAddress + } + return nil +} + +// GetSpeed returns the Speed field +func (e *Interface) GetSpeed() *int32 { + if e != nil && e.Speed != nil { + return e.Speed + } + return nil +} + +// GetWwn returns the Wwn field +func (e *Interface) GetWwn() *string { + if e != nil && e.Wwn != nil { + return e.Wwn + } + return nil +} + +// GetMgmtOnly returns the MgmtOnly field +func (e *Interface) GetMgmtOnly() *bool { + if e != nil && e.MgmtOnly != nil { + return e.MgmtOnly + } + return nil +} + +// GetDescription returns the Description field +func (e *Interface) GetDescription() *string { + if e != nil && e.Description != nil { + return e.Description + } + return nil +} + +// GetMarkConnected returns the MarkConnected field +func (e *Interface) GetMarkConnected() *bool { + if e != nil && e.MarkConnected != nil { + return e.MarkConnected + } + return nil +} + +// GetMode returns the Mode field +func (e *Interface) GetMode() string { + if e != nil && e.Mode != nil { + return *e.Mode + } + return "" +} + +// GetTags returns the Tags field +func (e *Interface) GetTags() []*diodepb.Tag { + var tags []*diodepb.Tag + for _, el := range e.Tags { + tags = append(tags, el.ConvertToProtoMessage().(*diodepb.Tag)) + } + return tags +} + +// ConvertToProtoEntityInterface converts a Interface to a diodepb.Entity +func (e *Interface) ConvertToProtoEntity() *diodepb.Entity { + return &diodepb.Entity{ + Entity: &diodepb.Entity_Interface{ + Interface: e.ConvertToProtoMessage().(*diodepb.Interface), + }, + } +} + +// Manufacturer is based on diodepb.Manufacturer +type Manufacturer struct { + Name *string + Slug *string + Description *string + Tags []*Tag +} + +// ConvertToProtoMessageManufacturer converts a Manufacturer to a diodepb.Manufacturer +func (e *Manufacturer) ConvertToProtoMessage() proto.Message { + return &diodepb.Manufacturer{ + Name: e.GetName(), + Slug: e.GetSlug(), + Description: e.GetDescription(), + Tags: e.GetTags(), + } +} + +// GetName returns the Name field +func (e *Manufacturer) GetName() string { + if e != nil && e.Name != nil { + return *e.Name + } + return "" +} + +// GetSlug returns the Slug field +func (e *Manufacturer) GetSlug() string { + if e != nil && e.Slug != nil { + return *e.Slug + } + return "" +} + +// GetDescription returns the Description field +func (e *Manufacturer) GetDescription() *string { + if e != nil && e.Description != nil { + return e.Description + } + return nil +} + +// GetTags returns the Tags field +func (e *Manufacturer) GetTags() []*diodepb.Tag { + var tags []*diodepb.Tag + for _, el := range e.Tags { + tags = append(tags, el.ConvertToProtoMessage().(*diodepb.Tag)) + } + return tags +} + +// ConvertToProtoEntityManufacturer converts a Manufacturer to a diodepb.Entity +func (e *Manufacturer) ConvertToProtoEntity() *diodepb.Entity { + return &diodepb.Entity{ + Entity: &diodepb.Entity_Manufacturer{ + Manufacturer: e.ConvertToProtoMessage().(*diodepb.Manufacturer), + }, + } +} + +// Platform is based on diodepb.Platform +type Platform struct { + Name *string + Slug *string + Manufacturer *Manufacturer + Description *string + Tags []*Tag +} + +// ConvertToProtoMessagePlatform converts a Platform to a diodepb.Platform +func (e *Platform) ConvertToProtoMessage() proto.Message { + return &diodepb.Platform{ + Name: e.GetName(), + Slug: e.GetSlug(), + Manufacturer: e.GetManufacturer(), + Description: e.GetDescription(), + Tags: e.GetTags(), + } +} + +// GetName returns the Name field +func (e *Platform) GetName() string { + if e != nil && e.Name != nil { + return *e.Name + } + return "" +} + +// GetSlug returns the Slug field +func (e *Platform) GetSlug() string { + if e != nil && e.Slug != nil { + return *e.Slug + } + return "" +} + +// GetManufacturer returns the Manufacturer field +func (e *Platform) GetManufacturer() *diodepb.Manufacturer { + if e != nil && e.Manufacturer != nil { + return e.Manufacturer.ConvertToProtoMessage().(*diodepb.Manufacturer) + } + return nil +} + +// GetDescription returns the Description field +func (e *Platform) GetDescription() *string { + if e != nil && e.Description != nil { + return e.Description + } + return nil +} + +// GetTags returns the Tags field +func (e *Platform) GetTags() []*diodepb.Tag { + var tags []*diodepb.Tag + for _, el := range e.Tags { + tags = append(tags, el.ConvertToProtoMessage().(*diodepb.Tag)) + } + return tags +} + +// ConvertToProtoEntityPlatform converts a Platform to a diodepb.Entity +func (e *Platform) ConvertToProtoEntity() *diodepb.Entity { + return &diodepb.Entity{ + Entity: &diodepb.Entity_Platform{ + Platform: e.ConvertToProtoMessage().(*diodepb.Platform), + }, + } +} + +// Prefix is based on diodepb.Prefix +type Prefix struct { + Prefix *string + Site *Site + Status *string + IsPool *bool + MarkUtilized *bool + Description *string + Comments *string + Tags []*Tag +} + +// ConvertToProtoMessagePrefix converts a Prefix to a diodepb.Prefix +func (e *Prefix) ConvertToProtoMessage() proto.Message { + return &diodepb.Prefix{ + Prefix: e.GetPrefix(), + Site: e.GetSite(), + Status: e.GetStatus(), + IsPool: e.GetIsPool(), + MarkUtilized: e.GetMarkUtilized(), + Description: e.GetDescription(), + Comments: e.GetComments(), + Tags: e.GetTags(), + } +} + +// GetPrefix returns the Prefix field +func (e *Prefix) GetPrefix() string { + if e != nil && e.Prefix != nil { + return *e.Prefix + } + return "" +} + +// GetSite returns the Site field +func (e *Prefix) GetSite() *diodepb.Site { + if e != nil && e.Site != nil { + return e.Site.ConvertToProtoMessage().(*diodepb.Site) + } + return nil +} + +// GetStatus returns the Status field +func (e *Prefix) GetStatus() string { + if e != nil && e.Status != nil { + return *e.Status + } + return "" +} + +// GetIsPool returns the IsPool field +func (e *Prefix) GetIsPool() *bool { + if e != nil && e.IsPool != nil { + return e.IsPool + } + return nil +} + +// GetMarkUtilized returns the MarkUtilized field +func (e *Prefix) GetMarkUtilized() *bool { + if e != nil && e.MarkUtilized != nil { + return e.MarkUtilized + } + return nil +} + +// GetDescription returns the Description field +func (e *Prefix) GetDescription() *string { + if e != nil && e.Description != nil { + return e.Description + } + return nil +} + +// GetComments returns the Comments field +func (e *Prefix) GetComments() *string { + if e != nil && e.Comments != nil { + return e.Comments + } + return nil +} + +// GetTags returns the Tags field +func (e *Prefix) GetTags() []*diodepb.Tag { + var tags []*diodepb.Tag + for _, el := range e.Tags { + tags = append(tags, el.ConvertToProtoMessage().(*diodepb.Tag)) + } + return tags +} + +// ConvertToProtoEntityPrefix converts a Prefix to a diodepb.Entity +func (e *Prefix) ConvertToProtoEntity() *diodepb.Entity { + return &diodepb.Entity{ + Entity: &diodepb.Entity_Prefix{ + Prefix: e.ConvertToProtoMessage().(*diodepb.Prefix), + }, + } +} + +// Role is based on diodepb.Role +type Role struct { + Name *string + Slug *string + Color *string + Description *string + Tags []*Tag +} + +// ConvertToProtoMessageRole converts a Role to a diodepb.Role +func (e *Role) ConvertToProtoMessage() proto.Message { + return &diodepb.Role{ + Name: e.GetName(), + Slug: e.GetSlug(), + Color: e.GetColor(), + Description: e.GetDescription(), + Tags: e.GetTags(), + } +} + +// GetName returns the Name field +func (e *Role) GetName() string { + if e != nil && e.Name != nil { + return *e.Name + } + return "" +} + +// GetSlug returns the Slug field +func (e *Role) GetSlug() string { + if e != nil && e.Slug != nil { + return *e.Slug + } + return "" +} + +// GetColor returns the Color field +func (e *Role) GetColor() string { + if e != nil && e.Color != nil { + return *e.Color + } + return "" +} + +// GetDescription returns the Description field +func (e *Role) GetDescription() *string { + if e != nil && e.Description != nil { + return e.Description + } + return nil +} + +// GetTags returns the Tags field +func (e *Role) GetTags() []*diodepb.Tag { + var tags []*diodepb.Tag + for _, el := range e.Tags { + tags = append(tags, el.ConvertToProtoMessage().(*diodepb.Tag)) + } + return tags +} + +// ConvertToProtoEntityRole converts a Role to a diodepb.Entity +func (e *Role) ConvertToProtoEntity() *diodepb.Entity { + return &diodepb.Entity{ + Entity: &diodepb.Entity_DeviceRole{ + DeviceRole: e.ConvertToProtoMessage().(*diodepb.Role), + }, + } +} + +// Site is based on diodepb.Site +type Site struct { + Name *string + Slug *string + Status *string + Facility *string + TimeZone *string + Description *string + Comments *string + Tags []*Tag +} + +// ConvertToProtoMessageSite converts a Site to a diodepb.Site +func (e *Site) ConvertToProtoMessage() proto.Message { + return &diodepb.Site{ + Name: e.GetName(), + Slug: e.GetSlug(), + Status: e.GetStatus(), + Facility: e.GetFacility(), + TimeZone: e.GetTimeZone(), + Description: e.GetDescription(), + Comments: e.GetComments(), + Tags: e.GetTags(), + } +} + +// GetName returns the Name field +func (e *Site) GetName() string { + if e != nil && e.Name != nil { + return *e.Name + } + return "" +} + +// GetSlug returns the Slug field +func (e *Site) GetSlug() string { + if e != nil && e.Slug != nil { + return *e.Slug + } + return "" +} + +// GetStatus returns the Status field +func (e *Site) GetStatus() string { + if e != nil && e.Status != nil { + return *e.Status + } + return "" +} + +// GetFacility returns the Facility field +func (e *Site) GetFacility() *string { + if e != nil && e.Facility != nil { + return e.Facility + } + return nil +} + +// GetTimeZone returns the TimeZone field +func (e *Site) GetTimeZone() *string { + if e != nil && e.TimeZone != nil { + return e.TimeZone + } + return nil +} + +// GetDescription returns the Description field +func (e *Site) GetDescription() *string { + if e != nil && e.Description != nil { + return e.Description + } + return nil +} + +// GetComments returns the Comments field +func (e *Site) GetComments() *string { + if e != nil && e.Comments != nil { + return e.Comments + } + return nil +} + +// GetTags returns the Tags field +func (e *Site) GetTags() []*diodepb.Tag { + var tags []*diodepb.Tag + for _, el := range e.Tags { + tags = append(tags, el.ConvertToProtoMessage().(*diodepb.Tag)) + } + return tags +} + +// ConvertToProtoEntitySite converts a Site to a diodepb.Entity +func (e *Site) ConvertToProtoEntity() *diodepb.Entity { + return &diodepb.Entity{ + Entity: &diodepb.Entity_Site{ + Site: e.ConvertToProtoMessage().(*diodepb.Site), + }, + } +} + +// Tag is based on diodepb.Tag +type Tag struct { + Name *string + Slug *string + Color *string +} + +// ConvertToProtoMessageTag converts a Tag to a diodepb.Tag +func (e *Tag) ConvertToProtoMessage() proto.Message { + return &diodepb.Tag{ + Name: e.GetName(), + Slug: e.GetSlug(), + Color: e.GetColor(), + } +} + +// GetName returns the Name field +func (e *Tag) GetName() string { + if e != nil && e.Name != nil { + return *e.Name + } + return "" +} + +// GetSlug returns the Slug field +func (e *Tag) GetSlug() string { + if e != nil && e.Slug != nil { + return *e.Slug + } + return "" +} + +// GetColor returns the Color field +func (e *Tag) GetColor() string { + if e != nil && e.Color != nil { + return *e.Color + } + return "" +} diff --git a/diode/ingester_test.go b/diode/ingester_test.go new file mode 100644 index 0000000..7bd9deb --- /dev/null +++ b/diode/ingester_test.go @@ -0,0 +1,1021 @@ +package diode + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/netboxlabs/diode-sdk-go/diode/v1/diodepb" +) + +func TestDeviceMethods(t *testing.T) { + tests := []struct { + name string + device *Device + expected interface{} + method func(*Device) interface{} + }{ + { + name: "GetName", + device: &Device{Name: String("device-1")}, + expected: "device-1", + method: func(d *Device) interface{} { + return d.GetName() + }, + }, + { + name: "GetDeviceFqdn", + device: &Device{DeviceFqdn: String("device-1.local")}, + expected: String("device-1.local"), + method: func(d *Device) interface{} { + return d.GetDeviceFqdn() + }, + }, + { + name: "GetDeviceType", + device: &Device{DeviceType: &DeviceType{Model: String("model-1")}}, + expected: &diodepb.DeviceType{ + Model: "model-1", + }, + method: func(d *Device) interface{} { + return d.GetDeviceType() + }, + }, + { + name: "GetRole", + device: &Device{Role: &Role{Name: String("role-1")}}, + expected: &diodepb.Role{ + Name: "role-1", + }, + method: func(d *Device) interface{} { + return d.GetRole() + }, + }, + { + name: "GetPlatform", + device: &Device{Platform: &Platform{Name: String("platform-1")}}, + expected: &diodepb.Platform{ + Name: "platform-1", + }, + method: func(d *Device) interface{} { + return d.GetPlatform() + }, + }, + { + name: "GetSerial", + device: &Device{Serial: String("serial-1")}, + expected: String("serial-1"), + method: func(d *Device) interface{} { + return d.GetSerial() + }, + }, + { + name: "GetSite", + device: &Device{Site: &Site{Name: String("site-1")}}, + expected: &diodepb.Site{ + Name: "site-1", + }, + method: func(d *Device) interface{} { + return d.GetSite() + }, + }, + { + name: "GetAssetTag", + device: &Device{AssetTag: String("asset-1")}, + expected: String("asset-1"), + method: func(d *Device) interface{} { + return d.GetAssetTag() + }, + }, + { + name: "GetStatus", + device: &Device{Status: String("active")}, + expected: "active", + method: func(d *Device) interface{} { + return d.GetStatus() + }, + }, + { + name: "GetDescription", + device: &Device{Description: String("description")}, + expected: String("description"), + method: func(d *Device) interface{} { + return d.GetDescription() + }, + }, + { + name: "GetComments", + device: &Device{Comments: String("comments")}, + expected: String("comments"), + method: func(d *Device) interface{} { + return d.GetComments() + }, + }, + { + name: "GetTags", + device: &Device{Tags: []*Tag{{Name: String("tag-1")}}}, + expected: []*diodepb.Tag{ + {Name: "tag-1"}, + }, + method: func(d *Device) interface{} { + return d.GetTags() + }, + }, + { + name: "GetPrimaryIp4", + device: &Device{PrimaryIp4: &IPAddress{Address: String("192.168.1.1")}}, + expected: &diodepb.IPAddress{ + Address: "192.168.1.1", + AssignedObject: (*diodepb.IPAddress_Interface)(nil), + }, + method: func(d *Device) interface{} { + return d.GetPrimaryIp4() + }, + }, + { + name: "GetPrimaryIp6", + device: &Device{PrimaryIp6: &IPAddress{Address: String("::1")}}, + expected: &diodepb.IPAddress{ + Address: "::1", + AssignedObject: (*diodepb.IPAddress_Interface)(nil), + }, + method: func(d *Device) interface{} { + return d.GetPrimaryIp6() + }, + }, + { + name: "ConvertToProtoMessage", + device: &Device{Name: String("device-1")}, + expected: &diodepb.Device{ + Name: "device-1", + }, + method: func(d *Device) interface{} { + return d.ConvertToProtoMessage() + }, + }, + { + name: "ConvertToProtoEntity", + device: &Device{Name: String("device-1")}, + expected: &diodepb.Entity{ + Entity: &diodepb.Entity_Device{ + Device: &diodepb.Device{ + Name: "device-1", + }, + }, + }, + method: func(d *Device) interface{} { + return d.ConvertToProtoEntity() + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, tt.method(tt.device)) + }) + } +} + +func TestDeviceTypeMethods(t *testing.T) { + tests := []struct { + name string + deviceType *DeviceType + expected interface{} + method func(*DeviceType) interface{} + }{ + { + name: "GetModel", + deviceType: &DeviceType{Model: String("model-1")}, + expected: "model-1", + method: func(d *DeviceType) interface{} { + return d.GetModel() + }, + }, + { + name: "GetManufacturer", + deviceType: &DeviceType{Manufacturer: &Manufacturer{ + Name: String("manufacturer-1"), + }}, + expected: &diodepb.Manufacturer{ + Name: "manufacturer-1", + }, + method: func(d *DeviceType) interface{} { + return d.GetManufacturer() + }, + }, + { + name: "GetPartNumber", + deviceType: &DeviceType{PartNumber: String("part-1")}, + expected: String("part-1"), + method: func(d *DeviceType) interface{} { + return d.GetPartNumber() + }, + }, + { + name: "GetDescription", + deviceType: &DeviceType{Description: String("description")}, + expected: String("description"), + method: func(d *DeviceType) interface{} { + return d.GetDescription() + }, + }, + { + name: "GetComments", + deviceType: &DeviceType{Comments: String("comments")}, + expected: String("comments"), + method: func(d *DeviceType) interface{} { + return d.GetComments() + }, + }, + { + name: "GetTags", + deviceType: &DeviceType{Tags: []*Tag{{Name: String("tag-1")}}}, + expected: []*diodepb.Tag{ + {Name: "tag-1"}, + }, + method: func(d *DeviceType) interface{} { + return d.GetTags() + }, + }, + { + name: "ConvertToProtoMessage", + deviceType: &DeviceType{Model: String("model-1")}, + expected: &diodepb.DeviceType{ + Model: "model-1", + }, + method: func(d *DeviceType) interface{} { + return d.ConvertToProtoMessage() + }, + }, + { + name: "ConvertToProtoEntity", + deviceType: &DeviceType{Model: String("model-1")}, + expected: &diodepb.Entity{ + Entity: &diodepb.Entity_DeviceType{ + DeviceType: &diodepb.DeviceType{ + Model: "model-1", + }, + }, + }, + method: func(d *DeviceType) interface{} { + return d.ConvertToProtoEntity() + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, tt.method(tt.deviceType)) + }) + } +} + +func TestIPAddressMethods(t *testing.T) { + tests := []struct { + name string + ipAddress *IPAddress + expected interface{} + method func(*IPAddress) interface{} + }{ + { + name: "ConvertToProtoMessage", + ipAddress: &IPAddress{Address: String("192.168.1.1")}, + expected: &diodepb.IPAddress{ + Address: "192.168.1.1", + AssignedObject: (*diodepb.IPAddress_Interface)(nil), + }, + method: func(ip *IPAddress) interface{} { + return ip.ConvertToProtoMessage() + }, + }, + { + name: "GetAddress", + ipAddress: &IPAddress{Address: String("192.168.1.1")}, + expected: "192.168.1.1", + method: func(ip *IPAddress) interface{} { + return ip.GetAddress() + }, + }, + { + name: "GetAssignedObject", + ipAddress: &IPAddress{AssignedObject: &Interface{}}, + expected: &diodepb.IPAddress_Interface{Interface: &diodepb.Interface{}}, + method: func(ip *IPAddress) interface{} { + return ip.GetAssignedObject() + }, + }, + { + name: "GetStatus", + ipAddress: &IPAddress{Status: String("active")}, + expected: "active", + method: func(ip *IPAddress) interface{} { + return ip.GetStatus() + }, + }, + { + name: "GetRole", + ipAddress: &IPAddress{Role: String("admin")}, + expected: "admin", + method: func(ip *IPAddress) interface{} { + return ip.GetRole() + }, + }, + { + name: "GetDnsName", + ipAddress: &IPAddress{DnsName: String("example.com")}, + expected: String("example.com"), + method: func(ip *IPAddress) interface{} { + return ip.GetDnsName() + }, + }, + { + name: "GetDescription", + ipAddress: &IPAddress{Description: String("Test description")}, + expected: String("Test description"), + method: func(ip *IPAddress) interface{} { + return ip.GetDescription() + }, + }, + { + name: "GetComments", + ipAddress: &IPAddress{Comments: String("Test comments")}, + expected: String("Test comments"), + method: func(ip *IPAddress) interface{} { + return ip.GetComments() + }, + }, + { + name: "GetTags", + ipAddress: &IPAddress{Tags: []*Tag{{Name: String("tag-1")}}}, + expected: []*diodepb.Tag{ + {Name: "tag-1"}, + }, + method: func(ip *IPAddress) interface{} { + return ip.GetTags() + }, + }, + { + name: "ConvertToProtoEntity", + ipAddress: &IPAddress{Address: String("192.168.1.1")}, + expected: &diodepb.Entity{ + Entity: &diodepb.Entity_IpAddress{ + IpAddress: &diodepb.IPAddress{ + Address: "192.168.1.1", + AssignedObject: (*diodepb.IPAddress_Interface)(nil), + }, + }, + }, + method: func(ip *IPAddress) interface{} { + return ip.ConvertToProtoEntity() + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, tt.method(tt.ipAddress)) + }) + } +} + +func TestInterfaceMethods(t *testing.T) { + tests := []struct { + name string + iface *Interface + expected interface{} + method func(*Interface) interface{} + }{ + { + name: "GetDevice", + iface: &Interface{Device: &Device{Name: String("device-1")}}, + expected: &diodepb.Device{Name: "device-1"}, + method: func(i *Interface) interface{} { + return i.GetDevice() + }, + }, + { + name: "GetName", + iface: &Interface{Name: String("eth0")}, + expected: "eth0", + method: func(i *Interface) interface{} { + return i.GetName() + }, + }, + { + name: "GetLabel", + iface: &Interface{Label: String("label-1")}, + expected: String("label-1"), + method: func(i *Interface) interface{} { + return i.GetLabel() + }, + }, + { + name: "GetType", + iface: &Interface{Type: String("type-1")}, + expected: "type-1", + method: func(i *Interface) interface{} { + return i.GetType() + }, + }, + { + name: "GetEnabled", + iface: &Interface{Enabled: Bool(true)}, + expected: Bool(true), + method: func(i *Interface) interface{} { + return i.GetEnabled() + }, + }, + { + name: "GetMtu", + iface: &Interface{Mtu: Int32(1500)}, + expected: Int32(1500), + method: func(i *Interface) interface{} { + return i.GetMtu() + }, + }, + { + name: "GetMacAddress", + iface: &Interface{MacAddress: String("00:1A:2B:3C:4D:5E")}, + expected: String("00:1A:2B:3C:4D:5E"), + method: func(i *Interface) interface{} { + return i.GetMacAddress() + }, + }, + { + name: "GetSpeed", + iface: &Interface{Speed: Int32(1000)}, + expected: Int32(1000), + method: func(i *Interface) interface{} { + return i.GetSpeed() + }, + }, + { + name: "GetWwn", + iface: &Interface{Wwn: String("wwn-1")}, + expected: String("wwn-1"), + method: func(i *Interface) interface{} { + return i.GetWwn() + }, + }, + { + name: "GetMgmtOnly", + iface: &Interface{MgmtOnly: Bool(true)}, + expected: Bool(true), + method: func(i *Interface) interface{} { + return i.GetMgmtOnly() + }, + }, + { + name: "GetDescription", + iface: &Interface{Description: String("Test description")}, + expected: String("Test description"), + method: func(i *Interface) interface{} { + return i.GetDescription() + }, + }, + { + name: "GetMarkConnected", + iface: &Interface{MarkConnected: Bool(true)}, + expected: Bool(true), + method: func(i *Interface) interface{} { + return i.GetMarkConnected() + }, + }, + { + name: "GetMode", + iface: &Interface{Mode: String("mode-1")}, + expected: "mode-1", + method: func(i *Interface) interface{} { + return i.GetMode() + }, + }, + { + name: "GetTags", + iface: &Interface{Tags: []*Tag{{Name: String("tag-1")}}}, + expected: []*diodepb.Tag{{Name: "tag-1"}}, + method: func(i *Interface) interface{} { + return i.GetTags() + }, + }, + { + name: "ConvertToProtoMessage", + iface: &Interface{Name: String("eth0")}, + expected: &diodepb.Interface{Name: "eth0"}, + method: func(i *Interface) interface{} { + return i.ConvertToProtoMessage() + }, + }, + { + name: "ConvertToProtoEntity", + iface: &Interface{Name: String("eth0")}, + expected: &diodepb.Entity{ + Entity: &diodepb.Entity_Interface{ + Interface: &diodepb.Interface{Name: "eth0"}, + }, + }, + method: func(i *Interface) interface{} { + return i.ConvertToProtoEntity() + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, tt.method(tt.iface)) + }) + } +} + +func TestManufacturerMethods(t *testing.T) { + tests := []struct { + name string + manufacturer *Manufacturer + expected interface{} + method func(*Manufacturer) interface{} + }{ + { + name: "GetName", + manufacturer: &Manufacturer{Name: String("manufacturer-1")}, + expected: "manufacturer-1", + method: func(m *Manufacturer) interface{} { + return m.GetName() + }, + }, + { + name: "GetSlug", + manufacturer: &Manufacturer{Slug: String("slug-1")}, + expected: "slug-1", + method: func(m *Manufacturer) interface{} { + return m.GetSlug() + }, + }, + { + name: "GetDescription", + manufacturer: &Manufacturer{Description: String("Test description")}, + expected: String("Test description"), + method: func(m *Manufacturer) interface{} { + return m.GetDescription() + }, + }, + { + name: "GetTags", + manufacturer: &Manufacturer{Tags: []*Tag{ + {Name: String("tag-1")}, + }}, + expected: []*diodepb.Tag{ + {Name: "tag-1"}, + }, + method: func(m *Manufacturer) interface{} { + return m.GetTags() + }, + }, + { + name: "ConvertToProtoMessage", + manufacturer: &Manufacturer{Name: String("manufacturer-1")}, + expected: &diodepb.Manufacturer{ + Name: "manufacturer-1", + }, + method: func(m *Manufacturer) interface{} { + return m.ConvertToProtoMessage() + }, + }, + { + name: "ConvertToProtoEntity", + manufacturer: &Manufacturer{Name: String("manufacturer-1")}, + expected: &diodepb.Entity{ + Entity: &diodepb.Entity_Manufacturer{ + Manufacturer: &diodepb.Manufacturer{ + Name: "manufacturer-1", + }, + }, + }, + method: func(m *Manufacturer) interface{} { + return m.ConvertToProtoEntity() + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, tt.method(tt.manufacturer)) + }) + } +} + +func TestPlatformMethods(t *testing.T) { + tests := []struct { + name string + platform *Platform + expected interface{} + method func(*Platform) interface{} + }{ + { + name: "GetName", + platform: &Platform{Name: String("platform-1")}, + expected: "platform-1", + method: func(p *Platform) interface{} { + return p.GetName() + }, + }, + { + name: "GetSlug", + platform: &Platform{Slug: String("slug-1")}, + expected: "slug-1", + method: func(p *Platform) interface{} { + return p.GetSlug() + }, + }, + { + name: "GetManufacturer", + platform: &Platform{Manufacturer: &Manufacturer{Name: String("manufacturer-1")}}, + expected: &diodepb.Manufacturer{Name: "manufacturer-1"}, + method: func(p *Platform) interface{} { + return p.GetManufacturer() + }, + }, + { + name: "GetDescription", + platform: &Platform{Description: String("Test description")}, + expected: String("Test description"), + method: func(p *Platform) interface{} { + return p.GetDescription() + }, + }, + { + name: "GetTags", + platform: &Platform{Tags: []*Tag{ + {Name: String("tag-1")}, + }}, + expected: []*diodepb.Tag{ + {Name: "tag-1"}, + }, + method: func(p *Platform) interface{} { + return p.GetTags() + }, + }, + { + name: "ConvertToProtoMessage", + platform: &Platform{Name: String("platform-1")}, + expected: &diodepb.Platform{ + Name: "platform-1", + }, + method: func(p *Platform) interface{} { + return p.ConvertToProtoMessage() + }, + }, + { + name: "ConvertToProtoEntity", + platform: &Platform{Name: String("platform-1")}, + expected: &diodepb.Entity{ + Entity: &diodepb.Entity_Platform{ + Platform: &diodepb.Platform{Name: "platform-1"}, + }, + }, + method: func(p *Platform) interface{} { + return p.ConvertToProtoEntity() + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, tt.method(tt.platform)) + }) + } +} + +func TestPrefixMethods(t *testing.T) { + tests := []struct { + name string + prefix *Prefix + expected interface{} + method func(*Prefix) interface{} + }{ + { + name: "GetPrefix", + prefix: &Prefix{Prefix: String("prefix-1")}, + expected: "prefix-1", + method: func(p *Prefix) interface{} { + return p.GetPrefix() + }, + }, + { + name: "GetSite", + prefix: &Prefix{Site: &Site{Name: String("site-1")}}, + expected: &diodepb.Site{Name: "site-1"}, + method: func(p *Prefix) interface{} { + return p.GetSite() + }, + }, + { + name: "GetStatus", + prefix: &Prefix{Status: String("active")}, + expected: "active", + method: func(p *Prefix) interface{} { + return p.GetStatus() + }, + }, + { + name: "GetIsPool", + prefix: &Prefix{IsPool: Bool(true)}, + expected: Bool(true), + method: func(p *Prefix) interface{} { + return p.GetIsPool() + }, + }, + { + name: "GetMarkUtilized", + prefix: &Prefix{MarkUtilized: Bool(true)}, + expected: Bool(true), + method: func(p *Prefix) interface{} { + return p.GetMarkUtilized() + }, + }, + { + name: "GetDescription", + prefix: &Prefix{Description: String("Test description")}, + expected: String("Test description"), + method: func(p *Prefix) interface{} { + return p.GetDescription() + }, + }, + { + name: "GetComments", + prefix: &Prefix{Comments: String("Test comments")}, + expected: String("Test comments"), + method: func(p *Prefix) interface{} { + return p.GetComments() + }, + }, + { + name: "GetTags", + prefix: &Prefix{Tags: []*Tag{ + {Name: String("tag-1")}, + }}, + expected: []*diodepb.Tag{ + {Name: "tag-1"}, + }, + method: func(p *Prefix) interface{} { + return p.GetTags() + }, + }, + { + name: "ConvertToProtoMessage", + prefix: &Prefix{Prefix: String("prefix-1")}, + expected: &diodepb.Prefix{Prefix: "prefix-1"}, + method: func(p *Prefix) interface{} { + return p.ConvertToProtoMessage() + }, + }, + { + name: "ConvertToProtoEntity", + prefix: &Prefix{Prefix: String("prefix-1")}, + expected: &diodepb.Entity{ + Entity: &diodepb.Entity_Prefix{ + Prefix: &diodepb.Prefix{Prefix: "prefix-1"}, + }, + }, + method: func(p *Prefix) interface{} { + return p.ConvertToProtoEntity() + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, tt.method(tt.prefix)) + }) + } +} + +func TestRoleMethods(t *testing.T) { + tests := []struct { + name string + role *Role + expected interface{} + method func(*Role) interface{} + }{ + { + name: "GetName", + role: &Role{Name: String("role-1")}, + expected: "role-1", + method: func(r *Role) interface{} { + return r.GetName() + }, + }, + { + name: "GetSlug", + role: &Role{Slug: String("slug-1")}, + expected: "slug-1", + method: func(r *Role) interface{} { + return r.GetSlug() + }, + }, + { + name: "GetColor", + role: &Role{Color: String("color-1")}, + expected: "color-1", + method: func(r *Role) interface{} { + return r.GetColor() + }, + }, + { + name: "GetDescription", + role: &Role{Description: String("Test description")}, + expected: String("Test description"), + method: func(r *Role) interface{} { + return r.GetDescription() + }, + }, + { + name: "GetTags", + role: &Role{Tags: []*Tag{ + {Name: String("tag-1")}, + }}, + expected: []*diodepb.Tag{ + {Name: "tag-1"}, + }, + method: func(r *Role) interface{} { + return r.GetTags() + }, + }, + { + name: "ConvertToProtoMessage", + role: &Role{Name: String("role-1")}, + expected: &diodepb.Role{Name: "role-1"}, + method: func(r *Role) interface{} { + return r.ConvertToProtoMessage() + }, + }, + { + name: "ConvertToProtoEntity", + role: &Role{Name: String("role-1")}, + expected: &diodepb.Entity{ + Entity: &diodepb.Entity_DeviceRole{ + DeviceRole: &diodepb.Role{Name: "role-1"}, + }, + }, + method: func(r *Role) interface{} { + return r.ConvertToProtoEntity() + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, tt.method(tt.role)) + }) + } +} + +func TestSiteMethods(t *testing.T) { + tests := []struct { + name string + site *Site + expected interface{} + method func(*Site) interface{} + }{ + { + name: "GetName", + site: &Site{Name: String("site-1")}, + expected: "site-1", + method: func(s *Site) interface{} { + return s.GetName() + }, + }, + { + name: "GetSlug", + site: &Site{Slug: String("slug-1")}, + expected: "slug-1", + method: func(s *Site) interface{} { + return s.GetSlug() + }, + }, + { + name: "GetStatus", + site: &Site{Status: String("active")}, + expected: "active", + method: func(s *Site) interface{} { + return s.GetStatus() + }, + }, + { + name: "GetFacility", + site: &Site{Facility: String("facility-1")}, + expected: String("facility-1"), + method: func(s *Site) interface{} { + return s.GetFacility() + }, + }, + { + name: "GetTimeZone", + site: &Site{TimeZone: String("UTC")}, + expected: String("UTC"), + method: func(s *Site) interface{} { + return s.GetTimeZone() + }, + }, + { + name: "GetDescription", + site: &Site{Description: String("Test description")}, + expected: String("Test description"), + method: func(s *Site) interface{} { + return s.GetDescription() + }, + }, + { + name: "GetComments", + site: &Site{Comments: String("Test comments")}, + expected: String("Test comments"), + method: func(s *Site) interface{} { + return s.GetComments() + }, + }, + { + name: "GetTags", + site: &Site{Tags: []*Tag{ + {Name: String("tag-1")}, + }}, + expected: []*diodepb.Tag{ + {Name: "tag-1"}, + }, + method: func(s *Site) interface{} { + return s.GetTags() + }, + }, + { + name: "ConvertToProtoMessage", + site: &Site{Name: String("site-1")}, + expected: &diodepb.Site{Name: "site-1"}, + method: func(s *Site) interface{} { + return s.ConvertToProtoMessage() + }, + }, + { + name: "ConvertToProtoEntity", + site: &Site{Name: String("site-1")}, + expected: &diodepb.Entity{ + Entity: &diodepb.Entity_Site{ + Site: &diodepb.Site{Name: "site-1"}, + }, + }, + method: func(s *Site) interface{} { + return s.ConvertToProtoEntity() + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, tt.method(tt.site)) + }) + } +} + +func TestTagMethods(t *testing.T) { + tests := []struct { + name string + tag *Tag + expected interface{} + method func(*Tag) interface{} + }{ + { + name: "GetName", + tag: &Tag{Name: String("tag-1")}, + expected: "tag-1", + method: func(t *Tag) interface{} { + return t.GetName() + }, + }, + { + name: "GetSlug", + tag: &Tag{Slug: String("slug-1")}, + expected: "slug-1", + method: func(t *Tag) interface{} { + return t.GetSlug() + }, + }, + { + name: "GetColor", + tag: &Tag{Color: String("color-1")}, + expected: "color-1", + method: func(t *Tag) interface{} { + return t.GetColor() + }, + }, + { + name: "ConvertToProtoMessage", + tag: &Tag{Name: String("tag-1")}, + expected: &diodepb.Tag{Name: "tag-1"}, + method: func(t *Tag) interface{} { + return t.ConvertToProtoMessage() + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.expected, tt.method(tt.tag)) + }) + } +} diff --git a/diode/ptr.go b/diode/ptr.go new file mode 100644 index 0000000..0c8bcba --- /dev/null +++ b/diode/ptr.go @@ -0,0 +1,51 @@ +package diode + +// Bool returns a pointer to the bool value passed in. +func Bool(v bool) *bool { + return &v +} + +// String returns a pointer to the string value passed in. +func String(v string) *string { + return &v +} + +// Int returns a pointer to the int value passed in. +func Int(v int) *int { + return &v +} + +// Int32 returns a pointer to the int32 value passed in. +func Int32(v int32) *int32 { + return &v +} + +// Int64 returns a pointer to the int64 value passed in. +func Int64(v int64) *int64 { + return &v +} + +// Uint returns a pointer to the uint value passed in. +func Uint(v uint) *uint { + return &v +} + +// Uint32 returns a pointer to the uint32 value passed in. +func Uint32(v uint32) *uint32 { + return &v +} + +// Uint64 returns a pointer to the uint64 value passed in. +func Uint64(v uint64) *uint64 { + return &v +} + +// Float32 returns a pointer to the float32 value passed in. +func Float32(v float32) *float32 { + return &v +} + +// Float64 returns a pointer to the float64 value passed in. +func Float64(v float64) *float64 { + return &v +} diff --git a/diode/ptr_test.go b/diode/ptr_test.go new file mode 100644 index 0000000..9e22a4a --- /dev/null +++ b/diode/ptr_test.go @@ -0,0 +1,77 @@ +package diode + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestBool(t *testing.T) { + val := true + ptr := Bool(val) + require.NotNil(t, ptr) + require.Equal(t, val, *ptr) +} + +func TestString(t *testing.T) { + val := "test" + ptr := String(val) + require.NotNil(t, ptr) + require.Equal(t, val, *ptr) +} + +func TestInt(t *testing.T) { + val := 42 + ptr := Int(val) + require.NotNil(t, ptr) + require.Equal(t, val, *ptr) +} + +func TestInt32(t *testing.T) { + val := int32(42) + ptr := Int32(val) + require.NotNil(t, ptr) + require.Equal(t, val, *ptr) +} + +func TestInt64(t *testing.T) { + val := int64(42) + ptr := Int64(val) + require.NotNil(t, ptr) + require.Equal(t, val, *ptr) +} + +func TestUint(t *testing.T) { + val := uint(42) + ptr := Uint(val) + require.NotNil(t, ptr) + require.Equal(t, val, *ptr) +} + +func TestUint32(t *testing.T) { + val := uint32(42) + ptr := Uint32(val) + require.NotNil(t, ptr) + require.Equal(t, val, *ptr) +} + +func TestUint64(t *testing.T) { + val := uint64(42) + ptr := Uint64(val) + require.NotNil(t, ptr) + require.Equal(t, val, *ptr) +} + +func TestFloat32(t *testing.T) { + val := float32(42.0) + ptr := Float32(val) + require.NotNil(t, ptr) + require.Equal(t, val, *ptr) +} + +func TestFloat64(t *testing.T) { + val := float64(42.0) + ptr := Float64(val) + require.NotNil(t, ptr) + require.Equal(t, val, *ptr) +} diff --git a/diode/v1/client.go b/diode/v1/client.go deleted file mode 100644 index e8f156f..0000000 --- a/diode/v1/client.go +++ /dev/null @@ -1,151 +0,0 @@ -package diode - -import ( - "context" - "crypto/tls" - "fmt" - "os" - "strconv" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/metadata" - - "github.com/netboxlabs/diode-sdk-go/diode/v1/diodepb" -) - -const ( - // SDKName is the name of the Diode SDK - SDKName = "diode-sdk-go" - - // SDKVersion is the version of the Diode SDK - SDKVersion = "0.1.0" - - // DiodeAPIKeyEnvVarName is the environment variable name for the Diode API key - DiodeAPIKeyEnvVarName = "DIODE_API_KEY" - - // DiodeGRPCInsecureEnvVarName is the environment variable name for the Diode gRPC disabling transport security - DiodeGRPCInsecureEnvVarName = "DIODE_GRPC_INSECURE" - - // DiodeGRPCHostEnvVarName is the environment variable name for the Diode gRPC host - DiodeGRPCHostEnvVarName = "DIODE_GRPC_HOST" - - // DiodeGRPCPortEnvVarName is the environment variable name for the Diode gRPC port - DiodeGRPCPortEnvVarName = "DIODE_GRPC_PORT" - - authAPIKeyName = "diode-api-key" - - defaultGRPCHost = "127.0.0.1" - - defaultGRPCPort = "8081" -) - -// Client is an interface that defines the methods available from Diode API -type Client interface { - // Close closes the connection to the API service - Close() error - - // Ingest sends an ingest request to the ingester service - Ingest(context.Context, *diodepb.IngestRequest, ...grpc.CallOption) (*diodepb.IngestResponse, error) -} - -// GRPCClient is a gRPC implementation of the ingester service -type GRPCClient struct { - // gRPC virtual connection - conn *grpc.ClientConn - - // The gRPC API client - client diodepb.IngesterServiceClient - - // An API key for the Diode API - apiKey *string -} - -// Close closes the connection to the API service -func (g *GRPCClient) Close() error { - if g.conn != nil { - return g.conn.Close() - } - return nil -} - -// Ingest sends an ingest request to the ingester service -func (g *GRPCClient) Ingest(ctx context.Context, req *diodepb.IngestRequest, opt ...grpc.CallOption) (*diodepb.IngestResponse, error) { - return g.client.Ingest(ctx, req, opt...) -} - -func authUnaryInterceptor(apiKey string) grpc.DialOption { - return grpc.WithUnaryInterceptor(func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error { - if apiKey != "" { - ctx = metadata.NewOutgoingContext(ctx, metadata.Pairs(authAPIKeyName, apiKey)) - } - return invoker(ctx, method, req, reply, cc, opts...) - }) -} - -// NewClient creates a new ingester client based on gRPC -func NewClient() (Client, error) { - apiKey, ok := os.LookupEnv(DiodeAPIKeyEnvVarName) - if !ok { - return nil, fmt.Errorf("environment variable %s not found", DiodeAPIKeyEnvVarName) - } - - dialOpts := []grpc.DialOption{ - grpc.WithUserAgent(userAgent()), - authUnaryInterceptor(apiKey), - } - - if grpcInsecure() { - dialOpts = append(dialOpts, grpc.WithTransportCredentials(insecure.NewCredentials())) - } else { - dialOpts = append(dialOpts, grpc.WithTransportCredentials(credentials.NewTLS(new(tls.Config)))) - } - - target := grpcTarget() - - conn, err := grpc.NewClient(target, dialOpts...) - if err != nil { - return nil, err - } - - c := &GRPCClient{ - conn: conn, - client: diodepb.NewIngesterServiceClient(conn), - apiKey: &apiKey, - } - - return c, nil -} - -func userAgent() string { - return fmt.Sprintf("%s/%s", SDKName, SDKVersion) -} - -func grpcTarget() string { - host, ok := os.LookupEnv(DiodeGRPCHostEnvVarName) - if !ok { - host = defaultGRPCHost - } - - port, ok := os.LookupEnv(DiodeGRPCPortEnvVarName) - if !ok { - port = defaultGRPCPort - } - - return fmt.Sprintf("%s:%s", host, port) -} - -func grpcInsecure() bool { - insecureStr, ok := os.LookupEnv(DiodeGRPCInsecureEnvVarName) - if !ok { - return false - } - - insecureVal, err := strconv.ParseBool(insecureStr) - if err != nil { - return false - } - - return insecureVal -} diff --git a/diode/v1/client_test.go b/diode/v1/client_test.go deleted file mode 100644 index 482ccf7..0000000 --- a/diode/v1/client_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package diode_test - -import ( - "os" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/netboxlabs/diode-sdk-go/diode/v1" -) - -func TestNewClient(t *testing.T) { - cleanUpEnvVars() - - _ = os.Setenv(diode.DiodeAPIKeyEnvVarName, "nothingtoseehere") - - client, err := diode.NewClient() - require.NoError(t, err) - require.NotNil(t, client) - require.NoError(t, client.Close()) -} - -func TestNewClientWithMissingAPIKey(t *testing.T) { - cleanUpEnvVars() - - client, err := diode.NewClient() - require.Nil(t, client) - require.EqualError(t, err, "environment variable DIODE_API_KEY not found") -} - -func TestNewClientWithInsecureGRPC(t *testing.T) { - tests := []struct { - desc string - value string - }{ - { - desc: "insecure gRPC enabled", - value: "true", - }, - { - desc: "insecure gRPC disabled", - value: "false", - }, - { - desc: "insecure gRPC disabled with invalid value", - value: "invalidvalue", - }, - } - - for _, tt := range tests { - t.Run(tt.desc, func(t *testing.T) { - cleanUpEnvVars() - - _ = os.Setenv(diode.DiodeAPIKeyEnvVarName, "nothingtoseehere") - _ = os.Setenv(diode.DiodeGRPCInsecureEnvVarName, tt.value) - - client, err := diode.NewClient() - require.NoError(t, err) - require.NotNil(t, client) - }) - } -} - -func cleanUpEnvVars() { - _ = os.Unsetenv(diode.DiodeAPIKeyEnvVarName) - _ = os.Unsetenv(diode.DiodeGRPCHostEnvVarName) - _ = os.Unsetenv(diode.DiodeGRPCPortEnvVarName) - _ = os.Unsetenv(diode.DiodeGRPCInsecureEnvVarName) -} diff --git a/diode/v1/diodepb/ingester.pb.go b/diode/v1/diodepb/ingester.pb.go index b4c3c49..3bf215a 100644 --- a/diode/v1/diodepb/ingester.pb.go +++ b/diode/v1/diodepb/ingester.pb.go @@ -29,16 +29,16 @@ type Device struct { unknownFields protoimpl.UnknownFields Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - DeviceFqdn string `protobuf:"bytes,2,opt,name=device_fqdn,json=deviceFqdn,proto3" json:"device_fqdn,omitempty"` + DeviceFqdn *string `protobuf:"bytes,2,opt,name=device_fqdn,json=deviceFqdn,proto3,oneof" json:"device_fqdn,omitempty"` DeviceType *DeviceType `protobuf:"bytes,3,opt,name=device_type,json=deviceType,proto3" json:"device_type,omitempty"` Role *Role `protobuf:"bytes,4,opt,name=role,proto3" json:"role,omitempty"` Platform *Platform `protobuf:"bytes,5,opt,name=platform,proto3" json:"platform,omitempty"` - Serial string `protobuf:"bytes,6,opt,name=serial,proto3" json:"serial,omitempty"` + Serial *string `protobuf:"bytes,6,opt,name=serial,proto3,oneof" json:"serial,omitempty"` Site *Site `protobuf:"bytes,7,opt,name=site,proto3" json:"site,omitempty"` - AssetTag string `protobuf:"bytes,8,opt,name=asset_tag,json=assetTag,proto3" json:"asset_tag,omitempty"` + AssetTag *string `protobuf:"bytes,8,opt,name=asset_tag,json=assetTag,proto3,oneof" json:"asset_tag,omitempty"` Status string `protobuf:"bytes,9,opt,name=status,proto3" json:"status,omitempty"` - Description string `protobuf:"bytes,10,opt,name=description,proto3" json:"description,omitempty"` - Comments string `protobuf:"bytes,11,opt,name=comments,proto3" json:"comments,omitempty"` + Description *string `protobuf:"bytes,10,opt,name=description,proto3,oneof" json:"description,omitempty"` + Comments *string `protobuf:"bytes,11,opt,name=comments,proto3,oneof" json:"comments,omitempty"` Tags []*Tag `protobuf:"bytes,12,rep,name=tags,proto3" json:"tags,omitempty"` PrimaryIp4 *IPAddress `protobuf:"bytes,13,opt,name=primary_ip4,json=primaryIp4,proto3" json:"primary_ip4,omitempty"` PrimaryIp6 *IPAddress `protobuf:"bytes,14,opt,name=primary_ip6,json=primaryIp6,proto3" json:"primary_ip6,omitempty"` @@ -84,8 +84,8 @@ func (x *Device) GetName() string { } func (x *Device) GetDeviceFqdn() string { - if x != nil { - return x.DeviceFqdn + if x != nil && x.DeviceFqdn != nil { + return *x.DeviceFqdn } return "" } @@ -112,8 +112,8 @@ func (x *Device) GetPlatform() *Platform { } func (x *Device) GetSerial() string { - if x != nil { - return x.Serial + if x != nil && x.Serial != nil { + return *x.Serial } return "" } @@ -126,8 +126,8 @@ func (x *Device) GetSite() *Site { } func (x *Device) GetAssetTag() string { - if x != nil { - return x.AssetTag + if x != nil && x.AssetTag != nil { + return *x.AssetTag } return "" } @@ -140,15 +140,15 @@ func (x *Device) GetStatus() string { } func (x *Device) GetDescription() string { - if x != nil { - return x.Description + if x != nil && x.Description != nil { + return *x.Description } return "" } func (x *Device) GetComments() string { - if x != nil { - return x.Comments + if x != nil && x.Comments != nil { + return *x.Comments } return "" } @@ -182,16 +182,16 @@ type Interface struct { Device *Device `protobuf:"bytes,1,opt,name=device,proto3" json:"device,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Label string `protobuf:"bytes,3,opt,name=label,proto3" json:"label,omitempty"` + Label *string `protobuf:"bytes,3,opt,name=label,proto3,oneof" json:"label,omitempty"` Type string `protobuf:"bytes,4,opt,name=type,proto3" json:"type,omitempty"` - Enabled bool `protobuf:"varint,5,opt,name=enabled,proto3" json:"enabled,omitempty"` - Mtu int32 `protobuf:"varint,6,opt,name=mtu,proto3" json:"mtu,omitempty"` - MacAddress string `protobuf:"bytes,7,opt,name=mac_address,json=macAddress,proto3" json:"mac_address,omitempty"` - Speed int32 `protobuf:"varint,8,opt,name=speed,proto3" json:"speed,omitempty"` - Wwn string `protobuf:"bytes,9,opt,name=wwn,proto3" json:"wwn,omitempty"` - MgmtOnly bool `protobuf:"varint,10,opt,name=mgmt_only,json=mgmtOnly,proto3" json:"mgmt_only,omitempty"` - Description string `protobuf:"bytes,11,opt,name=description,proto3" json:"description,omitempty"` - MarkConnected bool `protobuf:"varint,12,opt,name=mark_connected,json=markConnected,proto3" json:"mark_connected,omitempty"` + Enabled *bool `protobuf:"varint,5,opt,name=enabled,proto3,oneof" json:"enabled,omitempty"` + Mtu *int32 `protobuf:"varint,6,opt,name=mtu,proto3,oneof" json:"mtu,omitempty"` + MacAddress *string `protobuf:"bytes,7,opt,name=mac_address,json=macAddress,proto3,oneof" json:"mac_address,omitempty"` + Speed *int32 `protobuf:"varint,8,opt,name=speed,proto3,oneof" json:"speed,omitempty"` + Wwn *string `protobuf:"bytes,9,opt,name=wwn,proto3,oneof" json:"wwn,omitempty"` + MgmtOnly *bool `protobuf:"varint,10,opt,name=mgmt_only,json=mgmtOnly,proto3,oneof" json:"mgmt_only,omitempty"` + Description *string `protobuf:"bytes,11,opt,name=description,proto3,oneof" json:"description,omitempty"` + MarkConnected *bool `protobuf:"varint,12,opt,name=mark_connected,json=markConnected,proto3,oneof" json:"mark_connected,omitempty"` Mode string `protobuf:"bytes,13,opt,name=mode,proto3" json:"mode,omitempty"` Tags []*Tag `protobuf:"bytes,14,rep,name=tags,proto3" json:"tags,omitempty"` } @@ -243,8 +243,8 @@ func (x *Interface) GetName() string { } func (x *Interface) GetLabel() string { - if x != nil { - return x.Label + if x != nil && x.Label != nil { + return *x.Label } return "" } @@ -257,57 +257,57 @@ func (x *Interface) GetType() string { } func (x *Interface) GetEnabled() bool { - if x != nil { - return x.Enabled + if x != nil && x.Enabled != nil { + return *x.Enabled } return false } func (x *Interface) GetMtu() int32 { - if x != nil { - return x.Mtu + if x != nil && x.Mtu != nil { + return *x.Mtu } return 0 } func (x *Interface) GetMacAddress() string { - if x != nil { - return x.MacAddress + if x != nil && x.MacAddress != nil { + return *x.MacAddress } return "" } func (x *Interface) GetSpeed() int32 { - if x != nil { - return x.Speed + if x != nil && x.Speed != nil { + return *x.Speed } return 0 } func (x *Interface) GetWwn() string { - if x != nil { - return x.Wwn + if x != nil && x.Wwn != nil { + return *x.Wwn } return "" } func (x *Interface) GetMgmtOnly() bool { - if x != nil { - return x.MgmtOnly + if x != nil && x.MgmtOnly != nil { + return *x.MgmtOnly } return false } func (x *Interface) GetDescription() string { - if x != nil { - return x.Description + if x != nil && x.Description != nil { + return *x.Description } return "" } func (x *Interface) GetMarkConnected() bool { - if x != nil { - return x.MarkConnected + if x != nil && x.MarkConnected != nil { + return *x.MarkConnected } return false } @@ -339,9 +339,9 @@ type IPAddress struct { AssignedObject isIPAddress_AssignedObject `protobuf_oneof:"assigned_object"` Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` Role string `protobuf:"bytes,4,opt,name=role,proto3" json:"role,omitempty"` - DnsName string `protobuf:"bytes,5,opt,name=dns_name,json=dnsName,proto3" json:"dns_name,omitempty"` - Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` - Comments string `protobuf:"bytes,7,opt,name=comments,proto3" json:"comments,omitempty"` + DnsName *string `protobuf:"bytes,5,opt,name=dns_name,json=dnsName,proto3,oneof" json:"dns_name,omitempty"` + Description *string `protobuf:"bytes,6,opt,name=description,proto3,oneof" json:"description,omitempty"` + Comments *string `protobuf:"bytes,7,opt,name=comments,proto3,oneof" json:"comments,omitempty"` Tags []*Tag `protobuf:"bytes,8,rep,name=tags,proto3" json:"tags,omitempty"` } @@ -413,22 +413,22 @@ func (x *IPAddress) GetRole() string { } func (x *IPAddress) GetDnsName() string { - if x != nil { - return x.DnsName + if x != nil && x.DnsName != nil { + return *x.DnsName } return "" } func (x *IPAddress) GetDescription() string { - if x != nil { - return x.Description + if x != nil && x.Description != nil { + return *x.Description } return "" } func (x *IPAddress) GetComments() string { - if x != nil { - return x.Comments + if x != nil && x.Comments != nil { + return *x.Comments } return "" } @@ -459,9 +459,9 @@ type DeviceType struct { Model string `protobuf:"bytes,1,opt,name=model,proto3" json:"model,omitempty"` Slug string `protobuf:"bytes,2,opt,name=slug,proto3" json:"slug,omitempty"` Manufacturer *Manufacturer `protobuf:"bytes,3,opt,name=manufacturer,proto3" json:"manufacturer,omitempty"` - Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` - Comments string `protobuf:"bytes,5,opt,name=comments,proto3" json:"comments,omitempty"` - PartNumber string `protobuf:"bytes,6,opt,name=part_number,json=partNumber,proto3" json:"part_number,omitempty"` + Description *string `protobuf:"bytes,4,opt,name=description,proto3,oneof" json:"description,omitempty"` + Comments *string `protobuf:"bytes,5,opt,name=comments,proto3,oneof" json:"comments,omitempty"` + PartNumber *string `protobuf:"bytes,6,opt,name=part_number,json=partNumber,proto3,oneof" json:"part_number,omitempty"` Tags []*Tag `protobuf:"bytes,7,rep,name=tags,proto3" json:"tags,omitempty"` } @@ -519,22 +519,22 @@ func (x *DeviceType) GetManufacturer() *Manufacturer { } func (x *DeviceType) GetDescription() string { - if x != nil { - return x.Description + if x != nil && x.Description != nil { + return *x.Description } return "" } func (x *DeviceType) GetComments() string { - if x != nil { - return x.Comments + if x != nil && x.Comments != nil { + return *x.Comments } return "" } func (x *DeviceType) GetPartNumber() string { - if x != nil { - return x.PartNumber + if x != nil && x.PartNumber != nil { + return *x.PartNumber } return "" } @@ -552,10 +552,10 @@ type Manufacturer struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Slug string `protobuf:"bytes,2,opt,name=slug,proto3" json:"slug,omitempty"` - Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` - Tags []*Tag `protobuf:"bytes,4,rep,name=tags,proto3" json:"tags,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Slug string `protobuf:"bytes,2,opt,name=slug,proto3" json:"slug,omitempty"` + Description *string `protobuf:"bytes,3,opt,name=description,proto3,oneof" json:"description,omitempty"` + Tags []*Tag `protobuf:"bytes,4,rep,name=tags,proto3" json:"tags,omitempty"` } func (x *Manufacturer) Reset() { @@ -605,8 +605,8 @@ func (x *Manufacturer) GetSlug() string { } func (x *Manufacturer) GetDescription() string { - if x != nil { - return x.Description + if x != nil && x.Description != nil { + return *x.Description } return "" } @@ -627,7 +627,7 @@ type Platform struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` Slug string `protobuf:"bytes,2,opt,name=slug,proto3" json:"slug,omitempty"` Manufacturer *Manufacturer `protobuf:"bytes,3,opt,name=manufacturer,proto3" json:"manufacturer,omitempty"` - Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` + Description *string `protobuf:"bytes,4,opt,name=description,proto3,oneof" json:"description,omitempty"` Tags []*Tag `protobuf:"bytes,5,rep,name=tags,proto3" json:"tags,omitempty"` } @@ -685,8 +685,8 @@ func (x *Platform) GetManufacturer() *Manufacturer { } func (x *Platform) GetDescription() string { - if x != nil { - return x.Description + if x != nil && x.Description != nil { + return *x.Description } return "" } @@ -704,14 +704,14 @@ type Prefix struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Prefix string `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"` - Site *Site `protobuf:"bytes,2,opt,name=site,proto3" json:"site,omitempty"` - Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` - IsPool bool `protobuf:"varint,4,opt,name=is_pool,json=isPool,proto3" json:"is_pool,omitempty"` - MarkUtilized bool `protobuf:"varint,5,opt,name=mark_utilized,json=markUtilized,proto3" json:"mark_utilized,omitempty"` - Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` - Comments string `protobuf:"bytes,7,opt,name=comments,proto3" json:"comments,omitempty"` - Tags []*Tag `protobuf:"bytes,8,rep,name=tags,proto3" json:"tags,omitempty"` + Prefix string `protobuf:"bytes,1,opt,name=prefix,proto3" json:"prefix,omitempty"` + Site *Site `protobuf:"bytes,2,opt,name=site,proto3" json:"site,omitempty"` + Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` + IsPool *bool `protobuf:"varint,4,opt,name=is_pool,json=isPool,proto3,oneof" json:"is_pool,omitempty"` + MarkUtilized *bool `protobuf:"varint,5,opt,name=mark_utilized,json=markUtilized,proto3,oneof" json:"mark_utilized,omitempty"` + Description *string `protobuf:"bytes,6,opt,name=description,proto3,oneof" json:"description,omitempty"` + Comments *string `protobuf:"bytes,7,opt,name=comments,proto3,oneof" json:"comments,omitempty"` + Tags []*Tag `protobuf:"bytes,8,rep,name=tags,proto3" json:"tags,omitempty"` } func (x *Prefix) Reset() { @@ -768,29 +768,29 @@ func (x *Prefix) GetStatus() string { } func (x *Prefix) GetIsPool() bool { - if x != nil { - return x.IsPool + if x != nil && x.IsPool != nil { + return *x.IsPool } return false } func (x *Prefix) GetMarkUtilized() bool { - if x != nil { - return x.MarkUtilized + if x != nil && x.MarkUtilized != nil { + return *x.MarkUtilized } return false } func (x *Prefix) GetDescription() string { - if x != nil { - return x.Description + if x != nil && x.Description != nil { + return *x.Description } return "" } func (x *Prefix) GetComments() string { - if x != nil { - return x.Comments + if x != nil && x.Comments != nil { + return *x.Comments } return "" } @@ -808,11 +808,11 @@ type Role struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Slug string `protobuf:"bytes,2,opt,name=slug,proto3" json:"slug,omitempty"` - Color string `protobuf:"bytes,3,opt,name=color,proto3" json:"color,omitempty"` - Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` - Tags []*Tag `protobuf:"bytes,5,rep,name=tags,proto3" json:"tags,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Slug string `protobuf:"bytes,2,opt,name=slug,proto3" json:"slug,omitempty"` + Color string `protobuf:"bytes,3,opt,name=color,proto3" json:"color,omitempty"` + Description *string `protobuf:"bytes,4,opt,name=description,proto3,oneof" json:"description,omitempty"` + Tags []*Tag `protobuf:"bytes,5,rep,name=tags,proto3" json:"tags,omitempty"` } func (x *Role) Reset() { @@ -869,8 +869,8 @@ func (x *Role) GetColor() string { } func (x *Role) GetDescription() string { - if x != nil { - return x.Description + if x != nil && x.Description != nil { + return *x.Description } return "" } @@ -888,14 +888,14 @@ type Site struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Slug string `protobuf:"bytes,2,opt,name=slug,proto3" json:"slug,omitempty"` - Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` - Facility string `protobuf:"bytes,4,opt,name=facility,proto3" json:"facility,omitempty"` - TimeZone string `protobuf:"bytes,5,opt,name=time_zone,json=timeZone,proto3" json:"time_zone,omitempty"` - Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` - Comments string `protobuf:"bytes,7,opt,name=comments,proto3" json:"comments,omitempty"` - Tags []*Tag `protobuf:"bytes,8,rep,name=tags,proto3" json:"tags,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Slug string `protobuf:"bytes,2,opt,name=slug,proto3" json:"slug,omitempty"` + Status string `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` + Facility *string `protobuf:"bytes,4,opt,name=facility,proto3,oneof" json:"facility,omitempty"` + TimeZone *string `protobuf:"bytes,5,opt,name=time_zone,json=timeZone,proto3,oneof" json:"time_zone,omitempty"` + Description *string `protobuf:"bytes,6,opt,name=description,proto3,oneof" json:"description,omitempty"` + Comments *string `protobuf:"bytes,7,opt,name=comments,proto3,oneof" json:"comments,omitempty"` + Tags []*Tag `protobuf:"bytes,8,rep,name=tags,proto3" json:"tags,omitempty"` } func (x *Site) Reset() { @@ -952,29 +952,29 @@ func (x *Site) GetStatus() string { } func (x *Site) GetFacility() string { - if x != nil { - return x.Facility + if x != nil && x.Facility != nil { + return *x.Facility } return "" } func (x *Site) GetTimeZone() string { - if x != nil { - return x.TimeZone + if x != nil && x.TimeZone != nil { + return *x.TimeZone } return "" } func (x *Site) GetDescription() string { - if x != nil { - return x.Description + if x != nil && x.Description != nil { + return *x.Description } return "" } func (x *Site) GetComments() string { - if x != nil { - return x.Comments + if x != nil && x.Comments != nil { + return *x.Comments } return "" } @@ -1391,289 +1391,321 @@ var file_diode_v1_ingester_proto_rawDesc = []byte{ 0x2e, 0x76, 0x31, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x85, 0x05, + 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe4, 0x05, 0x0a, 0x06, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1b, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x40, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x66, 0x71, 0x64, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, - 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x46, 0x71, - 0x64, 0x6e, 0x12, 0x35, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0a, 0x64, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, 0x0a, 0x04, 0x72, 0x6f, 0x6c, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x2e, 0x0a, - 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x12, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, - 0x6f, 0x72, 0x6d, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1f, 0x0a, - 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x12, 0x22, - 0x0a, 0x04, 0x73, 0x69, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, - 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x74, 0x65, 0x52, 0x04, 0x73, 0x69, - 0x74, 0x65, 0x12, 0x25, 0x0a, 0x09, 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, - 0x08, 0x61, 0x73, 0x73, 0x65, 0x74, 0x54, 0x61, 0x67, 0x12, 0x63, 0x0a, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x4b, 0xfa, 0x42, 0x48, 0x72, 0x46, - 0x52, 0x07, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, - 0x65, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x67, - 0x65, 0x64, 0x52, 0x06, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x52, 0x09, 0x69, 0x6e, 0x76, 0x65, - 0x6e, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x0f, 0x64, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, - 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2a, - 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0b, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, - 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, - 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x0c, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x12, 0x34, 0x0a, 0x0b, 0x70, 0x72, 0x69, - 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x70, 0x34, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, - 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x50, 0x41, 0x64, 0x64, 0x72, - 0x65, 0x73, 0x73, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x49, 0x70, 0x34, 0x12, - 0x34, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x70, 0x36, 0x18, 0x0e, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x49, 0x50, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, - 0x72, 0x79, 0x49, 0x70, 0x36, 0x22, 0xd1, 0x10, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, - 0x61, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0xa2, 0x01, 0x02, 0x08, 0x01, 0x52, - 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x40, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x40, - 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x12, 0xfa, 0x0c, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0xe5, 0x0c, 0xfa, 0x42, 0xe1, 0x0c, 0x72, 0xde, 0x0c, - 0x52, 0x07, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x52, 0x06, 0x62, 0x72, 0x69, 0x64, 0x67, - 0x65, 0x52, 0x03, 0x6c, 0x61, 0x67, 0x52, 0x0a, 0x31, 0x30, 0x30, 0x62, 0x61, 0x73, 0x65, 0x2d, - 0x66, 0x78, 0x52, 0x0b, 0x31, 0x30, 0x30, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x6c, 0x66, 0x78, 0x52, - 0x0a, 0x31, 0x30, 0x30, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x74, 0x78, 0x52, 0x0a, 0x31, 0x30, 0x30, - 0x62, 0x61, 0x73, 0x65, 0x2d, 0x74, 0x31, 0x52, 0x0a, 0x31, 0x30, 0x30, 0x30, 0x62, 0x61, 0x73, - 0x65, 0x2d, 0x74, 0x52, 0x0f, 0x31, 0x30, 0x30, 0x30, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, - 0x67, 0x62, 0x69, 0x63, 0x52, 0x0e, 0x31, 0x30, 0x30, 0x30, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, - 0x2d, 0x73, 0x66, 0x70, 0x52, 0x0a, 0x32, 0x2e, 0x35, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x74, - 0x52, 0x08, 0x35, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x74, 0x52, 0x09, 0x31, 0x30, 0x67, 0x62, - 0x61, 0x73, 0x65, 0x2d, 0x74, 0x52, 0x0b, 0x31, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x63, - 0x78, 0x34, 0x52, 0x0e, 0x31, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x73, 0x66, - 0x70, 0x70, 0x52, 0x0d, 0x31, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x78, 0x66, - 0x70, 0x52, 0x10, 0x31, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x78, 0x65, 0x6e, - 0x70, 0x61, 0x6b, 0x52, 0x0c, 0x31, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x78, - 0x32, 0x52, 0x0f, 0x32, 0x35, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x73, 0x66, 0x70, - 0x32, 0x38, 0x52, 0x0f, 0x35, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x73, 0x66, - 0x70, 0x35, 0x36, 0x52, 0x0f, 0x34, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, - 0x73, 0x66, 0x70, 0x70, 0x52, 0x0f, 0x35, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, - 0x73, 0x66, 0x70, 0x32, 0x38, 0x52, 0x0e, 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, - 0x78, 0x2d, 0x63, 0x66, 0x70, 0x52, 0x0f, 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, - 0x78, 0x2d, 0x63, 0x66, 0x70, 0x32, 0x52, 0x0f, 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, - 0x2d, 0x78, 0x2d, 0x63, 0x66, 0x70, 0x34, 0x52, 0x0e, 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, - 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x78, 0x70, 0x52, 0x0f, 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, - 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x70, 0x61, 0x6b, 0x52, 0x0f, 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, - 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x64, 0x73, 0x66, 0x70, 0x52, 0x10, 0x31, 0x30, 0x30, 0x67, 0x62, - 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x73, 0x66, 0x70, 0x64, 0x64, 0x52, 0x11, 0x31, 0x30, 0x30, - 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x32, 0x38, 0x52, 0x11, - 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x64, - 0x64, 0x52, 0x0f, 0x32, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x66, - 0x70, 0x32, 0x52, 0x11, 0x32, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, - 0x73, 0x66, 0x70, 0x35, 0x36, 0x52, 0x11, 0x32, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, - 0x78, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x64, 0x64, 0x52, 0x0f, 0x34, 0x30, 0x30, 0x67, 0x62, 0x61, - 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x66, 0x70, 0x32, 0x52, 0x12, 0x34, 0x30, 0x30, 0x67, 0x62, - 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x31, 0x31, 0x32, 0x52, 0x11, 0x34, - 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x64, 0x64, - 0x52, 0x0f, 0x34, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x6f, 0x73, 0x66, - 0x70, 0x52, 0x13, 0x34, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x6f, 0x73, - 0x66, 0x70, 0x2d, 0x72, 0x68, 0x73, 0x52, 0x0f, 0x34, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, - 0x2d, 0x78, 0x2d, 0x63, 0x64, 0x66, 0x70, 0x52, 0x0f, 0x34, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, - 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x66, 0x70, 0x38, 0x52, 0x11, 0x38, 0x30, 0x30, 0x67, 0x62, 0x61, - 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x64, 0x64, 0x52, 0x0f, 0x38, 0x30, 0x30, - 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x6f, 0x73, 0x66, 0x70, 0x52, 0x0b, 0x31, 0x30, - 0x30, 0x30, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x6b, 0x78, 0x52, 0x0a, 0x31, 0x30, 0x67, 0x62, 0x61, - 0x73, 0x65, 0x2d, 0x6b, 0x72, 0x52, 0x0b, 0x31, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x6b, - 0x78, 0x34, 0x52, 0x0a, 0x32, 0x35, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x6b, 0x72, 0x52, 0x0b, - 0x34, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x6b, 0x72, 0x34, 0x52, 0x0a, 0x35, 0x30, 0x67, - 0x62, 0x61, 0x73, 0x65, 0x2d, 0x6b, 0x72, 0x52, 0x0c, 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, - 0x65, 0x2d, 0x6b, 0x70, 0x34, 0x52, 0x0c, 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, - 0x6b, 0x72, 0x32, 0x52, 0x0c, 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x6b, 0x72, - 0x34, 0x52, 0x0b, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x2e, 0x31, 0x31, 0x61, 0x52, 0x0b, - 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x2e, 0x31, 0x31, 0x67, 0x52, 0x0b, 0x69, 0x65, 0x65, - 0x65, 0x38, 0x30, 0x32, 0x2e, 0x31, 0x31, 0x6e, 0x52, 0x0c, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, - 0x32, 0x2e, 0x31, 0x31, 0x61, 0x63, 0x52, 0x0c, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x2e, - 0x31, 0x31, 0x61, 0x64, 0x52, 0x0c, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x2e, 0x31, 0x31, - 0x61, 0x78, 0x52, 0x0c, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x2e, 0x31, 0x31, 0x61, 0x79, - 0x52, 0x0c, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x2e, 0x31, 0x35, 0x2e, 0x31, 0x52, 0x0e, - 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2d, 0x77, 0x69, 0x72, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x52, 0x03, - 0x67, 0x73, 0x6d, 0x52, 0x04, 0x63, 0x64, 0x6d, 0x61, 0x52, 0x03, 0x6c, 0x74, 0x65, 0x52, 0x09, - 0x73, 0x6f, 0x6e, 0x65, 0x74, 0x2d, 0x6f, 0x63, 0x33, 0x52, 0x0a, 0x73, 0x6f, 0x6e, 0x65, 0x74, - 0x2d, 0x6f, 0x63, 0x31, 0x32, 0x52, 0x0a, 0x73, 0x6f, 0x6e, 0x65, 0x74, 0x2d, 0x6f, 0x63, 0x34, - 0x38, 0x52, 0x0b, 0x73, 0x6f, 0x6e, 0x65, 0x74, 0x2d, 0x6f, 0x63, 0x31, 0x39, 0x32, 0x52, 0x0b, - 0x73, 0x6f, 0x6e, 0x65, 0x74, 0x2d, 0x6f, 0x63, 0x37, 0x36, 0x38, 0x52, 0x0c, 0x73, 0x6f, 0x6e, - 0x65, 0x74, 0x2d, 0x6f, 0x63, 0x31, 0x39, 0x32, 0x30, 0x52, 0x0c, 0x73, 0x6f, 0x6e, 0x65, 0x74, - 0x2d, 0x6f, 0x63, 0x33, 0x38, 0x34, 0x30, 0x52, 0x08, 0x31, 0x67, 0x66, 0x63, 0x2d, 0x73, 0x66, - 0x70, 0x52, 0x08, 0x32, 0x67, 0x66, 0x63, 0x2d, 0x73, 0x66, 0x70, 0x52, 0x08, 0x34, 0x67, 0x66, - 0x63, 0x2d, 0x73, 0x66, 0x70, 0x52, 0x09, 0x38, 0x67, 0x66, 0x63, 0x2d, 0x73, 0x66, 0x70, 0x70, - 0x52, 0x0a, 0x31, 0x36, 0x67, 0x66, 0x63, 0x2d, 0x73, 0x66, 0x70, 0x70, 0x52, 0x0b, 0x33, 0x32, - 0x67, 0x66, 0x63, 0x2d, 0x73, 0x66, 0x70, 0x32, 0x38, 0x52, 0x0b, 0x36, 0x34, 0x67, 0x66, 0x63, - 0x2d, 0x71, 0x73, 0x66, 0x70, 0x70, 0x52, 0x0d, 0x31, 0x32, 0x38, 0x67, 0x66, 0x63, 0x2d, 0x71, - 0x73, 0x66, 0x70, 0x32, 0x38, 0x52, 0x0e, 0x69, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x62, 0x61, 0x6e, - 0x64, 0x2d, 0x73, 0x64, 0x72, 0x52, 0x0e, 0x69, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x62, 0x61, 0x6e, - 0x64, 0x2d, 0x64, 0x64, 0x72, 0x52, 0x0e, 0x69, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x62, 0x61, 0x6e, - 0x64, 0x2d, 0x71, 0x64, 0x72, 0x52, 0x10, 0x69, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x62, 0x61, 0x6e, - 0x64, 0x2d, 0x66, 0x64, 0x72, 0x31, 0x30, 0x52, 0x0e, 0x69, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x62, - 0x61, 0x6e, 0x64, 0x2d, 0x66, 0x64, 0x72, 0x52, 0x0e, 0x69, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x62, - 0x61, 0x6e, 0x64, 0x2d, 0x65, 0x64, 0x72, 0x52, 0x0e, 0x69, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x62, - 0x61, 0x6e, 0x64, 0x2d, 0x68, 0x64, 0x72, 0x52, 0x0e, 0x69, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x62, - 0x61, 0x6e, 0x64, 0x2d, 0x6e, 0x64, 0x72, 0x52, 0x0e, 0x69, 0x6e, 0x66, 0x69, 0x6e, 0x69, 0x62, - 0x61, 0x6e, 0x64, 0x2d, 0x78, 0x64, 0x72, 0x52, 0x02, 0x74, 0x31, 0x52, 0x02, 0x65, 0x31, 0x52, - 0x02, 0x74, 0x33, 0x52, 0x02, 0x65, 0x33, 0x52, 0x04, 0x78, 0x64, 0x73, 0x6c, 0x52, 0x06, 0x64, - 0x6f, 0x63, 0x73, 0x69, 0x73, 0x52, 0x04, 0x67, 0x70, 0x6f, 0x6e, 0x52, 0x06, 0x78, 0x67, 0x2d, - 0x70, 0x6f, 0x6e, 0x52, 0x07, 0x78, 0x67, 0x73, 0x2d, 0x70, 0x6f, 0x6e, 0x52, 0x07, 0x6e, 0x67, - 0x2d, 0x70, 0x6f, 0x6e, 0x32, 0x52, 0x04, 0x65, 0x70, 0x6f, 0x6e, 0x52, 0x08, 0x31, 0x30, 0x67, - 0x2d, 0x65, 0x70, 0x6f, 0x6e, 0x52, 0x0f, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2d, 0x73, 0x74, 0x61, - 0x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x52, 0x14, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2d, 0x73, 0x74, - 0x61, 0x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x2d, 0x70, 0x6c, 0x75, 0x73, 0x52, 0x0f, 0x63, 0x69, - 0x73, 0x63, 0x6f, 0x2d, 0x66, 0x6c, 0x65, 0x78, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x52, 0x14, 0x63, - 0x69, 0x73, 0x63, 0x6f, 0x2d, 0x66, 0x6c, 0x65, 0x78, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2d, 0x70, - 0x6c, 0x75, 0x73, 0x52, 0x12, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, - 0x77, 0x69, 0x73, 0x65, 0x2d, 0x38, 0x30, 0x52, 0x13, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2d, 0x73, - 0x74, 0x61, 0x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x2d, 0x31, 0x36, 0x30, 0x52, 0x13, 0x63, 0x69, - 0x73, 0x63, 0x6f, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x2d, 0x33, 0x32, - 0x30, 0x52, 0x13, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x77, 0x69, - 0x73, 0x65, 0x2d, 0x34, 0x38, 0x30, 0x52, 0x12, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2d, 0x73, 0x74, - 0x61, 0x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x2d, 0x31, 0x74, 0x52, 0x0b, 0x6a, 0x75, 0x6e, 0x69, - 0x70, 0x65, 0x72, 0x2d, 0x76, 0x63, 0x70, 0x52, 0x13, 0x65, 0x78, 0x74, 0x72, 0x65, 0x6d, 0x65, - 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x52, 0x17, 0x65, 0x78, - 0x74, 0x72, 0x65, 0x6d, 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x74, 0x61, 0x63, - 0x6b, 0x2d, 0x31, 0x32, 0x38, 0x52, 0x17, 0x65, 0x78, 0x74, 0x72, 0x65, 0x6d, 0x65, 0x2d, 0x73, - 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2d, 0x32, 0x35, 0x36, 0x52, 0x17, - 0x65, 0x78, 0x74, 0x72, 0x65, 0x6d, 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x74, - 0x61, 0x63, 0x6b, 0x2d, 0x35, 0x31, 0x32, 0x52, 0x05, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x52, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1d, - 0x0a, 0x03, 0x6d, 0x74, 0x75, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x42, 0x0b, 0xfa, 0x42, 0x08, - 0x1a, 0x06, 0x18, 0x80, 0x80, 0x04, 0x28, 0x01, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x12, 0x1f, 0x0a, - 0x0b, 0x6d, 0x61, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x1d, - 0x0a, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x42, 0x07, 0xfa, - 0x42, 0x04, 0x1a, 0x02, 0x28, 0x00, 0x52, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x12, 0x10, 0x0a, - 0x03, 0x77, 0x77, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x77, 0x77, 0x6e, 0x12, - 0x1b, 0x0a, 0x09, 0x6d, 0x67, 0x6d, 0x74, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x08, 0x6d, 0x67, 0x6d, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x12, 0x2a, 0x0a, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x61, 0x72, 0x6b, - 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, - 0x52, 0x0d, 0x6d, 0x61, 0x72, 0x6b, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x12, - 0x35, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xfa, - 0x42, 0x1e, 0x72, 0x1c, 0x52, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x06, 0x74, 0x61, - 0x67, 0x67, 0x65, 0x64, 0x52, 0x0a, 0x74, 0x61, 0x67, 0x67, 0x65, 0x64, 0x2d, 0x61, 0x6c, 0x6c, - 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x0e, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0xd3, 0x03, 0x0a, 0x09, 0x49, 0x50, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x21, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, - 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x70, - 0x01, 0x52, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x33, 0x0a, 0x09, 0x69, 0x6e, - 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, - 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, - 0x63, 0x65, 0x48, 0x00, 0x52, 0x09, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, - 0x48, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x30, 0xfa, 0x42, 0x2d, 0x72, 0x2b, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x08, - 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, - 0x61, 0x74, 0x65, 0x64, 0x52, 0x04, 0x64, 0x68, 0x63, 0x70, 0x52, 0x05, 0x73, 0x6c, 0x61, 0x61, - 0x63, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x54, 0x0a, 0x04, 0x72, 0x6f, 0x6c, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x40, 0xfa, 0x42, 0x3d, 0x72, 0x3b, 0x52, 0x08, - 0x6c, 0x6f, 0x6f, 0x70, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, - 0x61, 0x72, 0x79, 0x52, 0x07, 0x61, 0x6e, 0x79, 0x63, 0x61, 0x73, 0x74, 0x52, 0x03, 0x76, 0x69, - 0x70, 0x52, 0x04, 0x76, 0x72, 0x72, 0x70, 0x52, 0x04, 0x68, 0x73, 0x72, 0x70, 0x52, 0x04, 0x67, - 0x6c, 0x62, 0x70, 0x52, 0x04, 0x63, 0x61, 0x72, 0x70, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, - 0x50, 0x0a, 0x08, 0x64, 0x6e, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x35, 0xfa, 0x42, 0x32, 0x72, 0x30, 0x18, 0xff, 0x01, 0x32, 0x2b, 0x5e, 0x28, 0x5b, - 0x30, 0x2d, 0x39, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x5f, 0x2d, 0x5d, 0x2b, 0x7c, 0x5c, 0x2a, - 0x29, 0x28, 0x5c, 0x2e, 0x5b, 0x30, 0x2d, 0x39, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x5f, 0x2d, - 0x5d, 0x2b, 0x29, 0x2a, 0x5c, 0x2e, 0x3f, 0x24, 0x52, 0x07, 0x64, 0x6e, 0x73, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, - 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, - 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, - 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x42, 0x11, 0x0a, 0x0f, - 0x61, 0x73, 0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, - 0xaf, 0x02, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, - 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, - 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x64, 0x52, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, - 0x2f, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1b, 0xfa, - 0x42, 0x18, 0x72, 0x16, 0x10, 0x01, 0x18, 0x64, 0x32, 0x10, 0x5e, 0x5b, 0x2d, 0x61, 0x2d, 0x7a, - 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5f, 0x5d, 0x2b, 0x24, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, - 0x12, 0x3a, 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x4d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x52, 0x0c, - 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x6d, - 0x65, 0x6e, 0x74, 0x73, 0x12, 0x28, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x5f, 0x6e, 0x75, 0x6d, + 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x46, 0x71, 0x64, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x35, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x64, + 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x22, + 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, + 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x04, 0x72, 0x6f, + 0x6c, 0x65, 0x12, 0x2e, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x12, 0x24, 0x0a, 0x06, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x48, 0x01, 0x52, 0x06, 0x73, + 0x65, 0x72, 0x69, 0x61, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x04, 0x73, 0x69, 0x74, 0x65, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x69, 0x74, 0x65, 0x52, 0x04, 0x73, 0x69, 0x74, 0x65, 0x12, 0x2a, 0x0a, 0x09, + 0x61, 0x73, 0x73, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x48, 0x02, 0x52, 0x08, 0x61, 0x73, 0x73, + 0x65, 0x74, 0x54, 0x61, 0x67, 0x88, 0x01, 0x01, 0x12, 0x63, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x42, 0x4b, 0xfa, 0x42, 0x48, 0x72, 0x46, 0x52, + 0x07, 0x6f, 0x66, 0x66, 0x6c, 0x69, 0x6e, 0x65, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, + 0x52, 0x07, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x67, 0x65, + 0x64, 0x52, 0x06, 0x66, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x52, 0x09, 0x69, 0x6e, 0x76, 0x65, 0x6e, + 0x74, 0x6f, 0x72, 0x79, 0x52, 0x0f, 0x64, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2f, 0x0a, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x48, 0x03, 0x52, 0x0b, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x1f, + 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x04, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, + 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, + 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, + 0x67, 0x73, 0x12, 0x34, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x69, 0x70, + 0x34, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x49, 0x50, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x52, 0x0a, 0x70, 0x72, + 0x69, 0x6d, 0x61, 0x72, 0x79, 0x49, 0x70, 0x34, 0x12, 0x34, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x5f, 0x69, 0x70, 0x36, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x50, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x49, 0x70, 0x36, 0x42, 0x0e, + 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x66, 0x71, 0x64, 0x6e, 0x42, 0x09, + 0x0a, 0x07, 0x5f, 0x73, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x61, 0x73, + 0x73, 0x65, 0x74, 0x5f, 0x74, 0x61, 0x67, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x22, 0xef, 0x11, 0x0a, 0x09, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, + 0x63, 0x65, 0x12, 0x32, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0xa2, 0x01, 0x02, 0x08, 0x01, 0x52, 0x06, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x40, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x24, 0x0a, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x40, 0x48, + 0x00, 0x52, 0x05, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x88, 0x01, 0x01, 0x12, 0xfa, 0x0c, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0xe5, 0x0c, 0xfa, 0x42, 0xe1, + 0x0c, 0x72, 0xde, 0x0c, 0x52, 0x07, 0x76, 0x69, 0x72, 0x74, 0x75, 0x61, 0x6c, 0x52, 0x06, 0x62, + 0x72, 0x69, 0x64, 0x67, 0x65, 0x52, 0x03, 0x6c, 0x61, 0x67, 0x52, 0x0a, 0x31, 0x30, 0x30, 0x62, + 0x61, 0x73, 0x65, 0x2d, 0x66, 0x78, 0x52, 0x0b, 0x31, 0x30, 0x30, 0x62, 0x61, 0x73, 0x65, 0x2d, + 0x6c, 0x66, 0x78, 0x52, 0x0a, 0x31, 0x30, 0x30, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x74, 0x78, 0x52, + 0x0a, 0x31, 0x30, 0x30, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x74, 0x31, 0x52, 0x0a, 0x31, 0x30, 0x30, + 0x30, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x74, 0x52, 0x0f, 0x31, 0x30, 0x30, 0x30, 0x62, 0x61, 0x73, + 0x65, 0x2d, 0x78, 0x2d, 0x67, 0x62, 0x69, 0x63, 0x52, 0x0e, 0x31, 0x30, 0x30, 0x30, 0x62, 0x61, + 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x73, 0x66, 0x70, 0x52, 0x0a, 0x32, 0x2e, 0x35, 0x67, 0x62, 0x61, + 0x73, 0x65, 0x2d, 0x74, 0x52, 0x08, 0x35, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x74, 0x52, 0x09, + 0x31, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x74, 0x52, 0x0b, 0x31, 0x30, 0x67, 0x62, 0x61, + 0x73, 0x65, 0x2d, 0x63, 0x78, 0x34, 0x52, 0x0e, 0x31, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, + 0x78, 0x2d, 0x73, 0x66, 0x70, 0x70, 0x52, 0x0d, 0x31, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, + 0x78, 0x2d, 0x78, 0x66, 0x70, 0x52, 0x10, 0x31, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, + 0x2d, 0x78, 0x65, 0x6e, 0x70, 0x61, 0x6b, 0x52, 0x0c, 0x31, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, + 0x2d, 0x78, 0x2d, 0x78, 0x32, 0x52, 0x0f, 0x32, 0x35, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, + 0x2d, 0x73, 0x66, 0x70, 0x32, 0x38, 0x52, 0x0f, 0x35, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, + 0x78, 0x2d, 0x73, 0x66, 0x70, 0x35, 0x36, 0x52, 0x0f, 0x34, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, + 0x2d, 0x78, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x70, 0x52, 0x0f, 0x35, 0x30, 0x67, 0x62, 0x61, 0x73, + 0x65, 0x2d, 0x78, 0x2d, 0x73, 0x66, 0x70, 0x32, 0x38, 0x52, 0x0e, 0x31, 0x30, 0x30, 0x67, 0x62, + 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x66, 0x70, 0x52, 0x0f, 0x31, 0x30, 0x30, 0x67, 0x62, + 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x66, 0x70, 0x32, 0x52, 0x0f, 0x31, 0x30, 0x30, 0x67, + 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x66, 0x70, 0x34, 0x52, 0x0e, 0x31, 0x30, 0x30, + 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x78, 0x70, 0x52, 0x0f, 0x31, 0x30, 0x30, + 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x70, 0x61, 0x6b, 0x52, 0x0f, 0x31, 0x30, + 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x64, 0x73, 0x66, 0x70, 0x52, 0x10, 0x31, + 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x73, 0x66, 0x70, 0x64, 0x64, 0x52, + 0x11, 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, 0x73, 0x66, 0x70, + 0x32, 0x38, 0x52, 0x11, 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, + 0x73, 0x66, 0x70, 0x64, 0x64, 0x52, 0x0f, 0x32, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, + 0x78, 0x2d, 0x63, 0x66, 0x70, 0x32, 0x52, 0x11, 0x32, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, + 0x2d, 0x78, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x35, 0x36, 0x52, 0x11, 0x32, 0x30, 0x30, 0x67, 0x62, + 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x64, 0x64, 0x52, 0x0f, 0x34, 0x30, + 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x66, 0x70, 0x32, 0x52, 0x12, 0x34, + 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x31, 0x31, + 0x32, 0x52, 0x11, 0x34, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, 0x73, + 0x66, 0x70, 0x64, 0x64, 0x52, 0x0f, 0x34, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, + 0x2d, 0x6f, 0x73, 0x66, 0x70, 0x52, 0x13, 0x34, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, + 0x78, 0x2d, 0x6f, 0x73, 0x66, 0x70, 0x2d, 0x72, 0x68, 0x73, 0x52, 0x0f, 0x34, 0x30, 0x30, 0x67, + 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x64, 0x66, 0x70, 0x52, 0x0f, 0x34, 0x30, 0x30, + 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x63, 0x66, 0x70, 0x38, 0x52, 0x11, 0x38, 0x30, + 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x64, 0x64, 0x52, + 0x0f, 0x38, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x78, 0x2d, 0x6f, 0x73, 0x66, 0x70, + 0x52, 0x0b, 0x31, 0x30, 0x30, 0x30, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x6b, 0x78, 0x52, 0x0a, 0x31, + 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x6b, 0x72, 0x52, 0x0b, 0x31, 0x30, 0x67, 0x62, 0x61, + 0x73, 0x65, 0x2d, 0x6b, 0x78, 0x34, 0x52, 0x0a, 0x32, 0x35, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, + 0x6b, 0x72, 0x52, 0x0b, 0x34, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x6b, 0x72, 0x34, 0x52, + 0x0a, 0x35, 0x30, 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x6b, 0x72, 0x52, 0x0c, 0x31, 0x30, 0x30, + 0x67, 0x62, 0x61, 0x73, 0x65, 0x2d, 0x6b, 0x70, 0x34, 0x52, 0x0c, 0x31, 0x30, 0x30, 0x67, 0x62, + 0x61, 0x73, 0x65, 0x2d, 0x6b, 0x72, 0x32, 0x52, 0x0c, 0x31, 0x30, 0x30, 0x67, 0x62, 0x61, 0x73, + 0x65, 0x2d, 0x6b, 0x72, 0x34, 0x52, 0x0b, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x2e, 0x31, + 0x31, 0x61, 0x52, 0x0b, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x2e, 0x31, 0x31, 0x67, 0x52, + 0x0b, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x2e, 0x31, 0x31, 0x6e, 0x52, 0x0c, 0x69, 0x65, + 0x65, 0x65, 0x38, 0x30, 0x32, 0x2e, 0x31, 0x31, 0x61, 0x63, 0x52, 0x0c, 0x69, 0x65, 0x65, 0x65, + 0x38, 0x30, 0x32, 0x2e, 0x31, 0x31, 0x61, 0x64, 0x52, 0x0c, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, + 0x32, 0x2e, 0x31, 0x31, 0x61, 0x78, 0x52, 0x0c, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x2e, + 0x31, 0x31, 0x61, 0x79, 0x52, 0x0c, 0x69, 0x65, 0x65, 0x65, 0x38, 0x30, 0x32, 0x2e, 0x31, 0x35, + 0x2e, 0x31, 0x52, 0x0e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2d, 0x77, 0x69, 0x72, 0x65, 0x6c, 0x65, + 0x73, 0x73, 0x52, 0x03, 0x67, 0x73, 0x6d, 0x52, 0x04, 0x63, 0x64, 0x6d, 0x61, 0x52, 0x03, 0x6c, + 0x74, 0x65, 0x52, 0x09, 0x73, 0x6f, 0x6e, 0x65, 0x74, 0x2d, 0x6f, 0x63, 0x33, 0x52, 0x0a, 0x73, + 0x6f, 0x6e, 0x65, 0x74, 0x2d, 0x6f, 0x63, 0x31, 0x32, 0x52, 0x0a, 0x73, 0x6f, 0x6e, 0x65, 0x74, + 0x2d, 0x6f, 0x63, 0x34, 0x38, 0x52, 0x0b, 0x73, 0x6f, 0x6e, 0x65, 0x74, 0x2d, 0x6f, 0x63, 0x31, + 0x39, 0x32, 0x52, 0x0b, 0x73, 0x6f, 0x6e, 0x65, 0x74, 0x2d, 0x6f, 0x63, 0x37, 0x36, 0x38, 0x52, + 0x0c, 0x73, 0x6f, 0x6e, 0x65, 0x74, 0x2d, 0x6f, 0x63, 0x31, 0x39, 0x32, 0x30, 0x52, 0x0c, 0x73, + 0x6f, 0x6e, 0x65, 0x74, 0x2d, 0x6f, 0x63, 0x33, 0x38, 0x34, 0x30, 0x52, 0x08, 0x31, 0x67, 0x66, + 0x63, 0x2d, 0x73, 0x66, 0x70, 0x52, 0x08, 0x32, 0x67, 0x66, 0x63, 0x2d, 0x73, 0x66, 0x70, 0x52, + 0x08, 0x34, 0x67, 0x66, 0x63, 0x2d, 0x73, 0x66, 0x70, 0x52, 0x09, 0x38, 0x67, 0x66, 0x63, 0x2d, + 0x73, 0x66, 0x70, 0x70, 0x52, 0x0a, 0x31, 0x36, 0x67, 0x66, 0x63, 0x2d, 0x73, 0x66, 0x70, 0x70, + 0x52, 0x0b, 0x33, 0x32, 0x67, 0x66, 0x63, 0x2d, 0x73, 0x66, 0x70, 0x32, 0x38, 0x52, 0x0b, 0x36, + 0x34, 0x67, 0x66, 0x63, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x70, 0x52, 0x0d, 0x31, 0x32, 0x38, 0x67, + 0x66, 0x63, 0x2d, 0x71, 0x73, 0x66, 0x70, 0x32, 0x38, 0x52, 0x0e, 0x69, 0x6e, 0x66, 0x69, 0x6e, + 0x69, 0x62, 0x61, 0x6e, 0x64, 0x2d, 0x73, 0x64, 0x72, 0x52, 0x0e, 0x69, 0x6e, 0x66, 0x69, 0x6e, + 0x69, 0x62, 0x61, 0x6e, 0x64, 0x2d, 0x64, 0x64, 0x72, 0x52, 0x0e, 0x69, 0x6e, 0x66, 0x69, 0x6e, + 0x69, 0x62, 0x61, 0x6e, 0x64, 0x2d, 0x71, 0x64, 0x72, 0x52, 0x10, 0x69, 0x6e, 0x66, 0x69, 0x6e, + 0x69, 0x62, 0x61, 0x6e, 0x64, 0x2d, 0x66, 0x64, 0x72, 0x31, 0x30, 0x52, 0x0e, 0x69, 0x6e, 0x66, + 0x69, 0x6e, 0x69, 0x62, 0x61, 0x6e, 0x64, 0x2d, 0x66, 0x64, 0x72, 0x52, 0x0e, 0x69, 0x6e, 0x66, + 0x69, 0x6e, 0x69, 0x62, 0x61, 0x6e, 0x64, 0x2d, 0x65, 0x64, 0x72, 0x52, 0x0e, 0x69, 0x6e, 0x66, + 0x69, 0x6e, 0x69, 0x62, 0x61, 0x6e, 0x64, 0x2d, 0x68, 0x64, 0x72, 0x52, 0x0e, 0x69, 0x6e, 0x66, + 0x69, 0x6e, 0x69, 0x62, 0x61, 0x6e, 0x64, 0x2d, 0x6e, 0x64, 0x72, 0x52, 0x0e, 0x69, 0x6e, 0x66, + 0x69, 0x6e, 0x69, 0x62, 0x61, 0x6e, 0x64, 0x2d, 0x78, 0x64, 0x72, 0x52, 0x02, 0x74, 0x31, 0x52, + 0x02, 0x65, 0x31, 0x52, 0x02, 0x74, 0x33, 0x52, 0x02, 0x65, 0x33, 0x52, 0x04, 0x78, 0x64, 0x73, + 0x6c, 0x52, 0x06, 0x64, 0x6f, 0x63, 0x73, 0x69, 0x73, 0x52, 0x04, 0x67, 0x70, 0x6f, 0x6e, 0x52, + 0x06, 0x78, 0x67, 0x2d, 0x70, 0x6f, 0x6e, 0x52, 0x07, 0x78, 0x67, 0x73, 0x2d, 0x70, 0x6f, 0x6e, + 0x52, 0x07, 0x6e, 0x67, 0x2d, 0x70, 0x6f, 0x6e, 0x32, 0x52, 0x04, 0x65, 0x70, 0x6f, 0x6e, 0x52, + 0x08, 0x31, 0x30, 0x67, 0x2d, 0x65, 0x70, 0x6f, 0x6e, 0x52, 0x0f, 0x63, 0x69, 0x73, 0x63, 0x6f, + 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x52, 0x14, 0x63, 0x69, 0x73, 0x63, + 0x6f, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x2d, 0x70, 0x6c, 0x75, 0x73, + 0x52, 0x0f, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2d, 0x66, 0x6c, 0x65, 0x78, 0x73, 0x74, 0x61, 0x63, + 0x6b, 0x52, 0x14, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2d, 0x66, 0x6c, 0x65, 0x78, 0x73, 0x74, 0x61, + 0x63, 0x6b, 0x2d, 0x70, 0x6c, 0x75, 0x73, 0x52, 0x12, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2d, 0x73, + 0x74, 0x61, 0x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x2d, 0x38, 0x30, 0x52, 0x13, 0x63, 0x69, 0x73, + 0x63, 0x6f, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x2d, 0x31, 0x36, 0x30, + 0x52, 0x13, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x77, 0x69, 0x73, + 0x65, 0x2d, 0x33, 0x32, 0x30, 0x52, 0x13, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2d, 0x73, 0x74, 0x61, + 0x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x2d, 0x34, 0x38, 0x30, 0x52, 0x12, 0x63, 0x69, 0x73, 0x63, + 0x6f, 0x2d, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x77, 0x69, 0x73, 0x65, 0x2d, 0x31, 0x74, 0x52, 0x0b, + 0x6a, 0x75, 0x6e, 0x69, 0x70, 0x65, 0x72, 0x2d, 0x76, 0x63, 0x70, 0x52, 0x13, 0x65, 0x78, 0x74, + 0x72, 0x65, 0x6d, 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x74, 0x61, 0x63, 0x6b, + 0x52, 0x17, 0x65, 0x78, 0x74, 0x72, 0x65, 0x6d, 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x69, 0x74, + 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2d, 0x31, 0x32, 0x38, 0x52, 0x17, 0x65, 0x78, 0x74, 0x72, 0x65, + 0x6d, 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, 0x69, 0x74, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2d, 0x32, + 0x35, 0x36, 0x52, 0x17, 0x65, 0x78, 0x74, 0x72, 0x65, 0x6d, 0x65, 0x2d, 0x73, 0x75, 0x6d, 0x6d, + 0x69, 0x74, 0x73, 0x74, 0x61, 0x63, 0x6b, 0x2d, 0x35, 0x31, 0x32, 0x52, 0x05, 0x6f, 0x74, 0x68, + 0x65, 0x72, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x48, 0x01, 0x52, 0x07, 0x65, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x64, 0x88, 0x01, 0x01, 0x12, 0x22, 0x0a, 0x03, 0x6d, 0x74, 0x75, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x05, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x1a, 0x06, 0x18, 0x80, 0x80, 0x04, 0x28, + 0x01, 0x48, 0x02, 0x52, 0x03, 0x6d, 0x74, 0x75, 0x88, 0x01, 0x01, 0x12, 0x24, 0x0a, 0x0b, 0x6d, + 0x61, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x48, 0x03, 0x52, 0x0a, 0x6d, 0x61, 0x63, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x88, 0x01, + 0x01, 0x12, 0x22, 0x0a, 0x05, 0x73, 0x70, 0x65, 0x65, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, + 0x42, 0x07, 0xfa, 0x42, 0x04, 0x1a, 0x02, 0x28, 0x00, 0x48, 0x04, 0x52, 0x05, 0x73, 0x70, 0x65, + 0x65, 0x64, 0x88, 0x01, 0x01, 0x12, 0x15, 0x0a, 0x03, 0x77, 0x77, 0x6e, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x48, 0x05, 0x52, 0x03, 0x77, 0x77, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, + 0x6d, 0x67, 0x6d, 0x74, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x48, + 0x06, 0x52, 0x08, 0x6d, 0x67, 0x6d, 0x74, 0x4f, 0x6e, 0x6c, 0x79, 0x88, 0x01, 0x01, 0x12, 0x2f, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x48, 0x07, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, + 0x2a, 0x0a, 0x0e, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x08, 0x48, 0x08, 0x52, 0x0d, 0x6d, 0x61, 0x72, 0x6b, 0x43, + 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x88, 0x01, 0x01, 0x12, 0x35, 0x0a, 0x04, 0x6d, + 0x6f, 0x64, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x42, 0x21, 0xfa, 0x42, 0x1e, 0x72, 0x1c, + 0x52, 0x06, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x52, 0x06, 0x74, 0x61, 0x67, 0x67, 0x65, 0x64, + 0x52, 0x0a, 0x74, 0x61, 0x67, 0x67, 0x65, 0x64, 0x2d, 0x61, 0x6c, 0x6c, 0x52, 0x04, 0x6d, 0x6f, + 0x64, 0x65, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, + 0x04, 0x74, 0x61, 0x67, 0x73, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x42, + 0x0a, 0x0a, 0x08, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x42, 0x06, 0x0a, 0x04, 0x5f, + 0x6d, 0x74, 0x75, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x6d, 0x61, 0x63, 0x5f, 0x61, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x73, 0x70, 0x65, 0x65, 0x64, 0x42, 0x06, 0x0a, + 0x04, 0x5f, 0x77, 0x77, 0x6e, 0x42, 0x0c, 0x0a, 0x0a, 0x5f, 0x6d, 0x67, 0x6d, 0x74, 0x5f, 0x6f, + 0x6e, 0x6c, 0x79, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x42, 0x11, 0x0a, 0x0f, 0x5f, 0x6d, 0x61, 0x72, 0x6b, 0x5f, 0x63, 0x6f, 0x6e, + 0x6e, 0x65, 0x63, 0x74, 0x65, 0x64, 0x22, 0x8c, 0x04, 0x0a, 0x09, 0x49, 0x50, 0x41, 0x64, 0x64, + 0x72, 0x65, 0x73, 0x73, 0x12, 0x21, 0x0a, 0x07, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x70, 0x01, 0x52, 0x07, + 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x33, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x66, 0x61, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x69, 0x6f, + 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x48, + 0x00, 0x52, 0x09, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x48, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x30, 0xfa, 0x42, + 0x2d, 0x72, 0x2b, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x08, 0x72, 0x65, 0x73, + 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, + 0x64, 0x52, 0x04, 0x64, 0x68, 0x63, 0x70, 0x52, 0x05, 0x73, 0x6c, 0x61, 0x61, 0x63, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x54, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x40, 0xfa, 0x42, 0x3d, 0x72, 0x3b, 0x52, 0x08, 0x6c, 0x6f, 0x6f, + 0x70, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x09, 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x61, 0x72, 0x79, + 0x52, 0x07, 0x61, 0x6e, 0x79, 0x63, 0x61, 0x73, 0x74, 0x52, 0x03, 0x76, 0x69, 0x70, 0x52, 0x04, + 0x76, 0x72, 0x72, 0x70, 0x52, 0x04, 0x68, 0x73, 0x72, 0x70, 0x52, 0x04, 0x67, 0x6c, 0x62, 0x70, + 0x52, 0x04, 0x63, 0x61, 0x72, 0x70, 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x12, 0x55, 0x0a, 0x08, + 0x64, 0x6e, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x35, + 0xfa, 0x42, 0x32, 0x72, 0x30, 0x18, 0xff, 0x01, 0x32, 0x2b, 0x5e, 0x28, 0x5b, 0x30, 0x2d, 0x39, + 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x5f, 0x2d, 0x5d, 0x2b, 0x7c, 0x5c, 0x2a, 0x29, 0x28, 0x5c, + 0x2e, 0x5b, 0x30, 0x2d, 0x39, 0x41, 0x2d, 0x5a, 0x61, 0x2d, 0x7a, 0x5f, 0x2d, 0x5d, 0x2b, 0x29, + 0x2a, 0x5c, 0x2e, 0x3f, 0x24, 0x48, 0x01, 0x52, 0x07, 0x64, 0x6e, 0x73, 0x4e, 0x61, 0x6d, 0x65, + 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, + 0xc8, 0x01, 0x48, 0x02, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, + 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, + 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x42, 0x11, 0x0a, 0x0f, 0x61, 0x73, 0x73, 0x69, + 0x67, 0x6e, 0x65, 0x64, 0x5f, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x0b, 0x0a, 0x09, 0x5f, + 0x64, 0x6e, 0x73, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x6f, 0x6d, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xeb, 0x02, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x1f, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x64, 0x52, 0x05, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x1b, 0xfa, 0x42, 0x18, 0x72, 0x16, 0x10, 0x01, 0x18, 0x64, 0x32, 0x10, + 0x5e, 0x5b, 0x2d, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5f, 0x5d, 0x2b, 0x24, + 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x3a, 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, + 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, + 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, + 0x75, 0x72, 0x65, 0x72, 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, + 0x65, 0x72, 0x12, 0x2f, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, + 0x01, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, + 0x73, 0x88, 0x01, 0x01, 0x12, 0x2d, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x5f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, - 0x18, 0x32, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x21, - 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, - 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, - 0x73, 0x22, 0xad, 0x01, 0x0a, 0x0c, 0x4d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, - 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x64, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x1b, 0xfa, 0x42, 0x18, 0x72, 0x16, 0x10, 0x01, 0x18, 0x64, 0x32, 0x10, 0x5e, 0x5b, 0x2d, 0x61, - 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5f, 0x5d, 0x2b, 0x24, 0x52, 0x04, 0x73, 0x6c, - 0x75, 0x67, 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, - 0x01, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, - 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, - 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, - 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x08, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1d, + 0x18, 0x32, 0x48, 0x02, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x74, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, + 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x65, + 0x6e, 0x74, 0x73, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x5f, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x22, 0xc2, 0x01, 0x0a, 0x0c, 0x4d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, + 0x75, 0x72, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x64, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x1b, 0xfa, 0x42, 0x18, 0x72, 0x16, 0x10, 0x01, 0x18, 0x64, 0x32, 0x10, 0x5e, 0x5b, + 0x2d, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5f, 0x5d, 0x2b, 0x24, 0x52, 0x04, + 0x73, 0x6c, 0x75, 0x67, 0x12, 0x2f, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, + 0x18, 0xc8, 0x01, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, + 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xfa, 0x01, 0x0a, 0x08, 0x50, 0x6c, 0x61, + 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x1d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x64, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x1b, 0xfa, 0x42, 0x18, 0x72, 0x16, 0x10, 0x01, 0x18, 0x64, 0x32, 0x10, 0x5e, + 0x5b, 0x2d, 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5f, 0x5d, 0x2b, 0x24, 0x52, + 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x3a, 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, + 0x74, 0x75, 0x72, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, 0x69, + 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, + 0x72, 0x65, 0x72, 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, + 0x72, 0x12, 0x2f, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, + 0x48, 0x00, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, + 0x01, 0x01, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, + 0x04, 0x74, 0x61, 0x67, 0x73, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x8d, 0x03, 0x0a, 0x06, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, + 0x12, 0x1f, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x70, 0x01, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, + 0x78, 0x12, 0x22, 0x0a, 0x04, 0x73, 0x69, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0e, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x74, 0x65, 0x52, + 0x04, 0x73, 0x69, 0x74, 0x65, 0x12, 0x46, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2e, 0xfa, 0x42, 0x2b, 0x72, 0x29, 0x52, 0x06, 0x61, 0x63, + 0x74, 0x69, 0x76, 0x65, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x52, + 0x08, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x0a, 0x64, 0x65, 0x70, 0x72, 0x65, + 0x63, 0x61, 0x74, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, + 0x07, 0x69, 0x73, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, + 0x52, 0x06, 0x69, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x88, 0x01, 0x01, 0x12, 0x28, 0x0a, 0x0d, 0x6d, + 0x61, 0x72, 0x6b, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x08, 0x48, 0x01, 0x52, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x55, 0x74, 0x69, 0x6c, 0x69, 0x7a, + 0x65, 0x64, 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, + 0x03, 0x18, 0xc8, 0x01, 0x48, 0x02, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, + 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x6d, + 0x65, 0x6e, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, + 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x42, 0x0a, 0x0a, 0x08, 0x5f, 0x69, + 0x73, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x42, 0x10, 0x0a, 0x0e, 0x5f, 0x6d, 0x61, 0x72, 0x6b, 0x5f, + 0x75, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, 0x6f, 0x6d, + 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0xea, 0x01, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x64, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1b, 0xfa, 0x42, 0x18, 0x72, 0x16, 0x10, 0x01, 0x18, 0x64, 0x32, 0x10, 0x5e, 0x5b, 0x2d, 0x61, 0x2d, 0x7a, 0x41, 0x2d, - 0x5a, 0x30, 0x2d, 0x39, 0x5f, 0x5d, 0x2b, 0x24, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x3a, - 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x4d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x52, 0x0c, 0x6d, 0x61, - 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, - 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0xbe, 0x02, 0x0a, 0x06, 0x50, 0x72, - 0x65, 0x66, 0x69, 0x78, 0x12, 0x1f, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x70, 0x01, 0x52, 0x06, 0x70, - 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, 0x22, 0x0a, 0x04, 0x73, 0x69, 0x74, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x69, 0x74, 0x65, 0x52, 0x04, 0x73, 0x69, 0x74, 0x65, 0x12, 0x46, 0x0a, 0x06, 0x73, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2e, 0xfa, 0x42, 0x2b, 0x72, 0x29, - 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x09, 0x63, 0x6f, 0x6e, 0x74, 0x61, 0x69, - 0x6e, 0x65, 0x72, 0x52, 0x08, 0x72, 0x65, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x52, 0x0a, 0x64, - 0x65, 0x70, 0x72, 0x65, 0x63, 0x61, 0x74, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x70, 0x6f, 0x6f, 0x6c, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x50, 0x6f, 0x6f, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x61, - 0x72, 0x6b, 0x5f, 0x75, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x0c, 0x6d, 0x61, 0x72, 0x6b, 0x55, 0x74, 0x69, 0x6c, 0x69, 0x7a, 0x65, 0x64, 0x12, - 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x0b, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x63, - 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, - 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, - 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0xd5, 0x01, 0x0a, 0x04, 0x52, - 0x6f, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x64, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x1b, 0xfa, 0x42, 0x18, 0x72, 0x16, 0x10, 0x01, 0x18, 0x64, 0x32, 0x10, 0x5e, 0x5b, 0x2d, - 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5f, 0x5d, 0x2b, 0x24, 0x52, 0x04, 0x73, - 0x6c, 0x75, 0x67, 0x12, 0x2e, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x18, 0xfa, 0x42, 0x15, 0x72, 0x13, 0x10, 0x06, 0x18, 0x06, 0x32, 0x0d, 0x5e, - 0x5b, 0x30, 0x2d, 0x39, 0x61, 0x2d, 0x66, 0x5d, 0x7b, 0x36, 0x7d, 0x24, 0x52, 0x05, 0x63, 0x6f, - 0x6c, 0x6f, 0x72, 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, - 0xc8, 0x01, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x5a, 0x30, 0x2d, 0x39, 0x5f, 0x5d, 0x2b, 0x24, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x2e, + 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xfa, + 0x42, 0x15, 0x72, 0x13, 0x10, 0x06, 0x18, 0x06, 0x32, 0x0d, 0x5e, 0x5b, 0x30, 0x2d, 0x39, 0x61, + 0x2d, 0x66, 0x5d, 0x7b, 0x36, 0x7d, 0x24, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x12, 0x2f, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x48, 0x00, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, - 0x67, 0x73, 0x22, 0xd6, 0x02, 0x0a, 0x04, 0x53, 0x69, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x04, 0x6e, + 0x67, 0x73, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0xa2, 0x03, 0x0a, 0x04, 0x53, 0x69, 0x74, 0x65, 0x12, 0x1d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x64, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1b, 0xfa, 0x42, 0x18, 0x72, 0x16, 0x10, @@ -1683,95 +1715,100 @@ var file_diode_v1_ingester_proto_rawDesc = []byte{ 0x72, 0x34, 0x52, 0x07, 0x70, 0x6c, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x52, 0x07, 0x73, 0x74, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x0f, 0x64, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x69, 0x6e, 0x67, 0x52, 0x07, 0x72, - 0x65, 0x74, 0x69, 0x72, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x23, + 0x65, 0x74, 0x69, 0x72, 0x65, 0x64, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x28, 0x0a, 0x08, 0x66, 0x61, 0x63, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x52, 0x08, 0x66, 0x61, 0x63, 0x69, 0x6c, - 0x69, 0x74, 0x79, 0x12, 0x1b, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, - 0x12, 0x2a, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, - 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, - 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x21, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, - 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0x85, 0x01, 0x0a, 0x03, - 0x54, 0x61, 0x67, 0x12, 0x1d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x64, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x1b, 0xfa, 0x42, 0x18, 0x72, 0x16, 0x10, 0x01, 0x18, 0x64, 0x32, 0x10, 0x5e, 0x5b, 0x2d, - 0x61, 0x2d, 0x7a, 0x41, 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5f, 0x5d, 0x2b, 0x24, 0x52, 0x04, 0x73, - 0x6c, 0x75, 0x67, 0x12, 0x2e, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x42, 0x18, 0xfa, 0x42, 0x15, 0x72, 0x13, 0x10, 0x06, 0x18, 0x06, 0x32, 0x0d, 0x5e, - 0x5b, 0x30, 0x2d, 0x39, 0x61, 0x2d, 0x66, 0x5d, 0x7b, 0x36, 0x7d, 0x24, 0x52, 0x05, 0x63, 0x6f, - 0x6c, 0x6f, 0x72, 0x22, 0x9d, 0x04, 0x0a, 0x06, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x24, - 0x0a, 0x04, 0x73, 0x69, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, - 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, - 0x73, 0x69, 0x74, 0x65, 0x12, 0x30, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x50, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x48, 0x00, 0x52, 0x08, 0x70, 0x6c, - 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x12, 0x3c, 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, - 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, - 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, - 0x75, 0x72, 0x65, 0x72, 0x48, 0x00, 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, - 0x75, 0x72, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, - 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x31, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, - 0x6f, 0x6c, 0x65, 0x12, 0x37, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x48, 0x00, - 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x33, 0x0a, 0x09, - 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x13, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, - 0x66, 0x61, 0x63, 0x65, 0x48, 0x00, 0x52, 0x09, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, - 0x65, 0x12, 0x34, 0x0a, 0x0a, 0x69, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, - 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, - 0x2e, 0x49, 0x50, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x09, 0x69, 0x70, - 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, - 0x78, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, - 0x76, 0x31, 0x2e, 0x50, 0x72, 0x65, 0x66, 0x69, 0x78, 0x48, 0x00, 0x52, 0x06, 0x70, 0x72, 0x65, - 0x66, 0x69, 0x78, 0x12, 0x44, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0xb2, 0x01, 0x04, 0x08, 0x01, 0x38, 0x01, 0x52, 0x09, - 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x08, 0x0a, 0x06, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x22, 0xe4, 0x02, 0x0a, 0x0d, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, - 0x01, 0x52, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x39, 0x0a, 0x08, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x64, 0x69, - 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x42, 0x0b, 0xfa, - 0x42, 0x08, 0x92, 0x01, 0x05, 0x08, 0x01, 0x10, 0xe8, 0x07, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x69, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, - 0x0a, 0x11, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x61, 0x70, 0x70, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, - 0x10, 0x01, 0x18, 0xff, 0x01, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x41, - 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x14, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, - 0x65, 0x72, 0x5f, 0x61, 0x70, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, - 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, - 0x52, 0x12, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x08, 0x73, 0x64, 0x6b, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, - 0xff, 0x01, 0x52, 0x07, 0x73, 0x64, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x0b, 0x73, - 0x64, 0x6b, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, - 0x42, 0x1c, 0xfa, 0x42, 0x19, 0x72, 0x17, 0x32, 0x15, 0x5e, 0x28, 0x5c, 0x64, 0x29, 0x2b, 0x5c, - 0x2e, 0x28, 0x5c, 0x64, 0x29, 0x2b, 0x5c, 0x2e, 0x28, 0x5c, 0x64, 0x29, 0x2b, 0x24, 0x52, 0x0a, - 0x73, 0x64, 0x6b, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x28, 0x0a, 0x0e, 0x49, 0x6e, - 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x73, 0x32, 0x50, 0x0a, 0x0f, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, - 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x49, 0x6e, 0x67, 0x65, 0x73, - 0x74, 0x12, 0x17, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x67, - 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x64, 0x69, 0x6f, - 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6e, 0x65, 0x74, 0x62, 0x6f, 0x78, 0x6c, 0x61, 0x62, 0x73, 0x2f, - 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2d, 0x73, 0x64, 0x6b, 0x2d, 0x67, 0x6f, 0x2f, 0x64, 0x69, 0x6f, - 0x64, 0x65, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x18, 0x32, 0x48, 0x00, 0x52, 0x08, 0x66, 0x61, 0x63, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x88, 0x01, 0x01, 0x12, 0x20, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x01, 0x52, 0x08, 0x74, + 0x69, 0x6d, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x88, 0x01, 0x01, 0x12, 0x2f, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x48, 0x02, 0x52, 0x0b, 0x64, 0x65, 0x73, + 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x88, 0x01, 0x01, 0x12, 0x1f, 0x0a, 0x08, 0x63, + 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x48, 0x03, 0x52, + 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x88, 0x01, 0x01, 0x12, 0x21, 0x0a, 0x04, + 0x74, 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x64, 0x69, 0x6f, + 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x61, 0x67, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x42, + 0x0b, 0x0a, 0x09, 0x5f, 0x66, 0x61, 0x63, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x42, 0x0c, 0x0a, 0x0a, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x7a, 0x6f, 0x6e, 0x65, 0x42, 0x0e, 0x0a, 0x0c, 0x5f, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x0b, 0x0a, 0x09, 0x5f, 0x63, + 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x85, 0x01, 0x0a, 0x03, 0x54, 0x61, 0x67, 0x12, + 0x1d, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, + 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x64, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2f, + 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1b, 0xfa, 0x42, + 0x18, 0x72, 0x16, 0x10, 0x01, 0x18, 0x64, 0x32, 0x10, 0x5e, 0x5b, 0x2d, 0x61, 0x2d, 0x7a, 0x41, + 0x2d, 0x5a, 0x30, 0x2d, 0x39, 0x5f, 0x5d, 0x2b, 0x24, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, + 0x2e, 0x0a, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, + 0xfa, 0x42, 0x15, 0x72, 0x13, 0x10, 0x06, 0x18, 0x06, 0x32, 0x0d, 0x5e, 0x5b, 0x30, 0x2d, 0x39, + 0x61, 0x2d, 0x66, 0x5d, 0x7b, 0x36, 0x7d, 0x24, 0x52, 0x05, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x22, + 0x9d, 0x04, 0x0a, 0x06, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x24, 0x0a, 0x04, 0x73, 0x69, + 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x69, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x73, 0x69, 0x74, 0x65, + 0x12, 0x30, 0x0a, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c, + 0x61, 0x74, 0x66, 0x6f, 0x72, 0x6d, 0x48, 0x00, 0x52, 0x08, 0x70, 0x6c, 0x61, 0x74, 0x66, 0x6f, + 0x72, 0x6d, 0x12, 0x3c, 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, + 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, + 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, + 0x48, 0x00, 0x52, 0x0c, 0x6d, 0x61, 0x6e, 0x75, 0x66, 0x61, 0x63, 0x74, 0x75, 0x72, 0x65, 0x72, + 0x12, 0x2a, 0x0a, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x10, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x76, 0x69, + 0x63, 0x65, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x31, 0x0a, 0x0b, + 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0e, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6c, + 0x65, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x12, + 0x37, 0x0a, 0x0b, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x64, 0x65, + 0x76, 0x69, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x33, 0x0a, 0x09, 0x69, 0x6e, 0x74, 0x65, + 0x72, 0x66, 0x61, 0x63, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x69, + 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, + 0x48, 0x00, 0x52, 0x09, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x66, 0x61, 0x63, 0x65, 0x12, 0x34, 0x0a, + 0x0a, 0x69, 0x70, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x50, 0x41, + 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x48, 0x00, 0x52, 0x09, 0x69, 0x70, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x12, 0x2a, 0x0a, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x50, + 0x72, 0x65, 0x66, 0x69, 0x78, 0x48, 0x00, 0x52, 0x06, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x12, + 0x44, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x0a, + 0xfa, 0x42, 0x07, 0xb2, 0x01, 0x04, 0x08, 0x01, 0x38, 0x01, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x42, 0x08, 0x0a, 0x06, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, + 0xe4, 0x02, 0x0a, 0x0d, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x22, 0x0a, 0x06, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x52, 0x06, 0x73, + 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x39, 0x0a, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, + 0x76, 0x31, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x42, 0x0b, 0xfa, 0x42, 0x08, 0x92, 0x01, + 0x05, 0x08, 0x01, 0x10, 0xe8, 0x07, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, + 0x12, 0x18, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, + 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x11, 0x70, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x61, 0x70, 0x70, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, + 0x01, 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x41, 0x70, 0x70, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x14, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x5f, 0x61, + 0x70, 0x70, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x52, 0x12, 0x70, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x65, 0x72, 0x41, 0x70, 0x70, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x25, 0x0a, 0x08, 0x73, 0x64, 0x6b, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xff, 0x01, 0x52, 0x07, + 0x73, 0x64, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x0b, 0x73, 0x64, 0x6b, 0x5f, 0x76, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x42, 0x1c, 0xfa, 0x42, + 0x19, 0x72, 0x17, 0x32, 0x15, 0x5e, 0x28, 0x5c, 0x64, 0x29, 0x2b, 0x5c, 0x2e, 0x28, 0x5c, 0x64, + 0x29, 0x2b, 0x5c, 0x2e, 0x28, 0x5c, 0x64, 0x29, 0x2b, 0x24, 0x52, 0x0a, 0x73, 0x64, 0x6b, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x28, 0x0a, 0x0e, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x73, + 0x32, 0x50, 0x0a, 0x0f, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x12, 0x17, 0x2e, + 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x49, 0x6e, 0x67, 0x65, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x42, 0x35, 0x5a, 0x33, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x6e, 0x65, 0x74, 0x62, 0x6f, 0x78, 0x6c, 0x61, 0x62, 0x73, 0x2f, 0x64, 0x69, 0x6f, 0x64, + 0x65, 0x2d, 0x73, 0x64, 0x6b, 0x2d, 0x67, 0x6f, 0x2f, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x2f, 0x76, + 0x31, 0x2f, 0x64, 0x69, 0x6f, 0x64, 0x65, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -2007,9 +2044,17 @@ func file_diode_v1_ingester_proto_init() { } } } + file_diode_v1_ingester_proto_msgTypes[0].OneofWrappers = []interface{}{} + file_diode_v1_ingester_proto_msgTypes[1].OneofWrappers = []interface{}{} file_diode_v1_ingester_proto_msgTypes[2].OneofWrappers = []interface{}{ (*IPAddress_Interface)(nil), } + file_diode_v1_ingester_proto_msgTypes[3].OneofWrappers = []interface{}{} + file_diode_v1_ingester_proto_msgTypes[4].OneofWrappers = []interface{}{} + file_diode_v1_ingester_proto_msgTypes[5].OneofWrappers = []interface{}{} + file_diode_v1_ingester_proto_msgTypes[6].OneofWrappers = []interface{}{} + file_diode_v1_ingester_proto_msgTypes[7].OneofWrappers = []interface{}{} + file_diode_v1_ingester_proto_msgTypes[8].OneofWrappers = []interface{}{} file_diode_v1_ingester_proto_msgTypes[10].OneofWrappers = []interface{}{ (*Entity_Site)(nil), (*Entity_Platform)(nil), diff --git a/diode/v1/diodepb/ingester.pb.validate.go b/diode/v1/diodepb/ingester.pb.validate.go index 21e50c4..5db634b 100644 --- a/diode/v1/diodepb/ingester.pb.validate.go +++ b/diode/v1/diodepb/ingester.pb.validate.go @@ -70,17 +70,6 @@ func (m *Device) validate(all bool) error { errors = append(errors, err) } - if l := utf8.RuneCountInString(m.GetDeviceFqdn()); l < 1 || l > 255 { - err := DeviceValidationError{ - field: "DeviceFqdn", - reason: "value length must be between 1 and 255 runes, inclusive", - } - if !all { - return err - } - errors = append(errors, err) - } - if all { switch v := interface{}(m.GetDeviceType()).(type) { case interface{ ValidateAll() error }: @@ -168,17 +157,6 @@ func (m *Device) validate(all bool) error { } } - if utf8.RuneCountInString(m.GetSerial()) > 50 { - err := DeviceValidationError{ - field: "Serial", - reason: "value length must be at most 50 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - if all { switch v := interface{}(m.GetSite()).(type) { case interface{ ValidateAll() error }: @@ -208,17 +186,6 @@ func (m *Device) validate(all bool) error { } } - if utf8.RuneCountInString(m.GetAssetTag()) > 200 { - err := DeviceValidationError{ - field: "AssetTag", - reason: "value length must be at most 200 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - if _, ok := _Device_Status_InLookup[m.GetStatus()]; !ok { err := DeviceValidationError{ field: "Status", @@ -230,19 +197,6 @@ func (m *Device) validate(all bool) error { errors = append(errors, err) } - if utf8.RuneCountInString(m.GetDescription()) > 200 { - err := DeviceValidationError{ - field: "Description", - reason: "value length must be at most 200 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - - // no validation rules for Comments - for idx, item := range m.GetTags() { _, _ = idx, item @@ -335,6 +289,70 @@ func (m *Device) validate(all bool) error { } } + if m.DeviceFqdn != nil { + + if l := utf8.RuneCountInString(m.GetDeviceFqdn()); l < 1 || l > 255 { + err := DeviceValidationError{ + field: "DeviceFqdn", + reason: "value length must be between 1 and 255 runes, inclusive", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.Serial != nil { + + if utf8.RuneCountInString(m.GetSerial()) > 50 { + err := DeviceValidationError{ + field: "Serial", + reason: "value length must be at most 50 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.AssetTag != nil { + + if utf8.RuneCountInString(m.GetAssetTag()) > 200 { + err := DeviceValidationError{ + field: "AssetTag", + reason: "value length must be at most 200 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.Description != nil { + + if utf8.RuneCountInString(m.GetDescription()) > 200 { + err := DeviceValidationError{ + field: "Description", + reason: "value length must be at most 200 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.Comments != nil { + // no validation rules for Comments + } + if len(errors) > 0 { return DeviceMultiError(errors) } @@ -470,17 +488,6 @@ func (m *Interface) validate(all bool) error { errors = append(errors, err) } - if l := utf8.RuneCountInString(m.GetLabel()); l < 1 || l > 64 { - err := InterfaceValidationError{ - field: "Label", - reason: "value length must be between 1 and 64 runes, inclusive", - } - if !all { - return err - } - errors = append(errors, err) - } - if _, ok := _Interface_Type_InLookup[m.GetType()]; !ok { err := InterfaceValidationError{ field: "Type", @@ -492,49 +499,6 @@ func (m *Interface) validate(all bool) error { errors = append(errors, err) } - // no validation rules for Enabled - - if val := m.GetMtu(); val < 1 || val > 65536 { - err := InterfaceValidationError{ - field: "Mtu", - reason: "value must be inside range [1, 65536]", - } - if !all { - return err - } - errors = append(errors, err) - } - - // no validation rules for MacAddress - - if m.GetSpeed() < 0 { - err := InterfaceValidationError{ - field: "Speed", - reason: "value must be greater than or equal to 0", - } - if !all { - return err - } - errors = append(errors, err) - } - - // no validation rules for Wwn - - // no validation rules for MgmtOnly - - if utf8.RuneCountInString(m.GetDescription()) > 200 { - err := InterfaceValidationError{ - field: "Description", - reason: "value length must be at most 200 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - - // no validation rules for MarkConnected - if _, ok := _Interface_Mode_InLookup[m.GetMode()]; !ok { err := InterfaceValidationError{ field: "Mode", @@ -580,6 +544,86 @@ func (m *Interface) validate(all bool) error { } + if m.Label != nil { + + if l := utf8.RuneCountInString(m.GetLabel()); l < 1 || l > 64 { + err := InterfaceValidationError{ + field: "Label", + reason: "value length must be between 1 and 64 runes, inclusive", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.Enabled != nil { + // no validation rules for Enabled + } + + if m.Mtu != nil { + + if val := m.GetMtu(); val < 1 || val > 65536 { + err := InterfaceValidationError{ + field: "Mtu", + reason: "value must be inside range [1, 65536]", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.MacAddress != nil { + // no validation rules for MacAddress + } + + if m.Speed != nil { + + if m.GetSpeed() < 0 { + err := InterfaceValidationError{ + field: "Speed", + reason: "value must be greater than or equal to 0", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.Wwn != nil { + // no validation rules for Wwn + } + + if m.MgmtOnly != nil { + // no validation rules for MgmtOnly + } + + if m.Description != nil { + + if utf8.RuneCountInString(m.GetDescription()) > 200 { + err := InterfaceValidationError{ + field: "Description", + reason: "value length must be at most 200 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.MarkConnected != nil { + // no validation rules for MarkConnected + } + if len(errors) > 0 { return InterfaceMultiError(errors) } @@ -836,41 +880,6 @@ func (m *IPAddress) validate(all bool) error { errors = append(errors, err) } - if utf8.RuneCountInString(m.GetDnsName()) > 255 { - err := IPAddressValidationError{ - field: "DnsName", - reason: "value length must be at most 255 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - - if !_IPAddress_DnsName_Pattern.MatchString(m.GetDnsName()) { - err := IPAddressValidationError{ - field: "DnsName", - reason: "value does not match regex pattern \"^([0-9A-Za-z_-]+|\\\\*)(\\\\.[0-9A-Za-z_-]+)*\\\\.?$\"", - } - if !all { - return err - } - errors = append(errors, err) - } - - if utf8.RuneCountInString(m.GetDescription()) > 200 { - err := IPAddressValidationError{ - field: "Description", - reason: "value length must be at most 200 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - - // no validation rules for Comments - for idx, item := range m.GetTags() { _, _ = idx, item @@ -951,6 +960,51 @@ func (m *IPAddress) validate(all bool) error { _ = v // ensures v is used } + if m.DnsName != nil { + + if utf8.RuneCountInString(m.GetDnsName()) > 255 { + err := IPAddressValidationError{ + field: "DnsName", + reason: "value length must be at most 255 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + if !_IPAddress_DnsName_Pattern.MatchString(m.GetDnsName()) { + err := IPAddressValidationError{ + field: "DnsName", + reason: "value does not match regex pattern \"^([0-9A-Za-z_-]+|\\\\*)(\\\\.[0-9A-Za-z_-]+)*\\\\.?$\"", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.Description != nil { + + if utf8.RuneCountInString(m.GetDescription()) > 200 { + err := IPAddressValidationError{ + field: "Description", + reason: "value length must be at most 200 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.Comments != nil { + // no validation rules for Comments + } + if len(errors) > 0 { return IPAddressMultiError(errors) } @@ -1133,30 +1187,6 @@ func (m *DeviceType) validate(all bool) error { } } - if utf8.RuneCountInString(m.GetDescription()) > 200 { - err := DeviceTypeValidationError{ - field: "Description", - reason: "value length must be at most 200 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - - // no validation rules for Comments - - if utf8.RuneCountInString(m.GetPartNumber()) > 50 { - err := DeviceTypeValidationError{ - field: "PartNumber", - reason: "value length must be at most 50 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - for idx, item := range m.GetTags() { _, _ = idx, item @@ -1191,6 +1221,40 @@ func (m *DeviceType) validate(all bool) error { } + if m.Description != nil { + + if utf8.RuneCountInString(m.GetDescription()) > 200 { + err := DeviceTypeValidationError{ + field: "Description", + reason: "value length must be at most 200 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.Comments != nil { + // no validation rules for Comments + } + + if m.PartNumber != nil { + + if utf8.RuneCountInString(m.GetPartNumber()) > 50 { + err := DeviceTypeValidationError{ + field: "PartNumber", + reason: "value length must be at most 50 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + if len(errors) > 0 { return DeviceTypeMultiError(errors) } @@ -1325,17 +1389,6 @@ func (m *Manufacturer) validate(all bool) error { errors = append(errors, err) } - if utf8.RuneCountInString(m.GetDescription()) > 200 { - err := ManufacturerValidationError{ - field: "Description", - reason: "value length must be at most 200 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - for idx, item := range m.GetTags() { _, _ = idx, item @@ -1370,6 +1423,21 @@ func (m *Manufacturer) validate(all bool) error { } + if m.Description != nil { + + if utf8.RuneCountInString(m.GetDescription()) > 200 { + err := ManufacturerValidationError{ + field: "Description", + reason: "value length must be at most 200 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + if len(errors) > 0 { return ManufacturerMultiError(errors) } @@ -1533,17 +1601,6 @@ func (m *Platform) validate(all bool) error { } } - if utf8.RuneCountInString(m.GetDescription()) > 200 { - err := PlatformValidationError{ - field: "Description", - reason: "value length must be at most 200 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - for idx, item := range m.GetTags() { _, _ = idx, item @@ -1578,6 +1635,21 @@ func (m *Platform) validate(all bool) error { } + if m.Description != nil { + + if utf8.RuneCountInString(m.GetDescription()) > 200 { + err := PlatformValidationError{ + field: "Description", + reason: "value length must be at most 200 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + if len(errors) > 0 { return PlatformMultiError(errors) } @@ -1729,23 +1801,6 @@ func (m *Prefix) validate(all bool) error { errors = append(errors, err) } - // no validation rules for IsPool - - // no validation rules for MarkUtilized - - if utf8.RuneCountInString(m.GetDescription()) > 200 { - err := PrefixValidationError{ - field: "Description", - reason: "value length must be at most 200 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - - // no validation rules for Comments - for idx, item := range m.GetTags() { _, _ = idx, item @@ -1780,6 +1835,33 @@ func (m *Prefix) validate(all bool) error { } + if m.IsPool != nil { + // no validation rules for IsPool + } + + if m.MarkUtilized != nil { + // no validation rules for MarkUtilized + } + + if m.Description != nil { + + if utf8.RuneCountInString(m.GetDescription()) > 200 { + err := PrefixValidationError{ + field: "Description", + reason: "value length must be at most 200 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.Comments != nil { + // no validation rules for Comments + } + if len(errors) > 0 { return PrefixMultiError(errors) } @@ -1941,17 +2023,6 @@ func (m *Role) validate(all bool) error { errors = append(errors, err) } - if utf8.RuneCountInString(m.GetDescription()) > 200 { - err := RoleValidationError{ - field: "Description", - reason: "value length must be at most 200 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - for idx, item := range m.GetTags() { _, _ = idx, item @@ -1986,6 +2057,21 @@ func (m *Role) validate(all bool) error { } + if m.Description != nil { + + if utf8.RuneCountInString(m.GetDescription()) > 200 { + err := RoleValidationError{ + field: "Description", + reason: "value length must be at most 200 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + if len(errors) > 0 { return RoleMultiError(errors) } @@ -2132,32 +2218,6 @@ func (m *Site) validate(all bool) error { errors = append(errors, err) } - if utf8.RuneCountInString(m.GetFacility()) > 50 { - err := SiteValidationError{ - field: "Facility", - reason: "value length must be at most 50 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - - // no validation rules for TimeZone - - if utf8.RuneCountInString(m.GetDescription()) > 200 { - err := SiteValidationError{ - field: "Description", - reason: "value length must be at most 200 runes", - } - if !all { - return err - } - errors = append(errors, err) - } - - // no validation rules for Comments - for idx, item := range m.GetTags() { _, _ = idx, item @@ -2192,6 +2252,44 @@ func (m *Site) validate(all bool) error { } + if m.Facility != nil { + + if utf8.RuneCountInString(m.GetFacility()) > 50 { + err := SiteValidationError{ + field: "Facility", + reason: "value length must be at most 50 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.TimeZone != nil { + // no validation rules for TimeZone + } + + if m.Description != nil { + + if utf8.RuneCountInString(m.GetDescription()) > 200 { + err := SiteValidationError{ + field: "Description", + reason: "value length must be at most 200 runes", + } + if !all { + return err + } + errors = append(errors, err) + } + + } + + if m.Comments != nil { + // no validation rules for Comments + } + if len(errors) > 0 { return SiteMultiError(errors) } diff --git a/examples/main.go b/examples/main.go new file mode 100644 index 0000000..75331f9 --- /dev/null +++ b/examples/main.go @@ -0,0 +1,287 @@ +package main + +import ( + "context" + "log" + + "github.com/netboxlabs/diode-sdk-go/diode" +) + +func main() { + client, err := diode.NewClient( + "grpc://localhost:8080/diode", + "example-app", + "0.1.0", + diode.WithAPIKey("YOUR_API_KEY"), + ) + if err != nil { + log.Fatal(err) + } + + // Create a device + deviceEntity := &diode.Device{ + Name: diode.String("Device A"), + DeviceType: &diode.DeviceType{ + Model: diode.String("Device Type A"), + Manufacturer: &diode.Manufacturer{ + Name: diode.String("Manufacturer A"), + }, + }, + Platform: &diode.Platform{ + Name: diode.String("Platform A"), + Manufacturer: &diode.Manufacturer{ + Name: diode.String("Manufacturer A"), + }, + }, + Site: &diode.Site{ + Name: diode.String("Site ABC"), + }, + Role: &diode.Role{ + Name: diode.String("Role ABC"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 2"), + }, + }, + }, + Serial: diode.String("123456"), + AssetTag: diode.String("123456"), + Status: diode.String("active"), + Comments: diode.String("Lorem ipsum dolor sit amet"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 3"), + }, + }, + } + + // Create a device type + deviceTypeEntity := &diode.DeviceType{ + Model: diode.String("Device Type A"), + Manufacturer: &diode.Manufacturer{ + Name: diode.String("Manufacturer A"), + }, + PartNumber: diode.String("123456"), + Description: diode.String("Device Type A description"), + Comments: diode.String("Lorem ipsum dolor sit amet"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 2"), + }, + }, + } + + // Create an IP address + ipAddressEntity := &diode.IPAddress{ + Address: diode.String("192.168.0.1/24"), + AssignedObject: &diode.Interface{ + Name: diode.String("Interface ABC"), + Device: &diode.Device{ + Name: diode.String("Device ABC"), + DeviceType: &diode.DeviceType{ + Model: diode.String("Device Type ABC"), + Manufacturer: &diode.Manufacturer{ + Name: diode.String("Manufacturer ABC"), + }, + }, + Platform: &diode.Platform{ + Name: diode.String("Platform ABC"), + Manufacturer: &diode.Manufacturer{ + Name: diode.String("Manufacturer ABC"), + }, + }, + Site: &diode.Site{ + Name: diode.String("Site ABC"), + }, + Role: &diode.Role{ + Name: diode.String("Role ABC"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 2"), + }, + }, + }, + }, + }, + Status: diode.String("active"), + Role: diode.String("anycast"), + Description: diode.String("IP Address description"), + Comments: diode.String("Lorem ipsum dolor sit amet"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 2"), + }, + }, + } + + // Create an interface + interfaceEntity := &diode.Interface{ + Name: diode.String("Interface A"), + Device: &diode.Device{ + Name: diode.String("Device A"), + DeviceType: &diode.DeviceType{ + Model: diode.String("Device Type A"), + Manufacturer: &diode.Manufacturer{ + Name: diode.String("Manufacturer A"), + }, + }, + Platform: &diode.Platform{ + Name: diode.String("Platform A"), + Manufacturer: &diode.Manufacturer{ + Name: diode.String("Manufacturer A"), + }, + }, + Site: &diode.Site{ + Name: diode.String("Site ABC"), + }, + Role: &diode.Role{ + Name: diode.String("Role ABC"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 2"), + }, + }, + }, + }, + Type: diode.String("virtual"), + Enabled: diode.Bool(true), + Mtu: diode.Int32(1500), + MacAddress: diode.String("00:00:00:00:00:00"), + Description: diode.String("Interface A description"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 2"), + }, + }, + } + + // Create a manufacturer + manufacturerEntity := &diode.Manufacturer{ + Name: diode.String("Manufacturer A"), + Description: diode.String("Manufacturer A description"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 2"), + }, + }, + } + + // Create a platform + platformEntity := &diode.Platform{ + Name: diode.String("Platform A"), + Manufacturer: &diode.Manufacturer{ + Name: diode.String("Manufacturer A"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 2"), + }, + }, + }, + Description: diode.String("Platform A description"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 2"), + }, + }, + } + + // Create a prefix + prefixEntity := &diode.Prefix{ + Prefix: diode.String("192.168.0.0/32"), + Site: &diode.Site{ + Name: diode.String("Site ABC"), + }, + Status: diode.String("active"), + IsPool: diode.Bool(true), + MarkUtilized: diode.Bool(true), + Description: diode.String("Prefix description"), + Comments: diode.String("Lorem ipsum dolor sit amet"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 2"), + }, + }, + } + + // Create a role + roleEntity := &diode.Role{ + Name: diode.String("Role A"), + Color: diode.String("ffffff"), + Description: diode.String("Role A description"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 1"), + }, + { + Name: diode.String("tag 2"), + }, + }, + } + + // Create a site + siteEntity := &diode.Site{ + Name: diode.String("site A"), + Comments: diode.String("aaa"), + Tags: []*diode.Tag{ + { + Name: diode.String("tag 2"), + }, + }, + } + + entities := []diode.Entity{ + deviceEntity, + deviceTypeEntity, + ipAddressEntity, + interfaceEntity, + manufacturerEntity, + platformEntity, + prefixEntity, + roleEntity, + siteEntity, + } + + resp, err := client.Ingest(context.Background(), entities) + if err != nil { + log.Fatal(err) + } + if resp != nil && resp.Errors != nil { + log.Printf("Errors: %v\n", resp.Errors) + } else { + log.Printf("Success\n") + } + +} diff --git a/go.mod b/go.mod index 157b344..bdfbe1d 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.22 require ( github.com/envoyproxy/protoc-gen-validate v1.0.4 + github.com/google/uuid v1.6.0 github.com/stretchr/testify v1.9.0 google.golang.org/grpc v1.63.2 google.golang.org/protobuf v1.33.0 @@ -12,9 +13,9 @@ require ( require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/net v0.24.0 // indirect - golang.org/x/sys v0.19.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 1f62b90..5c571a2 100644 --- a/go.sum +++ b/go.sum @@ -4,16 +4,18 @@ github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= -golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de h1:cZGRis4/ot9uVm639a+rHCUaG0JJHEsdyzSQTMX+suY= google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de/go.mod h1:H4O17MA/PE9BsGx3w+a+W2VOLLD1Qf7oJneAoU6WktY= google.golang.org/grpc v1.63.2 h1:MUeiw1B2maTVZthpU5xvASfTh3LDbxHd6IJ6QQVU+xM= diff --git a/internal/cmd/codegen/main.go b/internal/cmd/codegen/main.go new file mode 100644 index 0000000..94ebd3a --- /dev/null +++ b/internal/cmd/codegen/main.go @@ -0,0 +1,9 @@ +package main + +import ( + "github.com/netboxlabs/diode-sdk-go/internal/codegen" +) + +func main() { + codegen.GenerateDiodeStructs() +} diff --git a/internal/codegen/codegen.go b/internal/codegen/codegen.go new file mode 100644 index 0000000..8e88e11 --- /dev/null +++ b/internal/codegen/codegen.go @@ -0,0 +1,309 @@ +package codegen + +import ( + "fmt" + "reflect" + "strings" + + "github.com/netboxlabs/diode-sdk-go/diode/v1/diodepb" + "google.golang.org/protobuf/reflect/protoreflect" + "google.golang.org/protobuf/runtime/protoimpl" +) + +type assignableEntity struct { + fieldName string + parentFieldName string + messageName string + nestedAssignableEntities map[string]assignableEntity +} + +type methodParams struct { + fieldName string + fieldType string + pointer bool + repeated bool + repeatedFieldType string + messageField bool + nestedFieldName string + nestedMessageName string +} + +// GenerateDiodeStructs generates diode structs based on the diodepb package +func GenerateDiodeStructs() { + assignableEntityTypes := retrieveTypesAssignableToEntities((*diodepb.Entity)(nil).ProtoReflect(), "") + + protoTypes := []protoreflect.ProtoMessage{ + (*diodepb.Device)(nil), + (*diodepb.DeviceType)(nil), + (*diodepb.IPAddress)(nil), + (*diodepb.Interface)(nil), + (*diodepb.Manufacturer)(nil), + (*diodepb.Platform)(nil), + (*diodepb.Prefix)(nil), + (*diodepb.Role)(nil), + (*diodepb.Site)(nil), + (*diodepb.Tag)(nil), + } + + fmt.Print("// Code generated by github.com/diode-sdk-go/internal/cmd/codegen. DO NOT EDIT.\n\n") + fmt.Print("package diode\n\n") + fmt.Print("import (\n") + fmt.Print("\t\"google.golang.org/protobuf/proto\"\n") + fmt.Print("\n") + fmt.Print("\t\"github.com/netboxlabs/diode-sdk-go/diode/v1/diodepb\"\n") + fmt.Print(")\n\n") + + fmt.Printf("// Entity is an interface that all entities must implement\n") + fmt.Printf("type Entity interface {\n") + fmt.Printf("\tConvertToProtoMessage() proto.Message\n") + fmt.Printf("\tConvertToProtoEntity() *diodepb.Entity\n") + fmt.Printf("}\n\n") + + for _, t := range protoTypes { + entityType := assignableEntityTypes[string(t.ProtoReflect().Type().Descriptor().Name())] + GenerateDiodeSDKStruct(t, entityType) + } +} + +// GenerateDiodeSDKStruct generates a struct based on the given proto message +func GenerateDiodeSDKStruct(pm protoreflect.ProtoMessage, ae assignableEntity) { + t := reflect.TypeOf(pm).Elem() + protoFields := pm.ProtoReflect().Descriptor().Fields() + + fmt.Printf("// %s is based on diodepb.%s\n", t.Name(), t.Name()) + fmt.Printf("type %s struct {\n", t.Name()) + var currentExportedFieldIdx int + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + if field.IsExported() { + protoField := protoFields.Get(currentExportedFieldIdx) + if protoField == nil { + panic(fmt.Sprintf("protoField is nil for %s", field.Name)) + } + + fieldTypeStr := strings.TrimPrefix(field.Type.String(), "*") + + if protoField.Kind() == protoreflect.MessageKind { + fieldTypeParts := strings.Split(fieldTypeStr, ".") + fieldTypeStr = fieldTypeParts[len(fieldTypeParts)-1] + + if field.Tag.Get("protobuf_oneof") != "" { + fieldTypeStr = string(protoField.Message().FullName().Name()) + } + + fieldTypeStr = "*" + fieldTypeStr + + if protoField.Cardinality() == protoreflect.Repeated { + fieldTypeStr = "[]" + fieldTypeStr + } + } else { + fieldTypeStr = "*" + fieldTypeStr + } + + fmt.Printf("\t%s %s\n", field.Name, fieldTypeStr) + currentExportedFieldIdx++ + } + } + fmt.Printf("}\n\n") + + methodsToGenerate := make([]methodParams, 0) + + fmt.Printf("// ConvertToProtoMessage%s converts a %s to a diodepb.%s\n", t.Name(), t.Name(), t.Name()) + fmt.Printf("func (e *%s) ConvertToProtoMessage() proto.Message {\n", t.Name()) + fmt.Printf("\treturn &diodepb.%s{\n", t.Name()) + currentExportedFieldIdx = 0 + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + if field.IsExported() { + protoField := protoFields.Get(currentExportedFieldIdx) + if protoField == nil { + panic(fmt.Sprintf("protoField is nil for %s", field.Name)) + } + + fieldType := field.Type.Kind() + + if protoField.Kind() == protoreflect.MessageKind { + mp := methodParams{ + fieldName: field.Name, + pointer: true, + messageField: true, + } + if protoField.Cardinality() != protoreflect.Repeated { + if ae.nestedAssignableEntities != nil { + mp.nestedFieldName = ae.nestedAssignableEntities[field.Name].fieldName + mp.nestedMessageName = ae.nestedAssignableEntities[field.Name].messageName + } else { + mp.fieldType = field.Type.Elem().Name() + } + } else { + mp.repeated = true + mp.repeatedFieldType = string(protoField.Message().Name()) + } + methodsToGenerate = append(methodsToGenerate, mp) + + fmt.Printf("\t\t%s: e.Get%s(),\n", field.Name, field.Name) + } else if fieldType == reflect.Ptr { + fmt.Printf("\t\t%s: e.Get%s(),\n", field.Name, field.Name) + + methodsToGenerate = append(methodsToGenerate, methodParams{ + fieldName: field.Name, + fieldType: field.Type.Elem().Name(), + pointer: true, + }) + } else { + mp := methodParams{ + fieldName: field.Name, + pointer: false, + } + if fieldType == reflect.String { + mp.fieldType = "string" + } else if fieldType == reflect.Bool { + mp.fieldType = "bool" + } else if fieldType == reflect.Int32 { + mp.fieldType = "int32" + } else { + panic(fmt.Sprintf("unsupported field type %s for %s", fieldType, field.Name)) + } + fmt.Printf("\t\t%s: e.Get%s(),\n", field.Name, field.Name) + + methodsToGenerate = append(methodsToGenerate, mp) + } + currentExportedFieldIdx++ + } + } + + fmt.Printf("\t}\n") + fmt.Printf("}\n\n") + + for _, mp := range methodsToGenerate { + generateGetterMethod(t, mp) + } + + if ae.fieldName == "" { + return + } + + fmt.Printf("// ConvertToProtoEntity%s converts a %s to a diodepb.Entity\n", t.Name(), t.Name()) + fmt.Printf("func (e *%s) ConvertToProtoEntity() *diodepb.Entity {\n", t.Name()) + fmt.Print("\treturn &diodepb.Entity{\n") + fmt.Printf("\t\tEntity: &diodepb.Entity_%s{\n", ae.fieldName) + fmt.Printf("\t\t\t%s: e.ConvertToProtoMessage().(*diodepb.%s),\n", ae.fieldName, t.Name()) + fmt.Print("\t\t},\n") + fmt.Print("\t}\n") + fmt.Printf("}\n\n") +} + +// retrieveTypesAssignableToEntities returns a map of entity names to their corresponding proto message names +func retrieveTypesAssignableToEntities(m protoreflect.Message, parentFieldName string) map[string]assignableEntity { + assignableEntityTypes := make(map[string]assignableEntity) + + if mi, ok := m.(interface{ ProtoMessageInfo() *protoimpl.MessageInfo }); ok { + exportedFields := exportedProtoFields(mi.ProtoMessageInfo().GoReflectType.Elem()) + + for _, wrapper := range mi.ProtoMessageInfo().OneofWrappers { + t := reflect.TypeOf(wrapper).Elem() + field := t.Field(0) + if protoMsg, ok2 := reflect.New(field.Type.Elem()).Interface().(protoreflect.ProtoMessage); ok2 { + ae := assignableEntity{ + fieldName: field.Name, + parentFieldName: parentFieldName, + messageName: t.Name(), + } + + fieldName := string(protoMsg.ProtoReflect().Type().Descriptor().Name()) + if parentFieldName != "" { + for i := 0; i < m.Type().Descriptor().Fields().Len(); i++ { + f := m.Type().Descriptor().Fields().Get(i) + + if f.ContainingOneof() != nil && f.Kind() == protoreflect.MessageKind { + fieldName = exportedFields[f.Index()].Name + } + } + } + + nestedAssignableEntityTypes := retrieveTypesAssignableToEntities(protoMsg.ProtoReflect(), t.Name()) + + if len(nestedAssignableEntityTypes) > 0 { + ae.nestedAssignableEntities = nestedAssignableEntityTypes + } + + assignableEntityTypes[fieldName] = ae + + } else { + panic(fmt.Sprintf("not a proto message: %s", field.Type.Elem().Name())) + } + } + } + + return assignableEntityTypes +} + +func exportedProtoFields(t reflect.Type) []reflect.StructField { + var fields []reflect.StructField + for i := 0; i < t.NumField(); i++ { + field := t.Field(i) + if field.PkgPath == "" { + fields = append(fields, field) + } + } + return fields +} + +func generateGetterMethod(t reflect.Type, params methodParams) { + fmt.Printf("// Get%s returns the %s field\n", params.fieldName, params.fieldName) + + returnType := params.fieldType + if params.messageField { + returnType = "*diodepb." + params.fieldType + if params.nestedFieldName != "" { + returnType = "*diodepb." + params.nestedMessageName + } + if params.repeated { + returnType = "[]*diodepb." + params.repeatedFieldType + } + } else if params.nestedFieldName != "" { + returnType = "*diodepb." + params.nestedMessageName + } else if params.pointer { + returnType = "*" + params.fieldType + } + + fmt.Printf("func (e *%s) Get%s() %s {\n", t.Name(), params.fieldName, returnType) + if params.messageField { + if !params.repeated { + fmt.Printf("\tif e != nil && e.%s != nil {\n", params.fieldName) + if params.nestedFieldName != "" { + fmt.Printf("\t\treturn &diodepb.%s{\n", params.nestedMessageName) + fmt.Printf("\t\t\t%s: e.%s.ConvertToProtoMessage().(*diodepb.%s),\n", params.nestedFieldName, params.fieldName, params.nestedFieldName) + fmt.Printf("\t\t}\n") + } else { + fmt.Printf("\t\treturn e.%s.ConvertToProtoMessage().(*diodepb.%s)\n", params.fieldName, params.fieldType) + } + fmt.Printf("\t}\n") + fmt.Printf("\treturn nil\n") + } else { + sliceVarName := strings.ToLower(params.fieldName) + fmt.Printf("\tvar %s []*diodepb.%s\n", sliceVarName, params.repeatedFieldType) + fmt.Printf("\tfor _, el := range e.%s {\n", params.fieldName) + fmt.Printf("\t\t%s = append(%s, el.ConvertToProtoMessage().(*diodepb.%s))\n", sliceVarName, sliceVarName, params.repeatedFieldType) + fmt.Printf("\t}\n") + fmt.Printf("\treturn %s\n", sliceVarName) + } + } else if params.pointer { + fmt.Printf("\tif e != nil && e.%s != nil {\n", params.fieldName) + if params.nestedFieldName != "" { + fmt.Printf("\t\treturn *diodepb.%s{\n", params.nestedFieldName) + fmt.Printf("\t\t\t%s: e.%s.ConvertToProtoMessage().(*diodepb.%s),\n", params.nestedFieldName, params.fieldName, params.nestedFieldName) + fmt.Printf("\t\t}\n") + } else { + fmt.Printf("\t\treturn e.%s\n", params.fieldName) + } + fmt.Printf("\t}\n") + fmt.Printf("\treturn nil\n") + } else { + fmt.Printf("\tif e != nil && e.%s != nil {\n", params.fieldName) + fmt.Printf("\t\treturn *e.%s\n", params.fieldName) + fmt.Printf("\t}\n") + fmt.Printf("\treturn \"\"\n") + } + fmt.Printf("}\n\n") +}