Repository: nats-io/nats.go
Pull request #1118 (2022-11-02 21:53:25)

Support stream alternates
Signed-off-by: Derek Collison <derek@nats.io>


Patch:
diff --git a/jsm.go b/jsm.go
index e71d37f..141d6cb 100644
--- a/jsm.go
+++ b/jsm.go
@@ -867,12 +867,20 @@ func (js *js) StreamInfo(stream string, opts ...JSOpt) (*StreamInfo, error) {
 
 // StreamInfo shows config and current state for this stream.
 type StreamInfo struct {
-	Config  StreamConfig        `json:"config"`
-	Created time.Time           `json:"created"`
-	State   StreamState         `json:"state"`
-	Cluster *ClusterInfo        `json:"cluster,omitempty"`
-	Mirror  *StreamSourceInfo   `json:"mirror,omitempty"`
-	Sources []*StreamSourceInfo `json:"sources,omitempty"`
+	Config     StreamConfig        `json:"config"`
+	Created    time.Time           `json:"created"`
+	State      StreamState         `json:"state"`
+	Cluster    *ClusterInfo        `json:"cluster,omitempty"`
+	Mirror     *StreamSourceInfo   `json:"mirror,omitempty"`
+	Sources    []*StreamSourceInfo `json:"sources,omitempty"`
+	Alternates []*StreamAlternate  `json:"alternates,omitempty"`
+}
+
+// StreamAlternate is an alternate stream represented by a mirror.
+type StreamAlternate struct {
+	Name    string `json:"name"`
+	Domain  string `json:"domain,omitempty"`
+	Cluster string `json:"cluster"`
 }
 
 // StreamSourceInfo shows information about an upstream stream source.
diff --git a/kv.go b/kv.go
index 3761a33..f127e61 100644
--- a/kv.go
+++ b/kv.go
@@ -1013,7 +1013,7 @@ func (js *js) KeyValueStoreNames() <-chan string {
 		defer close(ch)
 		for l.Next() {
 			for _, info := range l.Page() {
-				if !strings.HasPrefix(info.Config.Name, "KV_") {
+				if !strings.HasPrefix(info.Config.Name, kvBucketNamePre) {
 					continue
 				}
 				ch <- info.Config.Name
@@ -1033,10 +1033,10 @@ func (js *js) KeyValueStores() <-chan KeyValueStatus {
 		defer close(ch)
 		for l.Next() {
 			for _, info := range l.Page() {
-				if !strings.HasPrefix(info.Config.Name, "KV_") {
+				if !strings.HasPrefix(info.Config.Name, kvBucketNamePre) {
 					continue
 				}
-				ch <- &KeyValueBucketStatus{nfo: info, bucket: strings.TrimPrefix(info.Config.Name, "KV_")}
+				ch <- &KeyValueBucketStatus{nfo: info, bucket: strings.TrimPrefix(info.Config.Name, kvBucketNamePre)}
 			}
 		}
 	}()


Test patch:
diff --git a/test/js_test.go b/test/js_test.go
index ad1ac6a..124b470 100644
--- a/test/js_test.go
+++ b/test/js_test.go
@@ -8288,3 +8288,32 @@ func TestJetStreamCreateStreamDiscardPolicy(t *testing.T) {
 		})
 	}
 }
+
+func TestJetStreamStreamInfoAlternates(t *testing.T) {
+	withJSCluster(t, "R3S", 3, func(t *testing.T, nodes ...*jsServer) {
+		nc, js := jsClient(t, nodes[0].Server)
+		defer nc.Close()
+
+		_, err := js.AddStream(&nats.StreamConfig{
+			Name:     "TEST",
+			Subjects: []string{"foo"},
+		})
+		expectOk(t, err)
+
+		// Create a mirror as well.
+		_, err = js.AddStream(&nats.StreamConfig{
+			Name: "MIRROR",
+			Mirror: &nats.StreamSource{
+				Name: "TEST",
+			},
+		})
+		expectOk(t, err)
+
+		si, err := js.StreamInfo("TEST")
+		expectOk(t, err)
+
+		if len(si.Alternates) != 2 {
+			t.Fatalf("Expected 2 alternates, got %d", len(si.Alternates))
+		}
+	})
+}