Add Galaxy repository API and clients
This commit is contained in:
@@ -84,6 +84,87 @@ goroutine cleanup. Raw protobuf messages remain available through the
|
||||
`errors.As` for `GatewayError`, `CommandError`, and `MxAccessError`; command
|
||||
errors preserve the raw reply.
|
||||
|
||||
## Galaxy Repository browse
|
||||
|
||||
The `GalaxyRepository` service (proto package `galaxy_repository.v1`) is a
|
||||
read-only metadata-only browse over the AVEVA System Platform Galaxy
|
||||
Repository. It uses the same API-key authentication as the MXAccess Gateway
|
||||
and requires the `metadata:read` scope. Use `mxgateway.DialGalaxy` to obtain a
|
||||
`*GalaxyClient` that mirrors the connection-management conventions of
|
||||
`Client`:
|
||||
|
||||
```go
|
||||
galaxy, err := mxgateway.DialGalaxy(ctx, mxgateway.Options{
|
||||
Endpoint: "localhost:5000",
|
||||
APIKey: os.Getenv("MXGATEWAY_API_KEY"),
|
||||
Plaintext: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer galaxy.Close()
|
||||
|
||||
ok, err := galaxy.TestConnection(ctx)
|
||||
deployTime, present, err := galaxy.GetLastDeployTime(ctx)
|
||||
objects, err := galaxy.DiscoverHierarchy(ctx)
|
||||
```
|
||||
|
||||
`GetLastDeployTime` returns `(time.Time{}, false, nil)` when the server
|
||||
reports `present=false` (no deploy recorded). `DiscoverHierarchy` returns
|
||||
the generated `*GalaxyObject` slice with each object's dynamic attributes
|
||||
populated for direct contract access.
|
||||
|
||||
### Watching deploy events
|
||||
|
||||
`WatchDeployEvents` opens a server-streaming subscription. The server emits a
|
||||
bootstrap event with the current Galaxy state immediately on subscribe, then
|
||||
one `DeployEvent` per new deploy. `Sequence` is monotonic per server start;
|
||||
gaps signal dropped events. Pass a non-nil `lastSeenDeployTime` to suppress the
|
||||
bootstrap event when resuming from a known checkpoint:
|
||||
|
||||
```go
|
||||
streamCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
events, errs, err := galaxy.WatchDeployEvents(streamCtx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
case ev, ok := <-events:
|
||||
if !ok {
|
||||
return nil // stream completed (server EOF or ctx cancelled)
|
||||
}
|
||||
log.Printf("seq=%d objects=%d attrs=%d",
|
||||
ev.GetSequence(), ev.GetObjectCount(), ev.GetAttributeCount())
|
||||
case streamErr := <-errs:
|
||||
if streamErr != nil {
|
||||
return streamErr // *GatewayError
|
||||
}
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Cancel the supplied context to tear down the stream cleanly. Both channels
|
||||
close after EOF, cancellation, or a terminal error; surfaced errors are wrapped
|
||||
in `*GatewayError`.
|
||||
|
||||
The CLI exposes the same RPC via `galaxy-watch`:
|
||||
|
||||
```powershell
|
||||
go run ./cmd/mxgw-go galaxy-watch -plaintext
|
||||
go run ./cmd/mxgw-go galaxy-watch -plaintext -json
|
||||
go run ./cmd/mxgw-go galaxy-watch -plaintext -last-seen-deploy-time 2026-04-28T10:00:00Z
|
||||
go run ./cmd/mxgw-go galaxy-watch -plaintext -limit 5
|
||||
```
|
||||
|
||||
The command runs until Ctrl+C (or the optional `-limit` is reached) and prints
|
||||
one line per event in text mode or one JSON object per event with `-json`.
|
||||
|
||||
## CLI
|
||||
|
||||
The `mxgw-go` CLI emits JSON with redacted API keys for commands that connect to
|
||||
@@ -98,6 +179,10 @@ go run ./cmd/mxgw-go advise -session-id <id> -server-handle 1 -item-handle 1 -pl
|
||||
go run ./cmd/mxgw-go write -session-id <id> -server-handle 1 -item-handle 1 -type int32 -value 123 -plaintext -json
|
||||
go run ./cmd/mxgw-go stream-events -session-id <id> -plaintext -json
|
||||
go run ./cmd/mxgw-go smoke -item Area001.Tag.Value -plaintext -json
|
||||
go run ./cmd/mxgw-go galaxy-test-connection -plaintext -json
|
||||
go run ./cmd/mxgw-go galaxy-last-deploy -plaintext -json
|
||||
go run ./cmd/mxgw-go galaxy-discover -plaintext -json
|
||||
go run ./cmd/mxgw-go galaxy-watch -plaintext -json
|
||||
```
|
||||
|
||||
Use `-api-key-env MXGATEWAY_API_KEY` or `-api-key <key>` when authentication is
|
||||
|
||||
@@ -8,8 +8,10 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"gitea.dohertylan.com/dohertj2/mxaccessgw/clients/go/mxgateway"
|
||||
@@ -88,6 +90,14 @@ func runWithIO(ctx context.Context, args []string, stdout, stderr io.Writer) err
|
||||
return runStreamEvents(ctx, args[1:], stdout, stderr)
|
||||
case "smoke":
|
||||
return runSmoke(ctx, args[1:], stdout, stderr)
|
||||
case "galaxy-test-connection":
|
||||
return runGalaxyTestConnection(ctx, args[1:], stdout, stderr)
|
||||
case "galaxy-last-deploy":
|
||||
return runGalaxyLastDeploy(ctx, args[1:], stdout, stderr)
|
||||
case "galaxy-discover":
|
||||
return runGalaxyDiscover(ctx, args[1:], stdout, stderr)
|
||||
case "galaxy-watch":
|
||||
return runGalaxyWatch(ctx, args[1:], stdout, stderr)
|
||||
default:
|
||||
writeUsage(stderr)
|
||||
return fmt.Errorf("unknown command %q", args[0])
|
||||
@@ -651,5 +661,226 @@ type protojsonMessage interface {
|
||||
}
|
||||
|
||||
func writeUsage(writer io.Writer) {
|
||||
fmt.Fprintln(writer, "usage: mxgw-go <version|open-session|close-session|register|add-item|advise|subscribe-bulk|unsubscribe-bulk|write|stream-events|smoke>")
|
||||
fmt.Fprintln(writer, "usage: mxgw-go <version|open-session|close-session|register|add-item|advise|subscribe-bulk|unsubscribe-bulk|write|stream-events|smoke|galaxy-test-connection|galaxy-last-deploy|galaxy-discover|galaxy-watch>")
|
||||
}
|
||||
|
||||
func dialGalaxyForCommand(ctx context.Context, common *commonOptions) (*mxgateway.GalaxyClient, commonOptions, error) {
|
||||
options, err := common.resolved()
|
||||
if err != nil {
|
||||
return nil, options, err
|
||||
}
|
||||
|
||||
client, err := mxgateway.DialGalaxy(ctx, mxgateway.Options{
|
||||
Endpoint: options.Endpoint,
|
||||
APIKey: options.apiKeyValue,
|
||||
Plaintext: options.Plaintext,
|
||||
CACertFile: options.CACertFile,
|
||||
ServerNameOverride: options.ServerName,
|
||||
CallTimeout: options.timeout,
|
||||
})
|
||||
return client, options, err
|
||||
}
|
||||
|
||||
func runGalaxyTestConnection(ctx context.Context, args []string, stdout, stderr io.Writer) error {
|
||||
flags := flag.NewFlagSet("galaxy-test-connection", flag.ContinueOnError)
|
||||
flags.SetOutput(stderr)
|
||||
common := bindCommonFlags(flags)
|
||||
jsonOutput := flags.Bool("json", false, "write JSON output")
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, options, err := dialGalaxyForCommand(ctx, common)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
ok, err := client.TestConnection(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *jsonOutput {
|
||||
return writeJSON(stdout, map[string]any{
|
||||
"command": "galaxy-test-connection",
|
||||
"options": options,
|
||||
"ok": ok,
|
||||
})
|
||||
}
|
||||
fmt.Fprintln(stdout, ok)
|
||||
return nil
|
||||
}
|
||||
|
||||
func runGalaxyLastDeploy(ctx context.Context, args []string, stdout, stderr io.Writer) error {
|
||||
flags := flag.NewFlagSet("galaxy-last-deploy", flag.ContinueOnError)
|
||||
flags.SetOutput(stderr)
|
||||
common := bindCommonFlags(flags)
|
||||
jsonOutput := flags.Bool("json", false, "write JSON output")
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, options, err := dialGalaxyForCommand(ctx, common)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
deployTime, present, err := client.GetLastDeployTime(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *jsonOutput {
|
||||
payload := map[string]any{
|
||||
"command": "galaxy-last-deploy",
|
||||
"options": options,
|
||||
"present": present,
|
||||
}
|
||||
if present {
|
||||
payload["timeOfLastDeploy"] = deployTime.UTC().Format(time.RFC3339Nano)
|
||||
}
|
||||
return writeJSON(stdout, payload)
|
||||
}
|
||||
if !present {
|
||||
fmt.Fprintln(stdout, "absent")
|
||||
return nil
|
||||
}
|
||||
fmt.Fprintln(stdout, deployTime.UTC().Format(time.RFC3339Nano))
|
||||
return nil
|
||||
}
|
||||
|
||||
func runGalaxyDiscover(ctx context.Context, args []string, stdout, stderr io.Writer) error {
|
||||
flags := flag.NewFlagSet("galaxy-discover", flag.ContinueOnError)
|
||||
flags.SetOutput(stderr)
|
||||
common := bindCommonFlags(flags)
|
||||
jsonOutput := flags.Bool("json", false, "write JSON output")
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, options, err := dialGalaxyForCommand(ctx, common)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
objects, err := client.DiscoverHierarchy(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *jsonOutput {
|
||||
marshaled := make([]json.RawMessage, 0, len(objects))
|
||||
for _, obj := range objects {
|
||||
marshaled = append(marshaled, mustMarshalProto(obj))
|
||||
}
|
||||
return writeJSON(stdout, map[string]any{
|
||||
"command": "galaxy-discover",
|
||||
"options": options,
|
||||
"objects": marshaled,
|
||||
})
|
||||
}
|
||||
for _, obj := range objects {
|
||||
fmt.Fprintf(stdout, "%d\t%s\t%s\t(attrs=%d)\n", obj.GetGobjectId(), obj.GetTagName(), obj.GetContainedName(), len(obj.GetAttributes()))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func runGalaxyWatch(ctx context.Context, args []string, stdout, stderr io.Writer) error {
|
||||
flags := flag.NewFlagSet("galaxy-watch", flag.ContinueOnError)
|
||||
flags.SetOutput(stderr)
|
||||
common := bindCommonFlags(flags)
|
||||
jsonOutput := flags.Bool("json", false, "write JSON output")
|
||||
lastSeen := flags.String("last-seen-deploy-time", "", "RFC3339 timestamp; when set, suppresses the bootstrap event")
|
||||
limit := flags.Int("limit", 0, "maximum events to read; 0 means unbounded (Ctrl+C to stop)")
|
||||
|
||||
if err := flags.Parse(args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var lastSeenPtr *time.Time
|
||||
if *lastSeen != "" {
|
||||
parsed, err := time.Parse(time.RFC3339, *lastSeen)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid -last-seen-deploy-time: %w", err)
|
||||
}
|
||||
lastSeenPtr = &parsed
|
||||
}
|
||||
|
||||
client, _, err := dialGalaxyForCommand(ctx, common)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
signalCtx, stopSignals := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
|
||||
defer stopSignals()
|
||||
|
||||
streamCtx, cancelStream := context.WithCancel(signalCtx)
|
||||
defer cancelStream()
|
||||
|
||||
events, errs, err := client.WatchDeployEvents(streamCtx, lastSeenPtr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
count := 0
|
||||
for {
|
||||
select {
|
||||
case event, ok := <-events:
|
||||
if !ok {
|
||||
// Drain any terminal error before returning.
|
||||
if streamErr, errOk := <-errs; errOk && streamErr != nil {
|
||||
return streamErr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if *jsonOutput {
|
||||
fmt.Fprintln(stdout, string(mustMarshalProto(event)))
|
||||
} else {
|
||||
fmt.Fprintln(stdout, formatDeployEvent(event))
|
||||
}
|
||||
count++
|
||||
if *limit > 0 && count >= *limit {
|
||||
cancelStream()
|
||||
return nil
|
||||
}
|
||||
case streamErr, ok := <-errs:
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if streamErr != nil {
|
||||
return streamErr
|
||||
}
|
||||
case <-signalCtx.Done():
|
||||
cancelStream()
|
||||
// Allow goroutine to drain.
|
||||
for range events {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func formatDeployEvent(event *mxgateway.DeployEvent) string {
|
||||
observed := ""
|
||||
if ts := event.GetObservedAt(); ts != nil {
|
||||
observed = ts.AsTime().UTC().Format(time.RFC3339Nano)
|
||||
}
|
||||
deploy := "absent"
|
||||
if event.GetTimeOfLastDeployPresent() {
|
||||
if ts := event.GetTimeOfLastDeploy(); ts != nil {
|
||||
deploy = ts.AsTime().UTC().Format(time.RFC3339Nano)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf(
|
||||
"seq=%d observed=%s deploy=%s objects=%d attributes=%d",
|
||||
event.GetSequence(),
|
||||
observed,
|
||||
deploy,
|
||||
event.GetObjectCount(),
|
||||
event.GetAttributeCount(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -30,13 +30,17 @@ $env:Path = "$goPluginPath;$env:Path"
|
||||
--go_opt=paths=source_relative `
|
||||
"--go_opt=Mmxaccess_gateway.proto=$modulePath;generated" `
|
||||
"--go_opt=Mmxaccess_worker.proto=$modulePath;generated" `
|
||||
"--go_opt=Mgalaxy_repository.proto=$modulePath;generated" `
|
||||
mxaccess_gateway.proto `
|
||||
mxaccess_worker.proto
|
||||
mxaccess_worker.proto `
|
||||
galaxy_repository.proto
|
||||
|
||||
& $protoc `
|
||||
--proto_path=$protoRoot `
|
||||
--go-grpc_out=$outputRoot `
|
||||
--go-grpc_opt=paths=source_relative `
|
||||
"--go-grpc_opt=Mmxaccess_gateway.proto=$modulePath;generated" `
|
||||
mxaccess_gateway.proto
|
||||
"--go-grpc_opt=Mgalaxy_repository.proto=$modulePath;generated" `
|
||||
mxaccess_gateway.proto `
|
||||
galaxy_repository.proto
|
||||
|
||||
|
||||
@@ -0,0 +1,778 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v7.34.1
|
||||
// source: galaxy_repository.proto
|
||||
|
||||
package generated
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type TestConnectionRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TestConnectionRequest) Reset() {
|
||||
*x = TestConnectionRequest{}
|
||||
mi := &file_galaxy_repository_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TestConnectionRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TestConnectionRequest) ProtoMessage() {}
|
||||
|
||||
func (x *TestConnectionRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_galaxy_repository_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TestConnectionRequest.ProtoReflect.Descriptor instead.
|
||||
func (*TestConnectionRequest) Descriptor() ([]byte, []int) {
|
||||
return file_galaxy_repository_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type TestConnectionReply struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Ok bool `protobuf:"varint,1,opt,name=ok,proto3" json:"ok,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *TestConnectionReply) Reset() {
|
||||
*x = TestConnectionReply{}
|
||||
mi := &file_galaxy_repository_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *TestConnectionReply) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*TestConnectionReply) ProtoMessage() {}
|
||||
|
||||
func (x *TestConnectionReply) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_galaxy_repository_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use TestConnectionReply.ProtoReflect.Descriptor instead.
|
||||
func (*TestConnectionReply) Descriptor() ([]byte, []int) {
|
||||
return file_galaxy_repository_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *TestConnectionReply) GetOk() bool {
|
||||
if x != nil {
|
||||
return x.Ok
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type GetLastDeployTimeRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetLastDeployTimeRequest) Reset() {
|
||||
*x = GetLastDeployTimeRequest{}
|
||||
mi := &file_galaxy_repository_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetLastDeployTimeRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetLastDeployTimeRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetLastDeployTimeRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_galaxy_repository_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GetLastDeployTimeRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetLastDeployTimeRequest) Descriptor() ([]byte, []int) {
|
||||
return file_galaxy_repository_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
type GetLastDeployTimeReply struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Present bool `protobuf:"varint,1,opt,name=present,proto3" json:"present,omitempty"`
|
||||
TimeOfLastDeploy *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=time_of_last_deploy,json=timeOfLastDeploy,proto3" json:"time_of_last_deploy,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GetLastDeployTimeReply) Reset() {
|
||||
*x = GetLastDeployTimeReply{}
|
||||
mi := &file_galaxy_repository_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetLastDeployTimeReply) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetLastDeployTimeReply) ProtoMessage() {}
|
||||
|
||||
func (x *GetLastDeployTimeReply) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_galaxy_repository_proto_msgTypes[3]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GetLastDeployTimeReply.ProtoReflect.Descriptor instead.
|
||||
func (*GetLastDeployTimeReply) Descriptor() ([]byte, []int) {
|
||||
return file_galaxy_repository_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *GetLastDeployTimeReply) GetPresent() bool {
|
||||
if x != nil {
|
||||
return x.Present
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *GetLastDeployTimeReply) GetTimeOfLastDeploy() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.TimeOfLastDeploy
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DiscoverHierarchyRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *DiscoverHierarchyRequest) Reset() {
|
||||
*x = DiscoverHierarchyRequest{}
|
||||
mi := &file_galaxy_repository_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *DiscoverHierarchyRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DiscoverHierarchyRequest) ProtoMessage() {}
|
||||
|
||||
func (x *DiscoverHierarchyRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_galaxy_repository_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DiscoverHierarchyRequest.ProtoReflect.Descriptor instead.
|
||||
func (*DiscoverHierarchyRequest) Descriptor() ([]byte, []int) {
|
||||
return file_galaxy_repository_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
type DiscoverHierarchyReply struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Objects []*GalaxyObject `protobuf:"bytes,1,rep,name=objects,proto3" json:"objects,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *DiscoverHierarchyReply) Reset() {
|
||||
*x = DiscoverHierarchyReply{}
|
||||
mi := &file_galaxy_repository_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *DiscoverHierarchyReply) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DiscoverHierarchyReply) ProtoMessage() {}
|
||||
|
||||
func (x *DiscoverHierarchyReply) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_galaxy_repository_proto_msgTypes[5]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DiscoverHierarchyReply.ProtoReflect.Descriptor instead.
|
||||
func (*DiscoverHierarchyReply) Descriptor() ([]byte, []int) {
|
||||
return file_galaxy_repository_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *DiscoverHierarchyReply) GetObjects() []*GalaxyObject {
|
||||
if x != nil {
|
||||
return x.Objects
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type WatchDeployEventsRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Optional. When set, the bootstrap event is suppressed if the cached deploy
|
||||
// time matches this value. Future events are still emitted normally.
|
||||
LastSeenDeployTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=last_seen_deploy_time,json=lastSeenDeployTime,proto3" json:"last_seen_deploy_time,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *WatchDeployEventsRequest) Reset() {
|
||||
*x = WatchDeployEventsRequest{}
|
||||
mi := &file_galaxy_repository_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *WatchDeployEventsRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*WatchDeployEventsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *WatchDeployEventsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_galaxy_repository_proto_msgTypes[6]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use WatchDeployEventsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*WatchDeployEventsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_galaxy_repository_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *WatchDeployEventsRequest) GetLastSeenDeployTime() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.LastSeenDeployTime
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DeployEvent struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Monotonically increasing per server start. Gaps indicate dropped events.
|
||||
Sequence uint64 `protobuf:"varint,1,opt,name=sequence,proto3" json:"sequence,omitempty"`
|
||||
// Server wall-clock when the cache observed the deploy.
|
||||
ObservedAt *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=observed_at,json=observedAt,proto3" json:"observed_at,omitempty"`
|
||||
// Galaxy.time_of_last_deploy. Absent only when the Galaxy table reports null.
|
||||
TimeOfLastDeploy *timestamppb.Timestamp `protobuf:"bytes,3,opt,name=time_of_last_deploy,json=timeOfLastDeploy,proto3" json:"time_of_last_deploy,omitempty"`
|
||||
TimeOfLastDeployPresent bool `protobuf:"varint,4,opt,name=time_of_last_deploy_present,json=timeOfLastDeployPresent,proto3" json:"time_of_last_deploy_present,omitempty"`
|
||||
ObjectCount int32 `protobuf:"varint,5,opt,name=object_count,json=objectCount,proto3" json:"object_count,omitempty"`
|
||||
AttributeCount int32 `protobuf:"varint,6,opt,name=attribute_count,json=attributeCount,proto3" json:"attribute_count,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *DeployEvent) Reset() {
|
||||
*x = DeployEvent{}
|
||||
mi := &file_galaxy_repository_proto_msgTypes[7]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *DeployEvent) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*DeployEvent) ProtoMessage() {}
|
||||
|
||||
func (x *DeployEvent) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_galaxy_repository_proto_msgTypes[7]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use DeployEvent.ProtoReflect.Descriptor instead.
|
||||
func (*DeployEvent) Descriptor() ([]byte, []int) {
|
||||
return file_galaxy_repository_proto_rawDescGZIP(), []int{7}
|
||||
}
|
||||
|
||||
func (x *DeployEvent) GetSequence() uint64 {
|
||||
if x != nil {
|
||||
return x.Sequence
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *DeployEvent) GetObservedAt() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.ObservedAt
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *DeployEvent) GetTimeOfLastDeploy() *timestamppb.Timestamp {
|
||||
if x != nil {
|
||||
return x.TimeOfLastDeploy
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *DeployEvent) GetTimeOfLastDeployPresent() bool {
|
||||
if x != nil {
|
||||
return x.TimeOfLastDeployPresent
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *DeployEvent) GetObjectCount() int32 {
|
||||
if x != nil {
|
||||
return x.ObjectCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *DeployEvent) GetAttributeCount() int32 {
|
||||
if x != nil {
|
||||
return x.AttributeCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type GalaxyObject struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
GobjectId int32 `protobuf:"varint,1,opt,name=gobject_id,json=gobjectId,proto3" json:"gobject_id,omitempty"`
|
||||
TagName string `protobuf:"bytes,2,opt,name=tag_name,json=tagName,proto3" json:"tag_name,omitempty"`
|
||||
ContainedName string `protobuf:"bytes,3,opt,name=contained_name,json=containedName,proto3" json:"contained_name,omitempty"`
|
||||
BrowseName string `protobuf:"bytes,4,opt,name=browse_name,json=browseName,proto3" json:"browse_name,omitempty"`
|
||||
ParentGobjectId int32 `protobuf:"varint,5,opt,name=parent_gobject_id,json=parentGobjectId,proto3" json:"parent_gobject_id,omitempty"`
|
||||
IsArea bool `protobuf:"varint,6,opt,name=is_area,json=isArea,proto3" json:"is_area,omitempty"`
|
||||
CategoryId int32 `protobuf:"varint,7,opt,name=category_id,json=categoryId,proto3" json:"category_id,omitempty"`
|
||||
HostedByGobjectId int32 `protobuf:"varint,8,opt,name=hosted_by_gobject_id,json=hostedByGobjectId,proto3" json:"hosted_by_gobject_id,omitempty"`
|
||||
TemplateChain []string `protobuf:"bytes,9,rep,name=template_chain,json=templateChain,proto3" json:"template_chain,omitempty"`
|
||||
Attributes []*GalaxyAttribute `protobuf:"bytes,10,rep,name=attributes,proto3" json:"attributes,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GalaxyObject) Reset() {
|
||||
*x = GalaxyObject{}
|
||||
mi := &file_galaxy_repository_proto_msgTypes[8]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GalaxyObject) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GalaxyObject) ProtoMessage() {}
|
||||
|
||||
func (x *GalaxyObject) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_galaxy_repository_proto_msgTypes[8]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GalaxyObject.ProtoReflect.Descriptor instead.
|
||||
func (*GalaxyObject) Descriptor() ([]byte, []int) {
|
||||
return file_galaxy_repository_proto_rawDescGZIP(), []int{8}
|
||||
}
|
||||
|
||||
func (x *GalaxyObject) GetGobjectId() int32 {
|
||||
if x != nil {
|
||||
return x.GobjectId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GalaxyObject) GetTagName() string {
|
||||
if x != nil {
|
||||
return x.TagName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GalaxyObject) GetContainedName() string {
|
||||
if x != nil {
|
||||
return x.ContainedName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GalaxyObject) GetBrowseName() string {
|
||||
if x != nil {
|
||||
return x.BrowseName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GalaxyObject) GetParentGobjectId() int32 {
|
||||
if x != nil {
|
||||
return x.ParentGobjectId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GalaxyObject) GetIsArea() bool {
|
||||
if x != nil {
|
||||
return x.IsArea
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *GalaxyObject) GetCategoryId() int32 {
|
||||
if x != nil {
|
||||
return x.CategoryId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GalaxyObject) GetHostedByGobjectId() int32 {
|
||||
if x != nil {
|
||||
return x.HostedByGobjectId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GalaxyObject) GetTemplateChain() []string {
|
||||
if x != nil {
|
||||
return x.TemplateChain
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *GalaxyObject) GetAttributes() []*GalaxyAttribute {
|
||||
if x != nil {
|
||||
return x.Attributes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GalaxyAttribute struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
AttributeName string `protobuf:"bytes,1,opt,name=attribute_name,json=attributeName,proto3" json:"attribute_name,omitempty"`
|
||||
FullTagReference string `protobuf:"bytes,2,opt,name=full_tag_reference,json=fullTagReference,proto3" json:"full_tag_reference,omitempty"`
|
||||
MxDataType int32 `protobuf:"varint,3,opt,name=mx_data_type,json=mxDataType,proto3" json:"mx_data_type,omitempty"`
|
||||
DataTypeName string `protobuf:"bytes,4,opt,name=data_type_name,json=dataTypeName,proto3" json:"data_type_name,omitempty"`
|
||||
IsArray bool `protobuf:"varint,5,opt,name=is_array,json=isArray,proto3" json:"is_array,omitempty"`
|
||||
ArrayDimension int32 `protobuf:"varint,6,opt,name=array_dimension,json=arrayDimension,proto3" json:"array_dimension,omitempty"`
|
||||
ArrayDimensionPresent bool `protobuf:"varint,7,opt,name=array_dimension_present,json=arrayDimensionPresent,proto3" json:"array_dimension_present,omitempty"`
|
||||
MxAttributeCategory int32 `protobuf:"varint,8,opt,name=mx_attribute_category,json=mxAttributeCategory,proto3" json:"mx_attribute_category,omitempty"`
|
||||
SecurityClassification int32 `protobuf:"varint,9,opt,name=security_classification,json=securityClassification,proto3" json:"security_classification,omitempty"`
|
||||
IsHistorized bool `protobuf:"varint,10,opt,name=is_historized,json=isHistorized,proto3" json:"is_historized,omitempty"`
|
||||
IsAlarm bool `protobuf:"varint,11,opt,name=is_alarm,json=isAlarm,proto3" json:"is_alarm,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) Reset() {
|
||||
*x = GalaxyAttribute{}
|
||||
mi := &file_galaxy_repository_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GalaxyAttribute) ProtoMessage() {}
|
||||
|
||||
func (x *GalaxyAttribute) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_galaxy_repository_proto_msgTypes[9]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GalaxyAttribute.ProtoReflect.Descriptor instead.
|
||||
func (*GalaxyAttribute) Descriptor() ([]byte, []int) {
|
||||
return file_galaxy_repository_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) GetAttributeName() string {
|
||||
if x != nil {
|
||||
return x.AttributeName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) GetFullTagReference() string {
|
||||
if x != nil {
|
||||
return x.FullTagReference
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) GetMxDataType() int32 {
|
||||
if x != nil {
|
||||
return x.MxDataType
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) GetDataTypeName() string {
|
||||
if x != nil {
|
||||
return x.DataTypeName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) GetIsArray() bool {
|
||||
if x != nil {
|
||||
return x.IsArray
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) GetArrayDimension() int32 {
|
||||
if x != nil {
|
||||
return x.ArrayDimension
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) GetArrayDimensionPresent() bool {
|
||||
if x != nil {
|
||||
return x.ArrayDimensionPresent
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) GetMxAttributeCategory() int32 {
|
||||
if x != nil {
|
||||
return x.MxAttributeCategory
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) GetSecurityClassification() int32 {
|
||||
if x != nil {
|
||||
return x.SecurityClassification
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) GetIsHistorized() bool {
|
||||
if x != nil {
|
||||
return x.IsHistorized
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *GalaxyAttribute) GetIsAlarm() bool {
|
||||
if x != nil {
|
||||
return x.IsAlarm
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var File_galaxy_repository_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_galaxy_repository_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x17galaxy_repository.proto\x12\x14galaxy_repository.v1\x1a\x1fgoogle/protobuf/timestamp.proto\"\x17\n" +
|
||||
"\x15TestConnectionRequest\"%\n" +
|
||||
"\x13TestConnectionReply\x12\x0e\n" +
|
||||
"\x02ok\x18\x01 \x01(\bR\x02ok\"\x1a\n" +
|
||||
"\x18GetLastDeployTimeRequest\"}\n" +
|
||||
"\x16GetLastDeployTimeReply\x12\x18\n" +
|
||||
"\apresent\x18\x01 \x01(\bR\apresent\x12I\n" +
|
||||
"\x13time_of_last_deploy\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\x10timeOfLastDeploy\"\x1a\n" +
|
||||
"\x18DiscoverHierarchyRequest\"V\n" +
|
||||
"\x16DiscoverHierarchyReply\x12<\n" +
|
||||
"\aobjects\x18\x01 \x03(\v2\".galaxy_repository.v1.GalaxyObjectR\aobjects\"i\n" +
|
||||
"\x18WatchDeployEventsRequest\x12M\n" +
|
||||
"\x15last_seen_deploy_time\x18\x01 \x01(\v2\x1a.google.protobuf.TimestampR\x12lastSeenDeployTime\"\xbb\x02\n" +
|
||||
"\vDeployEvent\x12\x1a\n" +
|
||||
"\bsequence\x18\x01 \x01(\x04R\bsequence\x12;\n" +
|
||||
"\vobserved_at\x18\x02 \x01(\v2\x1a.google.protobuf.TimestampR\n" +
|
||||
"observedAt\x12I\n" +
|
||||
"\x13time_of_last_deploy\x18\x03 \x01(\v2\x1a.google.protobuf.TimestampR\x10timeOfLastDeploy\x12<\n" +
|
||||
"\x1btime_of_last_deploy_present\x18\x04 \x01(\bR\x17timeOfLastDeployPresent\x12!\n" +
|
||||
"\fobject_count\x18\x05 \x01(\x05R\vobjectCount\x12'\n" +
|
||||
"\x0fattribute_count\x18\x06 \x01(\x05R\x0eattributeCount\"\x95\x03\n" +
|
||||
"\fGalaxyObject\x12\x1d\n" +
|
||||
"\n" +
|
||||
"gobject_id\x18\x01 \x01(\x05R\tgobjectId\x12\x19\n" +
|
||||
"\btag_name\x18\x02 \x01(\tR\atagName\x12%\n" +
|
||||
"\x0econtained_name\x18\x03 \x01(\tR\rcontainedName\x12\x1f\n" +
|
||||
"\vbrowse_name\x18\x04 \x01(\tR\n" +
|
||||
"browseName\x12*\n" +
|
||||
"\x11parent_gobject_id\x18\x05 \x01(\x05R\x0fparentGobjectId\x12\x17\n" +
|
||||
"\ais_area\x18\x06 \x01(\bR\x06isArea\x12\x1f\n" +
|
||||
"\vcategory_id\x18\a \x01(\x05R\n" +
|
||||
"categoryId\x12/\n" +
|
||||
"\x14hosted_by_gobject_id\x18\b \x01(\x05R\x11hostedByGobjectId\x12%\n" +
|
||||
"\x0etemplate_chain\x18\t \x03(\tR\rtemplateChain\x12E\n" +
|
||||
"\n" +
|
||||
"attributes\x18\n" +
|
||||
" \x03(\v2%.galaxy_repository.v1.GalaxyAttributeR\n" +
|
||||
"attributes\"\xd7\x03\n" +
|
||||
"\x0fGalaxyAttribute\x12%\n" +
|
||||
"\x0eattribute_name\x18\x01 \x01(\tR\rattributeName\x12,\n" +
|
||||
"\x12full_tag_reference\x18\x02 \x01(\tR\x10fullTagReference\x12 \n" +
|
||||
"\fmx_data_type\x18\x03 \x01(\x05R\n" +
|
||||
"mxDataType\x12$\n" +
|
||||
"\x0edata_type_name\x18\x04 \x01(\tR\fdataTypeName\x12\x19\n" +
|
||||
"\bis_array\x18\x05 \x01(\bR\aisArray\x12'\n" +
|
||||
"\x0farray_dimension\x18\x06 \x01(\x05R\x0earrayDimension\x126\n" +
|
||||
"\x17array_dimension_present\x18\a \x01(\bR\x15arrayDimensionPresent\x122\n" +
|
||||
"\x15mx_attribute_category\x18\b \x01(\x05R\x13mxAttributeCategory\x127\n" +
|
||||
"\x17security_classification\x18\t \x01(\x05R\x16securityClassification\x12#\n" +
|
||||
"\ris_historized\x18\n" +
|
||||
" \x01(\bR\fisHistorized\x12\x19\n" +
|
||||
"\bis_alarm\x18\v \x01(\bR\aisAlarm2\xcc\x03\n" +
|
||||
"\x10GalaxyRepository\x12h\n" +
|
||||
"\x0eTestConnection\x12+.galaxy_repository.v1.TestConnectionRequest\x1a).galaxy_repository.v1.TestConnectionReply\x12q\n" +
|
||||
"\x11GetLastDeployTime\x12..galaxy_repository.v1.GetLastDeployTimeRequest\x1a,.galaxy_repository.v1.GetLastDeployTimeReply\x12q\n" +
|
||||
"\x11DiscoverHierarchy\x12..galaxy_repository.v1.DiscoverHierarchyRequest\x1a,.galaxy_repository.v1.DiscoverHierarchyReply\x12h\n" +
|
||||
"\x11WatchDeployEvents\x12..galaxy_repository.v1.WatchDeployEventsRequest\x1a!.galaxy_repository.v1.DeployEvent0\x01B#\xaa\x02 MxGateway.Contracts.Proto.Galaxyb\x06proto3"
|
||||
|
||||
var (
|
||||
file_galaxy_repository_proto_rawDescOnce sync.Once
|
||||
file_galaxy_repository_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_galaxy_repository_proto_rawDescGZIP() []byte {
|
||||
file_galaxy_repository_proto_rawDescOnce.Do(func() {
|
||||
file_galaxy_repository_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_galaxy_repository_proto_rawDesc), len(file_galaxy_repository_proto_rawDesc)))
|
||||
})
|
||||
return file_galaxy_repository_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_galaxy_repository_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
var file_galaxy_repository_proto_goTypes = []any{
|
||||
(*TestConnectionRequest)(nil), // 0: galaxy_repository.v1.TestConnectionRequest
|
||||
(*TestConnectionReply)(nil), // 1: galaxy_repository.v1.TestConnectionReply
|
||||
(*GetLastDeployTimeRequest)(nil), // 2: galaxy_repository.v1.GetLastDeployTimeRequest
|
||||
(*GetLastDeployTimeReply)(nil), // 3: galaxy_repository.v1.GetLastDeployTimeReply
|
||||
(*DiscoverHierarchyRequest)(nil), // 4: galaxy_repository.v1.DiscoverHierarchyRequest
|
||||
(*DiscoverHierarchyReply)(nil), // 5: galaxy_repository.v1.DiscoverHierarchyReply
|
||||
(*WatchDeployEventsRequest)(nil), // 6: galaxy_repository.v1.WatchDeployEventsRequest
|
||||
(*DeployEvent)(nil), // 7: galaxy_repository.v1.DeployEvent
|
||||
(*GalaxyObject)(nil), // 8: galaxy_repository.v1.GalaxyObject
|
||||
(*GalaxyAttribute)(nil), // 9: galaxy_repository.v1.GalaxyAttribute
|
||||
(*timestamppb.Timestamp)(nil), // 10: google.protobuf.Timestamp
|
||||
}
|
||||
var file_galaxy_repository_proto_depIdxs = []int32{
|
||||
10, // 0: galaxy_repository.v1.GetLastDeployTimeReply.time_of_last_deploy:type_name -> google.protobuf.Timestamp
|
||||
8, // 1: galaxy_repository.v1.DiscoverHierarchyReply.objects:type_name -> galaxy_repository.v1.GalaxyObject
|
||||
10, // 2: galaxy_repository.v1.WatchDeployEventsRequest.last_seen_deploy_time:type_name -> google.protobuf.Timestamp
|
||||
10, // 3: galaxy_repository.v1.DeployEvent.observed_at:type_name -> google.protobuf.Timestamp
|
||||
10, // 4: galaxy_repository.v1.DeployEvent.time_of_last_deploy:type_name -> google.protobuf.Timestamp
|
||||
9, // 5: galaxy_repository.v1.GalaxyObject.attributes:type_name -> galaxy_repository.v1.GalaxyAttribute
|
||||
0, // 6: galaxy_repository.v1.GalaxyRepository.TestConnection:input_type -> galaxy_repository.v1.TestConnectionRequest
|
||||
2, // 7: galaxy_repository.v1.GalaxyRepository.GetLastDeployTime:input_type -> galaxy_repository.v1.GetLastDeployTimeRequest
|
||||
4, // 8: galaxy_repository.v1.GalaxyRepository.DiscoverHierarchy:input_type -> galaxy_repository.v1.DiscoverHierarchyRequest
|
||||
6, // 9: galaxy_repository.v1.GalaxyRepository.WatchDeployEvents:input_type -> galaxy_repository.v1.WatchDeployEventsRequest
|
||||
1, // 10: galaxy_repository.v1.GalaxyRepository.TestConnection:output_type -> galaxy_repository.v1.TestConnectionReply
|
||||
3, // 11: galaxy_repository.v1.GalaxyRepository.GetLastDeployTime:output_type -> galaxy_repository.v1.GetLastDeployTimeReply
|
||||
5, // 12: galaxy_repository.v1.GalaxyRepository.DiscoverHierarchy:output_type -> galaxy_repository.v1.DiscoverHierarchyReply
|
||||
7, // 13: galaxy_repository.v1.GalaxyRepository.WatchDeployEvents:output_type -> galaxy_repository.v1.DeployEvent
|
||||
10, // [10:14] is the sub-list for method output_type
|
||||
6, // [6:10] is the sub-list for method input_type
|
||||
6, // [6:6] is the sub-list for extension type_name
|
||||
6, // [6:6] is the sub-list for extension extendee
|
||||
0, // [0:6] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_galaxy_repository_proto_init() }
|
||||
func file_galaxy_repository_proto_init() {
|
||||
if File_galaxy_repository_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_galaxy_repository_proto_rawDesc), len(file_galaxy_repository_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 10,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_galaxy_repository_proto_goTypes,
|
||||
DependencyIndexes: file_galaxy_repository_proto_depIdxs,
|
||||
MessageInfos: file_galaxy_repository_proto_msgTypes,
|
||||
}.Build()
|
||||
File_galaxy_repository_proto = out.File
|
||||
file_galaxy_repository_proto_goTypes = nil
|
||||
file_galaxy_repository_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.1
|
||||
// - protoc v7.34.1
|
||||
// source: galaxy_repository.proto
|
||||
|
||||
package generated
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
GalaxyRepository_TestConnection_FullMethodName = "/galaxy_repository.v1.GalaxyRepository/TestConnection"
|
||||
GalaxyRepository_GetLastDeployTime_FullMethodName = "/galaxy_repository.v1.GalaxyRepository/GetLastDeployTime"
|
||||
GalaxyRepository_DiscoverHierarchy_FullMethodName = "/galaxy_repository.v1.GalaxyRepository/DiscoverHierarchy"
|
||||
GalaxyRepository_WatchDeployEvents_FullMethodName = "/galaxy_repository.v1.GalaxyRepository/WatchDeployEvents"
|
||||
)
|
||||
|
||||
// GalaxyRepositoryClient is the client API for GalaxyRepository service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// Read-only browse over the AVEVA System Platform Galaxy Repository (ZB SQL
|
||||
// database). Lets clients enumerate the deployed object hierarchy and each
|
||||
// object's dynamic attributes so they know what tag references to subscribe
|
||||
// to via the MxAccessGateway service.
|
||||
type GalaxyRepositoryClient interface {
|
||||
TestConnection(ctx context.Context, in *TestConnectionRequest, opts ...grpc.CallOption) (*TestConnectionReply, error)
|
||||
GetLastDeployTime(ctx context.Context, in *GetLastDeployTimeRequest, opts ...grpc.CallOption) (*GetLastDeployTimeReply, error)
|
||||
DiscoverHierarchy(ctx context.Context, in *DiscoverHierarchyRequest, opts ...grpc.CallOption) (*DiscoverHierarchyReply, error)
|
||||
// Server-stream of deploy events. The server emits the current state immediately
|
||||
// on subscribe (so clients can bootstrap their cache without waiting for the next
|
||||
// deploy), then emits one event each time the gateway's hierarchy cache observes
|
||||
// a new galaxy.time_of_last_deploy. The sequence field is monotonically
|
||||
// increasing per server start; gaps indicate the per-subscriber buffer dropped
|
||||
// older events because the client was too slow.
|
||||
WatchDeployEvents(ctx context.Context, in *WatchDeployEventsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[DeployEvent], error)
|
||||
}
|
||||
|
||||
type galaxyRepositoryClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewGalaxyRepositoryClient(cc grpc.ClientConnInterface) GalaxyRepositoryClient {
|
||||
return &galaxyRepositoryClient{cc}
|
||||
}
|
||||
|
||||
func (c *galaxyRepositoryClient) TestConnection(ctx context.Context, in *TestConnectionRequest, opts ...grpc.CallOption) (*TestConnectionReply, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(TestConnectionReply)
|
||||
err := c.cc.Invoke(ctx, GalaxyRepository_TestConnection_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *galaxyRepositoryClient) GetLastDeployTime(ctx context.Context, in *GetLastDeployTimeRequest, opts ...grpc.CallOption) (*GetLastDeployTimeReply, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetLastDeployTimeReply)
|
||||
err := c.cc.Invoke(ctx, GalaxyRepository_GetLastDeployTime_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *galaxyRepositoryClient) DiscoverHierarchy(ctx context.Context, in *DiscoverHierarchyRequest, opts ...grpc.CallOption) (*DiscoverHierarchyReply, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(DiscoverHierarchyReply)
|
||||
err := c.cc.Invoke(ctx, GalaxyRepository_DiscoverHierarchy_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *galaxyRepositoryClient) WatchDeployEvents(ctx context.Context, in *WatchDeployEventsRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[DeployEvent], error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
stream, err := c.cc.NewStream(ctx, &GalaxyRepository_ServiceDesc.Streams[0], GalaxyRepository_WatchDeployEvents_FullMethodName, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &grpc.GenericClientStream[WatchDeployEventsRequest, DeployEvent]{ClientStream: stream}
|
||||
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := x.ClientStream.CloseSend(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type GalaxyRepository_WatchDeployEventsClient = grpc.ServerStreamingClient[DeployEvent]
|
||||
|
||||
// GalaxyRepositoryServer is the server API for GalaxyRepository service.
|
||||
// All implementations must embed UnimplementedGalaxyRepositoryServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// Read-only browse over the AVEVA System Platform Galaxy Repository (ZB SQL
|
||||
// database). Lets clients enumerate the deployed object hierarchy and each
|
||||
// object's dynamic attributes so they know what tag references to subscribe
|
||||
// to via the MxAccessGateway service.
|
||||
type GalaxyRepositoryServer interface {
|
||||
TestConnection(context.Context, *TestConnectionRequest) (*TestConnectionReply, error)
|
||||
GetLastDeployTime(context.Context, *GetLastDeployTimeRequest) (*GetLastDeployTimeReply, error)
|
||||
DiscoverHierarchy(context.Context, *DiscoverHierarchyRequest) (*DiscoverHierarchyReply, error)
|
||||
// Server-stream of deploy events. The server emits the current state immediately
|
||||
// on subscribe (so clients can bootstrap their cache without waiting for the next
|
||||
// deploy), then emits one event each time the gateway's hierarchy cache observes
|
||||
// a new galaxy.time_of_last_deploy. The sequence field is monotonically
|
||||
// increasing per server start; gaps indicate the per-subscriber buffer dropped
|
||||
// older events because the client was too slow.
|
||||
WatchDeployEvents(*WatchDeployEventsRequest, grpc.ServerStreamingServer[DeployEvent]) error
|
||||
mustEmbedUnimplementedGalaxyRepositoryServer()
|
||||
}
|
||||
|
||||
// UnimplementedGalaxyRepositoryServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedGalaxyRepositoryServer struct{}
|
||||
|
||||
func (UnimplementedGalaxyRepositoryServer) TestConnection(context.Context, *TestConnectionRequest) (*TestConnectionReply, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method TestConnection not implemented")
|
||||
}
|
||||
func (UnimplementedGalaxyRepositoryServer) GetLastDeployTime(context.Context, *GetLastDeployTimeRequest) (*GetLastDeployTimeReply, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetLastDeployTime not implemented")
|
||||
}
|
||||
func (UnimplementedGalaxyRepositoryServer) DiscoverHierarchy(context.Context, *DiscoverHierarchyRequest) (*DiscoverHierarchyReply, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method DiscoverHierarchy not implemented")
|
||||
}
|
||||
func (UnimplementedGalaxyRepositoryServer) WatchDeployEvents(*WatchDeployEventsRequest, grpc.ServerStreamingServer[DeployEvent]) error {
|
||||
return status.Error(codes.Unimplemented, "method WatchDeployEvents not implemented")
|
||||
}
|
||||
func (UnimplementedGalaxyRepositoryServer) mustEmbedUnimplementedGalaxyRepositoryServer() {}
|
||||
func (UnimplementedGalaxyRepositoryServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeGalaxyRepositoryServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to GalaxyRepositoryServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeGalaxyRepositoryServer interface {
|
||||
mustEmbedUnimplementedGalaxyRepositoryServer()
|
||||
}
|
||||
|
||||
func RegisterGalaxyRepositoryServer(s grpc.ServiceRegistrar, srv GalaxyRepositoryServer) {
|
||||
// If the following call panics, it indicates UnimplementedGalaxyRepositoryServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&GalaxyRepository_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _GalaxyRepository_TestConnection_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(TestConnectionRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GalaxyRepositoryServer).TestConnection(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: GalaxyRepository_TestConnection_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GalaxyRepositoryServer).TestConnection(ctx, req.(*TestConnectionRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GalaxyRepository_GetLastDeployTime_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetLastDeployTimeRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GalaxyRepositoryServer).GetLastDeployTime(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: GalaxyRepository_GetLastDeployTime_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GalaxyRepositoryServer).GetLastDeployTime(ctx, req.(*GetLastDeployTimeRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GalaxyRepository_DiscoverHierarchy_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(DiscoverHierarchyRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(GalaxyRepositoryServer).DiscoverHierarchy(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: GalaxyRepository_DiscoverHierarchy_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(GalaxyRepositoryServer).DiscoverHierarchy(ctx, req.(*DiscoverHierarchyRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _GalaxyRepository_WatchDeployEvents_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(WatchDeployEventsRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(GalaxyRepositoryServer).WatchDeployEvents(m, &grpc.GenericServerStream[WatchDeployEventsRequest, DeployEvent]{ServerStream: stream})
|
||||
}
|
||||
|
||||
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||
type GalaxyRepository_WatchDeployEventsServer = grpc.ServerStreamingServer[DeployEvent]
|
||||
|
||||
// GalaxyRepository_ServiceDesc is the grpc.ServiceDesc for GalaxyRepository service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var GalaxyRepository_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "galaxy_repository.v1.GalaxyRepository",
|
||||
HandlerType: (*GalaxyRepositoryServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "TestConnection",
|
||||
Handler: _GalaxyRepository_TestConnection_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetLastDeployTime",
|
||||
Handler: _GalaxyRepository_GetLastDeployTime_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "DiscoverHierarchy",
|
||||
Handler: _GalaxyRepository_DiscoverHierarchy_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
StreamName: "WatchDeployEvents",
|
||||
Handler: _GalaxyRepository_WatchDeployEvents_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "galaxy_repository.proto",
|
||||
}
|
||||
@@ -0,0 +1,246 @@
|
||||
package mxgateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"time"
|
||||
|
||||
pb "gitea.dohertylan.com/dohertj2/mxaccessgw/clients/go/internal/generated"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
// RawGalaxyRepositoryClient is the generated gRPC client interface for the
|
||||
// Galaxy Repository service exposed for callers that need direct contract
|
||||
// access.
|
||||
type RawGalaxyRepositoryClient = pb.GalaxyRepositoryClient
|
||||
|
||||
// Generated protobuf aliases for Galaxy Repository messages.
|
||||
type (
|
||||
TestConnectionRequest = pb.TestConnectionRequest
|
||||
TestConnectionReply = pb.TestConnectionReply
|
||||
GetLastDeployTimeRequest = pb.GetLastDeployTimeRequest
|
||||
GetLastDeployTimeReply = pb.GetLastDeployTimeReply
|
||||
DiscoverHierarchyRequest = pb.DiscoverHierarchyRequest
|
||||
DiscoverHierarchyReply = pb.DiscoverHierarchyReply
|
||||
GalaxyObject = pb.GalaxyObject
|
||||
GalaxyAttribute = pb.GalaxyAttribute
|
||||
WatchDeployEventsRequest = pb.WatchDeployEventsRequest
|
||||
DeployEvent = pb.DeployEvent
|
||||
)
|
||||
|
||||
// RawDeployEventStream is the generated WatchDeployEvents client stream.
|
||||
type RawDeployEventStream = grpc.ServerStreamingClient[pb.DeployEvent]
|
||||
|
||||
// GalaxyClient owns a gateway gRPC connection and exposes Galaxy Repository
|
||||
// browse helpers. It mirrors the structure of Client and uses the same
|
||||
// connection-management conventions.
|
||||
type GalaxyClient struct {
|
||||
conn *grpc.ClientConn
|
||||
raw pb.GalaxyRepositoryClient
|
||||
opts Options
|
||||
}
|
||||
|
||||
// DialGalaxy opens a gRPC connection to the gateway for the Galaxy Repository
|
||||
// service. It applies the same authentication metadata, transport security,
|
||||
// and dial-timeout behavior as Dial.
|
||||
func DialGalaxy(ctx context.Context, opts Options) (*GalaxyClient, error) {
|
||||
if opts.Endpoint == "" {
|
||||
return nil, errors.New("mxgateway: endpoint is required")
|
||||
}
|
||||
|
||||
dialCtx := ctx
|
||||
cancel := func() {}
|
||||
if opts.DialTimeout > 0 {
|
||||
dialCtx, cancel = context.WithTimeout(ctx, opts.DialTimeout)
|
||||
} else if _, ok := ctx.Deadline(); !ok {
|
||||
dialCtx, cancel = context.WithTimeout(ctx, defaultDialTimeout)
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
transportCredentials, err := resolveTransportCredentials(opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
dialOptions := []grpc.DialOption{
|
||||
grpc.WithTransportCredentials(transportCredentials),
|
||||
grpc.WithUnaryInterceptor(unaryAuthInterceptor(opts.APIKey)),
|
||||
grpc.WithStreamInterceptor(streamAuthInterceptor(opts.APIKey)),
|
||||
grpc.WithBlock(),
|
||||
}
|
||||
dialOptions = append(dialOptions, opts.DialOptions...)
|
||||
|
||||
conn, err := grpc.DialContext(dialCtx, opts.Endpoint, dialOptions...)
|
||||
if err != nil {
|
||||
return nil, &GatewayError{Op: "dial", Err: err}
|
||||
}
|
||||
|
||||
return NewGalaxyClient(conn, opts), nil
|
||||
}
|
||||
|
||||
// NewGalaxyClient wraps an existing gRPC connection for Galaxy Repository
|
||||
// access. The caller owns closing conn unless it calls Close on the returned
|
||||
// GalaxyClient.
|
||||
func NewGalaxyClient(conn *grpc.ClientConn, opts Options) *GalaxyClient {
|
||||
return &GalaxyClient{
|
||||
conn: conn,
|
||||
raw: pb.NewGalaxyRepositoryClient(conn),
|
||||
opts: opts,
|
||||
}
|
||||
}
|
||||
|
||||
// RawClient returns the generated gRPC client for command-specific parity
|
||||
// tests.
|
||||
func (c *GalaxyClient) RawClient() RawGalaxyRepositoryClient {
|
||||
return c.raw
|
||||
}
|
||||
|
||||
// TestConnection probes the Galaxy Repository service. It returns the server's
|
||||
// reported ok flag and a non-nil error only when the RPC itself fails.
|
||||
func (c *GalaxyClient) TestConnection(ctx context.Context) (bool, error) {
|
||||
callCtx, cancel := c.callContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
reply, err := c.raw.TestConnection(callCtx, &pb.TestConnectionRequest{})
|
||||
if err != nil {
|
||||
return false, &GatewayError{Op: "galaxy test connection", Err: err}
|
||||
}
|
||||
return reply.GetOk(), nil
|
||||
}
|
||||
|
||||
// GetLastDeployTime returns the Galaxy's last deploy timestamp. When the server
|
||||
// reports present=false (no deploy recorded yet) the call returns
|
||||
// (time.Time{}, false, nil). When present=true the timestamp is returned in
|
||||
// UTC with present=true.
|
||||
func (c *GalaxyClient) GetLastDeployTime(ctx context.Context) (time.Time, bool, error) {
|
||||
callCtx, cancel := c.callContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
reply, err := c.raw.GetLastDeployTime(callCtx, &pb.GetLastDeployTimeRequest{})
|
||||
if err != nil {
|
||||
return time.Time{}, false, &GatewayError{Op: "galaxy get last deploy time", Err: err}
|
||||
}
|
||||
if !reply.GetPresent() {
|
||||
return time.Time{}, false, nil
|
||||
}
|
||||
ts := reply.GetTimeOfLastDeploy()
|
||||
if ts == nil {
|
||||
return time.Time{}, false, nil
|
||||
}
|
||||
return ts.AsTime(), true, nil
|
||||
}
|
||||
|
||||
// DiscoverHierarchy returns the deployed Galaxy object hierarchy with each
|
||||
// object's dynamic attributes. The objects are returned in the order supplied
|
||||
// by the server.
|
||||
func (c *GalaxyClient) DiscoverHierarchy(ctx context.Context) ([]*GalaxyObject, error) {
|
||||
callCtx, cancel := c.callContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
reply, err := c.raw.DiscoverHierarchy(callCtx, &pb.DiscoverHierarchyRequest{})
|
||||
if err != nil {
|
||||
return nil, &GatewayError{Op: "galaxy discover hierarchy", Err: err}
|
||||
}
|
||||
return reply.GetObjects(), nil
|
||||
}
|
||||
|
||||
// WatchDeployEventsRaw starts the generated WatchDeployEvents stream for callers
|
||||
// that want direct control over Recv. The caller owns the returned stream's
|
||||
// lifetime via ctx cancellation.
|
||||
func (c *GalaxyClient) WatchDeployEventsRaw(ctx context.Context, req *WatchDeployEventsRequest) (RawDeployEventStream, error) {
|
||||
if req == nil {
|
||||
req = &pb.WatchDeployEventsRequest{}
|
||||
}
|
||||
|
||||
stream, err := c.raw.WatchDeployEvents(ctx, req)
|
||||
if err != nil {
|
||||
return nil, &GatewayError{Op: "galaxy watch deploy events", Err: err}
|
||||
}
|
||||
return stream, nil
|
||||
}
|
||||
|
||||
// WatchDeployEvents subscribes to Galaxy deploy events. The server emits a
|
||||
// bootstrap event with the current state immediately on subscribe, then one
|
||||
// event per new deploy. When lastSeenDeployTime is non-nil it is forwarded to
|
||||
// the server to suppress the bootstrap event.
|
||||
//
|
||||
// The returned event channel is closed when the server completes the stream
|
||||
// (io.EOF), when ctx is cancelled, or after a terminal error has been
|
||||
// delivered on the error channel. The error channel is also closed once the
|
||||
// stream tears down. Surfaced errors are wrapped in *GatewayError.
|
||||
//
|
||||
// Cancel ctx to tear the stream down cleanly.
|
||||
func (c *GalaxyClient) WatchDeployEvents(
|
||||
ctx context.Context,
|
||||
lastSeenDeployTime *time.Time,
|
||||
) (<-chan *DeployEvent, <-chan error, error) {
|
||||
req := &pb.WatchDeployEventsRequest{}
|
||||
if lastSeenDeployTime != nil {
|
||||
req.LastSeenDeployTime = timestamppb.New(*lastSeenDeployTime)
|
||||
}
|
||||
|
||||
stream, err := c.WatchDeployEventsRaw(ctx, req)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
events := make(chan *DeployEvent, 16)
|
||||
errs := make(chan error, 1)
|
||||
go func() {
|
||||
defer close(events)
|
||||
defer close(errs)
|
||||
for {
|
||||
event, recvErr := stream.Recv()
|
||||
if recvErr == nil {
|
||||
select {
|
||||
case events <- event:
|
||||
case <-ctx.Done():
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
if recvErr == io.EOF {
|
||||
return
|
||||
}
|
||||
if status.Code(recvErr) == codes.Canceled || ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case errs <- &GatewayError{Op: "galaxy watch deploy events", Err: recvErr}:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
return events, errs, nil
|
||||
}
|
||||
|
||||
// Close closes the underlying gRPC connection.
|
||||
func (c *GalaxyClient) Close() error {
|
||||
if c == nil || c.conn == nil {
|
||||
return nil
|
||||
}
|
||||
return c.conn.Close()
|
||||
}
|
||||
|
||||
func (c *GalaxyClient) callContext(ctx context.Context) (context.Context, context.CancelFunc) {
|
||||
timeout := c.opts.CallTimeout
|
||||
if timeout == 0 {
|
||||
timeout = defaultCallTimeout
|
||||
}
|
||||
if timeout < 0 {
|
||||
return ctx, func() {}
|
||||
}
|
||||
if deadline, ok := ctx.Deadline(); ok {
|
||||
timeoutDeadline := time.Now().Add(timeout)
|
||||
if deadline.Before(timeoutDeadline) {
|
||||
return ctx, func() {}
|
||||
}
|
||||
}
|
||||
return context.WithTimeout(ctx, timeout)
|
||||
}
|
||||
@@ -0,0 +1,427 @@
|
||||
package mxgateway
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
pb "gitea.dohertylan.com/dohertj2/mxaccessgw/clients/go/internal/generated"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/test/bufconn"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
)
|
||||
|
||||
func TestGalaxyTestConnectionAttachesAuthAndReturnsOk(t *testing.T) {
|
||||
fake := &fakeGalaxyServer{
|
||||
testReply: &pb.TestConnectionReply{Ok: true},
|
||||
}
|
||||
client, cleanup := newGalaxyBufconnClient(t, fake)
|
||||
defer cleanup()
|
||||
|
||||
ok, err := client.TestConnection(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("TestConnection() error = %v", err)
|
||||
}
|
||||
if !ok {
|
||||
t.Fatalf("TestConnection() ok = false, want true")
|
||||
}
|
||||
if got := fake.testAuth; got != "Bearer test-api-key" {
|
||||
t.Fatalf("authorization metadata = %q, want %q", got, "Bearer test-api-key")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGalaxyGetLastDeployTimeReturnsAbsentForPresentFalse(t *testing.T) {
|
||||
fake := &fakeGalaxyServer{
|
||||
deployReply: &pb.GetLastDeployTimeReply{Present: false},
|
||||
}
|
||||
client, cleanup := newGalaxyBufconnClient(t, fake)
|
||||
defer cleanup()
|
||||
|
||||
got, present, err := client.GetLastDeployTime(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("GetLastDeployTime() error = %v", err)
|
||||
}
|
||||
if present {
|
||||
t.Fatalf("present = true, want false")
|
||||
}
|
||||
if !got.IsZero() {
|
||||
t.Fatalf("time = %v, want zero", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGalaxyGetLastDeployTimeReturnsTimestampWhenPresent(t *testing.T) {
|
||||
want := time.Date(2026, 4, 28, 12, 34, 56, 0, time.UTC)
|
||||
fake := &fakeGalaxyServer{
|
||||
deployReply: &pb.GetLastDeployTimeReply{
|
||||
Present: true,
|
||||
TimeOfLastDeploy: timestamppb.New(want),
|
||||
},
|
||||
}
|
||||
client, cleanup := newGalaxyBufconnClient(t, fake)
|
||||
defer cleanup()
|
||||
|
||||
got, present, err := client.GetLastDeployTime(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("GetLastDeployTime() error = %v", err)
|
||||
}
|
||||
if !present {
|
||||
t.Fatalf("present = false, want true")
|
||||
}
|
||||
if !got.Equal(want) {
|
||||
t.Fatalf("time = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGalaxyGetLastDeployTimeReturnsAbsentWhenTimestampNil(t *testing.T) {
|
||||
fake := &fakeGalaxyServer{
|
||||
deployReply: &pb.GetLastDeployTimeReply{Present: true, TimeOfLastDeploy: nil},
|
||||
}
|
||||
client, cleanup := newGalaxyBufconnClient(t, fake)
|
||||
defer cleanup()
|
||||
|
||||
got, present, err := client.GetLastDeployTime(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("GetLastDeployTime() error = %v", err)
|
||||
}
|
||||
if present {
|
||||
t.Fatalf("present = true, want false (nil timestamp)")
|
||||
}
|
||||
if !got.IsZero() {
|
||||
t.Fatalf("time = %v, want zero", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGalaxyDiscoverHierarchyReturnsObjects(t *testing.T) {
|
||||
fake := &fakeGalaxyServer{
|
||||
discoverReply: &pb.DiscoverHierarchyReply{
|
||||
Objects: []*pb.GalaxyObject{
|
||||
{
|
||||
GobjectId: 1,
|
||||
TagName: "TestMachine_001",
|
||||
ContainedName: "TestMachine_001",
|
||||
BrowseName: "TestMachine_001",
|
||||
IsArea: false,
|
||||
CategoryId: 7,
|
||||
TemplateChain: []string{"$Object", "$AppObject"},
|
||||
Attributes: []*pb.GalaxyAttribute{
|
||||
{
|
||||
AttributeName: "DownloadPath",
|
||||
FullTagReference: "TestMachine_001.DownloadPath",
|
||||
MxDataType: 8,
|
||||
DataTypeName: "String",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
GobjectId: 2,
|
||||
TagName: "TestMachine_002",
|
||||
ContainedName: "TestMachine_002",
|
||||
ParentGobjectId: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
client, cleanup := newGalaxyBufconnClient(t, fake)
|
||||
defer cleanup()
|
||||
|
||||
objects, err := client.DiscoverHierarchy(context.Background())
|
||||
if err != nil {
|
||||
t.Fatalf("DiscoverHierarchy() error = %v", err)
|
||||
}
|
||||
if len(objects) != 2 {
|
||||
t.Fatalf("len(objects) = %d, want 2", len(objects))
|
||||
}
|
||||
if objects[0].GetTagName() != "TestMachine_001" {
|
||||
t.Fatalf("objects[0].TagName = %q", objects[0].GetTagName())
|
||||
}
|
||||
if len(objects[0].GetAttributes()) != 1 {
|
||||
t.Fatalf("len(attributes) = %d, want 1", len(objects[0].GetAttributes()))
|
||||
}
|
||||
if objects[0].GetAttributes()[0].GetFullTagReference() != "TestMachine_001.DownloadPath" {
|
||||
t.Fatalf("FullTagReference = %q", objects[0].GetAttributes()[0].GetFullTagReference())
|
||||
}
|
||||
}
|
||||
|
||||
func TestGalaxyDialReturnsGatewayErrorOnRpcFailure(t *testing.T) {
|
||||
fake := &fakeGalaxyServer{failTest: true}
|
||||
client, cleanup := newGalaxyBufconnClient(t, fake)
|
||||
defer cleanup()
|
||||
|
||||
_, err := client.TestConnection(context.Background())
|
||||
if err == nil {
|
||||
t.Fatal("TestConnection() error = nil, want error")
|
||||
}
|
||||
var gwErr *GatewayError
|
||||
if !errors.As(err, &gwErr) {
|
||||
t.Fatalf("error %T does not support errors.As(*GatewayError)", err)
|
||||
}
|
||||
if gwErr.Op != "galaxy test connection" {
|
||||
t.Fatalf("Op = %q, want %q", gwErr.Op, "galaxy test connection")
|
||||
}
|
||||
}
|
||||
|
||||
func TestGalaxyWatchDeployEventsReceivesEventsInOrder(t *testing.T) {
|
||||
bootstrap := time.Date(2026, 4, 28, 10, 0, 0, 0, time.UTC)
|
||||
deploy1 := time.Date(2026, 4, 28, 10, 5, 0, 0, time.UTC)
|
||||
deploy2 := time.Date(2026, 4, 28, 10, 6, 0, 0, time.UTC)
|
||||
fake := &fakeGalaxyServer{
|
||||
watchEvents: []*pb.DeployEvent{
|
||||
{
|
||||
Sequence: 1,
|
||||
ObservedAt: timestamppb.New(bootstrap),
|
||||
TimeOfLastDeploy: timestamppb.New(deploy1),
|
||||
TimeOfLastDeployPresent: true,
|
||||
ObjectCount: 10,
|
||||
AttributeCount: 42,
|
||||
},
|
||||
{
|
||||
Sequence: 2,
|
||||
ObservedAt: timestamppb.New(deploy2),
|
||||
TimeOfLastDeploy: timestamppb.New(deploy2),
|
||||
TimeOfLastDeployPresent: true,
|
||||
ObjectCount: 11,
|
||||
AttributeCount: 44,
|
||||
},
|
||||
},
|
||||
}
|
||||
client, cleanup := newGalaxyBufconnClient(t, fake)
|
||||
defer cleanup()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
events, errs, err := client.WatchDeployEvents(ctx, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("WatchDeployEvents() error = %v", err)
|
||||
}
|
||||
|
||||
got := make([]*DeployEvent, 0, 2)
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case ev, ok := <-events:
|
||||
if !ok {
|
||||
break loop
|
||||
}
|
||||
got = append(got, ev)
|
||||
case errVal := <-errs:
|
||||
if errVal != nil {
|
||||
t.Fatalf("error channel: %v", errVal)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
t.Fatalf("timeout waiting for events; got %d", len(got))
|
||||
}
|
||||
}
|
||||
|
||||
if len(got) != 2 {
|
||||
t.Fatalf("len(events) = %d, want 2", len(got))
|
||||
}
|
||||
if got[0].GetSequence() != 1 || got[1].GetSequence() != 2 {
|
||||
t.Fatalf("sequences = [%d,%d], want [1,2]", got[0].GetSequence(), got[1].GetSequence())
|
||||
}
|
||||
if !got[0].GetTimeOfLastDeployPresent() {
|
||||
t.Fatalf("event[0] TimeOfLastDeployPresent = false, want true")
|
||||
}
|
||||
if got[0].GetObjectCount() != 10 || got[0].GetAttributeCount() != 42 {
|
||||
t.Fatalf("event[0] counts = (%d,%d), want (10,42)", got[0].GetObjectCount(), got[0].GetAttributeCount())
|
||||
}
|
||||
if !got[0].GetTimeOfLastDeploy().AsTime().Equal(deploy1) {
|
||||
t.Fatalf("event[0] TimeOfLastDeploy = %v, want %v", got[0].GetTimeOfLastDeploy().AsTime(), deploy1)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGalaxyWatchDeployEventsForwardsLastSeenDeployTime(t *testing.T) {
|
||||
fake := &fakeGalaxyServer{
|
||||
watchEvents: []*pb.DeployEvent{
|
||||
{Sequence: 7},
|
||||
},
|
||||
}
|
||||
client, cleanup := newGalaxyBufconnClient(t, fake)
|
||||
defer cleanup()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
lastSeen := time.Date(2026, 4, 28, 9, 0, 0, 0, time.UTC)
|
||||
events, errs, err := client.WatchDeployEvents(ctx, &lastSeen)
|
||||
if err != nil {
|
||||
t.Fatalf("WatchDeployEvents() error = %v", err)
|
||||
}
|
||||
|
||||
// Drain everything.
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case _, ok := <-events:
|
||||
if !ok {
|
||||
break loop
|
||||
}
|
||||
case errVal := <-errs:
|
||||
if errVal != nil {
|
||||
t.Fatalf("error channel: %v", errVal)
|
||||
}
|
||||
case <-ctx.Done():
|
||||
t.Fatalf("timeout draining events")
|
||||
}
|
||||
}
|
||||
|
||||
if fake.watchRequest == nil {
|
||||
t.Fatalf("server did not receive a request")
|
||||
}
|
||||
gotTs := fake.watchRequest.GetLastSeenDeployTime()
|
||||
if gotTs == nil {
|
||||
t.Fatalf("LastSeenDeployTime = nil, want %v", lastSeen)
|
||||
}
|
||||
if !gotTs.AsTime().Equal(lastSeen) {
|
||||
t.Fatalf("LastSeenDeployTime = %v, want %v", gotTs.AsTime(), lastSeen)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGalaxyWatchDeployEventsCancelTearsDownStream(t *testing.T) {
|
||||
fake := &fakeGalaxyServer{
|
||||
watchEvents: []*pb.DeployEvent{
|
||||
{Sequence: 1},
|
||||
},
|
||||
watchHoldOpen: true,
|
||||
}
|
||||
client, cleanup := newGalaxyBufconnClient(t, fake)
|
||||
defer cleanup()
|
||||
|
||||
streamCtx, cancelStream := context.WithCancel(context.Background())
|
||||
|
||||
events, errs, err := client.WatchDeployEvents(streamCtx, nil)
|
||||
if err != nil {
|
||||
t.Fatalf("WatchDeployEvents() error = %v", err)
|
||||
}
|
||||
|
||||
// Wait for the bootstrap event to arrive.
|
||||
select {
|
||||
case ev, ok := <-events:
|
||||
if !ok {
|
||||
t.Fatalf("events channel closed before delivering bootstrap")
|
||||
}
|
||||
if ev.GetSequence() != 1 {
|
||||
t.Fatalf("got seq=%d, want 1", ev.GetSequence())
|
||||
}
|
||||
case <-time.After(2 * time.Second):
|
||||
t.Fatalf("timeout waiting for bootstrap event")
|
||||
}
|
||||
|
||||
// Cancel the stream; both channels must close cleanly without delivering an error.
|
||||
cancelStream()
|
||||
|
||||
deadline := time.After(2 * time.Second)
|
||||
for events != nil || errs != nil {
|
||||
select {
|
||||
case _, ok := <-events:
|
||||
if !ok {
|
||||
events = nil
|
||||
}
|
||||
case errVal, ok := <-errs:
|
||||
if !ok {
|
||||
errs = nil
|
||||
continue
|
||||
}
|
||||
if errVal != nil {
|
||||
t.Fatalf("error after cancel: %v", errVal)
|
||||
}
|
||||
case <-deadline:
|
||||
t.Fatalf("channels did not close after cancel; events nil=%v errs nil=%v", events == nil, errs == nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newGalaxyBufconnClient(t *testing.T, fake *fakeGalaxyServer) (*GalaxyClient, func()) {
|
||||
t.Helper()
|
||||
|
||||
listener := bufconn.Listen(bufSize)
|
||||
server := grpc.NewServer()
|
||||
pb.RegisterGalaxyRepositoryServer(server, fake)
|
||||
go func() {
|
||||
if err := server.Serve(listener); err != nil && !errors.Is(err, grpc.ErrServerStopped) {
|
||||
t.Errorf("bufconn server failed: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
dialer := func(ctx context.Context, _ string) (net.Conn, error) {
|
||||
return listener.DialContext(ctx)
|
||||
}
|
||||
client, err := DialGalaxy(context.Background(), Options{
|
||||
Endpoint: "bufnet",
|
||||
APIKey: "test-api-key",
|
||||
Plaintext: true,
|
||||
DialOptions: []grpc.DialOption{
|
||||
grpc.WithContextDialer(dialer),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("DialGalaxy() error = %v", err)
|
||||
}
|
||||
|
||||
return client, func() {
|
||||
client.Close()
|
||||
server.Stop()
|
||||
listener.Close()
|
||||
}
|
||||
}
|
||||
|
||||
type fakeGalaxyServer struct {
|
||||
pb.UnimplementedGalaxyRepositoryServer
|
||||
|
||||
testReply *pb.TestConnectionReply
|
||||
testAuth string
|
||||
failTest bool
|
||||
deployReply *pb.GetLastDeployTimeReply
|
||||
discoverReply *pb.DiscoverHierarchyReply
|
||||
watchEvents []*pb.DeployEvent
|
||||
watchRequest *pb.WatchDeployEventsRequest
|
||||
watchSendInterval time.Duration
|
||||
watchHoldOpen bool
|
||||
}
|
||||
|
||||
func (s *fakeGalaxyServer) TestConnection(ctx context.Context, req *pb.TestConnectionRequest) (*pb.TestConnectionReply, error) {
|
||||
s.testAuth = authorizationFromContext(ctx)
|
||||
if s.failTest {
|
||||
return nil, errors.New("simulated failure")
|
||||
}
|
||||
if s.testReply != nil {
|
||||
return s.testReply, nil
|
||||
}
|
||||
return &pb.TestConnectionReply{Ok: true}, nil
|
||||
}
|
||||
|
||||
func (s *fakeGalaxyServer) GetLastDeployTime(ctx context.Context, req *pb.GetLastDeployTimeRequest) (*pb.GetLastDeployTimeReply, error) {
|
||||
if s.deployReply != nil {
|
||||
return s.deployReply, nil
|
||||
}
|
||||
return &pb.GetLastDeployTimeReply{Present: false}, nil
|
||||
}
|
||||
|
||||
func (s *fakeGalaxyServer) DiscoverHierarchy(ctx context.Context, req *pb.DiscoverHierarchyRequest) (*pb.DiscoverHierarchyReply, error) {
|
||||
if s.discoverReply != nil {
|
||||
return s.discoverReply, nil
|
||||
}
|
||||
return &pb.DiscoverHierarchyReply{}, nil
|
||||
}
|
||||
|
||||
func (s *fakeGalaxyServer) WatchDeployEvents(req *pb.WatchDeployEventsRequest, stream grpc.ServerStreamingServer[pb.DeployEvent]) error {
|
||||
s.watchRequest = req
|
||||
for _, event := range s.watchEvents {
|
||||
if err := stream.Send(event); err != nil {
|
||||
return err
|
||||
}
|
||||
if s.watchSendInterval > 0 {
|
||||
select {
|
||||
case <-time.After(s.watchSendInterval):
|
||||
case <-stream.Context().Done():
|
||||
return stream.Context().Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
if s.watchHoldOpen {
|
||||
<-stream.Context().Done()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user