├── CODE-OF-CONDUCT.md ├── OWNERS ├── .gitignore ├── scripts └── cov.sh ├── .travis.yml ├── examples ├── stan-pub │ └── main.go ├── stan-sub │ └── main.go └── stan-bench │ └── main.go ├── pb ├── protocol.proto └── protocol.pb.go ├── benchmark_test.go ├── LICENSE ├── README.md ├── sub.go ├── stan.go └── stan_test.go /CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Community Code of Conduct 2 | 3 | NATS follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). 4 | 5 | -------------------------------------------------------------------------------- /OWNERS: -------------------------------------------------------------------------------- 1 | reviewers: 2 | - aricart 3 | - ColinSullivan1 4 | - derekcollison 5 | - kozlovic 6 | - wallyqs 7 | approvers: 8 | - derekcollison 9 | - kozlovic 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | 26 | # Eclipse stuff 27 | .project 28 | .settings/ 29 | -------------------------------------------------------------------------------- /scripts/cov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | # Run from directory above via ./scripts/cov.sh 3 | 4 | rm -rf ./cov 5 | mkdir cov 6 | go test -v -covermode=atomic -coverprofile=./cov/stan.out 7 | gocovmerge ./cov/*.out > acc.out 8 | rm -rf ./cov 9 | 10 | # If we have an arg, assume travis run and push to coveralls. Otherwise launch browser results 11 | if [[ -n $1 ]]; then 12 | $HOME/gopath/bin/goveralls -coverprofile=acc.out 13 | rm -rf ./acc.out 14 | else 15 | go tool cover -html=acc.out 16 | fi 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | sudo: false 3 | go: 4 | - 1.8.5 5 | - 1.9.2 6 | install: 7 | - go get -t ./... 8 | - go get github.com/nats-io/nats-streaming-server 9 | - go get github.com/mattn/goveralls 10 | - go get github.com/wadey/gocovmerge 11 | - go get -u honnef.co/go/tools/cmd/megacheck 12 | - go get -u github.com/client9/misspell/cmd/misspell 13 | before_script: 14 | - $(exit $(go fmt ./... | wc -l)) 15 | - go vet ./... 16 | - misspell -error -locale US . 17 | - megacheck ./... 18 | script: 19 | - go test -i -race ./... 20 | - go test -v -race ./... 21 | after_success: 22 | - if [[ "$TRAVIS_GO_VERSION" == 1.9.* ]]; then ./scripts/cov.sh TRAVIS; fi 23 | env: 24 | global: 25 | secure: OoCemKSHHH/SkkamHLWd0qh9qgQDx4/3fGuykYuzW/gjUhLlL0ThyUXOr3HOandoh3wTU8Ntj184WU6Sjh1oXzdDAYcI/ryNQXSmJ/DyGC6ffoj4Je/Rwj3sbwpaFTl1imawL8Lv6+5Dkb2JSbbbqapjbO3BhrrNfqLuQulqrLJKVaOyS5nOByiGFYsgjf/ac7Qrr9AnHhlkWRXoR+q8GlGG7qcKtLlmG5OqxifqfgQ+pcVtyeleT6zGPI0LUyr9gWHRZtMK9nYfxXuQK2d7V+SW4NBW1jdDKBHZbeJRxZ8N8rU8Nk3ka54YHXC2PeD8EloiAr5HkALuHbIdzyy40Y3rJyHfxyY6EYBcZEy+ZCRoqkVJ4NN4R46YE588BpYhT48YHK+lptM7YxrPtf08X+Cugc206X0hk/YFqqsaaNIwMfiTPbapuHxa8S4kgT2vDn3OTI53ZTrDiLVY3ZDp+EdUO1hiYFR6cpu5el/EQN5G0iW6sI69gOv26UmGI369D3fezbYPFPHHDao8xq7s8HdYUZleDNL0oCWK1MgL2g/Irbt5Kr6JjT/tpQOiiagqeR5dlV9mAiOZFr88gg7aqwOuSqmlULWVB4qYncQ6IBoednIHtrLW6H+2RfrZU01cI6tGSrXD+VoFnQ7aZwLxLc71VyN5khYPk0gGvyQhZxk= 26 | -------------------------------------------------------------------------------- /examples/stan-pub/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2018 The NATS Authors 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "flag" 18 | "fmt" 19 | "log" 20 | "os" 21 | "sync" 22 | "time" 23 | 24 | "github.com/nats-io/go-nats-streaming" 25 | ) 26 | 27 | var usageStr = ` 28 | Usage: stan-pub [options] 29 | 30 | Options: 31 | -s, --server NATS Streaming server URL(s) 32 | -c, --cluster NATS Streaming cluster name 33 | -id,--clientid NATS Streaming client ID 34 | -a, --async Asynchronous publish mode 35 | ` 36 | 37 | // NOTE: Use tls scheme for TLS, e.g. stan-pub -s tls://demo.nats.io:4443 foo hello 38 | func usage() { 39 | fmt.Printf("%s\n", usageStr) 40 | os.Exit(0) 41 | } 42 | 43 | func main() { 44 | var clusterID string 45 | var clientID string 46 | var async bool 47 | var URL string 48 | 49 | flag.StringVar(&URL, "s", stan.DefaultNatsURL, "The nats server URLs (separated by comma)") 50 | flag.StringVar(&URL, "server", stan.DefaultNatsURL, "The nats server URLs (separated by comma)") 51 | flag.StringVar(&clusterID, "c", "test-cluster", "The NATS Streaming cluster ID") 52 | flag.StringVar(&clusterID, "cluster", "test-cluster", "The NATS Streaming cluster ID") 53 | flag.StringVar(&clientID, "id", "stan-pub", "The NATS Streaming client ID to connect with") 54 | flag.StringVar(&clientID, "clientid", "stan-pub", "The NATS Streaming client ID to connect with") 55 | flag.BoolVar(&async, "a", false, "Publish asynchronously") 56 | flag.BoolVar(&async, "async", false, "Publish asynchronously") 57 | 58 | log.SetFlags(0) 59 | flag.Usage = usage 60 | flag.Parse() 61 | 62 | args := flag.Args() 63 | 64 | if len(args) < 1 { 65 | usage() 66 | } 67 | 68 | sc, err := stan.Connect(clusterID, clientID, stan.NatsURL(URL)) 69 | if err != nil { 70 | log.Fatalf("Can't connect: %v.\nMake sure a NATS Streaming Server is running at: %s", err, URL) 71 | } 72 | defer sc.Close() 73 | 74 | subj, msg := args[0], []byte(args[1]) 75 | 76 | ch := make(chan bool) 77 | var glock sync.Mutex 78 | var guid string 79 | acb := func(lguid string, err error) { 80 | glock.Lock() 81 | log.Printf("Received ACK for guid %s\n", lguid) 82 | defer glock.Unlock() 83 | if err != nil { 84 | log.Fatalf("Error in server ack for guid %s: %v\n", lguid, err) 85 | } 86 | if lguid != guid { 87 | log.Fatalf("Expected a matching guid in ack callback, got %s vs %s\n", lguid, guid) 88 | } 89 | ch <- true 90 | } 91 | 92 | if !async { 93 | err = sc.Publish(subj, msg) 94 | if err != nil { 95 | log.Fatalf("Error during publish: %v\n", err) 96 | } 97 | log.Printf("Published [%s] : '%s'\n", subj, msg) 98 | } else { 99 | glock.Lock() 100 | guid, err = sc.PublishAsync(subj, msg, acb) 101 | if err != nil { 102 | log.Fatalf("Error during async publish: %v\n", err) 103 | } 104 | glock.Unlock() 105 | if guid == "" { 106 | log.Fatal("Expected non-empty guid to be returned.") 107 | } 108 | log.Printf("Published [%s] : '%s' [guid: %s]\n", subj, msg, guid) 109 | 110 | select { 111 | case <-ch: 112 | break 113 | case <-time.After(5 * time.Second): 114 | log.Fatal("timeout") 115 | } 116 | 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /pb/protocol.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2018 The NATS Authors 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | // 14 | // Uses https://github.com/gogo/protobuf 15 | // compiled via `protoc -I=. -I=$GOPATH/src --gogofaster_out=. protocol.proto` 16 | 17 | syntax = "proto3"; 18 | package pb; 19 | 20 | import "github.com/gogo/protobuf/gogoproto/gogo.proto"; 21 | 22 | option (gogoproto.marshaler_all) = true; 23 | option (gogoproto.sizer_all) = true; 24 | option (gogoproto.unmarshaler_all) = true; 25 | option (gogoproto.goproto_getters_all) = false; 26 | 27 | // How messages are delivered to the STAN cluster 28 | message PubMsg { 29 | string clientID = 1; // ClientID 30 | string guid = 2; // guid 31 | string subject = 3; // subject 32 | string reply = 4; // optional reply 33 | bytes data = 5; // payload 34 | 35 | bytes sha256 = 10; // optional sha256 of data 36 | } 37 | 38 | // Used to ACK to publishers 39 | message PubAck { 40 | string guid = 1; // guid 41 | string error = 2; // err string, empty/omitted if no error 42 | } 43 | 44 | // Msg struct. Sequence is assigned for global ordering by 45 | // the cluster after the publisher has been acknowledged. 46 | message MsgProto { 47 | uint64 sequence = 1; // globally ordered sequence number for the subject's channel 48 | string subject = 2; // subject 49 | string reply = 3; // optional reply 50 | bytes data = 4; // payload 51 | int64 timestamp = 5; // received timestamp 52 | bool redelivered = 6; // Flag specifying if the message is being redelivered 53 | 54 | uint32 CRC32 = 10; // optional IEEE CRC32 55 | } 56 | 57 | // Ack will deliver an ack for a delivered msg. 58 | message Ack { 59 | string subject = 1; // Subject 60 | uint64 sequence = 2; // Sequence to acknowledge 61 | } 62 | 63 | // Connection Request 64 | message ConnectRequest { 65 | string clientID = 1; // Client name/identifier. 66 | string heartbeatInbox = 2; // Inbox for server initiated heartbeats. 67 | } 68 | 69 | // Response to a client connect 70 | message ConnectResponse { 71 | string pubPrefix = 1; // Prefix to use when publishing to this STAN cluster 72 | string subRequests = 2; // Subject to use for subscription requests 73 | string unsubRequests = 3; // Subject to use for unsubscribe requests 74 | string closeRequests = 4; // Subject for closing the stan connection 75 | string error = 5; // err string, empty/omitted if no error 76 | string subCloseRequests = 6; // Subject to use for subscription close requests 77 | 78 | string publicKey = 100; // Possibly used to sign acks, etc. 79 | } 80 | 81 | // Enum for start position type. 82 | enum StartPosition { 83 | NewOnly = 0; 84 | LastReceived = 1; 85 | TimeDeltaStart = 2; 86 | SequenceStart = 3; 87 | First = 4; 88 | } 89 | 90 | // Protocol for a client to subscribe 91 | message SubscriptionRequest { 92 | string clientID = 1; // ClientID 93 | string subject = 2; // Formal subject to subscribe to, e.g. foo.bar 94 | string qGroup = 3; // Optional queue group 95 | string inbox = 4; // Inbox subject to deliver messages on 96 | int32 maxInFlight = 5; // Maximum inflight messages without an ack allowed 97 | int32 ackWaitInSecs = 6; // Timeout for receiving an ack from the client 98 | string durableName = 7; // Optional durable name which survives client restarts 99 | StartPosition startPosition = 10; // Start position 100 | uint64 startSequence = 11; // Optional start sequence number 101 | int64 startTimeDelta = 12; // Optional start time 102 | } 103 | 104 | // Response for SubscriptionRequest and UnsubscribeRequests 105 | message SubscriptionResponse { 106 | string ackInbox = 2; // ackInbox for sending acks 107 | string error = 3; // err string, empty/omitted if no error 108 | } 109 | 110 | // Protocol for a clients to unsubscribe. Will return a SubscriptionResponse 111 | message UnsubscribeRequest { 112 | string clientID = 1; // ClientID 113 | string subject = 2; // subject for the subscription 114 | string inbox = 3; // Inbox subject to identify subscription 115 | string durableName = 4; // Optional durable name which survives client restarts 116 | } 117 | 118 | // Protocol for a client to close a connection 119 | message CloseRequest { 120 | string clientID = 1; // Client name provided to Connect() requests 121 | } 122 | 123 | // Response for CloseRequest 124 | message CloseResponse { 125 | string error = 1; // err string, empty/omitted if no error 126 | } 127 | -------------------------------------------------------------------------------- /examples/stan-sub/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2018 The NATS Authors 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "flag" 18 | "fmt" 19 | "log" 20 | "os" 21 | "os/signal" 22 | "time" 23 | 24 | "github.com/nats-io/go-nats-streaming" 25 | "github.com/nats-io/go-nats-streaming/pb" 26 | ) 27 | 28 | var usageStr = ` 29 | Usage: stan-sub [options] 30 | 31 | Options: 32 | -s, --server NATS Streaming server URL(s) 33 | -c, --cluster NATS Streaming cluster name 34 | -id,--clientid NATS Streaming client ID 35 | 36 | Subscription Options: 37 | --qgroup Queue group 38 | --seq Start at seqno 39 | --all Deliver all available messages 40 | --last Deliver starting with last published message 41 | --since Deliver messages in last interval (e.g. 1s, 1hr) 42 | (for more information: https://golang.org/pkg/time/#ParseDuration) 43 | --durable Durable subscriber name 44 | --unsubscribe Unsubscribe the durable on exit 45 | ` 46 | 47 | // NOTE: Use tls scheme for TLS, e.g. stan-sub -s tls://demo.nats.io:4443 foo 48 | func usage() { 49 | log.Fatalf(usageStr) 50 | } 51 | 52 | func printMsg(m *stan.Msg, i int) { 53 | log.Printf("[#%d] Received on [%s]: '%s'\n", i, m.Subject, m) 54 | } 55 | 56 | func main() { 57 | var clusterID string 58 | var clientID string 59 | var showTime bool 60 | var startSeq uint64 61 | var startDelta string 62 | var deliverAll bool 63 | var deliverLast bool 64 | var durable string 65 | var qgroup string 66 | var unsubscribe bool 67 | var URL string 68 | 69 | // defaultID := fmt.Sprintf("client.%s", nuid.Next()) 70 | 71 | flag.StringVar(&URL, "s", stan.DefaultNatsURL, "The nats server URLs (separated by comma)") 72 | flag.StringVar(&URL, "server", stan.DefaultNatsURL, "The nats server URLs (separated by comma)") 73 | flag.StringVar(&clusterID, "c", "test-cluster", "The NATS Streaming cluster ID") 74 | flag.StringVar(&clusterID, "cluster", "test-cluster", "The NATS Streaming cluster ID") 75 | flag.StringVar(&clientID, "id", "", "The NATS Streaming client ID to connect with") 76 | flag.StringVar(&clientID, "clientid", "", "The NATS Streaming client ID to connect with") 77 | flag.BoolVar(&showTime, "t", false, "Display timestamps") 78 | // Subscription options 79 | flag.Uint64Var(&startSeq, "seq", 0, "Start at sequence no.") 80 | flag.BoolVar(&deliverAll, "all", false, "Deliver all") 81 | flag.BoolVar(&deliverLast, "last", false, "Start with last value") 82 | flag.StringVar(&startDelta, "since", "", "Deliver messages since specified time offset") 83 | flag.StringVar(&durable, "durable", "", "Durable subscriber name") 84 | flag.StringVar(&qgroup, "qgroup", "", "Queue group name") 85 | flag.BoolVar(&unsubscribe, "unsubscribe", false, "Unsubscribe the durable on exit") 86 | 87 | log.SetFlags(0) 88 | flag.Usage = usage 89 | flag.Parse() 90 | 91 | args := flag.Args() 92 | 93 | if clientID == "" { 94 | log.Printf("Error: A unique client ID must be specified.") 95 | usage() 96 | } 97 | if len(args) < 1 { 98 | log.Printf("Error: A subject must be specified.") 99 | usage() 100 | } 101 | 102 | sc, err := stan.Connect(clusterID, clientID, stan.NatsURL(URL)) 103 | if err != nil { 104 | log.Fatalf("Can't connect: %v.\nMake sure a NATS Streaming Server is running at: %s", err, URL) 105 | } 106 | log.Printf("Connected to %s clusterID: [%s] clientID: [%s]\n", URL, clusterID, clientID) 107 | 108 | subj, i := args[0], 0 109 | 110 | mcb := func(msg *stan.Msg) { 111 | i++ 112 | printMsg(msg, i) 113 | } 114 | 115 | startOpt := stan.StartAt(pb.StartPosition_NewOnly) 116 | 117 | if startSeq != 0 { 118 | startOpt = stan.StartAtSequence(startSeq) 119 | } else if deliverLast { 120 | startOpt = stan.StartWithLastReceived() 121 | } else if deliverAll { 122 | log.Print("subscribing with DeliverAllAvailable") 123 | startOpt = stan.DeliverAllAvailable() 124 | } else if startDelta != "" { 125 | ago, err := time.ParseDuration(startDelta) 126 | if err != nil { 127 | sc.Close() 128 | log.Fatal(err) 129 | } 130 | startOpt = stan.StartAtTimeDelta(ago) 131 | } 132 | 133 | sub, err := sc.QueueSubscribe(subj, qgroup, mcb, startOpt, stan.DurableName(durable)) 134 | if err != nil { 135 | sc.Close() 136 | log.Fatal(err) 137 | } 138 | 139 | log.Printf("Listening on [%s], clientID=[%s], qgroup=[%s] durable=[%s]\n", subj, clientID, qgroup, durable) 140 | 141 | if showTime { 142 | log.SetFlags(log.LstdFlags) 143 | } 144 | 145 | // Wait for a SIGINT (perhaps triggered by user with CTRL-C) 146 | // Run cleanup when signal is received 147 | signalChan := make(chan os.Signal, 1) 148 | cleanupDone := make(chan bool) 149 | signal.Notify(signalChan, os.Interrupt) 150 | go func() { 151 | for range signalChan { 152 | fmt.Printf("\nReceived an interrupt, unsubscribing and closing connection...\n\n") 153 | // Do not unsubscribe a durable on exit, except if asked to. 154 | if durable == "" || unsubscribe { 155 | sub.Unsubscribe() 156 | } 157 | sc.Close() 158 | cleanupDone <- true 159 | } 160 | }() 161 | <-cleanupDone 162 | } 163 | -------------------------------------------------------------------------------- /examples/stan-bench/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2018 The NATS Authors 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | package main 15 | 16 | import ( 17 | "flag" 18 | "fmt" 19 | "io/ioutil" 20 | "log" 21 | "strings" 22 | "sync" 23 | "time" 24 | 25 | "github.com/nats-io/go-nats" 26 | "github.com/nats-io/go-nats-streaming" 27 | "github.com/nats-io/go-nats/bench" 28 | ) 29 | 30 | // Some sane defaults 31 | const ( 32 | DefaultNumMsgs = 100000 33 | DefaultNumPubs = 1 34 | DefaultNumSubs = 0 35 | DefaultAsync = false 36 | DefaultMessageSize = 128 37 | DefaultIgnoreOld = false 38 | DefaultMaxPubAcksInflight = 1000 39 | DefaultClientID = "benchmark" 40 | ) 41 | 42 | func usage() { 43 | log.Fatalf("Usage: stan-bench [-s server (%s)] [--tls] [-id CLIENT_ID] [-np NUM_PUBLISHERS] [-ns NUM_SUBSCRIBERS] [-n NUM_MSGS] [-ms MESSAGE_SIZE] [-csv csvfile] [-mpa MAX_NUMBER_OF_PUBLISHED_ACKS_INFLIGHT] [-io] [-a] \n", nats.DefaultURL) 44 | } 45 | 46 | var benchmark *bench.Benchmark 47 | 48 | func main() { 49 | var clusterID string 50 | flag.StringVar(&clusterID, "c", "test-cluster", "The NATS Streaming cluster ID") 51 | flag.StringVar(&clusterID, "cluster", "test-cluster", "The NATS Streaming cluster ID") 52 | 53 | var urls = flag.String("s", nats.DefaultURL, "The NATS server URLs (separated by comma") 54 | var tls = flag.Bool("tls", false, "Use TLS secure sonnection") 55 | var numPubs = flag.Int("np", DefaultNumPubs, "Number of concurrent publishers") 56 | var numSubs = flag.Int("ns", DefaultNumSubs, "Number of concurrent subscribers") 57 | var numMsgs = flag.Int("n", DefaultNumMsgs, "Number of messages to publish") 58 | var async = flag.Bool("a", DefaultAsync, "Async message publishing") 59 | var messageSize = flag.Int("ms", DefaultMessageSize, "Message size in bytes.") 60 | var ignoreOld = flag.Bool("io", DefaultIgnoreOld, "Subscribers ignore old messages") 61 | var maxPubAcks = flag.Int("mpa", DefaultMaxPubAcksInflight, "Max number of published acks in flight") 62 | var clientID = flag.String("id", DefaultClientID, "Benchmark process base client ID") 63 | var csvFile = flag.String("csv", "", "Save bench data to csv file") 64 | 65 | log.SetFlags(0) 66 | flag.Usage = usage 67 | flag.Parse() 68 | 69 | args := flag.Args() 70 | if len(args) != 1 { 71 | usage() 72 | } 73 | 74 | // Setup the option block 75 | opts := nats.GetDefaultOptions() 76 | opts.Servers = strings.Split(*urls, ",") 77 | for i, s := range opts.Servers { 78 | opts.Servers[i] = strings.Trim(s, " ") 79 | } 80 | 81 | opts.Secure = *tls 82 | 83 | benchmark = bench.NewBenchmark("NATS Streaming", *numSubs, *numPubs) 84 | 85 | var startwg sync.WaitGroup 86 | var donewg sync.WaitGroup 87 | 88 | donewg.Add(*numPubs + *numSubs) 89 | 90 | // Run Subscribers first 91 | startwg.Add(*numSubs) 92 | for i := 0; i < *numSubs; i++ { 93 | subID := fmt.Sprintf("%s-sub-%d", *clientID, i) 94 | go runSubscriber(&startwg, &donewg, opts, clusterID, *numMsgs, *messageSize, *ignoreOld, subID) 95 | } 96 | startwg.Wait() 97 | 98 | // Now Publishers 99 | startwg.Add(*numPubs) 100 | pubCounts := bench.MsgsPerClient(*numMsgs, *numPubs) 101 | for i := 0; i < *numPubs; i++ { 102 | pubID := fmt.Sprintf("%s-pub-%d", *clientID, i) 103 | go runPublisher(&startwg, &donewg, opts, clusterID, pubCounts[i], *messageSize, *async, pubID, *maxPubAcks) 104 | } 105 | 106 | log.Printf("Starting benchmark [msgs=%d, msgsize=%d, pubs=%d, subs=%d]\n", *numMsgs, *messageSize, *numPubs, *numSubs) 107 | 108 | startwg.Wait() 109 | donewg.Wait() 110 | 111 | benchmark.Close() 112 | fmt.Print(benchmark.Report()) 113 | 114 | if len(*csvFile) > 0 { 115 | csv := benchmark.CSV() 116 | ioutil.WriteFile(*csvFile, []byte(csv), 0644) 117 | fmt.Printf("Saved metric data in csv file %s\n", *csvFile) 118 | } 119 | } 120 | 121 | func runPublisher(startwg, donewg *sync.WaitGroup, opts nats.Options, clusterID string, numMsgs int, msgSize int, async bool, pubID string, maxPubAcksInflight int) { 122 | nc, err := opts.Connect() 123 | if err != nil { 124 | log.Fatalf("Publisher %s can't connect: %v\n", pubID, err) 125 | } 126 | snc, err := stan.Connect(clusterID, pubID, stan.MaxPubAcksInflight(maxPubAcksInflight), stan.NatsConn(nc)) 127 | if err != nil { 128 | log.Fatalf("Publisher %s can't connect: %v\n", pubID, err) 129 | } 130 | 131 | startwg.Done() 132 | 133 | args := flag.Args() 134 | 135 | subj := args[0] 136 | var msg []byte 137 | if msgSize > 0 { 138 | msg = make([]byte, msgSize) 139 | } 140 | published := 0 141 | start := time.Now() 142 | 143 | if async { 144 | ch := make(chan bool) 145 | acb := func(lguid string, err error) { 146 | published++ 147 | if published >= numMsgs { 148 | ch <- true 149 | } 150 | } 151 | for i := 0; i < numMsgs; i++ { 152 | _, err := snc.PublishAsync(subj, msg, acb) 153 | if err != nil { 154 | log.Fatal(err) 155 | } 156 | } 157 | <-ch 158 | } else { 159 | for i := 0; i < numMsgs; i++ { 160 | err := snc.Publish(subj, msg) 161 | if err != nil { 162 | log.Fatal(err) 163 | } 164 | published++ 165 | } 166 | } 167 | 168 | benchmark.AddPubSample(bench.NewSample(numMsgs, msgSize, start, time.Now(), snc.NatsConn())) 169 | snc.Close() 170 | nc.Close() 171 | donewg.Done() 172 | } 173 | 174 | func runSubscriber(startwg, donewg *sync.WaitGroup, opts nats.Options, clusterID string, numMsgs int, msgSize int, ignoreOld bool, subID string) { 175 | nc, err := opts.Connect() 176 | if err != nil { 177 | log.Fatalf("Subscriber %s can't connect: %v\n", subID, err) 178 | } 179 | snc, err := stan.Connect(clusterID, subID, stan.NatsConn(nc)) 180 | if err != nil { 181 | log.Fatalf("Subscriber %s can't connect: %v\n", subID, err) 182 | } 183 | 184 | args := flag.Args() 185 | subj := args[0] 186 | ch := make(chan time.Time, 2) 187 | 188 | received := 0 189 | mcb := func(msg *stan.Msg) { 190 | received++ 191 | if received == 1 { 192 | ch <- time.Now() 193 | } 194 | if received >= numMsgs { 195 | ch <- time.Now() 196 | } 197 | } 198 | 199 | if ignoreOld { 200 | snc.Subscribe(subj, mcb) 201 | } else { 202 | snc.Subscribe(subj, mcb, stan.DeliverAllAvailable()) 203 | } 204 | startwg.Done() 205 | 206 | start := <-ch 207 | end := <-ch 208 | benchmark.AddSubSample(bench.NewSample(numMsgs, msgSize, start, end, snc.NatsConn())) 209 | snc.Close() 210 | nc.Close() 211 | donewg.Done() 212 | } 213 | -------------------------------------------------------------------------------- /benchmark_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2018 The NATS Authors 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | package stan 14 | 15 | //////////////////////////////////////////////////////////////////////////////// 16 | // Benchmarks 17 | //////////////////////////////////////////////////////////////////////////////// 18 | 19 | import ( 20 | "fmt" 21 | "sync/atomic" 22 | "testing" 23 | "time" 24 | ) 25 | 26 | func BenchmarkPublish(b *testing.B) { 27 | b.StopTimer() 28 | 29 | // Run a NATS Streaming server 30 | s := RunServer(clusterName) 31 | defer s.Shutdown() 32 | sc := NewDefaultConnection(b) 33 | defer sc.Close() 34 | 35 | hw := []byte("Hello World") 36 | 37 | b.StartTimer() 38 | b.ReportAllocs() 39 | 40 | for i := 0; i < b.N; i++ { 41 | if err := sc.Publish("foo", hw); err != nil { 42 | b.Fatalf("Got error on publish: %v\n", err) 43 | } 44 | } 45 | } 46 | 47 | func BenchmarkPublishAsync(b *testing.B) { 48 | b.StopTimer() 49 | 50 | // Run a NATS Streaming server 51 | s := RunServer(clusterName) 52 | defer s.Shutdown() 53 | sc := NewDefaultConnection(b) 54 | defer sc.Close() 55 | 56 | hw := []byte("Hello World") 57 | 58 | ch := make(chan bool) 59 | received := int32(0) 60 | 61 | ah := func(guid string, err error) { 62 | if err != nil { 63 | b.Fatalf("Received an error in ack callback: %v\n", err) 64 | } 65 | if nr := atomic.AddInt32(&received, 1); nr >= int32(b.N) { 66 | ch <- true 67 | } 68 | } 69 | b.StartTimer() 70 | b.ReportAllocs() 71 | 72 | for i := 0; i < b.N; i++ { 73 | if _, err := sc.PublishAsync("foo", hw, ah); err != nil { 74 | //fmt.Printf("Client status %v, Server status %v\n", s.nc.Status(), (sc.(*conn)).nc.Status()) 75 | fmt.Printf("len(ackmap) = %d\n", len(sc.(*conn).pubAckMap)) 76 | 77 | b.Fatalf("Error from PublishAsync: %v\n", err) 78 | } 79 | } 80 | 81 | err := WaitTime(ch, 10*time.Second) 82 | if err != nil { 83 | fmt.Printf("sc error is %v\n", sc.(*conn).nc.LastError()) 84 | b.Fatal("Timed out waiting for ack messages") 85 | } else if atomic.LoadInt32(&received) != int32(b.N) { 86 | b.Fatalf("Received: %d", received) 87 | } 88 | 89 | // msgs, bytes, _ := sc.(*conn).ackSubscription.MaxPending() 90 | // fmt.Printf("max pending msgs:%d bytes:%d\n", msgs, bytes) 91 | } 92 | 93 | func BenchmarkSubscribe(b *testing.B) { 94 | b.StopTimer() 95 | 96 | // Run a NATS Streaming server 97 | s := RunServer(clusterName) 98 | defer s.Shutdown() 99 | sc := NewDefaultConnection(b) 100 | defer sc.Close() 101 | 102 | hw := []byte("Hello World") 103 | pch := make(chan bool) 104 | 105 | // Queue up all the messages. Keep this outside of the timing. 106 | for i := 0; i < b.N; i++ { 107 | if i == b.N-1 { 108 | // last one 109 | sc.PublishAsync("foo", hw, func(lguid string, err error) { 110 | if err != nil { 111 | b.Fatalf("Got an error from ack handler, %v", err) 112 | } 113 | pch <- true 114 | }) 115 | } else { 116 | sc.PublishAsync("foo", hw, nil) 117 | } 118 | } 119 | 120 | // Wait for published to finish 121 | if err := WaitTime(pch, 10*time.Second); err != nil { 122 | b.Fatalf("Error waiting for publish to finish\n") 123 | } 124 | 125 | ch := make(chan bool) 126 | received := int32(0) 127 | 128 | b.StartTimer() 129 | b.ReportAllocs() 130 | 131 | sc.Subscribe("foo", func(m *Msg) { 132 | if nr := atomic.AddInt32(&received, 1); nr >= int32(b.N) { 133 | ch <- true 134 | } 135 | }, DeliverAllAvailable()) 136 | 137 | err := WaitTime(ch, 10*time.Second) 138 | nr := atomic.LoadInt32(&received) 139 | if err != nil { 140 | b.Fatalf("Timed out waiting for messages, received only %d of %d\n", nr, b.N) 141 | } else if nr != int32(b.N) { 142 | b.Fatalf("Only Received: %d of %d", received, b.N) 143 | } 144 | } 145 | 146 | func BenchmarkQueueSubscribe(b *testing.B) { 147 | b.StopTimer() 148 | 149 | // Run a NATS Streaming server 150 | s := RunServer(clusterName) 151 | defer s.Shutdown() 152 | sc := NewDefaultConnection(b) 153 | defer sc.Close() 154 | 155 | hw := []byte("Hello World") 156 | pch := make(chan bool) 157 | 158 | // Queue up all the messages. Keep this outside of the timing. 159 | for i := 0; i < b.N; i++ { 160 | if i == b.N-1 { 161 | // last one 162 | sc.PublishAsync("foo", hw, func(lguid string, err error) { 163 | if err != nil { 164 | b.Fatalf("Got an error from ack handler, %v", err) 165 | } 166 | pch <- true 167 | }) 168 | } else { 169 | sc.PublishAsync("foo", hw, nil) 170 | } 171 | } 172 | 173 | // Wait for published to finish 174 | if err := WaitTime(pch, 10*time.Second); err != nil { 175 | b.Fatalf("Error waiting for publish to finish\n") 176 | } 177 | 178 | ch := make(chan bool) 179 | received := int32(0) 180 | 181 | b.StartTimer() 182 | b.ReportAllocs() 183 | 184 | mcb := func(m *Msg) { 185 | if nr := atomic.AddInt32(&received, 1); nr >= int32(b.N) { 186 | ch <- true 187 | } 188 | } 189 | 190 | sc.QueueSubscribe("foo", "bar", mcb, DeliverAllAvailable()) 191 | sc.QueueSubscribe("foo", "bar", mcb, DeliverAllAvailable()) 192 | sc.QueueSubscribe("foo", "bar", mcb, DeliverAllAvailable()) 193 | sc.QueueSubscribe("foo", "bar", mcb, DeliverAllAvailable()) 194 | 195 | err := WaitTime(ch, 20*time.Second) 196 | nr := atomic.LoadInt32(&received) 197 | if err != nil { 198 | b.Fatalf("Timed out waiting for messages, received only %d of %d\n", nr, b.N) 199 | } else if nr != int32(b.N) { 200 | b.Fatalf("Only Received: %d of %d", received, b.N) 201 | } 202 | } 203 | 204 | func BenchmarkPublishSubscribe(b *testing.B) { 205 | b.StopTimer() 206 | 207 | // Run a NATS Streaming server 208 | s := RunServer(clusterName) 209 | defer s.Shutdown() 210 | sc := NewDefaultConnection(b) 211 | defer sc.Close() 212 | 213 | hw := []byte("Hello World") 214 | 215 | ch := make(chan bool) 216 | received := int32(0) 217 | 218 | // Subscribe callback, counts msgs received. 219 | _, err := sc.Subscribe("foo", func(m *Msg) { 220 | if nr := atomic.AddInt32(&received, 1); nr >= int32(b.N) { 221 | ch <- true 222 | } 223 | }, DeliverAllAvailable()) 224 | 225 | if err != nil { 226 | b.Fatalf("Error subscribing, %v", err) 227 | } 228 | 229 | b.StartTimer() 230 | b.ReportAllocs() 231 | 232 | for i := 0; i < b.N; i++ { 233 | _, err := sc.PublishAsync("foo", hw, func(guid string, err error) { 234 | if err != nil { 235 | b.Fatalf("Received an error in publish ack callback: %v\n", err) 236 | } 237 | }) 238 | if err != nil { 239 | b.Fatalf("Error publishing %v\n", err) 240 | } 241 | } 242 | 243 | err = WaitTime(ch, 30*time.Second) 244 | nr := atomic.LoadInt32(&received) 245 | if err != nil { 246 | b.Fatalf("Timed out waiting for messages, received only %d of %d\n", nr, b.N) 247 | } else if nr != int32(b.N) { 248 | b.Fatalf("Only Received: %d of %d", received, b.N) 249 | } 250 | } 251 | 252 | func BenchmarkTimeNow(b *testing.B) { 253 | for i := 0; i < b.N; i++ { 254 | now := time.Now() 255 | now.Add(10 * time.Nanosecond) 256 | } 257 | } 258 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NATS Streaming 2 | 3 | NATS Streaming is an extremely performant, lightweight reliable streaming platform powered by [NATS](https://nats.io). 4 | 5 | [![License Apache 2](https://img.shields.io/badge/License-Apache2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) 6 | [![Build Status](https://travis-ci.org/nats-io/go-nats-streaming.svg?branch=master)](http://travis-ci.org/nats-io/go-nats-streaming) 7 | [![Coverage Status](https://coveralls.io/repos/nats-io/go-nats-streaming/badge.svg?branch=master)](https://coveralls.io/r/nats-io/go-nats-streaming?branch=master) 8 | 9 | NATS Streaming provides the following high-level feature set: 10 | - Log based persistence 11 | - At-Least-Once Delivery model, giving reliable message delivery 12 | - Rate matched on a per subscription basis 13 | - Replay/Restart 14 | - Last Value Semantics 15 | 16 | ## Notes 17 | 18 | - Please raise questions/issues via the [Issue Tracker](https://github.com/nats-io/go-nats-streaming/issues). 19 | 20 | ## Installation 21 | 22 | ```bash 23 | # Go client 24 | go get github.com/nats-io/go-nats-streaming 25 | ``` 26 | 27 | ## Basic Usage 28 | 29 | ```go 30 | 31 | sc, _ := stan.Connect(clusterID, clientID) 32 | 33 | // Simple Synchronous Publisher 34 | sc.Publish("foo", []byte("Hello World")) // does not return until an ack has been received from NATS Streaming 35 | 36 | // Simple Async Subscriber 37 | sub, _ := sc.Subscribe("foo", func(m *stan.Msg) { 38 | fmt.Printf("Received a message: %s\n", string(m.Data)) 39 | }) 40 | 41 | // Unsubscribe 42 | sub.Unsubscribe() 43 | 44 | // Close connection 45 | sc.Close() 46 | ``` 47 | 48 | ### Subscription Start (i.e. Replay) Options 49 | 50 | NATS Streaming subscriptions are similar to NATS subscriptions, but clients may start their subscription at an earlier point in the message stream, allowing them to receive messages that were published before this client registered interest. 51 | 52 | The options are described with examples below: 53 | 54 | ```go 55 | 56 | // Subscribe starting with most recently published value 57 | sub, err := sc.Subscribe("foo", func(m *stan.Msg) { 58 | fmt.Printf("Received a message: %s\n", string(m.Data)) 59 | }, stan.StartWithLastReceived()) 60 | 61 | // Receive all stored values in order 62 | sub, err := sc.Subscribe("foo", func(m *stan.Msg) { 63 | fmt.Printf("Received a message: %s\n", string(m.Data)) 64 | }, stan.DeliverAllAvailable()) 65 | 66 | // Receive messages starting at a specific sequence number 67 | sub, err := sc.Subscribe("foo", func(m *stan.Msg) { 68 | fmt.Printf("Received a message: %s\n", string(m.Data)) 69 | }, stan.StartAtSequence(22)) 70 | 71 | // Subscribe starting at a specific time 72 | var startTime time.Time 73 | ... 74 | sub, err := sc.Subscribe("foo", func(m *stan.Msg) { 75 | fmt.Printf("Received a message: %s\n", string(m.Data)) 76 | }, stan.StartAtTime(startTime)) 77 | 78 | // Subscribe starting a specific amount of time in the past (e.g. 30 seconds ago) 79 | sub, err := sc.Subscribe("foo", func(m *stan.Msg) { 80 | fmt.Printf("Received a message: %s\n", string(m.Data)) 81 | }, stan.StartAtTimeDelta(time.ParseDuration("30s"))) 82 | ``` 83 | 84 | ### Durable Subscriptions 85 | 86 | Replay of messages offers great flexibility for clients wishing to begin processing at some earlier point in the data stream. 87 | However, some clients just need to pick up where they left off from an earlier session, without having to manually track their position in the stream of messages. 88 | Durable subscriptions allow clients to assign a durable name to a subscription when it is created. 89 | Doing this causes the NATS Streaming server to track the last acknowledged message for that clientID + durable name, so that only messages since the last acknowledged message will be delivered to the client. 90 | 91 | ```go 92 | sc, _ := stan.Connect("test-cluster", "client-123") 93 | 94 | // Subscribe with durable name 95 | sc.Subscribe("foo", func(m *stan.Msg) { 96 | fmt.Printf("Received a message: %s\n", string(m.Data)) 97 | }, stan.DurableName("my-durable")) 98 | ... 99 | // client receives message sequence 1-40 100 | ... 101 | // client disconnects for an hour 102 | ... 103 | // client reconnects with same clientID "client-123" 104 | sc, _ := stan.Connect("test-cluster", "client-123") 105 | 106 | // client re-subscribes to "foo" with same durable name "my-durable" 107 | sc.Subscribe("foo", func(m *stan.Msg) { 108 | fmt.Printf("Received a message: %s\n", string(m.Data)) 109 | }, stan.DurableName("my-durable")) 110 | ... 111 | // client receives messages 41-current 112 | ``` 113 | 114 | ### Queue Groups 115 | 116 | All subscriptions with the same queue name (regardless of the connection 117 | they originate from) will form a queue group. 118 | Each message will be delivered to only one subscriber per queue group, 119 | using queuing semantics. You can have as many queue groups as you wish. 120 | 121 | Normal subscribers will continue to work as expected. 122 | 123 | #### Creating a Queue Group 124 | 125 | A queue group is automatically created when the first queue subscriber is 126 | created. If the group already exists, the member is added to the group. 127 | 128 | ```go 129 | sc, _ := stan.Connect("test-cluster", "clientid") 130 | 131 | // Create a queue subscriber on "foo" for group "bar" 132 | qsub1, _ := sc.QueueSubscribe("foo", "bar", qcb) 133 | 134 | // Add a second member 135 | qsub2, _ := sc.QueueSubscribe("foo", "bar", qcb) 136 | 137 | // Notice that you can have a regular subscriber on that subject 138 | sub, _ := sc.Subscribe("foo", cb) 139 | 140 | // A message on "foo" will be received by sub and qsub1 or qsub2. 141 | ``` 142 | 143 | #### Start Position 144 | 145 | Note that once a queue group is formed, a member's start position is ignored 146 | when added to the group. It will start receive messages from the last 147 | position in the group. 148 | 149 | Suppose the channel `foo` exists and there are `500` messages stored, the group 150 | `bar` is already created, there are two members and the last 151 | message sequence sent is `100`. A new member is added. Note its start position: 152 | 153 | ```go 154 | sc.QueueSubscribe("foo", "bar", qcb, stan.StartAtSequence(200)) 155 | ``` 156 | 157 | This will not produce an error, but the start position will be ignored. Assuming 158 | this member would be the one receiving the next message, it would receive message 159 | sequence `101`. 160 | 161 | #### Leaving the Group 162 | 163 | There are two ways of leaving the group: closing the subscriber's connection or 164 | calling `Unsubscribe`: 165 | 166 | ```go 167 | // Have qsub leave the queue group 168 | qsub.Unsubscribe() 169 | ``` 170 | 171 | If the leaving member had un-acknowledged messages, those messages are reassigned 172 | to the remaining members. 173 | 174 | #### Closing a Queue Group 175 | 176 | There is no special API for that. Once all members have left (either calling `Unsubscribe`, 177 | or their connections are closed), the group is removed from the server. 178 | 179 | The next call to `QueueSubscribe` with the same group name will create a brand new group, 180 | that is, the start position will take effect and delivery will start from there. 181 | 182 | ### Durable Queue Groups 183 | 184 | As described above, for non durable queue subscribers, when the last member leaves the group, 185 | that group is removed. A durable queue group allows you to have all members leave but still 186 | maintain state. When a member re-joins, it starts at the last position in that group. 187 | 188 | #### Creating a Durable Queue Group 189 | 190 | A durable queue group is created in a similar manner as that of a standard queue group, 191 | except the `DurableName` option must be used to specify durability. 192 | 193 | ```go 194 | sc.QueueSubscribe("foo", "bar", qcb, stan.DurableName("dur")) 195 | ``` 196 | A group called `dur:bar` (the concatenation of durable name and group name) is created in 197 | the server. This means two things: 198 | 199 | - The character `:` is not allowed for a queue subscriber's durable name. 200 | - Durable and non-durable queue groups with the same name can coexist. 201 | 202 | ```go 203 | // Non durable queue subscriber on group "bar" 204 | qsub, _ := sc.QueueSubscribe("foo", "bar", qcb) 205 | 206 | // Durable queue subscriber on group "bar" 207 | durQsub, _ := sc.QueueSubscribe("foo", "bar", qcb, stan.DurableName("mydurablegroup")) 208 | 209 | // The same message produced on "foo" would be received by both queue subscribers. 210 | ``` 211 | 212 | #### Start Position 213 | 214 | The rules for non-durable queue subscribers apply to durable subscribers. 215 | 216 | #### Leaving the Group 217 | 218 | As for non-durable queue subscribers, if a member's connection is closed, or if 219 | `Unsubscribe` its called, the member leaves the group. Any unacknowledged message 220 | is transferred to remaining members. See *Closing the Group* for important difference 221 | with non-durable queue subscribers. 222 | 223 | #### Closing the Group 224 | 225 | The *last* member calling `Unsubscribe` will close (that is destroy) the 226 | group. So if you want to maintain durability of the group, you should not be 227 | calling `Unsubscribe`. 228 | 229 | So unlike for non-durable queue subscribers, it is possible to maintain a queue group 230 | with no member in the server. When a new member re-joins the durable queue group, 231 | it will resume from where the group left of, actually first receiving all unacknowledged 232 | messages that may have been left when the last member previously left. 233 | 234 | 235 | ### Wildcard Subscriptions 236 | 237 | NATS Streaming subscriptions **do not** support wildcards. 238 | 239 | 240 | ## Advanced Usage 241 | 242 | ### Asynchronous Publishing 243 | 244 | The basic publish API (`Publish(subject, payload)`) is synchronous; it does not return control to the caller until the NATS Streaming server has acknowledged receipt of the message. To accomplish this, a [NUID](https://github.com/nats-io/nuid) is generated for the message on creation, and the client library waits for a publish acknowledgement from the server with a matching NUID before it returns control to the caller, possibly with an error indicating that the operation was not successful due to some server problem or authorization error. 245 | 246 | Advanced users may wish to process these publish acknowledgements manually to achieve higher publish throughput by not waiting on individual acknowledgements during the publish operation. An asynchronous publish API is provided for this purpose: 247 | 248 | ```go 249 | ackHandler := func(ackedNuid string, err error) { 250 | if err != nil { 251 | log.Printf("Warning: error publishing msg id %s: %v\n", ackedNuid, err.Error()) 252 | } else { 253 | log.Printf("Received ack for msg id %s\n", ackedNuid) 254 | } 255 | } 256 | 257 | // can also use PublishAsyncWithReply(subj, replysubj, payload, ah) 258 | nuid, err := sc.PublishAsync("foo", []byte("Hello World"), ackHandler) // returns immediately 259 | if err != nil { 260 | log.Printf("Error publishing msg %s: %v\n", nuid, err.Error()) 261 | } 262 | ``` 263 | 264 | ### Message Acknowledgements and Redelivery 265 | 266 | NATS Streaming offers At-Least-Once delivery semantics, meaning that once a message has been delivered to an eligible subscriber, if an acknowledgement is not received within the configured timeout interval, NATS Streaming will attempt redelivery of the message. 267 | This timeout interval is specified by the subscription option `AckWait`, which defaults to 30 seconds. 268 | 269 | By default, messages are automatically acknowledged by the NATS Streaming client library after the subscriber's message handler is invoked. However, there may be cases in which the subscribing client wishes to accelerate or defer acknowledgement of the message. 270 | To do this, the client must set manual acknowledgement mode on the subscription, and invoke `Ack()` on the `Msg`. ex: 271 | 272 | ```go 273 | // Subscribe with manual ack mode, and set AckWait to 60 seconds 274 | aw, _ := time.ParseDuration("60s") 275 | sub, err := sc.Subscribe("foo", func(m *stan.Msg) { 276 | m.Ack() // ack message before performing I/O intensive operation 277 | ///... 278 | fmt.Printf("Received a message: %s\n", string(m.Data)) 279 | }, stan.SetManualAckMode(), stan.AckWait(aw)) 280 | ``` 281 | 282 | ## Rate limiting/matching 283 | 284 | A classic problem of publish-subscribe messaging is matching the rate of message producers with the rate of message consumers. 285 | Message producers can often outpace the speed of the subscribers that are consuming their messages. 286 | This mismatch is commonly called a "fast producer/slow consumer" problem, and may result in dramatic resource utilization spikes in the underlying messaging system as it tries to buffer messages until the slow consumer(s) can catch up. 287 | 288 | ### Publisher rate limiting 289 | 290 | NATS Streaming provides a connection option called `MaxPubAcksInflight` that effectively limits the number of unacknowledged messages that a publisher may have in-flight at any given time. When this maximum is reached, further `PublishAsync()` calls will block until the number of unacknowledged messages falls below the specified limit. ex: 291 | 292 | ```go 293 | sc, _ := stan.Connect(clusterID, clientID, MaxPubAcksInflight(25)) 294 | 295 | ah := func(nuid string, err error) { 296 | // process the ack 297 | ... 298 | } 299 | 300 | for i := 1; i < 1000; i++ { 301 | // If the server is unable to keep up with the publisher, the number of outstanding acks will eventually 302 | // reach the max and this call will block 303 | guid, _ := sc.PublishAsync("foo", []byte("Hello World"), ah) 304 | } 305 | ``` 306 | 307 | ### Subscriber rate limiting 308 | 309 | Rate limiting may also be accomplished on the subscriber side, on a per-subscription basis, using a subscription option called `MaxInflight`. 310 | This option specifies the maximum number of outstanding acknowledgements (messages that have been delivered but not acknowledged) that NATS Streaming will allow for a given subscription. 311 | When this limit is reached, NATS Streaming will suspend delivery of messages to this subscription until the number of unacknowledged messages falls below the specified limit. ex: 312 | 313 | ```go 314 | // Subscribe with manual ack mode and a max in-flight limit of 25 315 | sc.Subscribe("foo", func(m *stan.Msg) { 316 | fmt.Printf("Received message #: %s\n", string(m.Data)) 317 | ... 318 | // Does not ack, or takes a very long time to ack 319 | ... 320 | // Message delivery will suspend when the number of unacknowledged messages reaches 25 321 | }, stan.SetManualAckMode(), stan.MaxInflight(25)) 322 | 323 | ``` 324 | 325 | ## License 326 | 327 | Unless otherwise noted, the NATS source files are distributed 328 | under the Apache Version 2.0 license found in the LICENSE file. -------------------------------------------------------------------------------- /sub.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2018 The NATS Authors 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | // Package stan is a Go client for the NATS Streaming messaging system (https://nats.io). 15 | package stan 16 | 17 | import ( 18 | "errors" 19 | "sync" 20 | "time" 21 | 22 | "github.com/nats-io/go-nats" 23 | "github.com/nats-io/go-nats-streaming/pb" 24 | ) 25 | 26 | const ( 27 | // DefaultAckWait indicates how long the server should wait for an ACK before resending a message 28 | DefaultAckWait = 30 * time.Second 29 | // DefaultMaxInflight indicates how many messages with outstanding ACKs the server can send 30 | DefaultMaxInflight = 1024 31 | ) 32 | 33 | // Msg is the client defined message, which includes proto, then back link to subscription. 34 | type Msg struct { 35 | pb.MsgProto // MsgProto: Seq, Subject, Reply[opt], Data, Timestamp, CRC32[opt] 36 | Sub Subscription 37 | } 38 | 39 | // Subscriptions and Options 40 | 41 | // Subscription represents a subscription within the NATS Streaming cluster. Subscriptions 42 | // will be rate matched and follow at-least delivery semantics. 43 | type Subscription interface { 44 | ClearMaxPending() error 45 | Delivered() (int64, error) 46 | Dropped() (int, error) 47 | IsValid() bool 48 | MaxPending() (int, int, error) 49 | Pending() (int, int, error) 50 | PendingLimits() (int, int, error) 51 | SetPendingLimits(msgLimit, bytesLimit int) error 52 | // Unsubscribe removes interest in the subscription. 53 | // For durables, it means that the durable interest is also removed from 54 | // the server. Restarting a durable with the same name will not resume 55 | // the subscription, it will be considered a new one. 56 | Unsubscribe() error 57 | 58 | // Close removes this subscriber from the server, but unlike Unsubscribe(), 59 | // the durable interest is not removed. If the client has connected to a server 60 | // for which this feature is not available, Close() will return a ErrNoServerSupport 61 | // error. 62 | Close() error 63 | } 64 | 65 | // A subscription represents a subscription to a stan cluster. 66 | type subscription struct { 67 | sync.RWMutex 68 | sc *conn 69 | subject string 70 | qgroup string 71 | inbox string 72 | ackInbox string 73 | inboxSub *nats.Subscription 74 | opts SubscriptionOptions 75 | cb MsgHandler 76 | } 77 | 78 | // SubscriptionOption is a function on the options for a subscription. 79 | type SubscriptionOption func(*SubscriptionOptions) error 80 | 81 | // MsgHandler is a callback function that processes messages delivered to 82 | // asynchronous subscribers. 83 | type MsgHandler func(msg *Msg) 84 | 85 | // SubscriptionOptions are used to control the Subscription's behavior. 86 | type SubscriptionOptions struct { 87 | // DurableName, if set will survive client restarts. 88 | DurableName string 89 | // Controls the number of messages the cluster will have inflight without an ACK. 90 | MaxInflight int 91 | // Controls the time the cluster will wait for an ACK for a given message. 92 | AckWait time.Duration 93 | // StartPosition enum from proto. 94 | StartAt pb.StartPosition 95 | // Optional start sequence number. 96 | StartSequence uint64 97 | // Optional start time. 98 | StartTime time.Time 99 | // Option to do Manual Acks 100 | ManualAcks bool 101 | } 102 | 103 | // DefaultSubscriptionOptions are the default subscriptions' options 104 | var DefaultSubscriptionOptions = SubscriptionOptions{ 105 | MaxInflight: DefaultMaxInflight, 106 | AckWait: DefaultAckWait, 107 | } 108 | 109 | // MaxInflight is an Option to set the maximum number of messages the cluster will send 110 | // without an ACK. 111 | func MaxInflight(m int) SubscriptionOption { 112 | return func(o *SubscriptionOptions) error { 113 | o.MaxInflight = m 114 | return nil 115 | } 116 | } 117 | 118 | // AckWait is an Option to set the timeout for waiting for an ACK from the cluster's 119 | // point of view for delivered messages. 120 | func AckWait(t time.Duration) SubscriptionOption { 121 | return func(o *SubscriptionOptions) error { 122 | o.AckWait = t 123 | return nil 124 | } 125 | } 126 | 127 | // StartAt sets the desired start position for the message stream. 128 | func StartAt(sp pb.StartPosition) SubscriptionOption { 129 | return func(o *SubscriptionOptions) error { 130 | o.StartAt = sp 131 | return nil 132 | } 133 | } 134 | 135 | // StartAtSequence sets the desired start sequence position and state. 136 | func StartAtSequence(seq uint64) SubscriptionOption { 137 | return func(o *SubscriptionOptions) error { 138 | o.StartAt = pb.StartPosition_SequenceStart 139 | o.StartSequence = seq 140 | return nil 141 | } 142 | } 143 | 144 | // StartAtTime sets the desired start time position and state. 145 | func StartAtTime(start time.Time) SubscriptionOption { 146 | return func(o *SubscriptionOptions) error { 147 | o.StartAt = pb.StartPosition_TimeDeltaStart 148 | o.StartTime = start 149 | return nil 150 | } 151 | } 152 | 153 | // StartAtTimeDelta sets the desired start time position and state using the delta. 154 | func StartAtTimeDelta(ago time.Duration) SubscriptionOption { 155 | return func(o *SubscriptionOptions) error { 156 | o.StartAt = pb.StartPosition_TimeDeltaStart 157 | o.StartTime = time.Now().Add(-ago) 158 | return nil 159 | } 160 | } 161 | 162 | // StartWithLastReceived is a helper function to set start position to last received. 163 | func StartWithLastReceived() SubscriptionOption { 164 | return func(o *SubscriptionOptions) error { 165 | o.StartAt = pb.StartPosition_LastReceived 166 | return nil 167 | } 168 | } 169 | 170 | // DeliverAllAvailable will deliver all messages available. 171 | func DeliverAllAvailable() SubscriptionOption { 172 | return func(o *SubscriptionOptions) error { 173 | o.StartAt = pb.StartPosition_First 174 | return nil 175 | } 176 | } 177 | 178 | // SetManualAckMode will allow clients to control their own acks to delivered messages. 179 | func SetManualAckMode() SubscriptionOption { 180 | return func(o *SubscriptionOptions) error { 181 | o.ManualAcks = true 182 | return nil 183 | } 184 | } 185 | 186 | // DurableName sets the DurableName for the subcriber. 187 | func DurableName(name string) SubscriptionOption { 188 | return func(o *SubscriptionOptions) error { 189 | o.DurableName = name 190 | return nil 191 | } 192 | } 193 | 194 | // Subscribe will perform a subscription with the given options to the NATS Streaming cluster. 195 | func (sc *conn) Subscribe(subject string, cb MsgHandler, options ...SubscriptionOption) (Subscription, error) { 196 | return sc.subscribe(subject, "", cb, options...) 197 | } 198 | 199 | // QueueSubscribe will perform a queue subscription with the given options to the NATS Streaming cluster. 200 | func (sc *conn) QueueSubscribe(subject, qgroup string, cb MsgHandler, options ...SubscriptionOption) (Subscription, error) { 201 | return sc.subscribe(subject, qgroup, cb, options...) 202 | } 203 | 204 | // subscribe will perform a subscription with the given options to the NATS Streaming cluster. 205 | func (sc *conn) subscribe(subject, qgroup string, cb MsgHandler, options ...SubscriptionOption) (Subscription, error) { 206 | sub := &subscription{subject: subject, qgroup: qgroup, inbox: nats.NewInbox(), cb: cb, sc: sc, opts: DefaultSubscriptionOptions} 207 | for _, opt := range options { 208 | if err := opt(&sub.opts); err != nil { 209 | return nil, err 210 | } 211 | } 212 | sc.Lock() 213 | if sc.nc == nil { 214 | sc.Unlock() 215 | return nil, ErrConnectionClosed 216 | } 217 | 218 | // Register subscription. 219 | sc.subMap[sub.inbox] = sub 220 | nc := sc.nc 221 | sc.Unlock() 222 | 223 | // Hold lock throughout. 224 | sub.Lock() 225 | defer sub.Unlock() 226 | 227 | // Listen for actual messages. 228 | nsub, err := nc.Subscribe(sub.inbox, sc.processMsg) 229 | if err != nil { 230 | return nil, err 231 | } 232 | sub.inboxSub = nsub 233 | 234 | // Create a subscription request 235 | // FIXME(dlc) add others. 236 | sr := &pb.SubscriptionRequest{ 237 | ClientID: sc.clientID, 238 | Subject: subject, 239 | QGroup: qgroup, 240 | Inbox: sub.inbox, 241 | MaxInFlight: int32(sub.opts.MaxInflight), 242 | AckWaitInSecs: int32(sub.opts.AckWait / time.Second), 243 | StartPosition: sub.opts.StartAt, 244 | DurableName: sub.opts.DurableName, 245 | } 246 | 247 | // Conditionals 248 | switch sr.StartPosition { 249 | case pb.StartPosition_TimeDeltaStart: 250 | sr.StartTimeDelta = time.Now().UnixNano() - sub.opts.StartTime.UnixNano() 251 | case pb.StartPosition_SequenceStart: 252 | sr.StartSequence = sub.opts.StartSequence 253 | } 254 | 255 | b, _ := sr.Marshal() 256 | reply, err := sc.nc.Request(sc.subRequests, b, sc.opts.ConnectTimeout) 257 | if err != nil { 258 | sub.inboxSub.Unsubscribe() 259 | if err == nats.ErrTimeout { 260 | err = ErrSubReqTimeout 261 | } 262 | return nil, err 263 | } 264 | r := &pb.SubscriptionResponse{} 265 | if err := r.Unmarshal(reply.Data); err != nil { 266 | sub.inboxSub.Unsubscribe() 267 | return nil, err 268 | } 269 | if r.Error != "" { 270 | sub.inboxSub.Unsubscribe() 271 | return nil, errors.New(r.Error) 272 | } 273 | sub.ackInbox = r.AckInbox 274 | 275 | return sub, nil 276 | } 277 | 278 | // ClearMaxPending resets the maximums seen so far. 279 | func (sub *subscription) ClearMaxPending() error { 280 | sub.Lock() 281 | defer sub.Unlock() 282 | if sub.inboxSub == nil { 283 | return ErrBadSubscription 284 | } 285 | return sub.inboxSub.ClearMaxPending() 286 | } 287 | 288 | // Delivered returns the number of delivered messages for this subscription. 289 | func (sub *subscription) Delivered() (int64, error) { 290 | sub.Lock() 291 | defer sub.Unlock() 292 | if sub.inboxSub == nil { 293 | return -1, ErrBadSubscription 294 | } 295 | return sub.inboxSub.Delivered() 296 | } 297 | 298 | // Dropped returns the number of known dropped messages for this subscription. 299 | // This will correspond to messages dropped by violations of PendingLimits. If 300 | // the server declares the connection a SlowConsumer, this number may not be 301 | // valid. 302 | func (sub *subscription) Dropped() (int, error) { 303 | sub.Lock() 304 | defer sub.Unlock() 305 | if sub.inboxSub == nil { 306 | return -1, ErrBadSubscription 307 | } 308 | return sub.inboxSub.Dropped() 309 | } 310 | 311 | // IsValid returns a boolean indicating whether the subscription 312 | // is still active. This will return false if the subscription has 313 | // already been closed. 314 | func (sub *subscription) IsValid() bool { 315 | sub.Lock() 316 | defer sub.Unlock() 317 | if sub.inboxSub == nil { 318 | return false 319 | } 320 | return sub.inboxSub.IsValid() 321 | } 322 | 323 | // MaxPending returns the maximum number of queued messages and queued bytes seen so far. 324 | func (sub *subscription) MaxPending() (int, int, error) { 325 | sub.Lock() 326 | defer sub.Unlock() 327 | if sub.inboxSub == nil { 328 | return -1, -1, ErrBadSubscription 329 | } 330 | return sub.inboxSub.MaxPending() 331 | } 332 | 333 | // Pending returns the number of queued messages and queued bytes in the client for this subscription. 334 | func (sub *subscription) Pending() (int, int, error) { 335 | sub.Lock() 336 | defer sub.Unlock() 337 | if sub.inboxSub == nil { 338 | return -1, -1, ErrBadSubscription 339 | } 340 | return sub.inboxSub.Pending() 341 | } 342 | 343 | // PendingLimits returns the current limits for this subscription. 344 | // If no error is returned, a negative value indicates that the 345 | // given metric is not limited. 346 | func (sub *subscription) PendingLimits() (int, int, error) { 347 | sub.Lock() 348 | defer sub.Unlock() 349 | if sub.inboxSub == nil { 350 | return -1, -1, ErrBadSubscription 351 | } 352 | return sub.inboxSub.PendingLimits() 353 | } 354 | 355 | // SetPendingLimits sets the limits for pending msgs and bytes for this subscription. 356 | // Zero is not allowed. Any negative value means that the given metric is not limited. 357 | func (sub *subscription) SetPendingLimits(msgLimit, bytesLimit int) error { 358 | sub.Lock() 359 | defer sub.Unlock() 360 | if sub.inboxSub == nil { 361 | return ErrBadSubscription 362 | } 363 | return sub.inboxSub.SetPendingLimits(msgLimit, bytesLimit) 364 | } 365 | 366 | // closeOrUnsubscribe performs either close or unsubsribe based on 367 | // given boolean. 368 | func (sub *subscription) closeOrUnsubscribe(doClose bool) error { 369 | sub.Lock() 370 | sc := sub.sc 371 | if sc == nil { 372 | // Already closed. 373 | sub.Unlock() 374 | return ErrBadSubscription 375 | } 376 | sub.sc = nil 377 | sub.inboxSub.Unsubscribe() 378 | sub.inboxSub = nil 379 | sub.Unlock() 380 | 381 | sc.Lock() 382 | if sc.nc == nil { 383 | sc.Unlock() 384 | return ErrConnectionClosed 385 | } 386 | 387 | delete(sc.subMap, sub.inbox) 388 | reqSubject := sc.unsubRequests 389 | if doClose { 390 | reqSubject = sc.subCloseRequests 391 | if reqSubject == "" { 392 | sc.Unlock() 393 | return ErrNoServerSupport 394 | } 395 | } 396 | 397 | // Snapshot connection to avoid data race, since the connection may be 398 | // closing while we try to send the request 399 | nc := sc.nc 400 | sc.Unlock() 401 | 402 | usr := &pb.UnsubscribeRequest{ 403 | ClientID: sc.clientID, 404 | Subject: sub.subject, 405 | Inbox: sub.ackInbox, 406 | } 407 | b, _ := usr.Marshal() 408 | reply, err := nc.Request(reqSubject, b, sc.opts.ConnectTimeout) 409 | if err != nil { 410 | if err == nats.ErrTimeout { 411 | if doClose { 412 | return ErrCloseReqTimeout 413 | } 414 | return ErrUnsubReqTimeout 415 | } 416 | return err 417 | } 418 | r := &pb.SubscriptionResponse{} 419 | if err := r.Unmarshal(reply.Data); err != nil { 420 | return err 421 | } 422 | if r.Error != "" { 423 | return errors.New(r.Error) 424 | } 425 | 426 | return nil 427 | } 428 | 429 | // Unsubscribe implements the Subscription interface 430 | func (sub *subscription) Unsubscribe() error { 431 | return sub.closeOrUnsubscribe(false) 432 | } 433 | 434 | // Close implements the Subscription interface 435 | func (sub *subscription) Close() error { 436 | return sub.closeOrUnsubscribe(true) 437 | } 438 | 439 | // Ack manually acknowledges a message. 440 | // The subscriber had to be created with SetManualAckMode() option. 441 | func (msg *Msg) Ack() error { 442 | if msg == nil { 443 | return ErrNilMsg 444 | } 445 | // Look up subscription (cannot be nil) 446 | sub := msg.Sub.(*subscription) 447 | sub.RLock() 448 | ackSubject := sub.ackInbox 449 | isManualAck := sub.opts.ManualAcks 450 | sc := sub.sc 451 | sub.RUnlock() 452 | 453 | // Check for error conditions. 454 | if !isManualAck { 455 | return ErrManualAck 456 | } 457 | if sc == nil { 458 | return ErrBadSubscription 459 | } 460 | // Get nc from the connection (needs locking to avoid race) 461 | sc.RLock() 462 | nc := sc.nc 463 | sc.RUnlock() 464 | if nc == nil { 465 | return ErrBadConnection 466 | } 467 | 468 | // Ack here. 469 | ack := &pb.Ack{Subject: msg.Subject, Sequence: msg.Sequence} 470 | b, _ := ack.Marshal() 471 | return nc.Publish(ackSubject, b) 472 | } 473 | -------------------------------------------------------------------------------- /stan.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2018 The NATS Authors 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | 14 | // Package stan is a Go client for the NATS Streaming messaging system (https://nats.io). 15 | package stan 16 | 17 | import ( 18 | "errors" 19 | "fmt" 20 | "runtime" 21 | "sync" 22 | "time" 23 | 24 | "github.com/nats-io/go-nats" 25 | "github.com/nats-io/go-nats-streaming/pb" 26 | "github.com/nats-io/nuid" 27 | ) 28 | 29 | // Version is the NATS Streaming Go Client version 30 | const Version = "0.3.4" 31 | 32 | const ( 33 | // DefaultNatsURL is the default URL the client connects to 34 | DefaultNatsURL = "nats://localhost:4222" 35 | // DefaultConnectWait is the default timeout used for the connect operation 36 | DefaultConnectWait = 2 * time.Second 37 | // DefaultDiscoverPrefix is the prefix subject used to connect to the NATS Streaming server 38 | DefaultDiscoverPrefix = "_STAN.discover" 39 | // DefaultACKPrefix is the prefix subject used to send ACKs to the NATS Streaming server 40 | DefaultACKPrefix = "_STAN.acks" 41 | // DefaultMaxPubAcksInflight is the default maximum number of published messages 42 | // without outstanding ACKs from the server 43 | DefaultMaxPubAcksInflight = 16384 44 | ) 45 | 46 | // Conn represents a connection to the NATS Streaming subsystem. It can Publish and 47 | // Subscribe to messages within the NATS Streaming cluster. 48 | type Conn interface { 49 | // Publish 50 | Publish(subject string, data []byte) error 51 | PublishAsync(subject string, data []byte, ah AckHandler) (string, error) 52 | 53 | // Subscribe 54 | Subscribe(subject string, cb MsgHandler, opts ...SubscriptionOption) (Subscription, error) 55 | 56 | // QueueSubscribe 57 | QueueSubscribe(subject, qgroup string, cb MsgHandler, opts ...SubscriptionOption) (Subscription, error) 58 | 59 | // Close 60 | Close() error 61 | 62 | // NatsConn returns the underlying NATS conn. Use this with care. For 63 | // example, closing the wrapped NATS conn will put the NATS Streaming Conn 64 | // in an invalid state. 65 | NatsConn() *nats.Conn 66 | } 67 | 68 | // Errors 69 | var ( 70 | ErrConnectReqTimeout = errors.New("stan: connect request timeout") 71 | ErrCloseReqTimeout = errors.New("stan: close request timeout") 72 | ErrSubReqTimeout = errors.New("stan: subscribe request timeout") 73 | ErrUnsubReqTimeout = errors.New("stan: unsubscribe request timeout") 74 | ErrConnectionClosed = errors.New("stan: connection closed") 75 | ErrTimeout = errors.New("stan: publish ack timeout") 76 | ErrBadAck = errors.New("stan: malformed ack") 77 | ErrBadSubscription = errors.New("stan: invalid subscription") 78 | ErrBadConnection = errors.New("stan: invalid connection") 79 | ErrManualAck = errors.New("stan: cannot manually ack in auto-ack mode") 80 | ErrNilMsg = errors.New("stan: nil message") 81 | ErrNoServerSupport = errors.New("stan: not supported by server") 82 | ) 83 | 84 | // AckHandler is used for Async Publishing to provide status of the ack. 85 | // The func will be passed the GUID and any error state. No error means the 86 | // message was successfully received by NATS Streaming. 87 | type AckHandler func(string, error) 88 | 89 | // Options can be used to a create a customized connection. 90 | type Options struct { 91 | NatsURL string 92 | NatsConn *nats.Conn 93 | ConnectTimeout time.Duration 94 | AckTimeout time.Duration 95 | DiscoverPrefix string 96 | MaxPubAcksInflight int 97 | } 98 | 99 | // DefaultOptions are the NATS Streaming client's default options 100 | var DefaultOptions = Options{ 101 | NatsURL: DefaultNatsURL, 102 | ConnectTimeout: DefaultConnectWait, 103 | AckTimeout: DefaultAckWait, 104 | DiscoverPrefix: DefaultDiscoverPrefix, 105 | MaxPubAcksInflight: DefaultMaxPubAcksInflight, 106 | } 107 | 108 | // Option is a function on the options for a connection. 109 | type Option func(*Options) error 110 | 111 | // NatsURL is an Option to set the URL the client should connect to. 112 | func NatsURL(u string) Option { 113 | return func(o *Options) error { 114 | o.NatsURL = u 115 | return nil 116 | } 117 | } 118 | 119 | // ConnectWait is an Option to set the timeout for establishing a connection. 120 | func ConnectWait(t time.Duration) Option { 121 | return func(o *Options) error { 122 | o.ConnectTimeout = t 123 | return nil 124 | } 125 | } 126 | 127 | // PubAckWait is an Option to set the timeout for waiting for an ACK for a 128 | // published message. 129 | func PubAckWait(t time.Duration) Option { 130 | return func(o *Options) error { 131 | o.AckTimeout = t 132 | return nil 133 | } 134 | } 135 | 136 | // MaxPubAcksInflight is an Option to set the maximum number of published 137 | // messages without outstanding ACKs from the server. 138 | func MaxPubAcksInflight(max int) Option { 139 | return func(o *Options) error { 140 | o.MaxPubAcksInflight = max 141 | return nil 142 | } 143 | } 144 | 145 | // NatsConn is an Option to set the underlying NATS connection to be used 146 | // by a NATS Streaming Conn object. 147 | func NatsConn(nc *nats.Conn) Option { 148 | return func(o *Options) error { 149 | o.NatsConn = nc 150 | return nil 151 | } 152 | } 153 | 154 | // A conn represents a bare connection to a stan cluster. 155 | type conn struct { 156 | sync.RWMutex 157 | clientID string 158 | pubPrefix string // Publish prefix set by stan, append our subject. 159 | subRequests string // Subject to send subscription requests. 160 | unsubRequests string // Subject to send unsubscribe requests. 161 | subCloseRequests string // Subject to send subscription close requests. 162 | closeRequests string // Subject to send close requests. 163 | ackSubject string // publish acks 164 | ackSubscription *nats.Subscription 165 | hbSubscription *nats.Subscription 166 | subMap map[string]*subscription 167 | pubAckMap map[string]*ack 168 | pubAckChan chan (struct{}) 169 | opts Options 170 | nc *nats.Conn 171 | ncOwned bool // NATS Streaming created the connection, so needs to close it. 172 | } 173 | 174 | // Closure for ack contexts. 175 | type ack struct { 176 | t *time.Timer 177 | ah AckHandler 178 | ch chan error 179 | } 180 | 181 | // Connect will form a connection to the NATS Streaming subsystem. 182 | // Note that clientID can contain only alphanumeric and `-` or `_` characters. 183 | func Connect(stanClusterID, clientID string, options ...Option) (Conn, error) { 184 | // Process Options 185 | c := conn{clientID: clientID, opts: DefaultOptions} 186 | for _, opt := range options { 187 | if err := opt(&c.opts); err != nil { 188 | return nil, err 189 | } 190 | } 191 | // Check if the user has provided a connection as an option 192 | c.nc = c.opts.NatsConn 193 | // Create a NATS connection if it doesn't exist. 194 | if c.nc == nil { 195 | nc, err := nats.Connect(c.opts.NatsURL, nats.Name(clientID)) 196 | if err != nil { 197 | return nil, err 198 | } 199 | c.nc = nc 200 | c.ncOwned = true 201 | } else if !c.nc.IsConnected() { 202 | // Bail if the custom NATS connection is disconnected 203 | return nil, ErrBadConnection 204 | } 205 | 206 | // Create a heartbeat inbox 207 | hbInbox := nats.NewInbox() 208 | var err error 209 | if c.hbSubscription, err = c.nc.Subscribe(hbInbox, c.processHeartBeat); err != nil { 210 | c.Close() 211 | return nil, err 212 | } 213 | 214 | // Send Request to discover the cluster 215 | discoverSubject := c.opts.DiscoverPrefix + "." + stanClusterID 216 | req := &pb.ConnectRequest{ClientID: clientID, HeartbeatInbox: hbInbox} 217 | b, _ := req.Marshal() 218 | reply, err := c.nc.Request(discoverSubject, b, c.opts.ConnectTimeout) 219 | if err != nil { 220 | c.Close() 221 | if err == nats.ErrTimeout { 222 | return nil, ErrConnectReqTimeout 223 | } 224 | return nil, err 225 | } 226 | // Process the response, grab server pubPrefix 227 | cr := &pb.ConnectResponse{} 228 | err = cr.Unmarshal(reply.Data) 229 | if err != nil { 230 | c.Close() 231 | return nil, err 232 | } 233 | if cr.Error != "" { 234 | c.Close() 235 | return nil, errors.New(cr.Error) 236 | } 237 | 238 | // Capture cluster configuration endpoints to publish and subscribe/unsubscribe. 239 | c.pubPrefix = cr.PubPrefix 240 | c.subRequests = cr.SubRequests 241 | c.unsubRequests = cr.UnsubRequests 242 | c.subCloseRequests = cr.SubCloseRequests 243 | c.closeRequests = cr.CloseRequests 244 | 245 | // Setup the ACK subscription 246 | c.ackSubject = DefaultACKPrefix + "." + nuid.Next() 247 | if c.ackSubscription, err = c.nc.Subscribe(c.ackSubject, c.processAck); err != nil { 248 | c.Close() 249 | return nil, err 250 | } 251 | c.ackSubscription.SetPendingLimits(1024*1024, 32*1024*1024) 252 | c.pubAckMap = make(map[string]*ack) 253 | 254 | // Create Subscription map 255 | c.subMap = make(map[string]*subscription) 256 | 257 | c.pubAckChan = make(chan struct{}, c.opts.MaxPubAcksInflight) 258 | 259 | // Attach a finalizer 260 | runtime.SetFinalizer(&c, func(sc *conn) { sc.Close() }) 261 | 262 | return &c, nil 263 | } 264 | 265 | // Close a connection to the stan system. 266 | func (sc *conn) Close() error { 267 | sc.Lock() 268 | defer sc.Unlock() 269 | 270 | if sc.nc == nil { 271 | // We are already closed. 272 | return nil 273 | } 274 | 275 | // Capture for NATS calls below. 276 | nc := sc.nc 277 | if sc.ncOwned { 278 | defer nc.Close() 279 | } 280 | 281 | // Signals we are closed. 282 | sc.nc = nil 283 | 284 | // Now close ourselves. 285 | if sc.ackSubscription != nil { 286 | sc.ackSubscription.Unsubscribe() 287 | } 288 | 289 | req := &pb.CloseRequest{ClientID: sc.clientID} 290 | b, _ := req.Marshal() 291 | reply, err := nc.Request(sc.closeRequests, b, sc.opts.ConnectTimeout) 292 | if err != nil { 293 | if err == nats.ErrTimeout { 294 | return ErrCloseReqTimeout 295 | } 296 | return err 297 | } 298 | cr := &pb.CloseResponse{} 299 | err = cr.Unmarshal(reply.Data) 300 | if err != nil { 301 | return err 302 | } 303 | if cr.Error != "" { 304 | return errors.New(cr.Error) 305 | } 306 | return nil 307 | } 308 | 309 | // NatsConn returns the underlying NATS conn. Use this with care. For example, 310 | // closing the wrapped NATS conn will put the NATS Streaming Conn in an invalid 311 | // state. 312 | func (sc *conn) NatsConn() *nats.Conn { 313 | return sc.nc 314 | } 315 | 316 | // Process a heartbeat from the NATS Streaming cluster 317 | func (sc *conn) processHeartBeat(m *nats.Msg) { 318 | // No payload assumed, just reply. 319 | sc.RLock() 320 | nc := sc.nc 321 | sc.RUnlock() 322 | if nc != nil { 323 | nc.Publish(m.Reply, nil) 324 | } 325 | } 326 | 327 | // Process an ack from the NATS Streaming cluster 328 | func (sc *conn) processAck(m *nats.Msg) { 329 | pa := &pb.PubAck{} 330 | err := pa.Unmarshal(m.Data) 331 | if err != nil { 332 | panic(fmt.Errorf("Error during ack unmarshal: %v", err)) 333 | } 334 | 335 | // Remove 336 | a := sc.removeAck(pa.Guid) 337 | if a != nil { 338 | // Capture error if it exists. 339 | if pa.Error != "" { 340 | err = errors.New(pa.Error) 341 | } 342 | if a.ah != nil { 343 | // Perform the ackHandler callback 344 | a.ah(pa.Guid, err) 345 | } else if a.ch != nil { 346 | // Send to channel directly 347 | a.ch <- err 348 | } 349 | } 350 | } 351 | 352 | // Publish will publish to the cluster and wait for an ACK. 353 | func (sc *conn) Publish(subject string, data []byte) error { 354 | ch := make(chan error) 355 | _, err := sc.publishAsync(subject, data, nil, ch) 356 | if err == nil { 357 | err = <-ch 358 | } 359 | return err 360 | } 361 | 362 | // PublishAsync will publish to the cluster on pubPrefix+subject and asynchronously 363 | // process the ACK or error state. It will return the GUID for the message being sent. 364 | func (sc *conn) PublishAsync(subject string, data []byte, ah AckHandler) (string, error) { 365 | return sc.publishAsync(subject, data, ah, nil) 366 | } 367 | 368 | func (sc *conn) publishAsync(subject string, data []byte, ah AckHandler, ch chan error) (string, error) { 369 | a := &ack{ah: ah, ch: ch} 370 | sc.Lock() 371 | if sc.nc == nil { 372 | sc.Unlock() 373 | return "", ErrConnectionClosed 374 | } 375 | 376 | subj := sc.pubPrefix + "." + subject 377 | // This is only what we need from PubMsg in the timer below, 378 | // so do this so that pe doesn't escape (and we same on new object) 379 | peGUID := nuid.Next() 380 | pe := &pb.PubMsg{ClientID: sc.clientID, Guid: peGUID, Subject: subject, Data: data} 381 | b, _ := pe.Marshal() 382 | 383 | // Map ack to guid. 384 | sc.pubAckMap[peGUID] = a 385 | // snapshot 386 | ackSubject := sc.ackSubject 387 | ackTimeout := sc.opts.AckTimeout 388 | pac := sc.pubAckChan 389 | sc.Unlock() 390 | 391 | // Use the buffered channel to control the number of outstanding acks. 392 | pac <- struct{}{} 393 | 394 | err := sc.nc.PublishRequest(subj, ackSubject, b) 395 | if err != nil { 396 | sc.removeAck(peGUID) 397 | return "", err 398 | } 399 | 400 | // Setup the timer for expiration. 401 | sc.Lock() 402 | a.t = time.AfterFunc(ackTimeout, func() { 403 | pubAck := sc.removeAck(peGUID) 404 | // processAck could get here before and handle the ack. 405 | // If that's the case, we would get nil here and simply return. 406 | if pubAck == nil { 407 | return 408 | } 409 | if pubAck.ah != nil { 410 | pubAck.ah(peGUID, ErrTimeout) 411 | } else if a.ch != nil { 412 | pubAck.ch <- ErrTimeout 413 | } 414 | }) 415 | sc.Unlock() 416 | 417 | return peGUID, nil 418 | } 419 | 420 | // removeAck removes the ack from the pubAckMap and cancels any state, e.g. timers 421 | func (sc *conn) removeAck(guid string) *ack { 422 | var t *time.Timer 423 | sc.Lock() 424 | a := sc.pubAckMap[guid] 425 | if a != nil { 426 | t = a.t 427 | delete(sc.pubAckMap, guid) 428 | } 429 | pac := sc.pubAckChan 430 | sc.Unlock() 431 | 432 | // Cancel timer if needed. 433 | if t != nil { 434 | t.Stop() 435 | } 436 | 437 | // Remove from channel to unblock PublishAsync 438 | if a != nil && len(pac) > 0 { 439 | <-pac 440 | } 441 | return a 442 | } 443 | 444 | // Process an msg from the NATS Streaming cluster 445 | func (sc *conn) processMsg(raw *nats.Msg) { 446 | msg := &Msg{} 447 | err := msg.Unmarshal(raw.Data) 448 | if err != nil { 449 | panic(fmt.Errorf("Error processing unmarshal for msg: %v", err)) 450 | } 451 | // Lookup the subscription 452 | sc.RLock() 453 | nc := sc.nc 454 | isClosed := nc == nil 455 | sub := sc.subMap[raw.Subject] 456 | sc.RUnlock() 457 | 458 | // Check if sub is no longer valid or connection has been closed. 459 | if sub == nil || isClosed { 460 | return 461 | } 462 | 463 | // Store in msg for backlink 464 | msg.Sub = sub 465 | 466 | sub.RLock() 467 | cb := sub.cb 468 | ackSubject := sub.ackInbox 469 | isManualAck := sub.opts.ManualAcks 470 | subsc := sub.sc // Can be nil if sub has been unsubscribed. 471 | sub.RUnlock() 472 | 473 | // Perform the callback 474 | if cb != nil && subsc != nil { 475 | cb(msg) 476 | } 477 | 478 | // Process auto-ack 479 | if !isManualAck && nc != nil { 480 | ack := &pb.Ack{Subject: msg.Subject, Sequence: msg.Sequence} 481 | b, _ := ack.Marshal() 482 | // FIXME(dlc) - Async error handler? Retry? 483 | nc.Publish(ackSubject, b) 484 | } 485 | } 486 | -------------------------------------------------------------------------------- /stan_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2016-2018 The NATS Authors 2 | // Licensed under the Apache License, Version 2.0 (the "License"); 3 | // you may not use this file except in compliance with the License. 4 | // You may obtain a copy of the License at 5 | // 6 | // http://www.apache.org/licenses/LICENSE-2.0 7 | // 8 | // Unless required by applicable law or agreed to in writing, software 9 | // distributed under the License is distributed on an "AS IS" BASIS, 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 | // See the License for the specific language governing permissions and 12 | // limitations under the License. 13 | package stan 14 | 15 | //////////////////////////////////////////////////////////////////////////////// 16 | // Package scoped specific tests here.. 17 | //////////////////////////////////////////////////////////////////////////////// 18 | 19 | import ( 20 | "bytes" 21 | "errors" 22 | "fmt" 23 | "math/rand" 24 | "runtime" 25 | "strconv" 26 | "strings" 27 | "sync" 28 | "sync/atomic" 29 | "testing" 30 | "time" 31 | 32 | natsd "github.com/nats-io/gnatsd/test" 33 | "github.com/nats-io/go-nats" 34 | "github.com/nats-io/go-nats-streaming/pb" 35 | "github.com/nats-io/nats-streaming-server/server" 36 | ) 37 | 38 | func RunServer(ID string) *server.StanServer { 39 | s, err := server.RunServer(ID) 40 | if err != nil { 41 | panic(err) 42 | } 43 | return s 44 | } 45 | 46 | func runServerWithOpts(sOpts *server.Options) *server.StanServer { 47 | s, err := server.RunServerWithOpts(sOpts, nil) 48 | if err != nil { 49 | panic(err) 50 | } 51 | return s 52 | } 53 | 54 | // Dumb wait program to sync on callbacks, etc... Will timeout 55 | func Wait(ch chan bool) error { 56 | return WaitTime(ch, 5*time.Second) 57 | } 58 | 59 | func WaitTime(ch chan bool, timeout time.Duration) error { 60 | select { 61 | case <-ch: 62 | return nil 63 | case <-time.After(timeout): 64 | } 65 | return errors.New("timeout") 66 | } 67 | 68 | func TestNoNats(t *testing.T) { 69 | if _, err := Connect("someNonExistentServerID", "myTestClient"); err != nats.ErrNoServers { 70 | t.Fatalf("Expected NATS: No Servers err, got %v\n", err) 71 | } 72 | } 73 | 74 | func TestUnreachable(t *testing.T) { 75 | s := natsd.RunDefaultServer() 76 | defer s.Shutdown() 77 | 78 | // Non-Existent or Unreachable 79 | connectTime := 25 * time.Millisecond 80 | start := time.Now() 81 | if _, err := Connect("someNonExistentServerID", "myTestClient", ConnectWait(connectTime)); err != ErrConnectReqTimeout { 82 | t.Fatalf("Expected Unreachable err, got %v\n", err) 83 | } 84 | if delta := time.Since(start); delta < connectTime { 85 | t.Fatalf("Expected to wait at least %v, but only waited %v\n", connectTime, delta) 86 | } 87 | } 88 | 89 | const ( 90 | clusterName = "my_test_cluster" 91 | clientName = "me" 92 | ) 93 | 94 | // So that we can pass tests and benchmarks... 95 | type tLogger interface { 96 | Fatalf(format string, args ...interface{}) 97 | Errorf(format string, args ...interface{}) 98 | } 99 | 100 | func stackFatalf(t tLogger, f string, args ...interface{}) { 101 | lines := make([]string, 0, 32) 102 | msg := fmt.Sprintf(f, args...) 103 | lines = append(lines, msg) 104 | 105 | // Generate the Stack of callers: 106 | for i := 1; true; i++ { 107 | _, file, line, ok := runtime.Caller(i) 108 | if !ok { 109 | break 110 | } 111 | msg := fmt.Sprintf("%d - %s:%d", i, file, line) 112 | lines = append(lines, msg) 113 | } 114 | 115 | t.Fatalf("%s", strings.Join(lines, "\n")) 116 | } 117 | 118 | func NewDefaultConnection(t tLogger) Conn { 119 | sc, err := Connect(clusterName, clientName) 120 | if err != nil { 121 | stackFatalf(t, "Expected to connect correctly, got err %v", err) 122 | } 123 | return sc 124 | } 125 | 126 | func TestConnClosedOnConnectFailure(t *testing.T) { 127 | s := natsd.RunDefaultServer() 128 | defer s.Shutdown() 129 | 130 | // Non-Existent or Unreachable 131 | connectTime := 25 * time.Millisecond 132 | if _, err := Connect("someNonExistentServerID", "myTestClient", ConnectWait(connectTime)); err != ErrConnectReqTimeout { 133 | t.Fatalf("Expected Unreachable err, got %v\n", err) 134 | } 135 | 136 | // Check that the underlying NATS connection has been closed. 137 | // We will first stop the server. If we have left the NATS connection 138 | // opened, it should be trying to reconnect. 139 | s.Shutdown() 140 | 141 | // Wait a bit 142 | time.Sleep(500 * time.Millisecond) 143 | 144 | // Inspecting go routines in search for a doReconnect 145 | buf := make([]byte, 10000) 146 | n := runtime.Stack(buf, true) 147 | if strings.Contains(string(buf[:n]), "doReconnect") { 148 | t.Fatal("NATS Connection suspected to not have been closed") 149 | } 150 | } 151 | 152 | func TestNatsConnNotClosedOnClose(t *testing.T) { 153 | // Run a NATS Streaming server 154 | s := RunServer(clusterName) 155 | defer s.Shutdown() 156 | 157 | // Create a NATS connection 158 | nc, err := nats.Connect(nats.DefaultURL) 159 | if err != nil { 160 | t.Fatalf("Unexpected error on Connect: %v", err) 161 | } 162 | defer nc.Close() 163 | 164 | // Pass this NATS connection to NATS Streaming 165 | sc, err := Connect(clusterName, clientName, NatsConn(nc)) 166 | if err != nil { 167 | t.Fatalf("Unexpected error on connect: %v", err) 168 | } 169 | // Now close the NATS Streaming connection 170 | sc.Close() 171 | 172 | // Verify that NATS connection is not closed 173 | if nc.IsClosed() { 174 | t.Fatal("NATS connection should NOT have been closed in Connect") 175 | } 176 | } 177 | 178 | func TestBasicConnect(t *testing.T) { 179 | // Run a NATS Streaming server 180 | s := RunServer(clusterName) 181 | defer s.Shutdown() 182 | sc := NewDefaultConnection(t) 183 | defer sc.Close() 184 | } 185 | 186 | func TestBasicPublish(t *testing.T) { 187 | // Run a NATS Streaming server 188 | s := RunServer(clusterName) 189 | defer s.Shutdown() 190 | sc := NewDefaultConnection(t) 191 | defer sc.Close() 192 | if err := sc.Publish("foo", []byte("Hello World!")); err != nil { 193 | t.Fatalf("Expected no errors on publish, got %v\n", err) 194 | } 195 | } 196 | 197 | func TestBasicPublishAsync(t *testing.T) { 198 | // Run a NATS Streaming server 199 | s := RunServer(clusterName) 200 | defer s.Shutdown() 201 | sc := NewDefaultConnection(t) 202 | defer sc.Close() 203 | ch := make(chan bool) 204 | var glock sync.Mutex 205 | var guid string 206 | acb := func(lguid string, err error) { 207 | glock.Lock() 208 | defer glock.Unlock() 209 | if lguid != guid { 210 | t.Fatalf("Expected a matching guid in ack callback, got %s vs %s\n", lguid, guid) 211 | } 212 | ch <- true 213 | } 214 | glock.Lock() 215 | guid, _ = sc.PublishAsync("foo", []byte("Hello World!"), acb) 216 | glock.Unlock() 217 | if guid == "" { 218 | t.Fatalf("Expected non-empty guid to be returned.") 219 | } 220 | if err := Wait(ch); err != nil { 221 | t.Fatal("Did not receive our ack callback") 222 | } 223 | } 224 | 225 | func TestTimeoutPublish(t *testing.T) { 226 | // Run a NATS Streaming server 227 | s := RunServer(clusterName) 228 | defer s.Shutdown() 229 | 230 | sc, err := Connect(clusterName, clientName, PubAckWait(50*time.Millisecond)) 231 | if err != nil { 232 | t.Fatalf("Expected to connect correctly, got err %v\n", err) 233 | } 234 | // Do not defer the connection close because we are going to 235 | // shutdown the server before the client connection is closed, 236 | // which would cause a 2 seconds delay on test exit. 237 | 238 | ch := make(chan bool) 239 | var glock sync.Mutex 240 | var guid string 241 | acb := func(lguid string, err error) { 242 | glock.Lock() 243 | defer glock.Unlock() 244 | if lguid != guid { 245 | t.Fatalf("Expected a matching guid in ack callback, got %s vs %s\n", lguid, guid) 246 | } 247 | if err != ErrTimeout { 248 | t.Fatalf("Expected a timeout error, got %v", err) 249 | } 250 | ch <- true 251 | } 252 | // Kill the NATS Streaming server so we timeout. 253 | s.Shutdown() 254 | glock.Lock() 255 | guid, _ = sc.PublishAsync("foo", []byte("Hello World!"), acb) 256 | glock.Unlock() 257 | if guid == "" { 258 | t.Fatalf("Expected non-empty guid to be returned.") 259 | } 260 | if err := Wait(ch); err != nil { 261 | t.Fatal("Did not receive our ack callback with a timeout err") 262 | } 263 | // Publish synchronously 264 | if err := sc.Publish("foo", []byte("hello")); err == nil || err != ErrTimeout { 265 | t.Fatalf("Expected Timeout error on publish, got %v", err) 266 | } 267 | } 268 | 269 | func TestPublishWithClosedNATSConn(t *testing.T) { 270 | // Run a NATS Streaming server 271 | s := RunServer(clusterName) 272 | defer s.Shutdown() 273 | 274 | nc, err := nats.Connect(nats.DefaultURL) 275 | if err != nil { 276 | t.Fatalf("Unexpected error on connect: %v", err) 277 | } 278 | defer nc.Close() 279 | sc, err := Connect(clusterName, clientName, NatsConn(nc)) 280 | if err != nil { 281 | t.Fatalf("Unexpected error on connect: %v", err) 282 | } 283 | defer sc.Close() 284 | // Close the NATS Connection 285 | nc.Close() 286 | msg := []byte("hello") 287 | // Publish should fail 288 | if err := sc.Publish("foo", msg); err == nil { 289 | t.Fatal("Expected error on publish") 290 | } 291 | // Even PublishAsync should fail right away 292 | if _, err := sc.PublishAsync("foo", msg, nil); err == nil { 293 | t.Fatal("Expected error on publish") 294 | } 295 | } 296 | 297 | func TestBasicSubscription(t *testing.T) { 298 | // Run a NATS Streaming server 299 | s := RunServer(clusterName) 300 | defer s.Shutdown() 301 | 302 | sc := NewDefaultConnection(t) 303 | defer sc.Close() 304 | 305 | sub, err := sc.Subscribe("foo", func(m *Msg) {}) 306 | if err != nil { 307 | t.Fatalf("Unexpected error on Subscribe, got %v", err) 308 | } 309 | defer sub.Unsubscribe() 310 | 311 | // Close connection 312 | sc.Close() 313 | 314 | // Expect ErrConnectionClosed on subscribe 315 | if _, err := sc.Subscribe("foo", func(m *Msg) {}); err == nil || err != ErrConnectionClosed { 316 | t.Fatalf("Expected ErrConnectionClosed on subscribe, got %v", err) 317 | } 318 | if _, err := sc.QueueSubscribe("foo", "bar", func(m *Msg) {}); err == nil || err != ErrConnectionClosed { 319 | t.Fatalf("Expected ErrConnectionClosed on subscribe, got %v", err) 320 | } 321 | } 322 | 323 | func TestBasicQueueSubscription(t *testing.T) { 324 | // Run a NATS Streaming server 325 | s := RunServer(clusterName) 326 | defer s.Shutdown() 327 | 328 | sc := NewDefaultConnection(t) 329 | defer sc.Close() 330 | 331 | ch := make(chan bool) 332 | count := uint32(0) 333 | cb := func(m *Msg) { 334 | if m.Sequence == 1 { 335 | if atomic.AddUint32(&count, 1) == 2 { 336 | ch <- true 337 | } 338 | } 339 | } 340 | 341 | sub, err := sc.QueueSubscribe("foo", "bar", cb) 342 | if err != nil { 343 | t.Fatalf("Expected no error on Subscribe, got %v\n", err) 344 | } 345 | defer sub.Unsubscribe() 346 | 347 | // Test that durable and non durable queue subscribers with 348 | // same name can coexist and they both receive the same message. 349 | if _, err = sc.QueueSubscribe("foo", "bar", cb, DurableName("durable-queue-sub")); err != nil { 350 | t.Fatalf("Unexpected error on QueueSubscribe with DurableName: %v", err) 351 | } 352 | 353 | // Publish a message 354 | if err := sc.Publish("foo", []byte("msg")); err != nil { 355 | t.Fatalf("Unexpected error on publish: %v", err) 356 | } 357 | // Wait for both messages to be received. 358 | if err := Wait(ch); err != nil { 359 | t.Fatal("Did not get our message") 360 | } 361 | 362 | // Check that one cannot use ':' for the queue durable name. 363 | if _, err := sc.QueueSubscribe("foo", "bar", cb, DurableName("my:dur")); err == nil { 364 | t.Fatal("Expected to get an error regarding durable name") 365 | } 366 | } 367 | 368 | func TestDurableQueueSubscriber(t *testing.T) { 369 | s := RunServer(clusterName) 370 | defer s.Shutdown() 371 | 372 | sc := NewDefaultConnection(t) 373 | defer sc.Close() 374 | 375 | total := 5 376 | for i := 0; i < total; i++ { 377 | if err := sc.Publish("foo", []byte("msg")); err != nil { 378 | t.Fatalf("Unexpected error on publish: %v", err) 379 | } 380 | } 381 | ch := make(chan bool) 382 | firstBatch := uint64(total) 383 | secondBatch := uint64(2 * total) 384 | cb := func(m *Msg) { 385 | if !m.Redelivered && 386 | (m.Sequence == uint64(firstBatch) || m.Sequence == uint64(secondBatch)) { 387 | ch <- true 388 | } 389 | } 390 | if _, err := sc.QueueSubscribe("foo", "bar", cb, 391 | DeliverAllAvailable(), 392 | DurableName("durable-queue-sub")); err != nil { 393 | t.Fatalf("Unexpected error on QueueSubscribe with DurableName: %v", err) 394 | } 395 | if err := Wait(ch); err != nil { 396 | t.Fatal("Did not get our message") 397 | } 398 | // Close connection 399 | sc.Close() 400 | 401 | // Create new connection 402 | sc = NewDefaultConnection(t) 403 | defer sc.Close() 404 | // Send more messages 405 | for i := 0; i < total; i++ { 406 | if err := sc.Publish("foo", []byte("msg")); err != nil { 407 | t.Fatalf("Unexpected error on publish: %v", err) 408 | } 409 | } 410 | // Create durable queue sub, it should receive from where it left of, 411 | // and ignore the start position 412 | if _, err := sc.QueueSubscribe("foo", "bar", cb, 413 | StartAtSequence(uint64(10*total)), 414 | DurableName("durable-queue-sub")); err != nil { 415 | t.Fatalf("Unexpected error on QueueSubscribe with DurableName: %v", err) 416 | } 417 | if err := Wait(ch); err != nil { 418 | t.Fatal("Did not get our message") 419 | } 420 | } 421 | 422 | func TestBasicPubSub(t *testing.T) { 423 | // Run a NATS Streaming server 424 | s := RunServer(clusterName) 425 | defer s.Shutdown() 426 | 427 | sc := NewDefaultConnection(t) 428 | defer sc.Close() 429 | 430 | ch := make(chan bool) 431 | received := int32(0) 432 | toSend := int32(500) 433 | hw := []byte("Hello World") 434 | msgMap := make(map[uint64]struct{}) 435 | 436 | sub, err := sc.Subscribe("foo", func(m *Msg) { 437 | if m.Subject != "foo" { 438 | t.Fatalf("Expected subject of 'foo', got '%s'\n", m.Subject) 439 | } 440 | if !bytes.Equal(m.Data, hw) { 441 | t.Fatalf("Wrong payload, got %q\n", m.Data) 442 | } 443 | // Make sure Seq and Timestamp are set 444 | if m.Sequence == 0 { 445 | t.Fatalf("Expected Sequence to be set\n") 446 | } 447 | if m.Timestamp == 0 { 448 | t.Fatalf("Expected timestamp to be set\n") 449 | } 450 | 451 | if _, ok := msgMap[m.Sequence]; ok { 452 | t.Fatalf("Detected duplicate for sequence: %d\n", m.Sequence) 453 | } 454 | msgMap[m.Sequence] = struct{}{} 455 | 456 | if nr := atomic.AddInt32(&received, 1); nr >= int32(toSend) { 457 | ch <- true 458 | } 459 | }) 460 | if err != nil { 461 | t.Fatalf("Unexpected error on Subscribe, got %v", err) 462 | } 463 | defer sub.Unsubscribe() 464 | 465 | for i := int32(0); i < toSend; i++ { 466 | if err := sc.Publish("foo", hw); err != nil { 467 | t.Fatalf("Received error on publish: %v\n", err) 468 | } 469 | } 470 | if err := WaitTime(ch, 1*time.Second); err != nil { 471 | t.Fatal("Did not receive our messages") 472 | } 473 | } 474 | 475 | func TestBasicPubQueueSub(t *testing.T) { 476 | // Run a NATS Streaming server 477 | s := RunServer(clusterName) 478 | defer s.Shutdown() 479 | 480 | sc := NewDefaultConnection(t) 481 | defer sc.Close() 482 | 483 | ch := make(chan bool) 484 | received := int32(0) 485 | toSend := int32(100) 486 | hw := []byte("Hello World") 487 | 488 | sub, err := sc.QueueSubscribe("foo", "bar", func(m *Msg) { 489 | if m.Subject != "foo" { 490 | t.Fatalf("Expected subject of 'foo', got '%s'\n", m.Subject) 491 | } 492 | if !bytes.Equal(m.Data, hw) { 493 | t.Fatalf("Wrong payload, got %q\n", m.Data) 494 | } 495 | // Make sure Seq and Timestamp are set 496 | if m.Sequence == 0 { 497 | t.Fatalf("Expected Sequence to be set\n") 498 | } 499 | if m.Timestamp == 0 { 500 | t.Fatalf("Expected timestamp to be set\n") 501 | } 502 | if nr := atomic.AddInt32(&received, 1); nr >= int32(toSend) { 503 | ch <- true 504 | } 505 | }) 506 | if err != nil { 507 | t.Fatalf("Unexpected error on Subscribe, got %v", err) 508 | } 509 | defer sub.Unsubscribe() 510 | 511 | for i := int32(0); i < toSend; i++ { 512 | sc.Publish("foo", hw) 513 | } 514 | if err := WaitTime(ch, 1*time.Second); err != nil { 515 | t.Fatal("Did not receive our messages") 516 | } 517 | } 518 | 519 | func TestSubscriptionStartPositionLast(t *testing.T) { 520 | // Run a NATS Streaming server 521 | s := RunServer(clusterName) 522 | defer s.Shutdown() 523 | 524 | sc := NewDefaultConnection(t) 525 | defer sc.Close() 526 | 527 | // Publish ten messages 528 | for i := 0; i < 10; i++ { 529 | data := []byte(fmt.Sprintf("%d", i)) 530 | sc.Publish("foo", data) 531 | } 532 | 533 | ch := make(chan bool) 534 | received := int32(0) 535 | 536 | mcb := func(m *Msg) { 537 | atomic.AddInt32(&received, 1) 538 | if m.Sequence != 10 { 539 | t.Fatalf("Wrong sequence received: got %d vs. %d\n", m.Sequence, 10) 540 | } 541 | ch <- true 542 | } 543 | // Now subscribe and set start position to last received. 544 | sub, err := sc.Subscribe("foo", mcb, StartWithLastReceived()) 545 | if err != nil { 546 | t.Fatalf("Unexpected error on Subscribe, got %v", err) 547 | } 548 | defer sub.Unsubscribe() 549 | 550 | // Check for sub setup 551 | rsub := sub.(*subscription) 552 | if rsub.opts.StartAt != pb.StartPosition_LastReceived { 553 | t.Fatalf("Incorrect StartAt state: %s\n", rsub.opts.StartAt) 554 | } 555 | 556 | if err := Wait(ch); err != nil { 557 | t.Fatal("Did not receive our message") 558 | } 559 | 560 | if received > int32(1) { 561 | t.Fatalf("Should have received only 1 message, but got %d\n", received) 562 | } 563 | } 564 | 565 | func TestSubscriptionStartAtSequence(t *testing.T) { 566 | // Run a NATS Streaming server 567 | s := RunServer(clusterName) 568 | defer s.Shutdown() 569 | 570 | sc := NewDefaultConnection(t) 571 | defer sc.Close() 572 | 573 | // Publish ten messages 574 | for i := 1; i <= 10; i++ { 575 | data := []byte(fmt.Sprintf("%d", i)) 576 | sc.Publish("foo", data) 577 | } 578 | 579 | ch := make(chan bool) 580 | received := int32(0) 581 | shouldReceive := int32(5) 582 | 583 | // Capture the messages that are delivered. 584 | savedMsgs := make([]*Msg, 0, 5) 585 | 586 | mcb := func(m *Msg) { 587 | savedMsgs = append(savedMsgs, m) 588 | if nr := atomic.AddInt32(&received, 1); nr >= int32(shouldReceive) { 589 | ch <- true 590 | } 591 | } 592 | 593 | // Now subscribe and set start position to #6, so should received 6-10. 594 | sub, err := sc.Subscribe("foo", mcb, StartAtSequence(6)) 595 | if err != nil { 596 | t.Fatalf("Expected no error on Subscribe, got %v\n", err) 597 | } 598 | defer sub.Unsubscribe() 599 | 600 | // Check for sub setup 601 | rsub := sub.(*subscription) 602 | if rsub.opts.StartAt != pb.StartPosition_SequenceStart { 603 | t.Fatalf("Incorrect StartAt state: %s\n", rsub.opts.StartAt) 604 | } 605 | 606 | if err := Wait(ch); err != nil { 607 | t.Fatal("Did not receive our messages") 608 | } 609 | 610 | // Check we received them in order. 611 | for i, seq := 0, uint64(6); i < 5; i++ { 612 | m := savedMsgs[i] 613 | // Check Sequence 614 | if m.Sequence != seq { 615 | t.Fatalf("Expected seq: %d, got %d\n", seq, m.Sequence) 616 | } 617 | // Check payload 618 | dseq, _ := strconv.Atoi(string(m.Data)) 619 | if dseq != int(seq) { 620 | t.Fatalf("Expected payload: %d, got %d\n", seq, dseq) 621 | } 622 | seq++ 623 | } 624 | } 625 | 626 | func TestSubscriptionStartAtTime(t *testing.T) { 627 | // Run a NATS Streaming server 628 | s := RunServer(clusterName) 629 | defer s.Shutdown() 630 | 631 | sc := NewDefaultConnection(t) 632 | defer sc.Close() 633 | 634 | // Publish first 5 635 | for i := 1; i <= 5; i++ { 636 | data := []byte(fmt.Sprintf("%d", i)) 637 | sc.Publish("foo", data) 638 | } 639 | 640 | // Buffer each side so slow tests still work. 641 | time.Sleep(250 * time.Millisecond) 642 | startTime := time.Now() 643 | time.Sleep(250 * time.Millisecond) 644 | 645 | // Publish last 5 646 | for i := 6; i <= 10; i++ { 647 | data := []byte(fmt.Sprintf("%d", i)) 648 | sc.Publish("foo", data) 649 | } 650 | 651 | ch := make(chan bool) 652 | received := int32(0) 653 | shouldReceive := int32(5) 654 | 655 | // Capture the messages that are delivered. 656 | savedMsgs := make([]*Msg, 0, 5) 657 | 658 | mcb := func(m *Msg) { 659 | savedMsgs = append(savedMsgs, m) 660 | if nr := atomic.AddInt32(&received, 1); nr >= int32(shouldReceive) { 661 | ch <- true 662 | } 663 | } 664 | 665 | // Now subscribe and set start position to #6, so should received 6-10. 666 | sub, err := sc.Subscribe("foo", mcb, StartAtTime(startTime)) 667 | if err != nil { 668 | t.Fatalf("Expected no error on Subscribe, got %v\n", err) 669 | } 670 | defer sub.Unsubscribe() 671 | 672 | // Check for sub setup 673 | rsub := sub.(*subscription) 674 | if rsub.opts.StartAt != pb.StartPosition_TimeDeltaStart { 675 | t.Fatalf("Incorrect StartAt state: %s\n", rsub.opts.StartAt) 676 | } 677 | 678 | if err := Wait(ch); err != nil { 679 | t.Fatal("Did not receive our messages") 680 | } 681 | 682 | // Check we received them in order. 683 | for i, seq := 0, uint64(6); i < 5; i++ { 684 | m := savedMsgs[i] 685 | // Check time is always greater than startTime 686 | if m.Timestamp < startTime.UnixNano() { 687 | t.Fatalf("Expected all messages to have timestamp > startTime.") 688 | } 689 | // Check Sequence 690 | if m.Sequence != seq { 691 | t.Fatalf("Expected seq: %d, got %d\n", seq, m.Sequence) 692 | } 693 | // Check payload 694 | dseq, _ := strconv.Atoi(string(m.Data)) 695 | if dseq != int(seq) { 696 | t.Fatalf("Expected payload: %d, got %d\n", seq, dseq) 697 | } 698 | seq++ 699 | } 700 | 701 | // Now test Ago helper 702 | delta := time.Since(startTime) 703 | 704 | sub, err = sc.Subscribe("foo", mcb, StartAtTimeDelta(delta)) 705 | if err != nil { 706 | t.Fatalf("Expected no error on Subscribe, got %v\n", err) 707 | } 708 | defer sub.Unsubscribe() 709 | 710 | if err := Wait(ch); err != nil { 711 | t.Fatal("Did not receive our messages") 712 | } 713 | } 714 | 715 | func TestSubscriptionStartAt(t *testing.T) { 716 | // Run a NATS Streaming server 717 | s := RunServer(clusterName) 718 | defer s.Shutdown() 719 | 720 | sc := NewDefaultConnection(t) 721 | defer sc.Close() 722 | 723 | // Publish ten messages 724 | for i := 1; i <= 10; i++ { 725 | sc.Publish("foo", []byte("hello")) 726 | } 727 | 728 | ch := make(chan bool) 729 | received := 0 730 | mcb := func(m *Msg) { 731 | received++ 732 | if received == 10 { 733 | ch <- true 734 | } 735 | } 736 | 737 | // Now subscribe and set start position to sequence. It should be 738 | // sequence 0 739 | sub, err := sc.Subscribe("foo", mcb, StartAt(pb.StartPosition_SequenceStart)) 740 | if err != nil { 741 | t.Fatalf("Expected no error on Subscribe, got %v", err) 742 | } 743 | defer sub.Unsubscribe() 744 | 745 | // Check for sub setup 746 | rsub := sub.(*subscription) 747 | if rsub.opts.StartAt != pb.StartPosition_SequenceStart { 748 | t.Fatalf("Incorrect StartAt state: %s\n", rsub.opts.StartAt) 749 | } 750 | 751 | if err := Wait(ch); err != nil { 752 | t.Fatal("Did not receive our messages") 753 | } 754 | } 755 | 756 | func TestSubscriptionStartAtFirst(t *testing.T) { 757 | // Run a NATS Streaming server 758 | s := RunServer(clusterName) 759 | defer s.Shutdown() 760 | 761 | sc := NewDefaultConnection(t) 762 | defer sc.Close() 763 | 764 | // Publish ten messages 765 | for i := 1; i <= 10; i++ { 766 | data := []byte(fmt.Sprintf("%d", i)) 767 | sc.Publish("foo", data) 768 | } 769 | 770 | ch := make(chan bool) 771 | received := int32(0) 772 | shouldReceive := int32(10) 773 | 774 | // Capture the messages that are delivered. 775 | savedMsgs := make([]*Msg, 0, 10) 776 | 777 | mcb := func(m *Msg) { 778 | savedMsgs = append(savedMsgs, m) 779 | if nr := atomic.AddInt32(&received, 1); nr >= int32(shouldReceive) { 780 | ch <- true 781 | } 782 | } 783 | 784 | // Now subscribe and set start position to #6, so should received 6-10. 785 | sub, err := sc.Subscribe("foo", mcb, DeliverAllAvailable()) 786 | if err != nil { 787 | t.Fatalf("Expected no error on Subscribe, got %v\n", err) 788 | } 789 | defer sub.Unsubscribe() 790 | 791 | // Check for sub setup 792 | rsub := sub.(*subscription) 793 | if rsub.opts.StartAt != pb.StartPosition_First { 794 | t.Fatalf("Incorrect StartAt state: %s\n", rsub.opts.StartAt) 795 | } 796 | 797 | if err := Wait(ch); err != nil { 798 | t.Fatal("Did not receive our messages") 799 | } 800 | 801 | if received != shouldReceive { 802 | t.Fatalf("Expected %d msgs but received %d\n", shouldReceive, received) 803 | } 804 | 805 | // Check we received them in order. 806 | for i, seq := 0, uint64(1); i < 10; i++ { 807 | m := savedMsgs[i] 808 | // Check Sequence 809 | if m.Sequence != seq { 810 | t.Fatalf("Expected seq: %d, got %d\n", seq, m.Sequence) 811 | } 812 | // Check payload 813 | dseq, _ := strconv.Atoi(string(m.Data)) 814 | if dseq != int(seq) { 815 | t.Fatalf("Expected payload: %d, got %d\n", seq, dseq) 816 | } 817 | seq++ 818 | } 819 | } 820 | 821 | func TestUnsubscribe(t *testing.T) { 822 | // Run a NATS Streaming server 823 | s := RunServer(clusterName) 824 | defer s.Shutdown() 825 | 826 | sc := NewDefaultConnection(t) 827 | defer sc.Close() 828 | 829 | // Create a valid one 830 | sc.Subscribe("foo", nil) 831 | 832 | // Now subscribe, but we will unsubscribe before sending any messages. 833 | sub, err := sc.Subscribe("foo", func(m *Msg) { 834 | t.Fatalf("Did not expect to receive any messages\n") 835 | }) 836 | if err != nil { 837 | t.Fatalf("Expected no error on Subscribe, got %v\n", err) 838 | } 839 | // Create another valid one 840 | sc.Subscribe("foo", nil) 841 | 842 | // Unsubscribe middle one. 843 | err = sub.Unsubscribe() 844 | if err != nil { 845 | t.Fatalf("Expected no errors from unsubscribe: got %v\n", err) 846 | } 847 | // Do it again, should not dump, but should get error. 848 | err = sub.Unsubscribe() 849 | if err == nil || err != ErrBadSubscription { 850 | t.Fatalf("Expected a bad subscription err, got %v\n", err) 851 | } 852 | 853 | // Publish ten messages 854 | for i := 1; i <= 10; i++ { 855 | data := []byte(fmt.Sprintf("%d", i)) 856 | sc.Publish("foo", data) 857 | } 858 | 859 | sc.Close() 860 | sc = NewDefaultConnection(t) 861 | defer sc.Close() 862 | sub1, err := sc.Subscribe("foo", func(_ *Msg) {}) 863 | if err != nil { 864 | t.Fatalf("Unexpected error on subscribe: %v", err) 865 | } 866 | sub2, err := sc.Subscribe("foo", func(_ *Msg) {}) 867 | if err != nil { 868 | t.Fatalf("Unexpected error on subscribe: %v", err) 869 | } 870 | // Override clientID to get an error on Subscription.Close() and Unsubscribe() 871 | sc.(*conn).Lock() 872 | sc.(*conn).clientID = "foobar" 873 | sc.(*conn).Unlock() 874 | if err := sub1.Close(); err == nil || !strings.Contains(err.Error(), "unknown") { 875 | t.Fatalf("Expected error about unknown clientID, got %v", err) 876 | } 877 | if err := sub2.Close(); err == nil || !strings.Contains(err.Error(), "unknown") { 878 | t.Fatalf("Expected error about unknown clientID, got %v", err) 879 | } 880 | } 881 | 882 | func TestUnsubscribeWhileConnClosing(t *testing.T) { 883 | // Run a NATS Streaming server 884 | s := RunServer(clusterName) 885 | defer s.Shutdown() 886 | 887 | sc, err := Connect(clusterName, clientName, PubAckWait(50*time.Millisecond)) 888 | if err != nil { 889 | t.Fatalf("Expected to connect correctly, got err %v\n", err) 890 | } 891 | defer sc.Close() 892 | 893 | sub, err := sc.Subscribe("foo", nil) 894 | if err != nil { 895 | t.Fatalf("Expected no error on Subscribe, got %v\n", err) 896 | } 897 | 898 | var wg sync.WaitGroup 899 | wg.Add(1) 900 | 901 | go func() { 902 | time.Sleep(time.Duration(rand.Intn(50)) * time.Millisecond) 903 | sc.Close() 904 | wg.Done() 905 | }() 906 | 907 | // Unsubscribe 908 | sub.Unsubscribe() 909 | 910 | wg.Wait() 911 | } 912 | 913 | func TestDupClientID(t *testing.T) { 914 | // Run a NATS Streaming server 915 | s := RunServer(clusterName) 916 | defer s.Shutdown() 917 | 918 | sc := NewDefaultConnection(t) 919 | defer sc.Close() 920 | 921 | if _, err := Connect(clusterName, clientName); err == nil { 922 | t.Fatal("Expected to get an error for duplicate clientID") 923 | } 924 | } 925 | 926 | func TestClose(t *testing.T) { 927 | // Run a NATS Streaming server 928 | s := RunServer(clusterName) 929 | defer s.Shutdown() 930 | 931 | sc := NewDefaultConnection(t) 932 | defer sc.Close() 933 | 934 | sub, err := sc.Subscribe("foo", func(m *Msg) { 935 | t.Fatalf("Did not expect to receive any messages\n") 936 | }) 937 | if err != nil { 938 | t.Fatalf("Expected no errors when subscribing, got %v\n", err) 939 | } 940 | 941 | err = sc.Close() 942 | if err != nil { 943 | t.Fatalf("Did not expect error on Close(), got %v\n", err) 944 | } 945 | 946 | if _, err := sc.PublishAsync("foo", []byte("Hello World!"), nil); err == nil || err != ErrConnectionClosed { 947 | t.Fatalf("Expected an ErrConnectionClosed on publish async to a closed connection, got %v", err) 948 | } 949 | 950 | if err := sc.Publish("foo", []byte("Hello World!")); err == nil || err != ErrConnectionClosed { 951 | t.Fatalf("Expected an ErrConnectionClosed error on publish to a closed connection, got %v", err) 952 | } 953 | 954 | if err := sub.Unsubscribe(); err == nil || err != ErrConnectionClosed { 955 | t.Fatalf("Expected an ErrConnectionClosed error on unsubscribe to a closed connection, got %v", err) 956 | } 957 | 958 | sc = NewDefaultConnection(t) 959 | // Override the clientID so that we get an error on close 960 | sc.(*conn).Lock() 961 | sc.(*conn).clientID = "foobar" 962 | sc.(*conn).Unlock() 963 | if err := sc.Close(); err == nil || !strings.Contains(err.Error(), "unknown") { 964 | t.Fatalf("Expected error about unknown clientID, got %v", err) 965 | } 966 | } 967 | 968 | func TestDoubleClose(t *testing.T) { 969 | s := RunServer(clusterName) 970 | defer s.Shutdown() 971 | 972 | sc := NewDefaultConnection(t) 973 | if err := sc.Close(); err != nil { 974 | t.Fatalf("Did not expect an error on first Close, got %v\n", err) 975 | } 976 | 977 | if err := sc.Close(); err != nil { 978 | t.Fatalf("Did not expect an error on second Close, got %v\n", err) 979 | } 980 | } 981 | 982 | func TestManualAck(t *testing.T) { 983 | // Run a NATS Streaming server 984 | s := RunServer(clusterName) 985 | defer s.Shutdown() 986 | 987 | sc := NewDefaultConnection(t) 988 | defer sc.Close() 989 | 990 | toSend := int32(100) 991 | hw := []byte("Hello World") 992 | 993 | for i := int32(0); i < toSend; i++ { 994 | sc.PublishAsync("foo", hw, nil) 995 | } 996 | sc.Publish("foo", hw) 997 | 998 | fch := make(chan bool) 999 | 1000 | // Test that we can't Ack if not in manual mode. 1001 | sub, err := sc.Subscribe("foo", func(m *Msg) { 1002 | if err := m.Ack(); err != ErrManualAck { 1003 | t.Fatalf("Expected an error trying to ack an auto-ack subscription") 1004 | } 1005 | fch <- true 1006 | }, DeliverAllAvailable()) 1007 | if err != nil { 1008 | t.Fatalf("Unexpected error on Subscribe, got %v", err) 1009 | } 1010 | 1011 | if err := Wait(fch); err != nil { 1012 | t.Fatal("Did not receive our first message") 1013 | } 1014 | sub.Unsubscribe() 1015 | 1016 | ch := make(chan bool) 1017 | sch := make(chan bool) 1018 | received := int32(0) 1019 | 1020 | msgs := make([]*Msg, 0, 101) 1021 | 1022 | // Test we only receive MaxInflight if we do not ack 1023 | sub, err = sc.Subscribe("foo", func(m *Msg) { 1024 | msgs = append(msgs, m) 1025 | if nr := atomic.AddInt32(&received, 1); nr == int32(10) { 1026 | ch <- true 1027 | } else if nr > 10 { 1028 | m.Ack() 1029 | if nr >= toSend+1 { // sync Publish +1 1030 | sch <- true 1031 | } 1032 | } 1033 | }, DeliverAllAvailable(), MaxInflight(10), SetManualAckMode()) 1034 | if err != nil { 1035 | t.Fatalf("Unexpected error on Subscribe, got %v", err) 1036 | } 1037 | defer sub.Unsubscribe() 1038 | 1039 | if err := Wait(ch); err != nil { 1040 | t.Fatal("Did not receive at least 10 messages") 1041 | } 1042 | // Wait a bit longer for other messages which would be an error. 1043 | time.Sleep(50 * time.Millisecond) 1044 | 1045 | if nr := atomic.LoadInt32(&received); nr != 10 { 1046 | t.Fatalf("Only expected to get 10 messages to match MaxInflight without Acks, got %d\n", nr) 1047 | } 1048 | 1049 | // Now make sure we get the rest of them. So ack the ones we have so far. 1050 | for _, m := range msgs { 1051 | if err := m.Ack(); err != nil { 1052 | t.Fatalf("Unexpected error on Ack: %v\n", err) 1053 | } 1054 | } 1055 | if err := Wait(sch); err != nil { 1056 | t.Fatal("Did not receive all our messages") 1057 | } 1058 | 1059 | if nr := atomic.LoadInt32(&received); nr != toSend+1 { 1060 | t.Fatalf("Did not receive correct number of messages: %d vs %d\n", nr, toSend+1) 1061 | } 1062 | 1063 | // Close connection 1064 | sc.Close() 1065 | if err := msgs[0].Ack(); err != ErrBadConnection { 1066 | t.Fatalf("Expected ErrBadConnection, got %v", err) 1067 | } 1068 | 1069 | // Close the subscription 1070 | sub.Unsubscribe() 1071 | if err := msgs[0].Ack(); err != ErrBadSubscription { 1072 | t.Fatalf("Expected ErrBadSubscription, got %v", err) 1073 | } 1074 | 1075 | // Test nil msg Ack 1076 | var m *Msg 1077 | if err := m.Ack(); err != ErrNilMsg { 1078 | t.Fatalf("Expected ErrNilMsg, got %v", err) 1079 | } 1080 | } 1081 | 1082 | func TestRedelivery(t *testing.T) { 1083 | // Run a NATS Streaming server 1084 | s := RunServer(clusterName) 1085 | defer s.Shutdown() 1086 | 1087 | sc := NewDefaultConnection(t) 1088 | defer sc.Close() 1089 | 1090 | toSend := int32(100) 1091 | hw := []byte("Hello World") 1092 | 1093 | for i := int32(0); i < toSend; i++ { 1094 | sc.Publish("foo", hw) 1095 | } 1096 | 1097 | // Make sure we get an error on bad ackWait 1098 | if _, err := sc.Subscribe("foo", nil, AckWait(20*time.Millisecond)); err == nil { 1099 | t.Fatalf("Expected an error for back AckWait time under 1 second\n") 1100 | } 1101 | 1102 | ch := make(chan bool) 1103 | sch := make(chan bool) 1104 | received := int32(0) 1105 | 1106 | ackRedeliverTime := 1 * time.Second 1107 | 1108 | sub, err := sc.Subscribe("foo", func(m *Msg) { 1109 | if nr := atomic.AddInt32(&received, 1); nr == toSend { 1110 | ch <- true 1111 | } else if nr == 2*toSend { 1112 | sch <- true 1113 | } 1114 | 1115 | }, DeliverAllAvailable(), MaxInflight(int(toSend+1)), AckWait(ackRedeliverTime), SetManualAckMode()) 1116 | if err != nil { 1117 | t.Fatalf("Unexpected error on Subscribe, got %v", err) 1118 | } 1119 | defer sub.Unsubscribe() 1120 | 1121 | if err := Wait(ch); err != nil { 1122 | t.Fatal("Did not receive first delivery of all messages") 1123 | } 1124 | if nr := atomic.LoadInt32(&received); nr != toSend { 1125 | t.Fatalf("Expected to get 100 messages, got %d\n", nr) 1126 | } 1127 | if err := Wait(sch); err != nil { 1128 | t.Fatal("Did not receive second re-delivery of all messages") 1129 | } 1130 | if nr := atomic.LoadInt32(&received); nr != 2*toSend { 1131 | t.Fatalf("Expected to get 200 messages, got %d\n", nr) 1132 | } 1133 | } 1134 | 1135 | func TestDurableSubscriber(t *testing.T) { 1136 | // Run a NATS Streaming server 1137 | s := RunServer(clusterName) 1138 | defer s.Shutdown() 1139 | 1140 | sc := NewDefaultConnection(t) 1141 | defer sc.Close() 1142 | 1143 | toSend := int32(100) 1144 | hw := []byte("Hello World") 1145 | 1146 | // Capture the messages that are delivered. 1147 | var msgsGuard sync.Mutex 1148 | savedMsgs := make([]*Msg, 0, toSend) 1149 | 1150 | for i := int32(0); i < toSend; i++ { 1151 | sc.Publish("foo", hw) 1152 | } 1153 | 1154 | ch := make(chan bool) 1155 | received := int32(0) 1156 | 1157 | _, err := sc.Subscribe("foo", func(m *Msg) { 1158 | if nr := atomic.AddInt32(&received, 1); nr == 10 { 1159 | sc.Close() 1160 | ch <- true 1161 | } else { 1162 | msgsGuard.Lock() 1163 | savedMsgs = append(savedMsgs, m) 1164 | msgsGuard.Unlock() 1165 | } 1166 | }, DeliverAllAvailable(), DurableName("durable-foo")) 1167 | if err != nil { 1168 | t.Fatalf("Unexpected error on Subscribe, got %v", err) 1169 | } 1170 | 1171 | if err := Wait(ch); err != nil { 1172 | t.Fatal("Did not receive first delivery of all messages") 1173 | } 1174 | // Reset in case we get more messages in the above callback 1175 | ch = make(chan bool) 1176 | 1177 | if nr := atomic.LoadInt32(&received); nr != 10 { 1178 | t.Fatalf("Expected to get only 10 messages, got %d\n", nr) 1179 | } 1180 | // This is auto-ack, so undo received for check. 1181 | // Close will prevent ack from going out, so #10 will be redelivered 1182 | atomic.AddInt32(&received, -1) 1183 | 1184 | // sc is closed here from above.. 1185 | 1186 | // Recreate the connection 1187 | sc, err = Connect(clusterName, clientName, PubAckWait(50*time.Millisecond)) 1188 | if err != nil { 1189 | t.Fatalf("Expected to connect correctly, got err %v\n", err) 1190 | } 1191 | defer sc.Close() 1192 | 1193 | // Create the same durable subscription. 1194 | _, err = sc.Subscribe("foo", func(m *Msg) { 1195 | msgsGuard.Lock() 1196 | savedMsgs = append(savedMsgs, m) 1197 | msgsGuard.Unlock() 1198 | if nr := atomic.AddInt32(&received, 1); nr == toSend { 1199 | ch <- true 1200 | } 1201 | }, DeliverAllAvailable(), DurableName("durable-foo")) 1202 | if err != nil { 1203 | t.Fatalf("Unexpected error on Subscribe, got %v", err) 1204 | } 1205 | 1206 | // Check that durables cannot be subscribed to again by same client. 1207 | _, err = sc.Subscribe("foo", nil, DurableName("durable-foo")) 1208 | if err == nil || err.Error() != server.ErrDupDurable.Error() { 1209 | t.Fatalf("Expected ErrDupSubscription error, got %v\n", err) 1210 | } 1211 | 1212 | // Check that durables with same name, but subscribed to differen subject are ok. 1213 | _, err = sc.Subscribe("bar", nil, DurableName("durable-foo")) 1214 | if err != nil { 1215 | t.Fatalf("Expected no error, got %v\n", err) 1216 | } 1217 | 1218 | if err := Wait(ch); err != nil { 1219 | t.Fatal("Did not receive delivery of all messages") 1220 | } 1221 | 1222 | if nr := atomic.LoadInt32(&received); nr != toSend { 1223 | t.Fatalf("Expected to get %d messages, got %d\n", toSend, nr) 1224 | } 1225 | msgsGuard.Lock() 1226 | numSaved := len(savedMsgs) 1227 | msgsGuard.Unlock() 1228 | if numSaved != int(toSend) { 1229 | t.Fatalf("Expected len(savedMsgs) to be %d, got %d\n", toSend, numSaved) 1230 | } 1231 | // Check we received them in order 1232 | msgsGuard.Lock() 1233 | defer msgsGuard.Unlock() 1234 | for i, m := range savedMsgs { 1235 | seqExpected := uint64(i + 1) 1236 | if m.Sequence != seqExpected { 1237 | t.Fatalf("Got wrong seq, expected %d, got %d\n", seqExpected, m.Sequence) 1238 | } 1239 | } 1240 | } 1241 | 1242 | func TestRedeliveredFlag(t *testing.T) { 1243 | // Run a NATS Streaming server 1244 | s := RunServer(clusterName) 1245 | defer s.Shutdown() 1246 | 1247 | sc := NewDefaultConnection(t) 1248 | defer sc.Close() 1249 | 1250 | toSend := int32(100) 1251 | hw := []byte("Hello World") 1252 | 1253 | for i := int32(0); i < toSend; i++ { 1254 | if err := sc.Publish("foo", hw); err != nil { 1255 | t.Fatalf("Error publishing message: %v\n", err) 1256 | } 1257 | } 1258 | 1259 | ch := make(chan bool) 1260 | received := int32(0) 1261 | 1262 | msgsLock := &sync.Mutex{} 1263 | msgs := make(map[uint64]*Msg) 1264 | 1265 | // Test we only receive MaxInflight if we do not ack 1266 | sub, err := sc.Subscribe("foo", func(m *Msg) { 1267 | // Remember the message. 1268 | msgsLock.Lock() 1269 | msgs[m.Sequence] = m 1270 | msgsLock.Unlock() 1271 | 1272 | // Only Ack odd numbers 1273 | if m.Sequence%2 != 0 { 1274 | if err := m.Ack(); err != nil { 1275 | t.Fatalf("Unexpected error on Ack: %v\n", err) 1276 | } 1277 | } 1278 | 1279 | if nr := atomic.AddInt32(&received, 1); nr == toSend { 1280 | ch <- true 1281 | } 1282 | }, DeliverAllAvailable(), AckWait(1*time.Second), SetManualAckMode()) 1283 | if err != nil { 1284 | t.Fatalf("Unexpected error on Subscribe, got %v", err) 1285 | } 1286 | defer sub.Unsubscribe() 1287 | 1288 | if err := Wait(ch); err != nil { 1289 | t.Fatal("Did not receive at least 10 messages") 1290 | } 1291 | time.Sleep(1500 * time.Millisecond) // Wait for redelivery 1292 | 1293 | msgsLock.Lock() 1294 | defer msgsLock.Unlock() 1295 | 1296 | for _, m := range msgs { 1297 | // Expect all even msgs to have been redelivered. 1298 | if m.Sequence%2 == 0 && !m.Redelivered { 1299 | t.Fatalf("Expected a redelivered flag to be set on msg %d\n", m.Sequence) 1300 | } 1301 | } 1302 | } 1303 | 1304 | // TestNoDuplicatesOnSubscriberStart tests that a subscriber does not 1305 | // receive duplicate when requesting a replay while messages are being 1306 | // published on its subject. 1307 | func TestNoDuplicatesOnSubscriberStart(t *testing.T) { 1308 | // Run a NATS Streaming server 1309 | s := RunServer(clusterName) 1310 | defer s.Shutdown() 1311 | 1312 | sc, err := Connect(clusterName, clientName) 1313 | if err != nil { 1314 | t.Fatalf("Expected to connect correctly, got err %v\n", err) 1315 | } 1316 | 1317 | defer sc.Close() 1318 | 1319 | batch := int32(100) 1320 | ch := make(chan bool) 1321 | pch := make(chan bool) 1322 | received := int32(0) 1323 | sent := int32(0) 1324 | 1325 | mcb := func(m *Msg) { 1326 | // signal when we've reached the expected messages count 1327 | if nr := atomic.AddInt32(&received, 1); nr == atomic.LoadInt32(&sent) { 1328 | ch <- true 1329 | } 1330 | } 1331 | 1332 | publish := func() { 1333 | // publish until the receiver starts, then one additional batch. 1334 | // This primes NATS Streaming with messages, and gives us a point to stop 1335 | // when the subscriber has started processing messages. 1336 | for atomic.LoadInt32(&received) == 0 { 1337 | for i := int32(0); i < batch; i++ { 1338 | atomic.AddInt32(&sent, 1) 1339 | sc.PublishAsync("foo", []byte("hello"), nil) 1340 | } 1341 | // signal that we've published a batch. 1342 | pch <- true 1343 | } 1344 | } 1345 | 1346 | go publish() 1347 | 1348 | // wait until the publisher has published at least one batch 1349 | Wait(pch) 1350 | 1351 | // start the subscriber 1352 | sub, err := sc.Subscribe("foo", mcb, DeliverAllAvailable()) 1353 | if err != nil { 1354 | t.Fatalf("Expected no error on Subscribe, got %v\n", err) 1355 | } 1356 | 1357 | defer sub.Unsubscribe() 1358 | 1359 | // Wait for our expected count. 1360 | if err := Wait(ch); err != nil { 1361 | t.Fatal("Did not receive our messages") 1362 | } 1363 | 1364 | // Wait to see if the subscriber receives any duplicate messages. 1365 | time.Sleep(250 * time.Millisecond) 1366 | 1367 | // Make sure we've receive the exact count of sent messages. 1368 | if atomic.LoadInt32(&received) != atomic.LoadInt32(&sent) { 1369 | t.Fatalf("Expected %d msgs but received %d\n", sent, received) 1370 | } 1371 | } 1372 | 1373 | func TestMaxChannels(t *testing.T) { 1374 | // Set a small number of max channels 1375 | opts := server.GetDefaultOptions() 1376 | opts.ID = clusterName 1377 | opts.MaxChannels = 10 1378 | 1379 | // Run a NATS Streaming server 1380 | s := runServerWithOpts(opts) 1381 | defer s.Shutdown() 1382 | 1383 | sc := NewDefaultConnection(t) 1384 | defer sc.Close() 1385 | 1386 | hw := []byte("Hello World") 1387 | var subject string 1388 | 1389 | // These all should work fine 1390 | for i := 0; i < opts.MaxChannels; i++ { 1391 | subject = fmt.Sprintf("CHAN-%d", i) 1392 | sc.PublishAsync(subject, hw, nil) 1393 | } 1394 | // This one should error 1395 | if err := sc.Publish("CHAN_MAX", hw); err == nil { 1396 | t.Fatalf("Expected an error signaling too many channels\n") 1397 | } 1398 | } 1399 | 1400 | func TestRaceOnClose(t *testing.T) { 1401 | s := RunServer(clusterName) 1402 | defer s.Shutdown() 1403 | 1404 | sc := NewDefaultConnection(t) 1405 | defer sc.Close() 1406 | 1407 | // Seems that this sleep makes it happen all the time. 1408 | time.Sleep(1250 * time.Millisecond) 1409 | } 1410 | 1411 | func TestRaceAckOnClose(t *testing.T) { 1412 | s := RunServer(clusterName) 1413 | defer s.Shutdown() 1414 | 1415 | sc := NewDefaultConnection(t) 1416 | defer sc.Close() 1417 | 1418 | toSend := 100 1419 | 1420 | // Send our messages 1421 | for i := 0; i < toSend; i++ { 1422 | if err := sc.Publish("foo", []byte("msg")); err != nil { 1423 | t.Fatalf("Unexpected error on publish: %v", err) 1424 | } 1425 | } 1426 | 1427 | cb := func(m *Msg) { 1428 | m.Ack() 1429 | } 1430 | if _, err := sc.Subscribe("foo", cb, SetManualAckMode(), 1431 | DeliverAllAvailable()); err != nil { 1432 | t.Fatalf("Unexpected error on subscribe: %v", err) 1433 | } 1434 | // Close while ack'ing may happen 1435 | time.Sleep(10 * time.Millisecond) 1436 | sc.Close() 1437 | } 1438 | 1439 | func TestNatsConn(t *testing.T) { 1440 | s := RunServer(clusterName) 1441 | defer s.Shutdown() 1442 | sc := NewDefaultConnection(t) 1443 | defer sc.Close() 1444 | 1445 | // Make sure we can get the STAN-created Conn. 1446 | nc := sc.NatsConn() 1447 | 1448 | if nc.Status() != nats.CONNECTED { 1449 | t.Fatal("Should have status set to CONNECTED") 1450 | } 1451 | nc.Close() 1452 | if nc.Status() != nats.CLOSED { 1453 | t.Fatal("Should have status set to CLOSED") 1454 | } 1455 | 1456 | sc.Close() 1457 | if sc.NatsConn() != nil { 1458 | t.Fatal("Wrapped conn should be nil after close") 1459 | } 1460 | 1461 | // Bail if we have a custom connection but not connected 1462 | cnc := nats.Conn{Opts: nats.GetDefaultOptions()} 1463 | if _, err := Connect(clusterName, clientName, NatsConn(&cnc)); err != ErrBadConnection { 1464 | t.Fatalf("Expected to get an invalid connection error, got %v", err) 1465 | } 1466 | 1467 | // Allow custom conn only if already connected 1468 | opts := nats.GetDefaultOptions() 1469 | nc, err := opts.Connect() 1470 | if err != nil { 1471 | t.Fatalf("Expected to connect correctly, got err %v", err) 1472 | } 1473 | sc, err = Connect(clusterName, clientName, NatsConn(nc)) 1474 | if err != nil { 1475 | t.Fatalf("Expected to connect correctly, got err %v", err) 1476 | } 1477 | nc.Close() 1478 | if nc.Status() != nats.CLOSED { 1479 | t.Fatal("Should have status set to CLOSED") 1480 | } 1481 | sc.Close() 1482 | 1483 | // Make sure we can get the Conn we provide. 1484 | opts = nats.GetDefaultOptions() 1485 | nc, err = opts.Connect() 1486 | if err != nil { 1487 | t.Fatalf("Expected to connect correctly, got err %v", err) 1488 | } 1489 | defer nc.Close() 1490 | sc, err = Connect(clusterName, clientName, NatsConn(nc)) 1491 | if err != nil { 1492 | t.Fatalf("Expected to connect correctly, got err %v", err) 1493 | } 1494 | defer sc.Close() 1495 | if sc.NatsConn() != nc { 1496 | t.Fatal("Unexpected wrapped conn") 1497 | } 1498 | } 1499 | 1500 | func TestMaxPubAcksInflight(t *testing.T) { 1501 | s := RunServer(clusterName) 1502 | defer s.Shutdown() 1503 | 1504 | nc, err := nats.Connect(nats.DefaultURL) 1505 | if err != nil { 1506 | t.Fatalf("Unexpected error on connect: %v", err) 1507 | } 1508 | defer nc.Close() 1509 | 1510 | sc, err := Connect(clusterName, clientName, 1511 | MaxPubAcksInflight(1), 1512 | PubAckWait(time.Second), 1513 | NatsConn(nc)) 1514 | if err != nil { 1515 | t.Fatalf("Expected to connect correctly, got err %v", err) 1516 | } 1517 | // Don't defer the close of connection since the server is stopped, 1518 | // the close would delay the test. 1519 | 1520 | // Cause the ACK to not come by shutdown the server now 1521 | s.Shutdown() 1522 | 1523 | msg := []byte("hello") 1524 | 1525 | // Send more than one message, if MaxPubAcksInflight() works, one 1526 | // of the publish call should block for up to PubAckWait. 1527 | start := time.Now() 1528 | for i := 0; i < 2; i++ { 1529 | if _, err := sc.PublishAsync("foo", msg, nil); err != nil { 1530 | t.Fatalf("Unexpected error on publish: %v", err) 1531 | } 1532 | } 1533 | end := time.Now() 1534 | // So if the loop ended before the PubAckWait timeout, then it's a failure. 1535 | if end.Sub(start) < time.Second { 1536 | t.Fatal("Should have blocked after 1 message sent") 1537 | } 1538 | } 1539 | 1540 | func TestNatsURLOption(t *testing.T) { 1541 | s := RunServer(clusterName) 1542 | defer s.Shutdown() 1543 | 1544 | sc, err := Connect(clusterName, clientName, NatsURL("nats://localhost:5555")) 1545 | if err == nil { 1546 | sc.Close() 1547 | t.Fatal("Expected connect to fail") 1548 | } 1549 | } 1550 | 1551 | func TestSubscriptionPending(t *testing.T) { 1552 | // Run a NATS Streaming server 1553 | s := RunServer(clusterName) 1554 | defer s.Shutdown() 1555 | 1556 | sc := NewDefaultConnection(t) 1557 | defer sc.Close() 1558 | 1559 | nc := sc.NatsConn() 1560 | 1561 | total := 100 1562 | msg := []byte("0123456789") 1563 | 1564 | inCb := make(chan bool) 1565 | block := make(chan bool) 1566 | cb := func(m *Msg) { 1567 | inCb <- true 1568 | <-block 1569 | } 1570 | 1571 | sub, _ := sc.QueueSubscribe("foo", "bar", cb) 1572 | defer sub.Unsubscribe() 1573 | 1574 | // Publish five messages 1575 | for i := 0; i < total; i++ { 1576 | sc.Publish("foo", msg) 1577 | } 1578 | nc.Flush() 1579 | 1580 | // Wait for our first message 1581 | if err := Wait(inCb); err != nil { 1582 | t.Fatal("No message received") 1583 | } 1584 | 1585 | m, b, _ := sub.Pending() 1586 | // FIXME(jack0) - nats streaming appends clientid, guid, and subject to messages so bytes pending is greater than message size 1587 | mlen := len(msg) + 19 1588 | totalSize := total * mlen 1589 | 1590 | if m != total && m != total-1 { 1591 | t.Fatalf("Expected msgs of %d or %d, got %d\n", total, total-1, m) 1592 | } 1593 | if b != totalSize && b != totalSize-mlen { 1594 | t.Fatalf("Expected bytes of %d or %d, got %d\n", 1595 | totalSize, totalSize-mlen, b) 1596 | } 1597 | 1598 | // Make sure max has been set. Since we block after the first message is 1599 | // received, MaxPending should be >= total - 1 and <= total 1600 | mm, bm, _ := sub.MaxPending() 1601 | if mm < total-1 || mm > total { 1602 | t.Fatalf("Expected max msgs (%d) to be between %d and %d\n", 1603 | mm, total-1, total) 1604 | } 1605 | if bm < totalSize-mlen || bm > totalSize { 1606 | t.Fatalf("Expected max bytes (%d) to be between %d and %d\n", 1607 | bm, totalSize, totalSize-mlen) 1608 | } 1609 | // Check that clear works. 1610 | sub.ClearMaxPending() 1611 | mm, bm, _ = sub.MaxPending() 1612 | if mm != 0 { 1613 | t.Fatalf("Expected max msgs to be 0 vs %d after clearing\n", mm) 1614 | } 1615 | if bm != 0 { 1616 | t.Fatalf("Expected max bytes to be 0 vs %d after clearing\n", bm) 1617 | } 1618 | 1619 | close(block) 1620 | sub.Unsubscribe() 1621 | 1622 | // These calls should fail once the subscription is closed. 1623 | if _, _, err := sub.Pending(); err == nil { 1624 | t.Fatal("Calling Pending() on closed subscription should fail") 1625 | } 1626 | if _, _, err := sub.MaxPending(); err == nil { 1627 | t.Fatal("Calling MaxPending() on closed subscription should fail") 1628 | } 1629 | if err := sub.ClearMaxPending(); err == nil { 1630 | t.Fatal("Calling ClearMaxPending() on closed subscription should fail") 1631 | } 1632 | } 1633 | 1634 | func TestTimeoutOnRequests(t *testing.T) { 1635 | ns := natsd.RunDefaultServer() 1636 | defer ns.Shutdown() 1637 | 1638 | opts := server.GetDefaultOptions() 1639 | opts.ID = clusterName 1640 | opts.NATSServerURL = nats.DefaultURL 1641 | s := runServerWithOpts(opts) 1642 | defer s.Shutdown() 1643 | 1644 | sc := NewDefaultConnection(t) 1645 | defer sc.Close() 1646 | 1647 | sub1, err := sc.Subscribe("foo", func(_ *Msg) {}) 1648 | if err != nil { 1649 | t.Fatalf("Unexpected error on subscribe: %v", err) 1650 | } 1651 | sub2, err := sc.Subscribe("foo", func(_ *Msg) {}) 1652 | if err != nil { 1653 | t.Fatalf("Unexpected error on subscribe: %v", err) 1654 | } 1655 | 1656 | // For this test, change the reqTimeout to very low value 1657 | sc.(*conn).Lock() 1658 | sc.(*conn).opts.ConnectTimeout = 10 * time.Millisecond 1659 | sc.(*conn).Unlock() 1660 | 1661 | // Shutdown server 1662 | s.Shutdown() 1663 | 1664 | // Subscribe 1665 | if _, err := sc.Subscribe("foo", func(_ *Msg) {}); err != ErrSubReqTimeout { 1666 | t.Fatalf("Expected %v error, got %v", ErrSubReqTimeout, err) 1667 | } 1668 | 1669 | // If connecting to an old server... 1670 | if sc.(*conn).subCloseRequests == "" { 1671 | // Trick the API into thinking that it can send, 1672 | // and make sure the call times-out 1673 | sc.(*conn).Lock() 1674 | sc.(*conn).subCloseRequests = "sub.close.subject" 1675 | sc.(*conn).Unlock() 1676 | } 1677 | // Subscription Close 1678 | if err := sub1.Close(); err != ErrCloseReqTimeout { 1679 | t.Fatalf("Expected %v error, got %v", ErrCloseReqTimeout, err) 1680 | } 1681 | // Unsubscribe 1682 | if err := sub2.Unsubscribe(); err != ErrUnsubReqTimeout { 1683 | t.Fatalf("Expected %v error, got %v", ErrUnsubReqTimeout, err) 1684 | } 1685 | // Connection Close 1686 | if err := sc.Close(); err != ErrCloseReqTimeout { 1687 | t.Fatalf("Expected %v error, got %v", ErrCloseReqTimeout, err) 1688 | } 1689 | } 1690 | 1691 | func TestSlowAsyncSubscriber(t *testing.T) { 1692 | // Run a NATS Streaming server 1693 | s := RunServer(clusterName) 1694 | defer s.Shutdown() 1695 | 1696 | sc := NewDefaultConnection(t) 1697 | defer sc.Close() 1698 | 1699 | nc := sc.NatsConn() 1700 | 1701 | bch := make(chan bool) 1702 | 1703 | sub, _ := sc.Subscribe("foo", func(_ *Msg) { 1704 | // block to back us up.. 1705 | <-bch 1706 | }) 1707 | // Make sure these are the defaults 1708 | pm, pb, _ := sub.PendingLimits() 1709 | if pm != nats.DefaultSubPendingMsgsLimit { 1710 | t.Fatalf("Pending limit for number of msgs incorrect, expected %d, got %d\n", nats.DefaultSubPendingMsgsLimit, pm) 1711 | } 1712 | if pb != nats.DefaultSubPendingBytesLimit { 1713 | t.Fatalf("Pending limit for number of bytes incorrect, expected %d, got %d\n", nats.DefaultSubPendingBytesLimit, pb) 1714 | } 1715 | 1716 | // Set new limits 1717 | pml := 100 1718 | pbl := 1024 * 1024 1719 | 1720 | sub.SetPendingLimits(pml, pbl) 1721 | 1722 | // Make sure the set is correct 1723 | pm, pb, _ = sub.PendingLimits() 1724 | if pm != pml { 1725 | t.Fatalf("Pending limit for number of msgs incorrect, expected %d, got %d\n", pml, pm) 1726 | } 1727 | if pb != pbl { 1728 | t.Fatalf("Pending limit for number of bytes incorrect, expected %d, got %d\n", pbl, pb) 1729 | } 1730 | 1731 | for i := 0; i < (int(pml) + 100); i++ { 1732 | sc.Publish("foo", []byte("Hello")) 1733 | } 1734 | 1735 | timeout := 5 * time.Second 1736 | start := time.Now() 1737 | err := nc.FlushTimeout(timeout) 1738 | elapsed := time.Since(start) 1739 | if elapsed >= timeout { 1740 | t.Fatalf("Flush did not return before timeout") 1741 | } 1742 | // We want flush to work, so expect no error for it. 1743 | if err != nil { 1744 | t.Fatalf("Expected no error from Flush()\n") 1745 | } 1746 | if nc.LastError() != nats.ErrSlowConsumer { 1747 | t.Fatal("Expected LastError to indicate slow consumer") 1748 | } 1749 | // release the sub 1750 | bch <- true 1751 | } 1752 | 1753 | func TestSubscriberClose(t *testing.T) { 1754 | s := RunServer(clusterName) 1755 | defer s.Shutdown() 1756 | 1757 | sc := NewDefaultConnection(t) 1758 | defer sc.Close() 1759 | 1760 | // If old server, Close() is expected to fail. 1761 | supported := sc.(*conn).subCloseRequests != "" 1762 | 1763 | checkClose := func(sub Subscription) { 1764 | err := sub.Close() 1765 | if supported && err != nil { 1766 | t.Fatalf("Unexpected error on close: %v", err) 1767 | } else if !supported && err != ErrNoServerSupport { 1768 | t.Fatalf("Expected %v, got %v", ErrNoServerSupport, err) 1769 | } 1770 | } 1771 | 1772 | count := 1 1773 | if supported { 1774 | count = 2 1775 | } 1776 | for i := 0; i < count; i++ { 1777 | sub, err := sc.Subscribe("foo", func(_ *Msg) {}) 1778 | if err != nil { 1779 | t.Fatalf("Unexpected error on subscribe: %v", err) 1780 | } 1781 | checkClose(sub) 1782 | 1783 | qsub, err := sc.QueueSubscribe("foo", "group", func(_ *Msg) {}) 1784 | if err != nil { 1785 | t.Fatalf("Unexpected error on subscribe: %v", err) 1786 | } 1787 | checkClose(qsub) 1788 | 1789 | if supported { 1790 | // Repeat the tests but pretend server does not support close 1791 | sc.(*conn).Lock() 1792 | sc.(*conn).subCloseRequests = "" 1793 | sc.(*conn).Unlock() 1794 | supported = false 1795 | } 1796 | } 1797 | 1798 | sub, err := sc.Subscribe("foo", func(_ *Msg) {}) 1799 | if err != nil { 1800 | t.Fatalf("Unexpected error on subscribe: %v", err) 1801 | } 1802 | closedNC, err := nats.Connect(nats.DefaultURL) 1803 | if err != nil { 1804 | t.Fatalf("Unexpected error on connect: %v", err) 1805 | } 1806 | closedNC.Close() 1807 | // Swap current NATS connection with this closed connection 1808 | sc.(*conn).Lock() 1809 | savedNC := sc.(*conn).nc 1810 | sc.(*conn).nc = closedNC 1811 | sc.(*conn).Unlock() 1812 | if err := sub.Unsubscribe(); err == nil { 1813 | t.Fatal("Expected error on close") 1814 | } 1815 | // Restore NATS connection 1816 | sc.(*conn).Lock() 1817 | sc.(*conn).nc = savedNC 1818 | sc.(*conn).Unlock() 1819 | 1820 | sc.Close() 1821 | 1822 | closeSubscriber(t, "dursub", "sub") 1823 | closeSubscriber(t, "durqueuesub", "queue") 1824 | } 1825 | 1826 | func TestOptionNatsName(t *testing.T) { 1827 | s := RunServer(clusterName) 1828 | defer s.Shutdown() 1829 | sc := NewDefaultConnection(t) 1830 | defer sc.Close() 1831 | 1832 | // Make sure we can get the STAN-created Conn. 1833 | nc := sc.NatsConn() 1834 | 1835 | if n := nc.Opts.Name; n != clientName { 1836 | t.Fatalf("Unexpected nats client name: %s", n) 1837 | } 1838 | } 1839 | 1840 | func closeSubscriber(t *testing.T, channel, subType string) { 1841 | sc := NewDefaultConnection(t) 1842 | defer sc.Close() 1843 | 1844 | // Send 1 message 1845 | if err := sc.Publish(channel, []byte("msg")); err != nil { 1846 | t.Fatalf("Unexpected error on publish: %v", err) 1847 | } 1848 | count := 0 1849 | ch := make(chan bool) 1850 | errCh := make(chan bool) 1851 | cb := func(m *Msg) { 1852 | count++ 1853 | if m.Sequence != uint64(count) { 1854 | errCh <- true 1855 | return 1856 | } 1857 | ch <- true 1858 | } 1859 | // Create a durable 1860 | var sub Subscription 1861 | var err error 1862 | if subType == "sub" { 1863 | sub, err = sc.Subscribe(channel, cb, DurableName("dur"), DeliverAllAvailable()) 1864 | } else { 1865 | sub, err = sc.QueueSubscribe(channel, "group", cb, DurableName("dur"), DeliverAllAvailable()) 1866 | } 1867 | if err != nil { 1868 | stackFatalf(t, "Unexpected error on subscribe: %v", err) 1869 | } 1870 | // Wait to receive 1st message 1871 | if err := Wait(ch); err != nil { 1872 | stackFatalf(t, "Did not get our message") 1873 | } 1874 | // Wait a bit to reduce risk of server processing unsubscribe before ACK 1875 | time.Sleep(500 * time.Millisecond) 1876 | // Close durable 1877 | err = sub.Close() 1878 | // Feature supported or not by the server 1879 | supported := sc.(*conn).subCloseRequests != "" 1880 | // If connecting to an older server, error is expected 1881 | if !supported && err != ErrNoServerSupport { 1882 | stackFatalf(t, "Expected %v error, got %v", ErrNoServerSupport, err) 1883 | } 1884 | if !supported { 1885 | // Nothing much to test 1886 | sub.Unsubscribe() 1887 | return 1888 | } 1889 | // Here, server supports feature 1890 | if err != nil { 1891 | stackFatalf(t, "Unexpected error on close: %v", err) 1892 | } 1893 | // Send 2nd message 1894 | if err := sc.Publish(channel, []byte("msg")); err != nil { 1895 | stackFatalf(t, "Unexpected error on publish: %v", err) 1896 | } 1897 | // Restart durable 1898 | if subType == "sub" { 1899 | sub, err = sc.Subscribe(channel, cb, DurableName("dur"), DeliverAllAvailable()) 1900 | } else { 1901 | sub, err = sc.QueueSubscribe(channel, "group", cb, DurableName("dur"), DeliverAllAvailable()) 1902 | } 1903 | if err != nil { 1904 | stackFatalf(t, "Unexpected error on subscribe: %v", err) 1905 | } 1906 | defer sub.Unsubscribe() 1907 | select { 1908 | case <-errCh: 1909 | stackFatalf(t, "Unexpected message received") 1910 | case <-ch: 1911 | case <-time.After(5 * time.Second): 1912 | stackFatalf(t, "Timeout waiting for messages") 1913 | } 1914 | } 1915 | 1916 | func TestDuplicateProcessingOfPubAck(t *testing.T) { 1917 | // We run our tests on Windows VM and this test would fail because 1918 | // server would be a slow consumer. So skipping for now. 1919 | if runtime.GOOS == "windows" { 1920 | t.SkipNow() 1921 | } 1922 | s := RunServer(clusterName) 1923 | defer s.Shutdown() 1924 | 1925 | // Use a very small timeout purposely 1926 | sc, err := Connect(clusterName, clientName, PubAckWait(time.Millisecond)) 1927 | if err != nil { 1928 | t.Fatalf("Error on connect: %v", err) 1929 | } 1930 | defer sc.Close() 1931 | 1932 | total := 10000 1933 | pubAcks := make(map[string]struct{}, total) 1934 | gotBug := false 1935 | errCh := make(chan error) 1936 | msg := []byte("msg") 1937 | count := 0 1938 | done := make(chan bool) 1939 | mu := &sync.Mutex{} 1940 | 1941 | ackHandler := func(guid string, err error) { 1942 | mu.Lock() 1943 | if gotBug { 1944 | mu.Unlock() 1945 | return 1946 | } 1947 | if _, exist := pubAcks[guid]; exist { 1948 | gotBug = true 1949 | errCh <- fmt.Errorf("Duplicate processing of PubAck %d guid=%v", (count + 1), guid) 1950 | mu.Unlock() 1951 | return 1952 | } 1953 | pubAcks[guid] = struct{}{} 1954 | count++ 1955 | if count == total { 1956 | done <- true 1957 | } 1958 | mu.Unlock() 1959 | } 1960 | for i := 0; i < total; i++ { 1961 | sc.PublishAsync("foo", msg, ackHandler) 1962 | } 1963 | select { 1964 | case <-done: 1965 | case e := <-errCh: 1966 | t.Fatal(e) 1967 | case <-time.After(10 * time.Second): 1968 | t.Fatal("Test took too long") 1969 | } 1970 | // If we are here is that we have published `total` messages. 1971 | // Since the bug is about processing duplicate PubAck, 1972 | // wait a bit more. 1973 | select { 1974 | case e := <-errCh: 1975 | t.Fatal(e) 1976 | case <-time.After(100 * time.Millisecond): 1977 | // This is more than the PubAckWait, so we should be good now. 1978 | } 1979 | } 1980 | 1981 | func TestSubDelivered(t *testing.T) { 1982 | s := RunServer(clusterName) 1983 | defer s.Shutdown() 1984 | 1985 | sc := NewDefaultConnection(t) 1986 | defer sc.Close() 1987 | 1988 | total := 10 1989 | count := 0 1990 | ch := make(chan bool) 1991 | sub, err := sc.Subscribe("foo", func(_ *Msg) { 1992 | count++ 1993 | if count == total { 1994 | ch <- true 1995 | } 1996 | }) 1997 | if err != nil { 1998 | t.Fatalf("Unexpected error on subscriber: %v", err) 1999 | } 2000 | defer sub.Unsubscribe() 2001 | 2002 | for i := 0; i < total; i++ { 2003 | if err := sc.Publish("foo", []byte("hello")); err != nil { 2004 | t.Fatalf("Unexpected error on publish: %v", err) 2005 | } 2006 | } 2007 | // Wait for all messages 2008 | if err := Wait(ch); err != nil { 2009 | t.Fatal("Did not get our messages") 2010 | } 2011 | if n, err := sub.Delivered(); err != nil || n != int64(total) { 2012 | t.Fatalf("Expected %d messages delivered, got %d, err=%v", total, n, err) 2013 | } 2014 | sub.Unsubscribe() 2015 | if n, err := sub.Delivered(); err != ErrBadSubscription || n != int64(-1) { 2016 | t.Fatalf("Expected ErrBadSubscription, got %d, err=%v", n, err) 2017 | } 2018 | } 2019 | 2020 | func TestSubDropped(t *testing.T) { 2021 | s := RunServer(clusterName) 2022 | defer s.Shutdown() 2023 | 2024 | sc := NewDefaultConnection(t) 2025 | defer sc.Close() 2026 | 2027 | total := 1000 2028 | count := 0 2029 | ch := make(chan bool) 2030 | blocked := make(chan bool) 2031 | ready := make(chan bool) 2032 | sub, err := sc.Subscribe("foo", func(_ *Msg) { 2033 | count++ 2034 | if count == 1 { 2035 | ready <- true 2036 | <-blocked 2037 | ch <- true 2038 | } 2039 | }) 2040 | if err != nil { 2041 | t.Fatalf("Unexpected error on subscriber: %v", err) 2042 | } 2043 | defer sub.Unsubscribe() 2044 | 2045 | // Set low pending limits 2046 | sub.SetPendingLimits(1, -1) 2047 | 2048 | for i := 0; i < total; i++ { 2049 | if err := sc.Publish("foo", []byte("hello")); err != nil { 2050 | t.Fatalf("Unexpected error on publish: %v", err) 2051 | } 2052 | } 2053 | // Wait for sub to receive first message and block 2054 | if err := Wait(ready); err != nil { 2055 | t.Fatal("Did not get our first message") 2056 | } 2057 | 2058 | // Messages should be dropped 2059 | if n, err := sub.Dropped(); err != nil || n == 0 { 2060 | t.Fatalf("Messages should have been dropped, got %d, err=%v", n, err) 2061 | } 2062 | 2063 | // Unblock and wait for end 2064 | close(blocked) 2065 | if err := Wait(ch); err != nil { 2066 | t.Fatal("Callback did not return") 2067 | } 2068 | sub.Unsubscribe() 2069 | // Now subscription is closed, this should return error 2070 | if n, err := sub.Dropped(); err != ErrBadSubscription || n != -1 { 2071 | t.Fatalf("Expected ErrBadSubscription, got %d, err=%v", n, err) 2072 | } 2073 | } 2074 | 2075 | func TestSubIsValid(t *testing.T) { 2076 | s := RunServer(clusterName) 2077 | defer s.Shutdown() 2078 | 2079 | sc := NewDefaultConnection(t) 2080 | defer sc.Close() 2081 | 2082 | sub, err := sc.Subscribe("foo", func(_ *Msg) {}) 2083 | if err != nil { 2084 | t.Fatalf("Unexpected error on subscriber: %v", err) 2085 | } 2086 | defer sub.Unsubscribe() 2087 | if !sub.IsValid() { 2088 | t.Fatal("Subscription should be valid") 2089 | } 2090 | sub.Unsubscribe() 2091 | if sub.IsValid() { 2092 | t.Fatal("Subscription should not be valid") 2093 | } 2094 | } 2095 | -------------------------------------------------------------------------------- /pb/protocol.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-gogo. 2 | // source: protocol.proto 3 | // DO NOT EDIT! 4 | 5 | /* 6 | Package pb is a generated protocol buffer package. 7 | 8 | It is generated from these files: 9 | protocol.proto 10 | 11 | It has these top-level messages: 12 | PubMsg 13 | PubAck 14 | MsgProto 15 | Ack 16 | ConnectRequest 17 | ConnectResponse 18 | SubscriptionRequest 19 | SubscriptionResponse 20 | UnsubscribeRequest 21 | CloseRequest 22 | CloseResponse 23 | */ 24 | package pb 25 | 26 | import proto "github.com/gogo/protobuf/proto" 27 | import fmt "fmt" 28 | import math "math" 29 | import _ "github.com/gogo/protobuf/gogoproto" 30 | 31 | import io "io" 32 | 33 | // Reference imports to suppress errors if they are not otherwise used. 34 | var _ = proto.Marshal 35 | var _ = fmt.Errorf 36 | var _ = math.Inf 37 | 38 | // Enum for start position type. 39 | type StartPosition int32 40 | 41 | const ( 42 | StartPosition_NewOnly StartPosition = 0 43 | StartPosition_LastReceived StartPosition = 1 44 | StartPosition_TimeDeltaStart StartPosition = 2 45 | StartPosition_SequenceStart StartPosition = 3 46 | StartPosition_First StartPosition = 4 47 | ) 48 | 49 | var StartPosition_name = map[int32]string{ 50 | 0: "NewOnly", 51 | 1: "LastReceived", 52 | 2: "TimeDeltaStart", 53 | 3: "SequenceStart", 54 | 4: "First", 55 | } 56 | var StartPosition_value = map[string]int32{ 57 | "NewOnly": 0, 58 | "LastReceived": 1, 59 | "TimeDeltaStart": 2, 60 | "SequenceStart": 3, 61 | "First": 4, 62 | } 63 | 64 | func (x StartPosition) String() string { 65 | return proto.EnumName(StartPosition_name, int32(x)) 66 | } 67 | 68 | // How messages are delivered to the STAN cluster 69 | type PubMsg struct { 70 | ClientID string `protobuf:"bytes,1,opt,name=clientID,proto3" json:"clientID,omitempty"` 71 | Guid string `protobuf:"bytes,2,opt,name=guid,proto3" json:"guid,omitempty"` 72 | Subject string `protobuf:"bytes,3,opt,name=subject,proto3" json:"subject,omitempty"` 73 | Reply string `protobuf:"bytes,4,opt,name=reply,proto3" json:"reply,omitempty"` 74 | Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` 75 | Sha256 []byte `protobuf:"bytes,10,opt,name=sha256,proto3" json:"sha256,omitempty"` 76 | } 77 | 78 | func (m *PubMsg) Reset() { *m = PubMsg{} } 79 | func (m *PubMsg) String() string { return proto.CompactTextString(m) } 80 | func (*PubMsg) ProtoMessage() {} 81 | 82 | // Used to ACK to publishers 83 | type PubAck struct { 84 | Guid string `protobuf:"bytes,1,opt,name=guid,proto3" json:"guid,omitempty"` 85 | Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` 86 | } 87 | 88 | func (m *PubAck) Reset() { *m = PubAck{} } 89 | func (m *PubAck) String() string { return proto.CompactTextString(m) } 90 | func (*PubAck) ProtoMessage() {} 91 | 92 | // Msg struct. Sequence is assigned for global ordering by 93 | // the cluster after the publisher has been acknowledged. 94 | type MsgProto struct { 95 | Sequence uint64 `protobuf:"varint,1,opt,name=sequence,proto3" json:"sequence,omitempty"` 96 | Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"` 97 | Reply string `protobuf:"bytes,3,opt,name=reply,proto3" json:"reply,omitempty"` 98 | Data []byte `protobuf:"bytes,4,opt,name=data,proto3" json:"data,omitempty"` 99 | Timestamp int64 `protobuf:"varint,5,opt,name=timestamp,proto3" json:"timestamp,omitempty"` 100 | Redelivered bool `protobuf:"varint,6,opt,name=redelivered,proto3" json:"redelivered,omitempty"` 101 | CRC32 uint32 `protobuf:"varint,10,opt,name=CRC32,proto3" json:"CRC32,omitempty"` 102 | } 103 | 104 | func (m *MsgProto) Reset() { *m = MsgProto{} } 105 | func (m *MsgProto) String() string { return proto.CompactTextString(m) } 106 | func (*MsgProto) ProtoMessage() {} 107 | 108 | // Ack will deliver an ack for a delivered msg. 109 | type Ack struct { 110 | Subject string `protobuf:"bytes,1,opt,name=subject,proto3" json:"subject,omitempty"` 111 | Sequence uint64 `protobuf:"varint,2,opt,name=sequence,proto3" json:"sequence,omitempty"` 112 | } 113 | 114 | func (m *Ack) Reset() { *m = Ack{} } 115 | func (m *Ack) String() string { return proto.CompactTextString(m) } 116 | func (*Ack) ProtoMessage() {} 117 | 118 | // Connection Request 119 | type ConnectRequest struct { 120 | ClientID string `protobuf:"bytes,1,opt,name=clientID,proto3" json:"clientID,omitempty"` 121 | HeartbeatInbox string `protobuf:"bytes,2,opt,name=heartbeatInbox,proto3" json:"heartbeatInbox,omitempty"` 122 | } 123 | 124 | func (m *ConnectRequest) Reset() { *m = ConnectRequest{} } 125 | func (m *ConnectRequest) String() string { return proto.CompactTextString(m) } 126 | func (*ConnectRequest) ProtoMessage() {} 127 | 128 | // Response to a client connect 129 | type ConnectResponse struct { 130 | PubPrefix string `protobuf:"bytes,1,opt,name=pubPrefix,proto3" json:"pubPrefix,omitempty"` 131 | SubRequests string `protobuf:"bytes,2,opt,name=subRequests,proto3" json:"subRequests,omitempty"` 132 | UnsubRequests string `protobuf:"bytes,3,opt,name=unsubRequests,proto3" json:"unsubRequests,omitempty"` 133 | CloseRequests string `protobuf:"bytes,4,opt,name=closeRequests,proto3" json:"closeRequests,omitempty"` 134 | Error string `protobuf:"bytes,5,opt,name=error,proto3" json:"error,omitempty"` 135 | SubCloseRequests string `protobuf:"bytes,6,opt,name=subCloseRequests,proto3" json:"subCloseRequests,omitempty"` 136 | PublicKey string `protobuf:"bytes,100,opt,name=publicKey,proto3" json:"publicKey,omitempty"` 137 | } 138 | 139 | func (m *ConnectResponse) Reset() { *m = ConnectResponse{} } 140 | func (m *ConnectResponse) String() string { return proto.CompactTextString(m) } 141 | func (*ConnectResponse) ProtoMessage() {} 142 | 143 | // Protocol for a client to subscribe 144 | type SubscriptionRequest struct { 145 | ClientID string `protobuf:"bytes,1,opt,name=clientID,proto3" json:"clientID,omitempty"` 146 | Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"` 147 | QGroup string `protobuf:"bytes,3,opt,name=qGroup,proto3" json:"qGroup,omitempty"` 148 | Inbox string `protobuf:"bytes,4,opt,name=inbox,proto3" json:"inbox,omitempty"` 149 | MaxInFlight int32 `protobuf:"varint,5,opt,name=maxInFlight,proto3" json:"maxInFlight,omitempty"` 150 | AckWaitInSecs int32 `protobuf:"varint,6,opt,name=ackWaitInSecs,proto3" json:"ackWaitInSecs,omitempty"` 151 | DurableName string `protobuf:"bytes,7,opt,name=durableName,proto3" json:"durableName,omitempty"` 152 | StartPosition StartPosition `protobuf:"varint,10,opt,name=startPosition,proto3,enum=pb.StartPosition" json:"startPosition,omitempty"` 153 | StartSequence uint64 `protobuf:"varint,11,opt,name=startSequence,proto3" json:"startSequence,omitempty"` 154 | StartTimeDelta int64 `protobuf:"varint,12,opt,name=startTimeDelta,proto3" json:"startTimeDelta,omitempty"` 155 | } 156 | 157 | func (m *SubscriptionRequest) Reset() { *m = SubscriptionRequest{} } 158 | func (m *SubscriptionRequest) String() string { return proto.CompactTextString(m) } 159 | func (*SubscriptionRequest) ProtoMessage() {} 160 | 161 | // Response for SubscriptionRequest and UnsubscribeRequests 162 | type SubscriptionResponse struct { 163 | AckInbox string `protobuf:"bytes,2,opt,name=ackInbox,proto3" json:"ackInbox,omitempty"` 164 | Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` 165 | } 166 | 167 | func (m *SubscriptionResponse) Reset() { *m = SubscriptionResponse{} } 168 | func (m *SubscriptionResponse) String() string { return proto.CompactTextString(m) } 169 | func (*SubscriptionResponse) ProtoMessage() {} 170 | 171 | // Protocol for a clients to unsubscribe. Will return a SubscriptionResponse 172 | type UnsubscribeRequest struct { 173 | ClientID string `protobuf:"bytes,1,opt,name=clientID,proto3" json:"clientID,omitempty"` 174 | Subject string `protobuf:"bytes,2,opt,name=subject,proto3" json:"subject,omitempty"` 175 | Inbox string `protobuf:"bytes,3,opt,name=inbox,proto3" json:"inbox,omitempty"` 176 | DurableName string `protobuf:"bytes,4,opt,name=durableName,proto3" json:"durableName,omitempty"` 177 | } 178 | 179 | func (m *UnsubscribeRequest) Reset() { *m = UnsubscribeRequest{} } 180 | func (m *UnsubscribeRequest) String() string { return proto.CompactTextString(m) } 181 | func (*UnsubscribeRequest) ProtoMessage() {} 182 | 183 | // Protocol for a client to close a connection 184 | type CloseRequest struct { 185 | ClientID string `protobuf:"bytes,1,opt,name=clientID,proto3" json:"clientID,omitempty"` 186 | } 187 | 188 | func (m *CloseRequest) Reset() { *m = CloseRequest{} } 189 | func (m *CloseRequest) String() string { return proto.CompactTextString(m) } 190 | func (*CloseRequest) ProtoMessage() {} 191 | 192 | // Response for CloseRequest 193 | type CloseResponse struct { 194 | Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` 195 | } 196 | 197 | func (m *CloseResponse) Reset() { *m = CloseResponse{} } 198 | func (m *CloseResponse) String() string { return proto.CompactTextString(m) } 199 | func (*CloseResponse) ProtoMessage() {} 200 | 201 | func init() { 202 | proto.RegisterType((*PubMsg)(nil), "pb.PubMsg") 203 | proto.RegisterType((*PubAck)(nil), "pb.PubAck") 204 | proto.RegisterType((*MsgProto)(nil), "pb.MsgProto") 205 | proto.RegisterType((*Ack)(nil), "pb.Ack") 206 | proto.RegisterType((*ConnectRequest)(nil), "pb.ConnectRequest") 207 | proto.RegisterType((*ConnectResponse)(nil), "pb.ConnectResponse") 208 | proto.RegisterType((*SubscriptionRequest)(nil), "pb.SubscriptionRequest") 209 | proto.RegisterType((*SubscriptionResponse)(nil), "pb.SubscriptionResponse") 210 | proto.RegisterType((*UnsubscribeRequest)(nil), "pb.UnsubscribeRequest") 211 | proto.RegisterType((*CloseRequest)(nil), "pb.CloseRequest") 212 | proto.RegisterType((*CloseResponse)(nil), "pb.CloseResponse") 213 | proto.RegisterEnum("pb.StartPosition", StartPosition_name, StartPosition_value) 214 | } 215 | func (m *PubMsg) Marshal() (data []byte, err error) { 216 | size := m.Size() 217 | data = make([]byte, size) 218 | n, err := m.MarshalTo(data) 219 | if err != nil { 220 | return nil, err 221 | } 222 | return data[:n], nil 223 | } 224 | 225 | func (m *PubMsg) MarshalTo(data []byte) (int, error) { 226 | var i int 227 | _ = i 228 | var l int 229 | _ = l 230 | if len(m.ClientID) > 0 { 231 | data[i] = 0xa 232 | i++ 233 | i = encodeVarintProtocol(data, i, uint64(len(m.ClientID))) 234 | i += copy(data[i:], m.ClientID) 235 | } 236 | if len(m.Guid) > 0 { 237 | data[i] = 0x12 238 | i++ 239 | i = encodeVarintProtocol(data, i, uint64(len(m.Guid))) 240 | i += copy(data[i:], m.Guid) 241 | } 242 | if len(m.Subject) > 0 { 243 | data[i] = 0x1a 244 | i++ 245 | i = encodeVarintProtocol(data, i, uint64(len(m.Subject))) 246 | i += copy(data[i:], m.Subject) 247 | } 248 | if len(m.Reply) > 0 { 249 | data[i] = 0x22 250 | i++ 251 | i = encodeVarintProtocol(data, i, uint64(len(m.Reply))) 252 | i += copy(data[i:], m.Reply) 253 | } 254 | if m.Data != nil { 255 | if len(m.Data) > 0 { 256 | data[i] = 0x2a 257 | i++ 258 | i = encodeVarintProtocol(data, i, uint64(len(m.Data))) 259 | i += copy(data[i:], m.Data) 260 | } 261 | } 262 | if m.Sha256 != nil { 263 | if len(m.Sha256) > 0 { 264 | data[i] = 0x52 265 | i++ 266 | i = encodeVarintProtocol(data, i, uint64(len(m.Sha256))) 267 | i += copy(data[i:], m.Sha256) 268 | } 269 | } 270 | return i, nil 271 | } 272 | 273 | func (m *PubAck) Marshal() (data []byte, err error) { 274 | size := m.Size() 275 | data = make([]byte, size) 276 | n, err := m.MarshalTo(data) 277 | if err != nil { 278 | return nil, err 279 | } 280 | return data[:n], nil 281 | } 282 | 283 | func (m *PubAck) MarshalTo(data []byte) (int, error) { 284 | var i int 285 | _ = i 286 | var l int 287 | _ = l 288 | if len(m.Guid) > 0 { 289 | data[i] = 0xa 290 | i++ 291 | i = encodeVarintProtocol(data, i, uint64(len(m.Guid))) 292 | i += copy(data[i:], m.Guid) 293 | } 294 | if len(m.Error) > 0 { 295 | data[i] = 0x12 296 | i++ 297 | i = encodeVarintProtocol(data, i, uint64(len(m.Error))) 298 | i += copy(data[i:], m.Error) 299 | } 300 | return i, nil 301 | } 302 | 303 | func (m *MsgProto) Marshal() (data []byte, err error) { 304 | size := m.Size() 305 | data = make([]byte, size) 306 | n, err := m.MarshalTo(data) 307 | if err != nil { 308 | return nil, err 309 | } 310 | return data[:n], nil 311 | } 312 | 313 | func (m *MsgProto) MarshalTo(data []byte) (int, error) { 314 | var i int 315 | _ = i 316 | var l int 317 | _ = l 318 | if m.Sequence != 0 { 319 | data[i] = 0x8 320 | i++ 321 | i = encodeVarintProtocol(data, i, uint64(m.Sequence)) 322 | } 323 | if len(m.Subject) > 0 { 324 | data[i] = 0x12 325 | i++ 326 | i = encodeVarintProtocol(data, i, uint64(len(m.Subject))) 327 | i += copy(data[i:], m.Subject) 328 | } 329 | if len(m.Reply) > 0 { 330 | data[i] = 0x1a 331 | i++ 332 | i = encodeVarintProtocol(data, i, uint64(len(m.Reply))) 333 | i += copy(data[i:], m.Reply) 334 | } 335 | if m.Data != nil { 336 | if len(m.Data) > 0 { 337 | data[i] = 0x22 338 | i++ 339 | i = encodeVarintProtocol(data, i, uint64(len(m.Data))) 340 | i += copy(data[i:], m.Data) 341 | } 342 | } 343 | if m.Timestamp != 0 { 344 | data[i] = 0x28 345 | i++ 346 | i = encodeVarintProtocol(data, i, uint64(m.Timestamp)) 347 | } 348 | if m.Redelivered { 349 | data[i] = 0x30 350 | i++ 351 | if m.Redelivered { 352 | data[i] = 1 353 | } else { 354 | data[i] = 0 355 | } 356 | i++ 357 | } 358 | if m.CRC32 != 0 { 359 | data[i] = 0x50 360 | i++ 361 | i = encodeVarintProtocol(data, i, uint64(m.CRC32)) 362 | } 363 | return i, nil 364 | } 365 | 366 | func (m *Ack) Marshal() (data []byte, err error) { 367 | size := m.Size() 368 | data = make([]byte, size) 369 | n, err := m.MarshalTo(data) 370 | if err != nil { 371 | return nil, err 372 | } 373 | return data[:n], nil 374 | } 375 | 376 | func (m *Ack) MarshalTo(data []byte) (int, error) { 377 | var i int 378 | _ = i 379 | var l int 380 | _ = l 381 | if len(m.Subject) > 0 { 382 | data[i] = 0xa 383 | i++ 384 | i = encodeVarintProtocol(data, i, uint64(len(m.Subject))) 385 | i += copy(data[i:], m.Subject) 386 | } 387 | if m.Sequence != 0 { 388 | data[i] = 0x10 389 | i++ 390 | i = encodeVarintProtocol(data, i, uint64(m.Sequence)) 391 | } 392 | return i, nil 393 | } 394 | 395 | func (m *ConnectRequest) Marshal() (data []byte, err error) { 396 | size := m.Size() 397 | data = make([]byte, size) 398 | n, err := m.MarshalTo(data) 399 | if err != nil { 400 | return nil, err 401 | } 402 | return data[:n], nil 403 | } 404 | 405 | func (m *ConnectRequest) MarshalTo(data []byte) (int, error) { 406 | var i int 407 | _ = i 408 | var l int 409 | _ = l 410 | if len(m.ClientID) > 0 { 411 | data[i] = 0xa 412 | i++ 413 | i = encodeVarintProtocol(data, i, uint64(len(m.ClientID))) 414 | i += copy(data[i:], m.ClientID) 415 | } 416 | if len(m.HeartbeatInbox) > 0 { 417 | data[i] = 0x12 418 | i++ 419 | i = encodeVarintProtocol(data, i, uint64(len(m.HeartbeatInbox))) 420 | i += copy(data[i:], m.HeartbeatInbox) 421 | } 422 | return i, nil 423 | } 424 | 425 | func (m *ConnectResponse) Marshal() (data []byte, err error) { 426 | size := m.Size() 427 | data = make([]byte, size) 428 | n, err := m.MarshalTo(data) 429 | if err != nil { 430 | return nil, err 431 | } 432 | return data[:n], nil 433 | } 434 | 435 | func (m *ConnectResponse) MarshalTo(data []byte) (int, error) { 436 | var i int 437 | _ = i 438 | var l int 439 | _ = l 440 | if len(m.PubPrefix) > 0 { 441 | data[i] = 0xa 442 | i++ 443 | i = encodeVarintProtocol(data, i, uint64(len(m.PubPrefix))) 444 | i += copy(data[i:], m.PubPrefix) 445 | } 446 | if len(m.SubRequests) > 0 { 447 | data[i] = 0x12 448 | i++ 449 | i = encodeVarintProtocol(data, i, uint64(len(m.SubRequests))) 450 | i += copy(data[i:], m.SubRequests) 451 | } 452 | if len(m.UnsubRequests) > 0 { 453 | data[i] = 0x1a 454 | i++ 455 | i = encodeVarintProtocol(data, i, uint64(len(m.UnsubRequests))) 456 | i += copy(data[i:], m.UnsubRequests) 457 | } 458 | if len(m.CloseRequests) > 0 { 459 | data[i] = 0x22 460 | i++ 461 | i = encodeVarintProtocol(data, i, uint64(len(m.CloseRequests))) 462 | i += copy(data[i:], m.CloseRequests) 463 | } 464 | if len(m.Error) > 0 { 465 | data[i] = 0x2a 466 | i++ 467 | i = encodeVarintProtocol(data, i, uint64(len(m.Error))) 468 | i += copy(data[i:], m.Error) 469 | } 470 | if len(m.SubCloseRequests) > 0 { 471 | data[i] = 0x32 472 | i++ 473 | i = encodeVarintProtocol(data, i, uint64(len(m.SubCloseRequests))) 474 | i += copy(data[i:], m.SubCloseRequests) 475 | } 476 | if len(m.PublicKey) > 0 { 477 | data[i] = 0xa2 478 | i++ 479 | data[i] = 0x6 480 | i++ 481 | i = encodeVarintProtocol(data, i, uint64(len(m.PublicKey))) 482 | i += copy(data[i:], m.PublicKey) 483 | } 484 | return i, nil 485 | } 486 | 487 | func (m *SubscriptionRequest) Marshal() (data []byte, err error) { 488 | size := m.Size() 489 | data = make([]byte, size) 490 | n, err := m.MarshalTo(data) 491 | if err != nil { 492 | return nil, err 493 | } 494 | return data[:n], nil 495 | } 496 | 497 | func (m *SubscriptionRequest) MarshalTo(data []byte) (int, error) { 498 | var i int 499 | _ = i 500 | var l int 501 | _ = l 502 | if len(m.ClientID) > 0 { 503 | data[i] = 0xa 504 | i++ 505 | i = encodeVarintProtocol(data, i, uint64(len(m.ClientID))) 506 | i += copy(data[i:], m.ClientID) 507 | } 508 | if len(m.Subject) > 0 { 509 | data[i] = 0x12 510 | i++ 511 | i = encodeVarintProtocol(data, i, uint64(len(m.Subject))) 512 | i += copy(data[i:], m.Subject) 513 | } 514 | if len(m.QGroup) > 0 { 515 | data[i] = 0x1a 516 | i++ 517 | i = encodeVarintProtocol(data, i, uint64(len(m.QGroup))) 518 | i += copy(data[i:], m.QGroup) 519 | } 520 | if len(m.Inbox) > 0 { 521 | data[i] = 0x22 522 | i++ 523 | i = encodeVarintProtocol(data, i, uint64(len(m.Inbox))) 524 | i += copy(data[i:], m.Inbox) 525 | } 526 | if m.MaxInFlight != 0 { 527 | data[i] = 0x28 528 | i++ 529 | i = encodeVarintProtocol(data, i, uint64(m.MaxInFlight)) 530 | } 531 | if m.AckWaitInSecs != 0 { 532 | data[i] = 0x30 533 | i++ 534 | i = encodeVarintProtocol(data, i, uint64(m.AckWaitInSecs)) 535 | } 536 | if len(m.DurableName) > 0 { 537 | data[i] = 0x3a 538 | i++ 539 | i = encodeVarintProtocol(data, i, uint64(len(m.DurableName))) 540 | i += copy(data[i:], m.DurableName) 541 | } 542 | if m.StartPosition != 0 { 543 | data[i] = 0x50 544 | i++ 545 | i = encodeVarintProtocol(data, i, uint64(m.StartPosition)) 546 | } 547 | if m.StartSequence != 0 { 548 | data[i] = 0x58 549 | i++ 550 | i = encodeVarintProtocol(data, i, uint64(m.StartSequence)) 551 | } 552 | if m.StartTimeDelta != 0 { 553 | data[i] = 0x60 554 | i++ 555 | i = encodeVarintProtocol(data, i, uint64(m.StartTimeDelta)) 556 | } 557 | return i, nil 558 | } 559 | 560 | func (m *SubscriptionResponse) Marshal() (data []byte, err error) { 561 | size := m.Size() 562 | data = make([]byte, size) 563 | n, err := m.MarshalTo(data) 564 | if err != nil { 565 | return nil, err 566 | } 567 | return data[:n], nil 568 | } 569 | 570 | func (m *SubscriptionResponse) MarshalTo(data []byte) (int, error) { 571 | var i int 572 | _ = i 573 | var l int 574 | _ = l 575 | if len(m.AckInbox) > 0 { 576 | data[i] = 0x12 577 | i++ 578 | i = encodeVarintProtocol(data, i, uint64(len(m.AckInbox))) 579 | i += copy(data[i:], m.AckInbox) 580 | } 581 | if len(m.Error) > 0 { 582 | data[i] = 0x1a 583 | i++ 584 | i = encodeVarintProtocol(data, i, uint64(len(m.Error))) 585 | i += copy(data[i:], m.Error) 586 | } 587 | return i, nil 588 | } 589 | 590 | func (m *UnsubscribeRequest) Marshal() (data []byte, err error) { 591 | size := m.Size() 592 | data = make([]byte, size) 593 | n, err := m.MarshalTo(data) 594 | if err != nil { 595 | return nil, err 596 | } 597 | return data[:n], nil 598 | } 599 | 600 | func (m *UnsubscribeRequest) MarshalTo(data []byte) (int, error) { 601 | var i int 602 | _ = i 603 | var l int 604 | _ = l 605 | if len(m.ClientID) > 0 { 606 | data[i] = 0xa 607 | i++ 608 | i = encodeVarintProtocol(data, i, uint64(len(m.ClientID))) 609 | i += copy(data[i:], m.ClientID) 610 | } 611 | if len(m.Subject) > 0 { 612 | data[i] = 0x12 613 | i++ 614 | i = encodeVarintProtocol(data, i, uint64(len(m.Subject))) 615 | i += copy(data[i:], m.Subject) 616 | } 617 | if len(m.Inbox) > 0 { 618 | data[i] = 0x1a 619 | i++ 620 | i = encodeVarintProtocol(data, i, uint64(len(m.Inbox))) 621 | i += copy(data[i:], m.Inbox) 622 | } 623 | if len(m.DurableName) > 0 { 624 | data[i] = 0x22 625 | i++ 626 | i = encodeVarintProtocol(data, i, uint64(len(m.DurableName))) 627 | i += copy(data[i:], m.DurableName) 628 | } 629 | return i, nil 630 | } 631 | 632 | func (m *CloseRequest) Marshal() (data []byte, err error) { 633 | size := m.Size() 634 | data = make([]byte, size) 635 | n, err := m.MarshalTo(data) 636 | if err != nil { 637 | return nil, err 638 | } 639 | return data[:n], nil 640 | } 641 | 642 | func (m *CloseRequest) MarshalTo(data []byte) (int, error) { 643 | var i int 644 | _ = i 645 | var l int 646 | _ = l 647 | if len(m.ClientID) > 0 { 648 | data[i] = 0xa 649 | i++ 650 | i = encodeVarintProtocol(data, i, uint64(len(m.ClientID))) 651 | i += copy(data[i:], m.ClientID) 652 | } 653 | return i, nil 654 | } 655 | 656 | func (m *CloseResponse) Marshal() (data []byte, err error) { 657 | size := m.Size() 658 | data = make([]byte, size) 659 | n, err := m.MarshalTo(data) 660 | if err != nil { 661 | return nil, err 662 | } 663 | return data[:n], nil 664 | } 665 | 666 | func (m *CloseResponse) MarshalTo(data []byte) (int, error) { 667 | var i int 668 | _ = i 669 | var l int 670 | _ = l 671 | if len(m.Error) > 0 { 672 | data[i] = 0xa 673 | i++ 674 | i = encodeVarintProtocol(data, i, uint64(len(m.Error))) 675 | i += copy(data[i:], m.Error) 676 | } 677 | return i, nil 678 | } 679 | 680 | func encodeFixed64Protocol(data []byte, offset int, v uint64) int { 681 | data[offset] = uint8(v) 682 | data[offset+1] = uint8(v >> 8) 683 | data[offset+2] = uint8(v >> 16) 684 | data[offset+3] = uint8(v >> 24) 685 | data[offset+4] = uint8(v >> 32) 686 | data[offset+5] = uint8(v >> 40) 687 | data[offset+6] = uint8(v >> 48) 688 | data[offset+7] = uint8(v >> 56) 689 | return offset + 8 690 | } 691 | func encodeFixed32Protocol(data []byte, offset int, v uint32) int { 692 | data[offset] = uint8(v) 693 | data[offset+1] = uint8(v >> 8) 694 | data[offset+2] = uint8(v >> 16) 695 | data[offset+3] = uint8(v >> 24) 696 | return offset + 4 697 | } 698 | func encodeVarintProtocol(data []byte, offset int, v uint64) int { 699 | for v >= 1<<7 { 700 | data[offset] = uint8(v&0x7f | 0x80) 701 | v >>= 7 702 | offset++ 703 | } 704 | data[offset] = uint8(v) 705 | return offset + 1 706 | } 707 | func (m *PubMsg) Size() (n int) { 708 | var l int 709 | _ = l 710 | l = len(m.ClientID) 711 | if l > 0 { 712 | n += 1 + l + sovProtocol(uint64(l)) 713 | } 714 | l = len(m.Guid) 715 | if l > 0 { 716 | n += 1 + l + sovProtocol(uint64(l)) 717 | } 718 | l = len(m.Subject) 719 | if l > 0 { 720 | n += 1 + l + sovProtocol(uint64(l)) 721 | } 722 | l = len(m.Reply) 723 | if l > 0 { 724 | n += 1 + l + sovProtocol(uint64(l)) 725 | } 726 | if m.Data != nil { 727 | l = len(m.Data) 728 | if l > 0 { 729 | n += 1 + l + sovProtocol(uint64(l)) 730 | } 731 | } 732 | if m.Sha256 != nil { 733 | l = len(m.Sha256) 734 | if l > 0 { 735 | n += 1 + l + sovProtocol(uint64(l)) 736 | } 737 | } 738 | return n 739 | } 740 | 741 | func (m *PubAck) Size() (n int) { 742 | var l int 743 | _ = l 744 | l = len(m.Guid) 745 | if l > 0 { 746 | n += 1 + l + sovProtocol(uint64(l)) 747 | } 748 | l = len(m.Error) 749 | if l > 0 { 750 | n += 1 + l + sovProtocol(uint64(l)) 751 | } 752 | return n 753 | } 754 | 755 | func (m *MsgProto) Size() (n int) { 756 | var l int 757 | _ = l 758 | if m.Sequence != 0 { 759 | n += 1 + sovProtocol(uint64(m.Sequence)) 760 | } 761 | l = len(m.Subject) 762 | if l > 0 { 763 | n += 1 + l + sovProtocol(uint64(l)) 764 | } 765 | l = len(m.Reply) 766 | if l > 0 { 767 | n += 1 + l + sovProtocol(uint64(l)) 768 | } 769 | if m.Data != nil { 770 | l = len(m.Data) 771 | if l > 0 { 772 | n += 1 + l + sovProtocol(uint64(l)) 773 | } 774 | } 775 | if m.Timestamp != 0 { 776 | n += 1 + sovProtocol(uint64(m.Timestamp)) 777 | } 778 | if m.Redelivered { 779 | n += 2 780 | } 781 | if m.CRC32 != 0 { 782 | n += 1 + sovProtocol(uint64(m.CRC32)) 783 | } 784 | return n 785 | } 786 | 787 | func (m *Ack) Size() (n int) { 788 | var l int 789 | _ = l 790 | l = len(m.Subject) 791 | if l > 0 { 792 | n += 1 + l + sovProtocol(uint64(l)) 793 | } 794 | if m.Sequence != 0 { 795 | n += 1 + sovProtocol(uint64(m.Sequence)) 796 | } 797 | return n 798 | } 799 | 800 | func (m *ConnectRequest) Size() (n int) { 801 | var l int 802 | _ = l 803 | l = len(m.ClientID) 804 | if l > 0 { 805 | n += 1 + l + sovProtocol(uint64(l)) 806 | } 807 | l = len(m.HeartbeatInbox) 808 | if l > 0 { 809 | n += 1 + l + sovProtocol(uint64(l)) 810 | } 811 | return n 812 | } 813 | 814 | func (m *ConnectResponse) Size() (n int) { 815 | var l int 816 | _ = l 817 | l = len(m.PubPrefix) 818 | if l > 0 { 819 | n += 1 + l + sovProtocol(uint64(l)) 820 | } 821 | l = len(m.SubRequests) 822 | if l > 0 { 823 | n += 1 + l + sovProtocol(uint64(l)) 824 | } 825 | l = len(m.UnsubRequests) 826 | if l > 0 { 827 | n += 1 + l + sovProtocol(uint64(l)) 828 | } 829 | l = len(m.CloseRequests) 830 | if l > 0 { 831 | n += 1 + l + sovProtocol(uint64(l)) 832 | } 833 | l = len(m.Error) 834 | if l > 0 { 835 | n += 1 + l + sovProtocol(uint64(l)) 836 | } 837 | l = len(m.SubCloseRequests) 838 | if l > 0 { 839 | n += 1 + l + sovProtocol(uint64(l)) 840 | } 841 | l = len(m.PublicKey) 842 | if l > 0 { 843 | n += 2 + l + sovProtocol(uint64(l)) 844 | } 845 | return n 846 | } 847 | 848 | func (m *SubscriptionRequest) Size() (n int) { 849 | var l int 850 | _ = l 851 | l = len(m.ClientID) 852 | if l > 0 { 853 | n += 1 + l + sovProtocol(uint64(l)) 854 | } 855 | l = len(m.Subject) 856 | if l > 0 { 857 | n += 1 + l + sovProtocol(uint64(l)) 858 | } 859 | l = len(m.QGroup) 860 | if l > 0 { 861 | n += 1 + l + sovProtocol(uint64(l)) 862 | } 863 | l = len(m.Inbox) 864 | if l > 0 { 865 | n += 1 + l + sovProtocol(uint64(l)) 866 | } 867 | if m.MaxInFlight != 0 { 868 | n += 1 + sovProtocol(uint64(m.MaxInFlight)) 869 | } 870 | if m.AckWaitInSecs != 0 { 871 | n += 1 + sovProtocol(uint64(m.AckWaitInSecs)) 872 | } 873 | l = len(m.DurableName) 874 | if l > 0 { 875 | n += 1 + l + sovProtocol(uint64(l)) 876 | } 877 | if m.StartPosition != 0 { 878 | n += 1 + sovProtocol(uint64(m.StartPosition)) 879 | } 880 | if m.StartSequence != 0 { 881 | n += 1 + sovProtocol(uint64(m.StartSequence)) 882 | } 883 | if m.StartTimeDelta != 0 { 884 | n += 1 + sovProtocol(uint64(m.StartTimeDelta)) 885 | } 886 | return n 887 | } 888 | 889 | func (m *SubscriptionResponse) Size() (n int) { 890 | var l int 891 | _ = l 892 | l = len(m.AckInbox) 893 | if l > 0 { 894 | n += 1 + l + sovProtocol(uint64(l)) 895 | } 896 | l = len(m.Error) 897 | if l > 0 { 898 | n += 1 + l + sovProtocol(uint64(l)) 899 | } 900 | return n 901 | } 902 | 903 | func (m *UnsubscribeRequest) Size() (n int) { 904 | var l int 905 | _ = l 906 | l = len(m.ClientID) 907 | if l > 0 { 908 | n += 1 + l + sovProtocol(uint64(l)) 909 | } 910 | l = len(m.Subject) 911 | if l > 0 { 912 | n += 1 + l + sovProtocol(uint64(l)) 913 | } 914 | l = len(m.Inbox) 915 | if l > 0 { 916 | n += 1 + l + sovProtocol(uint64(l)) 917 | } 918 | l = len(m.DurableName) 919 | if l > 0 { 920 | n += 1 + l + sovProtocol(uint64(l)) 921 | } 922 | return n 923 | } 924 | 925 | func (m *CloseRequest) Size() (n int) { 926 | var l int 927 | _ = l 928 | l = len(m.ClientID) 929 | if l > 0 { 930 | n += 1 + l + sovProtocol(uint64(l)) 931 | } 932 | return n 933 | } 934 | 935 | func (m *CloseResponse) Size() (n int) { 936 | var l int 937 | _ = l 938 | l = len(m.Error) 939 | if l > 0 { 940 | n += 1 + l + sovProtocol(uint64(l)) 941 | } 942 | return n 943 | } 944 | 945 | func sovProtocol(x uint64) (n int) { 946 | for { 947 | n++ 948 | x >>= 7 949 | if x == 0 { 950 | break 951 | } 952 | } 953 | return n 954 | } 955 | func sozProtocol(x uint64) (n int) { 956 | return sovProtocol(uint64((x << 1) ^ uint64((int64(x) >> 63)))) 957 | } 958 | func (m *PubMsg) Unmarshal(data []byte) error { 959 | l := len(data) 960 | iNdEx := 0 961 | for iNdEx < l { 962 | preIndex := iNdEx 963 | var wire uint64 964 | for shift := uint(0); ; shift += 7 { 965 | if shift >= 64 { 966 | return ErrIntOverflowProtocol 967 | } 968 | if iNdEx >= l { 969 | return io.ErrUnexpectedEOF 970 | } 971 | b := data[iNdEx] 972 | iNdEx++ 973 | wire |= (uint64(b) & 0x7F) << shift 974 | if b < 0x80 { 975 | break 976 | } 977 | } 978 | fieldNum := int32(wire >> 3) 979 | wireType := int(wire & 0x7) 980 | if wireType == 4 { 981 | return fmt.Errorf("proto: PubMsg: wiretype end group for non-group") 982 | } 983 | if fieldNum <= 0 { 984 | return fmt.Errorf("proto: PubMsg: illegal tag %d (wire type %d)", fieldNum, wire) 985 | } 986 | switch fieldNum { 987 | case 1: 988 | if wireType != 2 { 989 | return fmt.Errorf("proto: wrong wireType = %d for field ClientID", wireType) 990 | } 991 | var stringLen uint64 992 | for shift := uint(0); ; shift += 7 { 993 | if shift >= 64 { 994 | return ErrIntOverflowProtocol 995 | } 996 | if iNdEx >= l { 997 | return io.ErrUnexpectedEOF 998 | } 999 | b := data[iNdEx] 1000 | iNdEx++ 1001 | stringLen |= (uint64(b) & 0x7F) << shift 1002 | if b < 0x80 { 1003 | break 1004 | } 1005 | } 1006 | intStringLen := int(stringLen) 1007 | if intStringLen < 0 { 1008 | return ErrInvalidLengthProtocol 1009 | } 1010 | postIndex := iNdEx + intStringLen 1011 | if postIndex > l { 1012 | return io.ErrUnexpectedEOF 1013 | } 1014 | m.ClientID = string(data[iNdEx:postIndex]) 1015 | iNdEx = postIndex 1016 | case 2: 1017 | if wireType != 2 { 1018 | return fmt.Errorf("proto: wrong wireType = %d for field Guid", wireType) 1019 | } 1020 | var stringLen uint64 1021 | for shift := uint(0); ; shift += 7 { 1022 | if shift >= 64 { 1023 | return ErrIntOverflowProtocol 1024 | } 1025 | if iNdEx >= l { 1026 | return io.ErrUnexpectedEOF 1027 | } 1028 | b := data[iNdEx] 1029 | iNdEx++ 1030 | stringLen |= (uint64(b) & 0x7F) << shift 1031 | if b < 0x80 { 1032 | break 1033 | } 1034 | } 1035 | intStringLen := int(stringLen) 1036 | if intStringLen < 0 { 1037 | return ErrInvalidLengthProtocol 1038 | } 1039 | postIndex := iNdEx + intStringLen 1040 | if postIndex > l { 1041 | return io.ErrUnexpectedEOF 1042 | } 1043 | m.Guid = string(data[iNdEx:postIndex]) 1044 | iNdEx = postIndex 1045 | case 3: 1046 | if wireType != 2 { 1047 | return fmt.Errorf("proto: wrong wireType = %d for field Subject", wireType) 1048 | } 1049 | var stringLen uint64 1050 | for shift := uint(0); ; shift += 7 { 1051 | if shift >= 64 { 1052 | return ErrIntOverflowProtocol 1053 | } 1054 | if iNdEx >= l { 1055 | return io.ErrUnexpectedEOF 1056 | } 1057 | b := data[iNdEx] 1058 | iNdEx++ 1059 | stringLen |= (uint64(b) & 0x7F) << shift 1060 | if b < 0x80 { 1061 | break 1062 | } 1063 | } 1064 | intStringLen := int(stringLen) 1065 | if intStringLen < 0 { 1066 | return ErrInvalidLengthProtocol 1067 | } 1068 | postIndex := iNdEx + intStringLen 1069 | if postIndex > l { 1070 | return io.ErrUnexpectedEOF 1071 | } 1072 | m.Subject = string(data[iNdEx:postIndex]) 1073 | iNdEx = postIndex 1074 | case 4: 1075 | if wireType != 2 { 1076 | return fmt.Errorf("proto: wrong wireType = %d for field Reply", wireType) 1077 | } 1078 | var stringLen uint64 1079 | for shift := uint(0); ; shift += 7 { 1080 | if shift >= 64 { 1081 | return ErrIntOverflowProtocol 1082 | } 1083 | if iNdEx >= l { 1084 | return io.ErrUnexpectedEOF 1085 | } 1086 | b := data[iNdEx] 1087 | iNdEx++ 1088 | stringLen |= (uint64(b) & 0x7F) << shift 1089 | if b < 0x80 { 1090 | break 1091 | } 1092 | } 1093 | intStringLen := int(stringLen) 1094 | if intStringLen < 0 { 1095 | return ErrInvalidLengthProtocol 1096 | } 1097 | postIndex := iNdEx + intStringLen 1098 | if postIndex > l { 1099 | return io.ErrUnexpectedEOF 1100 | } 1101 | m.Reply = string(data[iNdEx:postIndex]) 1102 | iNdEx = postIndex 1103 | case 5: 1104 | if wireType != 2 { 1105 | return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) 1106 | } 1107 | var byteLen int 1108 | for shift := uint(0); ; shift += 7 { 1109 | if shift >= 64 { 1110 | return ErrIntOverflowProtocol 1111 | } 1112 | if iNdEx >= l { 1113 | return io.ErrUnexpectedEOF 1114 | } 1115 | b := data[iNdEx] 1116 | iNdEx++ 1117 | byteLen |= (int(b) & 0x7F) << shift 1118 | if b < 0x80 { 1119 | break 1120 | } 1121 | } 1122 | if byteLen < 0 { 1123 | return ErrInvalidLengthProtocol 1124 | } 1125 | postIndex := iNdEx + byteLen 1126 | if postIndex > l { 1127 | return io.ErrUnexpectedEOF 1128 | } 1129 | m.Data = append(m.Data[:0], data[iNdEx:postIndex]...) 1130 | if m.Data == nil { 1131 | m.Data = []byte{} 1132 | } 1133 | iNdEx = postIndex 1134 | case 10: 1135 | if wireType != 2 { 1136 | return fmt.Errorf("proto: wrong wireType = %d for field Sha256", wireType) 1137 | } 1138 | var byteLen int 1139 | for shift := uint(0); ; shift += 7 { 1140 | if shift >= 64 { 1141 | return ErrIntOverflowProtocol 1142 | } 1143 | if iNdEx >= l { 1144 | return io.ErrUnexpectedEOF 1145 | } 1146 | b := data[iNdEx] 1147 | iNdEx++ 1148 | byteLen |= (int(b) & 0x7F) << shift 1149 | if b < 0x80 { 1150 | break 1151 | } 1152 | } 1153 | if byteLen < 0 { 1154 | return ErrInvalidLengthProtocol 1155 | } 1156 | postIndex := iNdEx + byteLen 1157 | if postIndex > l { 1158 | return io.ErrUnexpectedEOF 1159 | } 1160 | m.Sha256 = append(m.Sha256[:0], data[iNdEx:postIndex]...) 1161 | if m.Sha256 == nil { 1162 | m.Sha256 = []byte{} 1163 | } 1164 | iNdEx = postIndex 1165 | default: 1166 | iNdEx = preIndex 1167 | skippy, err := skipProtocol(data[iNdEx:]) 1168 | if err != nil { 1169 | return err 1170 | } 1171 | if skippy < 0 { 1172 | return ErrInvalidLengthProtocol 1173 | } 1174 | if (iNdEx + skippy) > l { 1175 | return io.ErrUnexpectedEOF 1176 | } 1177 | iNdEx += skippy 1178 | } 1179 | } 1180 | 1181 | if iNdEx > l { 1182 | return io.ErrUnexpectedEOF 1183 | } 1184 | return nil 1185 | } 1186 | func (m *PubAck) Unmarshal(data []byte) error { 1187 | l := len(data) 1188 | iNdEx := 0 1189 | for iNdEx < l { 1190 | preIndex := iNdEx 1191 | var wire uint64 1192 | for shift := uint(0); ; shift += 7 { 1193 | if shift >= 64 { 1194 | return ErrIntOverflowProtocol 1195 | } 1196 | if iNdEx >= l { 1197 | return io.ErrUnexpectedEOF 1198 | } 1199 | b := data[iNdEx] 1200 | iNdEx++ 1201 | wire |= (uint64(b) & 0x7F) << shift 1202 | if b < 0x80 { 1203 | break 1204 | } 1205 | } 1206 | fieldNum := int32(wire >> 3) 1207 | wireType := int(wire & 0x7) 1208 | if wireType == 4 { 1209 | return fmt.Errorf("proto: PubAck: wiretype end group for non-group") 1210 | } 1211 | if fieldNum <= 0 { 1212 | return fmt.Errorf("proto: PubAck: illegal tag %d (wire type %d)", fieldNum, wire) 1213 | } 1214 | switch fieldNum { 1215 | case 1: 1216 | if wireType != 2 { 1217 | return fmt.Errorf("proto: wrong wireType = %d for field Guid", wireType) 1218 | } 1219 | var stringLen uint64 1220 | for shift := uint(0); ; shift += 7 { 1221 | if shift >= 64 { 1222 | return ErrIntOverflowProtocol 1223 | } 1224 | if iNdEx >= l { 1225 | return io.ErrUnexpectedEOF 1226 | } 1227 | b := data[iNdEx] 1228 | iNdEx++ 1229 | stringLen |= (uint64(b) & 0x7F) << shift 1230 | if b < 0x80 { 1231 | break 1232 | } 1233 | } 1234 | intStringLen := int(stringLen) 1235 | if intStringLen < 0 { 1236 | return ErrInvalidLengthProtocol 1237 | } 1238 | postIndex := iNdEx + intStringLen 1239 | if postIndex > l { 1240 | return io.ErrUnexpectedEOF 1241 | } 1242 | m.Guid = string(data[iNdEx:postIndex]) 1243 | iNdEx = postIndex 1244 | case 2: 1245 | if wireType != 2 { 1246 | return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) 1247 | } 1248 | var stringLen uint64 1249 | for shift := uint(0); ; shift += 7 { 1250 | if shift >= 64 { 1251 | return ErrIntOverflowProtocol 1252 | } 1253 | if iNdEx >= l { 1254 | return io.ErrUnexpectedEOF 1255 | } 1256 | b := data[iNdEx] 1257 | iNdEx++ 1258 | stringLen |= (uint64(b) & 0x7F) << shift 1259 | if b < 0x80 { 1260 | break 1261 | } 1262 | } 1263 | intStringLen := int(stringLen) 1264 | if intStringLen < 0 { 1265 | return ErrInvalidLengthProtocol 1266 | } 1267 | postIndex := iNdEx + intStringLen 1268 | if postIndex > l { 1269 | return io.ErrUnexpectedEOF 1270 | } 1271 | m.Error = string(data[iNdEx:postIndex]) 1272 | iNdEx = postIndex 1273 | default: 1274 | iNdEx = preIndex 1275 | skippy, err := skipProtocol(data[iNdEx:]) 1276 | if err != nil { 1277 | return err 1278 | } 1279 | if skippy < 0 { 1280 | return ErrInvalidLengthProtocol 1281 | } 1282 | if (iNdEx + skippy) > l { 1283 | return io.ErrUnexpectedEOF 1284 | } 1285 | iNdEx += skippy 1286 | } 1287 | } 1288 | 1289 | if iNdEx > l { 1290 | return io.ErrUnexpectedEOF 1291 | } 1292 | return nil 1293 | } 1294 | func (m *MsgProto) Unmarshal(data []byte) error { 1295 | l := len(data) 1296 | iNdEx := 0 1297 | for iNdEx < l { 1298 | preIndex := iNdEx 1299 | var wire uint64 1300 | for shift := uint(0); ; shift += 7 { 1301 | if shift >= 64 { 1302 | return ErrIntOverflowProtocol 1303 | } 1304 | if iNdEx >= l { 1305 | return io.ErrUnexpectedEOF 1306 | } 1307 | b := data[iNdEx] 1308 | iNdEx++ 1309 | wire |= (uint64(b) & 0x7F) << shift 1310 | if b < 0x80 { 1311 | break 1312 | } 1313 | } 1314 | fieldNum := int32(wire >> 3) 1315 | wireType := int(wire & 0x7) 1316 | if wireType == 4 { 1317 | return fmt.Errorf("proto: MsgProto: wiretype end group for non-group") 1318 | } 1319 | if fieldNum <= 0 { 1320 | return fmt.Errorf("proto: MsgProto: illegal tag %d (wire type %d)", fieldNum, wire) 1321 | } 1322 | switch fieldNum { 1323 | case 1: 1324 | if wireType != 0 { 1325 | return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) 1326 | } 1327 | m.Sequence = 0 1328 | for shift := uint(0); ; shift += 7 { 1329 | if shift >= 64 { 1330 | return ErrIntOverflowProtocol 1331 | } 1332 | if iNdEx >= l { 1333 | return io.ErrUnexpectedEOF 1334 | } 1335 | b := data[iNdEx] 1336 | iNdEx++ 1337 | m.Sequence |= (uint64(b) & 0x7F) << shift 1338 | if b < 0x80 { 1339 | break 1340 | } 1341 | } 1342 | case 2: 1343 | if wireType != 2 { 1344 | return fmt.Errorf("proto: wrong wireType = %d for field Subject", wireType) 1345 | } 1346 | var stringLen uint64 1347 | for shift := uint(0); ; shift += 7 { 1348 | if shift >= 64 { 1349 | return ErrIntOverflowProtocol 1350 | } 1351 | if iNdEx >= l { 1352 | return io.ErrUnexpectedEOF 1353 | } 1354 | b := data[iNdEx] 1355 | iNdEx++ 1356 | stringLen |= (uint64(b) & 0x7F) << shift 1357 | if b < 0x80 { 1358 | break 1359 | } 1360 | } 1361 | intStringLen := int(stringLen) 1362 | if intStringLen < 0 { 1363 | return ErrInvalidLengthProtocol 1364 | } 1365 | postIndex := iNdEx + intStringLen 1366 | if postIndex > l { 1367 | return io.ErrUnexpectedEOF 1368 | } 1369 | m.Subject = string(data[iNdEx:postIndex]) 1370 | iNdEx = postIndex 1371 | case 3: 1372 | if wireType != 2 { 1373 | return fmt.Errorf("proto: wrong wireType = %d for field Reply", wireType) 1374 | } 1375 | var stringLen uint64 1376 | for shift := uint(0); ; shift += 7 { 1377 | if shift >= 64 { 1378 | return ErrIntOverflowProtocol 1379 | } 1380 | if iNdEx >= l { 1381 | return io.ErrUnexpectedEOF 1382 | } 1383 | b := data[iNdEx] 1384 | iNdEx++ 1385 | stringLen |= (uint64(b) & 0x7F) << shift 1386 | if b < 0x80 { 1387 | break 1388 | } 1389 | } 1390 | intStringLen := int(stringLen) 1391 | if intStringLen < 0 { 1392 | return ErrInvalidLengthProtocol 1393 | } 1394 | postIndex := iNdEx + intStringLen 1395 | if postIndex > l { 1396 | return io.ErrUnexpectedEOF 1397 | } 1398 | m.Reply = string(data[iNdEx:postIndex]) 1399 | iNdEx = postIndex 1400 | case 4: 1401 | if wireType != 2 { 1402 | return fmt.Errorf("proto: wrong wireType = %d for field Data", wireType) 1403 | } 1404 | var byteLen int 1405 | for shift := uint(0); ; shift += 7 { 1406 | if shift >= 64 { 1407 | return ErrIntOverflowProtocol 1408 | } 1409 | if iNdEx >= l { 1410 | return io.ErrUnexpectedEOF 1411 | } 1412 | b := data[iNdEx] 1413 | iNdEx++ 1414 | byteLen |= (int(b) & 0x7F) << shift 1415 | if b < 0x80 { 1416 | break 1417 | } 1418 | } 1419 | if byteLen < 0 { 1420 | return ErrInvalidLengthProtocol 1421 | } 1422 | postIndex := iNdEx + byteLen 1423 | if postIndex > l { 1424 | return io.ErrUnexpectedEOF 1425 | } 1426 | m.Data = append(m.Data[:0], data[iNdEx:postIndex]...) 1427 | if m.Data == nil { 1428 | m.Data = []byte{} 1429 | } 1430 | iNdEx = postIndex 1431 | case 5: 1432 | if wireType != 0 { 1433 | return fmt.Errorf("proto: wrong wireType = %d for field Timestamp", wireType) 1434 | } 1435 | m.Timestamp = 0 1436 | for shift := uint(0); ; shift += 7 { 1437 | if shift >= 64 { 1438 | return ErrIntOverflowProtocol 1439 | } 1440 | if iNdEx >= l { 1441 | return io.ErrUnexpectedEOF 1442 | } 1443 | b := data[iNdEx] 1444 | iNdEx++ 1445 | m.Timestamp |= (int64(b) & 0x7F) << shift 1446 | if b < 0x80 { 1447 | break 1448 | } 1449 | } 1450 | case 6: 1451 | if wireType != 0 { 1452 | return fmt.Errorf("proto: wrong wireType = %d for field Redelivered", wireType) 1453 | } 1454 | var v int 1455 | for shift := uint(0); ; shift += 7 { 1456 | if shift >= 64 { 1457 | return ErrIntOverflowProtocol 1458 | } 1459 | if iNdEx >= l { 1460 | return io.ErrUnexpectedEOF 1461 | } 1462 | b := data[iNdEx] 1463 | iNdEx++ 1464 | v |= (int(b) & 0x7F) << shift 1465 | if b < 0x80 { 1466 | break 1467 | } 1468 | } 1469 | m.Redelivered = bool(v != 0) 1470 | case 10: 1471 | if wireType != 0 { 1472 | return fmt.Errorf("proto: wrong wireType = %d for field CRC32", wireType) 1473 | } 1474 | m.CRC32 = 0 1475 | for shift := uint(0); ; shift += 7 { 1476 | if shift >= 64 { 1477 | return ErrIntOverflowProtocol 1478 | } 1479 | if iNdEx >= l { 1480 | return io.ErrUnexpectedEOF 1481 | } 1482 | b := data[iNdEx] 1483 | iNdEx++ 1484 | m.CRC32 |= (uint32(b) & 0x7F) << shift 1485 | if b < 0x80 { 1486 | break 1487 | } 1488 | } 1489 | default: 1490 | iNdEx = preIndex 1491 | skippy, err := skipProtocol(data[iNdEx:]) 1492 | if err != nil { 1493 | return err 1494 | } 1495 | if skippy < 0 { 1496 | return ErrInvalidLengthProtocol 1497 | } 1498 | if (iNdEx + skippy) > l { 1499 | return io.ErrUnexpectedEOF 1500 | } 1501 | iNdEx += skippy 1502 | } 1503 | } 1504 | 1505 | if iNdEx > l { 1506 | return io.ErrUnexpectedEOF 1507 | } 1508 | return nil 1509 | } 1510 | func (m *Ack) Unmarshal(data []byte) error { 1511 | l := len(data) 1512 | iNdEx := 0 1513 | for iNdEx < l { 1514 | preIndex := iNdEx 1515 | var wire uint64 1516 | for shift := uint(0); ; shift += 7 { 1517 | if shift >= 64 { 1518 | return ErrIntOverflowProtocol 1519 | } 1520 | if iNdEx >= l { 1521 | return io.ErrUnexpectedEOF 1522 | } 1523 | b := data[iNdEx] 1524 | iNdEx++ 1525 | wire |= (uint64(b) & 0x7F) << shift 1526 | if b < 0x80 { 1527 | break 1528 | } 1529 | } 1530 | fieldNum := int32(wire >> 3) 1531 | wireType := int(wire & 0x7) 1532 | if wireType == 4 { 1533 | return fmt.Errorf("proto: Ack: wiretype end group for non-group") 1534 | } 1535 | if fieldNum <= 0 { 1536 | return fmt.Errorf("proto: Ack: illegal tag %d (wire type %d)", fieldNum, wire) 1537 | } 1538 | switch fieldNum { 1539 | case 1: 1540 | if wireType != 2 { 1541 | return fmt.Errorf("proto: wrong wireType = %d for field Subject", wireType) 1542 | } 1543 | var stringLen uint64 1544 | for shift := uint(0); ; shift += 7 { 1545 | if shift >= 64 { 1546 | return ErrIntOverflowProtocol 1547 | } 1548 | if iNdEx >= l { 1549 | return io.ErrUnexpectedEOF 1550 | } 1551 | b := data[iNdEx] 1552 | iNdEx++ 1553 | stringLen |= (uint64(b) & 0x7F) << shift 1554 | if b < 0x80 { 1555 | break 1556 | } 1557 | } 1558 | intStringLen := int(stringLen) 1559 | if intStringLen < 0 { 1560 | return ErrInvalidLengthProtocol 1561 | } 1562 | postIndex := iNdEx + intStringLen 1563 | if postIndex > l { 1564 | return io.ErrUnexpectedEOF 1565 | } 1566 | m.Subject = string(data[iNdEx:postIndex]) 1567 | iNdEx = postIndex 1568 | case 2: 1569 | if wireType != 0 { 1570 | return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType) 1571 | } 1572 | m.Sequence = 0 1573 | for shift := uint(0); ; shift += 7 { 1574 | if shift >= 64 { 1575 | return ErrIntOverflowProtocol 1576 | } 1577 | if iNdEx >= l { 1578 | return io.ErrUnexpectedEOF 1579 | } 1580 | b := data[iNdEx] 1581 | iNdEx++ 1582 | m.Sequence |= (uint64(b) & 0x7F) << shift 1583 | if b < 0x80 { 1584 | break 1585 | } 1586 | } 1587 | default: 1588 | iNdEx = preIndex 1589 | skippy, err := skipProtocol(data[iNdEx:]) 1590 | if err != nil { 1591 | return err 1592 | } 1593 | if skippy < 0 { 1594 | return ErrInvalidLengthProtocol 1595 | } 1596 | if (iNdEx + skippy) > l { 1597 | return io.ErrUnexpectedEOF 1598 | } 1599 | iNdEx += skippy 1600 | } 1601 | } 1602 | 1603 | if iNdEx > l { 1604 | return io.ErrUnexpectedEOF 1605 | } 1606 | return nil 1607 | } 1608 | func (m *ConnectRequest) Unmarshal(data []byte) error { 1609 | l := len(data) 1610 | iNdEx := 0 1611 | for iNdEx < l { 1612 | preIndex := iNdEx 1613 | var wire uint64 1614 | for shift := uint(0); ; shift += 7 { 1615 | if shift >= 64 { 1616 | return ErrIntOverflowProtocol 1617 | } 1618 | if iNdEx >= l { 1619 | return io.ErrUnexpectedEOF 1620 | } 1621 | b := data[iNdEx] 1622 | iNdEx++ 1623 | wire |= (uint64(b) & 0x7F) << shift 1624 | if b < 0x80 { 1625 | break 1626 | } 1627 | } 1628 | fieldNum := int32(wire >> 3) 1629 | wireType := int(wire & 0x7) 1630 | if wireType == 4 { 1631 | return fmt.Errorf("proto: ConnectRequest: wiretype end group for non-group") 1632 | } 1633 | if fieldNum <= 0 { 1634 | return fmt.Errorf("proto: ConnectRequest: illegal tag %d (wire type %d)", fieldNum, wire) 1635 | } 1636 | switch fieldNum { 1637 | case 1: 1638 | if wireType != 2 { 1639 | return fmt.Errorf("proto: wrong wireType = %d for field ClientID", wireType) 1640 | } 1641 | var stringLen uint64 1642 | for shift := uint(0); ; shift += 7 { 1643 | if shift >= 64 { 1644 | return ErrIntOverflowProtocol 1645 | } 1646 | if iNdEx >= l { 1647 | return io.ErrUnexpectedEOF 1648 | } 1649 | b := data[iNdEx] 1650 | iNdEx++ 1651 | stringLen |= (uint64(b) & 0x7F) << shift 1652 | if b < 0x80 { 1653 | break 1654 | } 1655 | } 1656 | intStringLen := int(stringLen) 1657 | if intStringLen < 0 { 1658 | return ErrInvalidLengthProtocol 1659 | } 1660 | postIndex := iNdEx + intStringLen 1661 | if postIndex > l { 1662 | return io.ErrUnexpectedEOF 1663 | } 1664 | m.ClientID = string(data[iNdEx:postIndex]) 1665 | iNdEx = postIndex 1666 | case 2: 1667 | if wireType != 2 { 1668 | return fmt.Errorf("proto: wrong wireType = %d for field HeartbeatInbox", wireType) 1669 | } 1670 | var stringLen uint64 1671 | for shift := uint(0); ; shift += 7 { 1672 | if shift >= 64 { 1673 | return ErrIntOverflowProtocol 1674 | } 1675 | if iNdEx >= l { 1676 | return io.ErrUnexpectedEOF 1677 | } 1678 | b := data[iNdEx] 1679 | iNdEx++ 1680 | stringLen |= (uint64(b) & 0x7F) << shift 1681 | if b < 0x80 { 1682 | break 1683 | } 1684 | } 1685 | intStringLen := int(stringLen) 1686 | if intStringLen < 0 { 1687 | return ErrInvalidLengthProtocol 1688 | } 1689 | postIndex := iNdEx + intStringLen 1690 | if postIndex > l { 1691 | return io.ErrUnexpectedEOF 1692 | } 1693 | m.HeartbeatInbox = string(data[iNdEx:postIndex]) 1694 | iNdEx = postIndex 1695 | default: 1696 | iNdEx = preIndex 1697 | skippy, err := skipProtocol(data[iNdEx:]) 1698 | if err != nil { 1699 | return err 1700 | } 1701 | if skippy < 0 { 1702 | return ErrInvalidLengthProtocol 1703 | } 1704 | if (iNdEx + skippy) > l { 1705 | return io.ErrUnexpectedEOF 1706 | } 1707 | iNdEx += skippy 1708 | } 1709 | } 1710 | 1711 | if iNdEx > l { 1712 | return io.ErrUnexpectedEOF 1713 | } 1714 | return nil 1715 | } 1716 | func (m *ConnectResponse) Unmarshal(data []byte) error { 1717 | l := len(data) 1718 | iNdEx := 0 1719 | for iNdEx < l { 1720 | preIndex := iNdEx 1721 | var wire uint64 1722 | for shift := uint(0); ; shift += 7 { 1723 | if shift >= 64 { 1724 | return ErrIntOverflowProtocol 1725 | } 1726 | if iNdEx >= l { 1727 | return io.ErrUnexpectedEOF 1728 | } 1729 | b := data[iNdEx] 1730 | iNdEx++ 1731 | wire |= (uint64(b) & 0x7F) << shift 1732 | if b < 0x80 { 1733 | break 1734 | } 1735 | } 1736 | fieldNum := int32(wire >> 3) 1737 | wireType := int(wire & 0x7) 1738 | if wireType == 4 { 1739 | return fmt.Errorf("proto: ConnectResponse: wiretype end group for non-group") 1740 | } 1741 | if fieldNum <= 0 { 1742 | return fmt.Errorf("proto: ConnectResponse: illegal tag %d (wire type %d)", fieldNum, wire) 1743 | } 1744 | switch fieldNum { 1745 | case 1: 1746 | if wireType != 2 { 1747 | return fmt.Errorf("proto: wrong wireType = %d for field PubPrefix", wireType) 1748 | } 1749 | var stringLen uint64 1750 | for shift := uint(0); ; shift += 7 { 1751 | if shift >= 64 { 1752 | return ErrIntOverflowProtocol 1753 | } 1754 | if iNdEx >= l { 1755 | return io.ErrUnexpectedEOF 1756 | } 1757 | b := data[iNdEx] 1758 | iNdEx++ 1759 | stringLen |= (uint64(b) & 0x7F) << shift 1760 | if b < 0x80 { 1761 | break 1762 | } 1763 | } 1764 | intStringLen := int(stringLen) 1765 | if intStringLen < 0 { 1766 | return ErrInvalidLengthProtocol 1767 | } 1768 | postIndex := iNdEx + intStringLen 1769 | if postIndex > l { 1770 | return io.ErrUnexpectedEOF 1771 | } 1772 | m.PubPrefix = string(data[iNdEx:postIndex]) 1773 | iNdEx = postIndex 1774 | case 2: 1775 | if wireType != 2 { 1776 | return fmt.Errorf("proto: wrong wireType = %d for field SubRequests", wireType) 1777 | } 1778 | var stringLen uint64 1779 | for shift := uint(0); ; shift += 7 { 1780 | if shift >= 64 { 1781 | return ErrIntOverflowProtocol 1782 | } 1783 | if iNdEx >= l { 1784 | return io.ErrUnexpectedEOF 1785 | } 1786 | b := data[iNdEx] 1787 | iNdEx++ 1788 | stringLen |= (uint64(b) & 0x7F) << shift 1789 | if b < 0x80 { 1790 | break 1791 | } 1792 | } 1793 | intStringLen := int(stringLen) 1794 | if intStringLen < 0 { 1795 | return ErrInvalidLengthProtocol 1796 | } 1797 | postIndex := iNdEx + intStringLen 1798 | if postIndex > l { 1799 | return io.ErrUnexpectedEOF 1800 | } 1801 | m.SubRequests = string(data[iNdEx:postIndex]) 1802 | iNdEx = postIndex 1803 | case 3: 1804 | if wireType != 2 { 1805 | return fmt.Errorf("proto: wrong wireType = %d for field UnsubRequests", wireType) 1806 | } 1807 | var stringLen uint64 1808 | for shift := uint(0); ; shift += 7 { 1809 | if shift >= 64 { 1810 | return ErrIntOverflowProtocol 1811 | } 1812 | if iNdEx >= l { 1813 | return io.ErrUnexpectedEOF 1814 | } 1815 | b := data[iNdEx] 1816 | iNdEx++ 1817 | stringLen |= (uint64(b) & 0x7F) << shift 1818 | if b < 0x80 { 1819 | break 1820 | } 1821 | } 1822 | intStringLen := int(stringLen) 1823 | if intStringLen < 0 { 1824 | return ErrInvalidLengthProtocol 1825 | } 1826 | postIndex := iNdEx + intStringLen 1827 | if postIndex > l { 1828 | return io.ErrUnexpectedEOF 1829 | } 1830 | m.UnsubRequests = string(data[iNdEx:postIndex]) 1831 | iNdEx = postIndex 1832 | case 4: 1833 | if wireType != 2 { 1834 | return fmt.Errorf("proto: wrong wireType = %d for field CloseRequests", wireType) 1835 | } 1836 | var stringLen uint64 1837 | for shift := uint(0); ; shift += 7 { 1838 | if shift >= 64 { 1839 | return ErrIntOverflowProtocol 1840 | } 1841 | if iNdEx >= l { 1842 | return io.ErrUnexpectedEOF 1843 | } 1844 | b := data[iNdEx] 1845 | iNdEx++ 1846 | stringLen |= (uint64(b) & 0x7F) << shift 1847 | if b < 0x80 { 1848 | break 1849 | } 1850 | } 1851 | intStringLen := int(stringLen) 1852 | if intStringLen < 0 { 1853 | return ErrInvalidLengthProtocol 1854 | } 1855 | postIndex := iNdEx + intStringLen 1856 | if postIndex > l { 1857 | return io.ErrUnexpectedEOF 1858 | } 1859 | m.CloseRequests = string(data[iNdEx:postIndex]) 1860 | iNdEx = postIndex 1861 | case 5: 1862 | if wireType != 2 { 1863 | return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) 1864 | } 1865 | var stringLen uint64 1866 | for shift := uint(0); ; shift += 7 { 1867 | if shift >= 64 { 1868 | return ErrIntOverflowProtocol 1869 | } 1870 | if iNdEx >= l { 1871 | return io.ErrUnexpectedEOF 1872 | } 1873 | b := data[iNdEx] 1874 | iNdEx++ 1875 | stringLen |= (uint64(b) & 0x7F) << shift 1876 | if b < 0x80 { 1877 | break 1878 | } 1879 | } 1880 | intStringLen := int(stringLen) 1881 | if intStringLen < 0 { 1882 | return ErrInvalidLengthProtocol 1883 | } 1884 | postIndex := iNdEx + intStringLen 1885 | if postIndex > l { 1886 | return io.ErrUnexpectedEOF 1887 | } 1888 | m.Error = string(data[iNdEx:postIndex]) 1889 | iNdEx = postIndex 1890 | case 6: 1891 | if wireType != 2 { 1892 | return fmt.Errorf("proto: wrong wireType = %d for field SubCloseRequests", wireType) 1893 | } 1894 | var stringLen uint64 1895 | for shift := uint(0); ; shift += 7 { 1896 | if shift >= 64 { 1897 | return ErrIntOverflowProtocol 1898 | } 1899 | if iNdEx >= l { 1900 | return io.ErrUnexpectedEOF 1901 | } 1902 | b := data[iNdEx] 1903 | iNdEx++ 1904 | stringLen |= (uint64(b) & 0x7F) << shift 1905 | if b < 0x80 { 1906 | break 1907 | } 1908 | } 1909 | intStringLen := int(stringLen) 1910 | if intStringLen < 0 { 1911 | return ErrInvalidLengthProtocol 1912 | } 1913 | postIndex := iNdEx + intStringLen 1914 | if postIndex > l { 1915 | return io.ErrUnexpectedEOF 1916 | } 1917 | m.SubCloseRequests = string(data[iNdEx:postIndex]) 1918 | iNdEx = postIndex 1919 | case 100: 1920 | if wireType != 2 { 1921 | return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType) 1922 | } 1923 | var stringLen uint64 1924 | for shift := uint(0); ; shift += 7 { 1925 | if shift >= 64 { 1926 | return ErrIntOverflowProtocol 1927 | } 1928 | if iNdEx >= l { 1929 | return io.ErrUnexpectedEOF 1930 | } 1931 | b := data[iNdEx] 1932 | iNdEx++ 1933 | stringLen |= (uint64(b) & 0x7F) << shift 1934 | if b < 0x80 { 1935 | break 1936 | } 1937 | } 1938 | intStringLen := int(stringLen) 1939 | if intStringLen < 0 { 1940 | return ErrInvalidLengthProtocol 1941 | } 1942 | postIndex := iNdEx + intStringLen 1943 | if postIndex > l { 1944 | return io.ErrUnexpectedEOF 1945 | } 1946 | m.PublicKey = string(data[iNdEx:postIndex]) 1947 | iNdEx = postIndex 1948 | default: 1949 | iNdEx = preIndex 1950 | skippy, err := skipProtocol(data[iNdEx:]) 1951 | if err != nil { 1952 | return err 1953 | } 1954 | if skippy < 0 { 1955 | return ErrInvalidLengthProtocol 1956 | } 1957 | if (iNdEx + skippy) > l { 1958 | return io.ErrUnexpectedEOF 1959 | } 1960 | iNdEx += skippy 1961 | } 1962 | } 1963 | 1964 | if iNdEx > l { 1965 | return io.ErrUnexpectedEOF 1966 | } 1967 | return nil 1968 | } 1969 | func (m *SubscriptionRequest) Unmarshal(data []byte) error { 1970 | l := len(data) 1971 | iNdEx := 0 1972 | for iNdEx < l { 1973 | preIndex := iNdEx 1974 | var wire uint64 1975 | for shift := uint(0); ; shift += 7 { 1976 | if shift >= 64 { 1977 | return ErrIntOverflowProtocol 1978 | } 1979 | if iNdEx >= l { 1980 | return io.ErrUnexpectedEOF 1981 | } 1982 | b := data[iNdEx] 1983 | iNdEx++ 1984 | wire |= (uint64(b) & 0x7F) << shift 1985 | if b < 0x80 { 1986 | break 1987 | } 1988 | } 1989 | fieldNum := int32(wire >> 3) 1990 | wireType := int(wire & 0x7) 1991 | if wireType == 4 { 1992 | return fmt.Errorf("proto: SubscriptionRequest: wiretype end group for non-group") 1993 | } 1994 | if fieldNum <= 0 { 1995 | return fmt.Errorf("proto: SubscriptionRequest: illegal tag %d (wire type %d)", fieldNum, wire) 1996 | } 1997 | switch fieldNum { 1998 | case 1: 1999 | if wireType != 2 { 2000 | return fmt.Errorf("proto: wrong wireType = %d for field ClientID", wireType) 2001 | } 2002 | var stringLen uint64 2003 | for shift := uint(0); ; shift += 7 { 2004 | if shift >= 64 { 2005 | return ErrIntOverflowProtocol 2006 | } 2007 | if iNdEx >= l { 2008 | return io.ErrUnexpectedEOF 2009 | } 2010 | b := data[iNdEx] 2011 | iNdEx++ 2012 | stringLen |= (uint64(b) & 0x7F) << shift 2013 | if b < 0x80 { 2014 | break 2015 | } 2016 | } 2017 | intStringLen := int(stringLen) 2018 | if intStringLen < 0 { 2019 | return ErrInvalidLengthProtocol 2020 | } 2021 | postIndex := iNdEx + intStringLen 2022 | if postIndex > l { 2023 | return io.ErrUnexpectedEOF 2024 | } 2025 | m.ClientID = string(data[iNdEx:postIndex]) 2026 | iNdEx = postIndex 2027 | case 2: 2028 | if wireType != 2 { 2029 | return fmt.Errorf("proto: wrong wireType = %d for field Subject", wireType) 2030 | } 2031 | var stringLen uint64 2032 | for shift := uint(0); ; shift += 7 { 2033 | if shift >= 64 { 2034 | return ErrIntOverflowProtocol 2035 | } 2036 | if iNdEx >= l { 2037 | return io.ErrUnexpectedEOF 2038 | } 2039 | b := data[iNdEx] 2040 | iNdEx++ 2041 | stringLen |= (uint64(b) & 0x7F) << shift 2042 | if b < 0x80 { 2043 | break 2044 | } 2045 | } 2046 | intStringLen := int(stringLen) 2047 | if intStringLen < 0 { 2048 | return ErrInvalidLengthProtocol 2049 | } 2050 | postIndex := iNdEx + intStringLen 2051 | if postIndex > l { 2052 | return io.ErrUnexpectedEOF 2053 | } 2054 | m.Subject = string(data[iNdEx:postIndex]) 2055 | iNdEx = postIndex 2056 | case 3: 2057 | if wireType != 2 { 2058 | return fmt.Errorf("proto: wrong wireType = %d for field QGroup", wireType) 2059 | } 2060 | var stringLen uint64 2061 | for shift := uint(0); ; shift += 7 { 2062 | if shift >= 64 { 2063 | return ErrIntOverflowProtocol 2064 | } 2065 | if iNdEx >= l { 2066 | return io.ErrUnexpectedEOF 2067 | } 2068 | b := data[iNdEx] 2069 | iNdEx++ 2070 | stringLen |= (uint64(b) & 0x7F) << shift 2071 | if b < 0x80 { 2072 | break 2073 | } 2074 | } 2075 | intStringLen := int(stringLen) 2076 | if intStringLen < 0 { 2077 | return ErrInvalidLengthProtocol 2078 | } 2079 | postIndex := iNdEx + intStringLen 2080 | if postIndex > l { 2081 | return io.ErrUnexpectedEOF 2082 | } 2083 | m.QGroup = string(data[iNdEx:postIndex]) 2084 | iNdEx = postIndex 2085 | case 4: 2086 | if wireType != 2 { 2087 | return fmt.Errorf("proto: wrong wireType = %d for field Inbox", wireType) 2088 | } 2089 | var stringLen uint64 2090 | for shift := uint(0); ; shift += 7 { 2091 | if shift >= 64 { 2092 | return ErrIntOverflowProtocol 2093 | } 2094 | if iNdEx >= l { 2095 | return io.ErrUnexpectedEOF 2096 | } 2097 | b := data[iNdEx] 2098 | iNdEx++ 2099 | stringLen |= (uint64(b) & 0x7F) << shift 2100 | if b < 0x80 { 2101 | break 2102 | } 2103 | } 2104 | intStringLen := int(stringLen) 2105 | if intStringLen < 0 { 2106 | return ErrInvalidLengthProtocol 2107 | } 2108 | postIndex := iNdEx + intStringLen 2109 | if postIndex > l { 2110 | return io.ErrUnexpectedEOF 2111 | } 2112 | m.Inbox = string(data[iNdEx:postIndex]) 2113 | iNdEx = postIndex 2114 | case 5: 2115 | if wireType != 0 { 2116 | return fmt.Errorf("proto: wrong wireType = %d for field MaxInFlight", wireType) 2117 | } 2118 | m.MaxInFlight = 0 2119 | for shift := uint(0); ; shift += 7 { 2120 | if shift >= 64 { 2121 | return ErrIntOverflowProtocol 2122 | } 2123 | if iNdEx >= l { 2124 | return io.ErrUnexpectedEOF 2125 | } 2126 | b := data[iNdEx] 2127 | iNdEx++ 2128 | m.MaxInFlight |= (int32(b) & 0x7F) << shift 2129 | if b < 0x80 { 2130 | break 2131 | } 2132 | } 2133 | case 6: 2134 | if wireType != 0 { 2135 | return fmt.Errorf("proto: wrong wireType = %d for field AckWaitInSecs", wireType) 2136 | } 2137 | m.AckWaitInSecs = 0 2138 | for shift := uint(0); ; shift += 7 { 2139 | if shift >= 64 { 2140 | return ErrIntOverflowProtocol 2141 | } 2142 | if iNdEx >= l { 2143 | return io.ErrUnexpectedEOF 2144 | } 2145 | b := data[iNdEx] 2146 | iNdEx++ 2147 | m.AckWaitInSecs |= (int32(b) & 0x7F) << shift 2148 | if b < 0x80 { 2149 | break 2150 | } 2151 | } 2152 | case 7: 2153 | if wireType != 2 { 2154 | return fmt.Errorf("proto: wrong wireType = %d for field DurableName", wireType) 2155 | } 2156 | var stringLen uint64 2157 | for shift := uint(0); ; shift += 7 { 2158 | if shift >= 64 { 2159 | return ErrIntOverflowProtocol 2160 | } 2161 | if iNdEx >= l { 2162 | return io.ErrUnexpectedEOF 2163 | } 2164 | b := data[iNdEx] 2165 | iNdEx++ 2166 | stringLen |= (uint64(b) & 0x7F) << shift 2167 | if b < 0x80 { 2168 | break 2169 | } 2170 | } 2171 | intStringLen := int(stringLen) 2172 | if intStringLen < 0 { 2173 | return ErrInvalidLengthProtocol 2174 | } 2175 | postIndex := iNdEx + intStringLen 2176 | if postIndex > l { 2177 | return io.ErrUnexpectedEOF 2178 | } 2179 | m.DurableName = string(data[iNdEx:postIndex]) 2180 | iNdEx = postIndex 2181 | case 10: 2182 | if wireType != 0 { 2183 | return fmt.Errorf("proto: wrong wireType = %d for field StartPosition", wireType) 2184 | } 2185 | m.StartPosition = 0 2186 | for shift := uint(0); ; shift += 7 { 2187 | if shift >= 64 { 2188 | return ErrIntOverflowProtocol 2189 | } 2190 | if iNdEx >= l { 2191 | return io.ErrUnexpectedEOF 2192 | } 2193 | b := data[iNdEx] 2194 | iNdEx++ 2195 | m.StartPosition |= (StartPosition(b) & 0x7F) << shift 2196 | if b < 0x80 { 2197 | break 2198 | } 2199 | } 2200 | case 11: 2201 | if wireType != 0 { 2202 | return fmt.Errorf("proto: wrong wireType = %d for field StartSequence", wireType) 2203 | } 2204 | m.StartSequence = 0 2205 | for shift := uint(0); ; shift += 7 { 2206 | if shift >= 64 { 2207 | return ErrIntOverflowProtocol 2208 | } 2209 | if iNdEx >= l { 2210 | return io.ErrUnexpectedEOF 2211 | } 2212 | b := data[iNdEx] 2213 | iNdEx++ 2214 | m.StartSequence |= (uint64(b) & 0x7F) << shift 2215 | if b < 0x80 { 2216 | break 2217 | } 2218 | } 2219 | case 12: 2220 | if wireType != 0 { 2221 | return fmt.Errorf("proto: wrong wireType = %d for field StartTimeDelta", wireType) 2222 | } 2223 | m.StartTimeDelta = 0 2224 | for shift := uint(0); ; shift += 7 { 2225 | if shift >= 64 { 2226 | return ErrIntOverflowProtocol 2227 | } 2228 | if iNdEx >= l { 2229 | return io.ErrUnexpectedEOF 2230 | } 2231 | b := data[iNdEx] 2232 | iNdEx++ 2233 | m.StartTimeDelta |= (int64(b) & 0x7F) << shift 2234 | if b < 0x80 { 2235 | break 2236 | } 2237 | } 2238 | default: 2239 | iNdEx = preIndex 2240 | skippy, err := skipProtocol(data[iNdEx:]) 2241 | if err != nil { 2242 | return err 2243 | } 2244 | if skippy < 0 { 2245 | return ErrInvalidLengthProtocol 2246 | } 2247 | if (iNdEx + skippy) > l { 2248 | return io.ErrUnexpectedEOF 2249 | } 2250 | iNdEx += skippy 2251 | } 2252 | } 2253 | 2254 | if iNdEx > l { 2255 | return io.ErrUnexpectedEOF 2256 | } 2257 | return nil 2258 | } 2259 | func (m *SubscriptionResponse) Unmarshal(data []byte) error { 2260 | l := len(data) 2261 | iNdEx := 0 2262 | for iNdEx < l { 2263 | preIndex := iNdEx 2264 | var wire uint64 2265 | for shift := uint(0); ; shift += 7 { 2266 | if shift >= 64 { 2267 | return ErrIntOverflowProtocol 2268 | } 2269 | if iNdEx >= l { 2270 | return io.ErrUnexpectedEOF 2271 | } 2272 | b := data[iNdEx] 2273 | iNdEx++ 2274 | wire |= (uint64(b) & 0x7F) << shift 2275 | if b < 0x80 { 2276 | break 2277 | } 2278 | } 2279 | fieldNum := int32(wire >> 3) 2280 | wireType := int(wire & 0x7) 2281 | if wireType == 4 { 2282 | return fmt.Errorf("proto: SubscriptionResponse: wiretype end group for non-group") 2283 | } 2284 | if fieldNum <= 0 { 2285 | return fmt.Errorf("proto: SubscriptionResponse: illegal tag %d (wire type %d)", fieldNum, wire) 2286 | } 2287 | switch fieldNum { 2288 | case 2: 2289 | if wireType != 2 { 2290 | return fmt.Errorf("proto: wrong wireType = %d for field AckInbox", wireType) 2291 | } 2292 | var stringLen uint64 2293 | for shift := uint(0); ; shift += 7 { 2294 | if shift >= 64 { 2295 | return ErrIntOverflowProtocol 2296 | } 2297 | if iNdEx >= l { 2298 | return io.ErrUnexpectedEOF 2299 | } 2300 | b := data[iNdEx] 2301 | iNdEx++ 2302 | stringLen |= (uint64(b) & 0x7F) << shift 2303 | if b < 0x80 { 2304 | break 2305 | } 2306 | } 2307 | intStringLen := int(stringLen) 2308 | if intStringLen < 0 { 2309 | return ErrInvalidLengthProtocol 2310 | } 2311 | postIndex := iNdEx + intStringLen 2312 | if postIndex > l { 2313 | return io.ErrUnexpectedEOF 2314 | } 2315 | m.AckInbox = string(data[iNdEx:postIndex]) 2316 | iNdEx = postIndex 2317 | case 3: 2318 | if wireType != 2 { 2319 | return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) 2320 | } 2321 | var stringLen uint64 2322 | for shift := uint(0); ; shift += 7 { 2323 | if shift >= 64 { 2324 | return ErrIntOverflowProtocol 2325 | } 2326 | if iNdEx >= l { 2327 | return io.ErrUnexpectedEOF 2328 | } 2329 | b := data[iNdEx] 2330 | iNdEx++ 2331 | stringLen |= (uint64(b) & 0x7F) << shift 2332 | if b < 0x80 { 2333 | break 2334 | } 2335 | } 2336 | intStringLen := int(stringLen) 2337 | if intStringLen < 0 { 2338 | return ErrInvalidLengthProtocol 2339 | } 2340 | postIndex := iNdEx + intStringLen 2341 | if postIndex > l { 2342 | return io.ErrUnexpectedEOF 2343 | } 2344 | m.Error = string(data[iNdEx:postIndex]) 2345 | iNdEx = postIndex 2346 | default: 2347 | iNdEx = preIndex 2348 | skippy, err := skipProtocol(data[iNdEx:]) 2349 | if err != nil { 2350 | return err 2351 | } 2352 | if skippy < 0 { 2353 | return ErrInvalidLengthProtocol 2354 | } 2355 | if (iNdEx + skippy) > l { 2356 | return io.ErrUnexpectedEOF 2357 | } 2358 | iNdEx += skippy 2359 | } 2360 | } 2361 | 2362 | if iNdEx > l { 2363 | return io.ErrUnexpectedEOF 2364 | } 2365 | return nil 2366 | } 2367 | func (m *UnsubscribeRequest) Unmarshal(data []byte) error { 2368 | l := len(data) 2369 | iNdEx := 0 2370 | for iNdEx < l { 2371 | preIndex := iNdEx 2372 | var wire uint64 2373 | for shift := uint(0); ; shift += 7 { 2374 | if shift >= 64 { 2375 | return ErrIntOverflowProtocol 2376 | } 2377 | if iNdEx >= l { 2378 | return io.ErrUnexpectedEOF 2379 | } 2380 | b := data[iNdEx] 2381 | iNdEx++ 2382 | wire |= (uint64(b) & 0x7F) << shift 2383 | if b < 0x80 { 2384 | break 2385 | } 2386 | } 2387 | fieldNum := int32(wire >> 3) 2388 | wireType := int(wire & 0x7) 2389 | if wireType == 4 { 2390 | return fmt.Errorf("proto: UnsubscribeRequest: wiretype end group for non-group") 2391 | } 2392 | if fieldNum <= 0 { 2393 | return fmt.Errorf("proto: UnsubscribeRequest: illegal tag %d (wire type %d)", fieldNum, wire) 2394 | } 2395 | switch fieldNum { 2396 | case 1: 2397 | if wireType != 2 { 2398 | return fmt.Errorf("proto: wrong wireType = %d for field ClientID", wireType) 2399 | } 2400 | var stringLen uint64 2401 | for shift := uint(0); ; shift += 7 { 2402 | if shift >= 64 { 2403 | return ErrIntOverflowProtocol 2404 | } 2405 | if iNdEx >= l { 2406 | return io.ErrUnexpectedEOF 2407 | } 2408 | b := data[iNdEx] 2409 | iNdEx++ 2410 | stringLen |= (uint64(b) & 0x7F) << shift 2411 | if b < 0x80 { 2412 | break 2413 | } 2414 | } 2415 | intStringLen := int(stringLen) 2416 | if intStringLen < 0 { 2417 | return ErrInvalidLengthProtocol 2418 | } 2419 | postIndex := iNdEx + intStringLen 2420 | if postIndex > l { 2421 | return io.ErrUnexpectedEOF 2422 | } 2423 | m.ClientID = string(data[iNdEx:postIndex]) 2424 | iNdEx = postIndex 2425 | case 2: 2426 | if wireType != 2 { 2427 | return fmt.Errorf("proto: wrong wireType = %d for field Subject", wireType) 2428 | } 2429 | var stringLen uint64 2430 | for shift := uint(0); ; shift += 7 { 2431 | if shift >= 64 { 2432 | return ErrIntOverflowProtocol 2433 | } 2434 | if iNdEx >= l { 2435 | return io.ErrUnexpectedEOF 2436 | } 2437 | b := data[iNdEx] 2438 | iNdEx++ 2439 | stringLen |= (uint64(b) & 0x7F) << shift 2440 | if b < 0x80 { 2441 | break 2442 | } 2443 | } 2444 | intStringLen := int(stringLen) 2445 | if intStringLen < 0 { 2446 | return ErrInvalidLengthProtocol 2447 | } 2448 | postIndex := iNdEx + intStringLen 2449 | if postIndex > l { 2450 | return io.ErrUnexpectedEOF 2451 | } 2452 | m.Subject = string(data[iNdEx:postIndex]) 2453 | iNdEx = postIndex 2454 | case 3: 2455 | if wireType != 2 { 2456 | return fmt.Errorf("proto: wrong wireType = %d for field Inbox", wireType) 2457 | } 2458 | var stringLen uint64 2459 | for shift := uint(0); ; shift += 7 { 2460 | if shift >= 64 { 2461 | return ErrIntOverflowProtocol 2462 | } 2463 | if iNdEx >= l { 2464 | return io.ErrUnexpectedEOF 2465 | } 2466 | b := data[iNdEx] 2467 | iNdEx++ 2468 | stringLen |= (uint64(b) & 0x7F) << shift 2469 | if b < 0x80 { 2470 | break 2471 | } 2472 | } 2473 | intStringLen := int(stringLen) 2474 | if intStringLen < 0 { 2475 | return ErrInvalidLengthProtocol 2476 | } 2477 | postIndex := iNdEx + intStringLen 2478 | if postIndex > l { 2479 | return io.ErrUnexpectedEOF 2480 | } 2481 | m.Inbox = string(data[iNdEx:postIndex]) 2482 | iNdEx = postIndex 2483 | case 4: 2484 | if wireType != 2 { 2485 | return fmt.Errorf("proto: wrong wireType = %d for field DurableName", wireType) 2486 | } 2487 | var stringLen uint64 2488 | for shift := uint(0); ; shift += 7 { 2489 | if shift >= 64 { 2490 | return ErrIntOverflowProtocol 2491 | } 2492 | if iNdEx >= l { 2493 | return io.ErrUnexpectedEOF 2494 | } 2495 | b := data[iNdEx] 2496 | iNdEx++ 2497 | stringLen |= (uint64(b) & 0x7F) << shift 2498 | if b < 0x80 { 2499 | break 2500 | } 2501 | } 2502 | intStringLen := int(stringLen) 2503 | if intStringLen < 0 { 2504 | return ErrInvalidLengthProtocol 2505 | } 2506 | postIndex := iNdEx + intStringLen 2507 | if postIndex > l { 2508 | return io.ErrUnexpectedEOF 2509 | } 2510 | m.DurableName = string(data[iNdEx:postIndex]) 2511 | iNdEx = postIndex 2512 | default: 2513 | iNdEx = preIndex 2514 | skippy, err := skipProtocol(data[iNdEx:]) 2515 | if err != nil { 2516 | return err 2517 | } 2518 | if skippy < 0 { 2519 | return ErrInvalidLengthProtocol 2520 | } 2521 | if (iNdEx + skippy) > l { 2522 | return io.ErrUnexpectedEOF 2523 | } 2524 | iNdEx += skippy 2525 | } 2526 | } 2527 | 2528 | if iNdEx > l { 2529 | return io.ErrUnexpectedEOF 2530 | } 2531 | return nil 2532 | } 2533 | func (m *CloseRequest) Unmarshal(data []byte) error { 2534 | l := len(data) 2535 | iNdEx := 0 2536 | for iNdEx < l { 2537 | preIndex := iNdEx 2538 | var wire uint64 2539 | for shift := uint(0); ; shift += 7 { 2540 | if shift >= 64 { 2541 | return ErrIntOverflowProtocol 2542 | } 2543 | if iNdEx >= l { 2544 | return io.ErrUnexpectedEOF 2545 | } 2546 | b := data[iNdEx] 2547 | iNdEx++ 2548 | wire |= (uint64(b) & 0x7F) << shift 2549 | if b < 0x80 { 2550 | break 2551 | } 2552 | } 2553 | fieldNum := int32(wire >> 3) 2554 | wireType := int(wire & 0x7) 2555 | if wireType == 4 { 2556 | return fmt.Errorf("proto: CloseRequest: wiretype end group for non-group") 2557 | } 2558 | if fieldNum <= 0 { 2559 | return fmt.Errorf("proto: CloseRequest: illegal tag %d (wire type %d)", fieldNum, wire) 2560 | } 2561 | switch fieldNum { 2562 | case 1: 2563 | if wireType != 2 { 2564 | return fmt.Errorf("proto: wrong wireType = %d for field ClientID", wireType) 2565 | } 2566 | var stringLen uint64 2567 | for shift := uint(0); ; shift += 7 { 2568 | if shift >= 64 { 2569 | return ErrIntOverflowProtocol 2570 | } 2571 | if iNdEx >= l { 2572 | return io.ErrUnexpectedEOF 2573 | } 2574 | b := data[iNdEx] 2575 | iNdEx++ 2576 | stringLen |= (uint64(b) & 0x7F) << shift 2577 | if b < 0x80 { 2578 | break 2579 | } 2580 | } 2581 | intStringLen := int(stringLen) 2582 | if intStringLen < 0 { 2583 | return ErrInvalidLengthProtocol 2584 | } 2585 | postIndex := iNdEx + intStringLen 2586 | if postIndex > l { 2587 | return io.ErrUnexpectedEOF 2588 | } 2589 | m.ClientID = string(data[iNdEx:postIndex]) 2590 | iNdEx = postIndex 2591 | default: 2592 | iNdEx = preIndex 2593 | skippy, err := skipProtocol(data[iNdEx:]) 2594 | if err != nil { 2595 | return err 2596 | } 2597 | if skippy < 0 { 2598 | return ErrInvalidLengthProtocol 2599 | } 2600 | if (iNdEx + skippy) > l { 2601 | return io.ErrUnexpectedEOF 2602 | } 2603 | iNdEx += skippy 2604 | } 2605 | } 2606 | 2607 | if iNdEx > l { 2608 | return io.ErrUnexpectedEOF 2609 | } 2610 | return nil 2611 | } 2612 | func (m *CloseResponse) Unmarshal(data []byte) error { 2613 | l := len(data) 2614 | iNdEx := 0 2615 | for iNdEx < l { 2616 | preIndex := iNdEx 2617 | var wire uint64 2618 | for shift := uint(0); ; shift += 7 { 2619 | if shift >= 64 { 2620 | return ErrIntOverflowProtocol 2621 | } 2622 | if iNdEx >= l { 2623 | return io.ErrUnexpectedEOF 2624 | } 2625 | b := data[iNdEx] 2626 | iNdEx++ 2627 | wire |= (uint64(b) & 0x7F) << shift 2628 | if b < 0x80 { 2629 | break 2630 | } 2631 | } 2632 | fieldNum := int32(wire >> 3) 2633 | wireType := int(wire & 0x7) 2634 | if wireType == 4 { 2635 | return fmt.Errorf("proto: CloseResponse: wiretype end group for non-group") 2636 | } 2637 | if fieldNum <= 0 { 2638 | return fmt.Errorf("proto: CloseResponse: illegal tag %d (wire type %d)", fieldNum, wire) 2639 | } 2640 | switch fieldNum { 2641 | case 1: 2642 | if wireType != 2 { 2643 | return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) 2644 | } 2645 | var stringLen uint64 2646 | for shift := uint(0); ; shift += 7 { 2647 | if shift >= 64 { 2648 | return ErrIntOverflowProtocol 2649 | } 2650 | if iNdEx >= l { 2651 | return io.ErrUnexpectedEOF 2652 | } 2653 | b := data[iNdEx] 2654 | iNdEx++ 2655 | stringLen |= (uint64(b) & 0x7F) << shift 2656 | if b < 0x80 { 2657 | break 2658 | } 2659 | } 2660 | intStringLen := int(stringLen) 2661 | if intStringLen < 0 { 2662 | return ErrInvalidLengthProtocol 2663 | } 2664 | postIndex := iNdEx + intStringLen 2665 | if postIndex > l { 2666 | return io.ErrUnexpectedEOF 2667 | } 2668 | m.Error = string(data[iNdEx:postIndex]) 2669 | iNdEx = postIndex 2670 | default: 2671 | iNdEx = preIndex 2672 | skippy, err := skipProtocol(data[iNdEx:]) 2673 | if err != nil { 2674 | return err 2675 | } 2676 | if skippy < 0 { 2677 | return ErrInvalidLengthProtocol 2678 | } 2679 | if (iNdEx + skippy) > l { 2680 | return io.ErrUnexpectedEOF 2681 | } 2682 | iNdEx += skippy 2683 | } 2684 | } 2685 | 2686 | if iNdEx > l { 2687 | return io.ErrUnexpectedEOF 2688 | } 2689 | return nil 2690 | } 2691 | func skipProtocol(data []byte) (n int, err error) { 2692 | l := len(data) 2693 | iNdEx := 0 2694 | for iNdEx < l { 2695 | var wire uint64 2696 | for shift := uint(0); ; shift += 7 { 2697 | if shift >= 64 { 2698 | return 0, ErrIntOverflowProtocol 2699 | } 2700 | if iNdEx >= l { 2701 | return 0, io.ErrUnexpectedEOF 2702 | } 2703 | b := data[iNdEx] 2704 | iNdEx++ 2705 | wire |= (uint64(b) & 0x7F) << shift 2706 | if b < 0x80 { 2707 | break 2708 | } 2709 | } 2710 | wireType := int(wire & 0x7) 2711 | switch wireType { 2712 | case 0: 2713 | for shift := uint(0); ; shift += 7 { 2714 | if shift >= 64 { 2715 | return 0, ErrIntOverflowProtocol 2716 | } 2717 | if iNdEx >= l { 2718 | return 0, io.ErrUnexpectedEOF 2719 | } 2720 | iNdEx++ 2721 | if data[iNdEx-1] < 0x80 { 2722 | break 2723 | } 2724 | } 2725 | return iNdEx, nil 2726 | case 1: 2727 | iNdEx += 8 2728 | return iNdEx, nil 2729 | case 2: 2730 | var length int 2731 | for shift := uint(0); ; shift += 7 { 2732 | if shift >= 64 { 2733 | return 0, ErrIntOverflowProtocol 2734 | } 2735 | if iNdEx >= l { 2736 | return 0, io.ErrUnexpectedEOF 2737 | } 2738 | b := data[iNdEx] 2739 | iNdEx++ 2740 | length |= (int(b) & 0x7F) << shift 2741 | if b < 0x80 { 2742 | break 2743 | } 2744 | } 2745 | iNdEx += length 2746 | if length < 0 { 2747 | return 0, ErrInvalidLengthProtocol 2748 | } 2749 | return iNdEx, nil 2750 | case 3: 2751 | for { 2752 | var innerWire uint64 2753 | var start int = iNdEx 2754 | for shift := uint(0); ; shift += 7 { 2755 | if shift >= 64 { 2756 | return 0, ErrIntOverflowProtocol 2757 | } 2758 | if iNdEx >= l { 2759 | return 0, io.ErrUnexpectedEOF 2760 | } 2761 | b := data[iNdEx] 2762 | iNdEx++ 2763 | innerWire |= (uint64(b) & 0x7F) << shift 2764 | if b < 0x80 { 2765 | break 2766 | } 2767 | } 2768 | innerWireType := int(innerWire & 0x7) 2769 | if innerWireType == 4 { 2770 | break 2771 | } 2772 | next, err := skipProtocol(data[start:]) 2773 | if err != nil { 2774 | return 0, err 2775 | } 2776 | iNdEx = start + next 2777 | } 2778 | return iNdEx, nil 2779 | case 4: 2780 | return iNdEx, nil 2781 | case 5: 2782 | iNdEx += 4 2783 | return iNdEx, nil 2784 | default: 2785 | return 0, fmt.Errorf("proto: illegal wireType %d", wireType) 2786 | } 2787 | } 2788 | panic("unreachable") 2789 | } 2790 | 2791 | var ( 2792 | ErrInvalidLengthProtocol = fmt.Errorf("proto: negative length found during unmarshaling") 2793 | ErrIntOverflowProtocol = fmt.Errorf("proto: integer overflow") 2794 | ) 2795 | --------------------------------------------------------------------------------