diff --git a/gateway/Dockerfile b/gateway/Dockerfile index 26adc11c..555a424e 100644 --- a/gateway/Dockerfile +++ b/gateway/Dockerfile @@ -6,7 +6,6 @@ RUN curl -sL https://github.com/alexellis/license-check/releases/download/0.2.2/ WORKDIR /go/src/github.com/openfaas/faas/gateway - COPY vendor vendor COPY handlers handlers @@ -20,13 +19,20 @@ COPY plugin plugin COPY server.go . # Run a gofmt and exclude all vendored code. -RUN license-check -path ./ --verbose=false "Alex Ellis" "OpenFaaS Project" \ +RUN license-check -path ./ --verbose=false "Alex Ellis" "OpenFaaS Project" "OpenFaaS Authors" \ && test -z "$(gofmt -l $(find . -type f -name '*.go' -not -path "./vendor/*"))" \ && go test $(go list ./... | grep -v integration | grep -v /vendor/ | grep -v /template/) -cover \ && CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o gateway . FROM alpine:3.7 +LABEL org.label-schema.license="MIT" \ + org.label-schema.vcs-url="https://github.com/openfaas/faas" \ + org.label-schema.vcs-type="Git" \ + org.label-schema.name="openfaas/faas" \ + org.label-schema.vendor="openfaas" \ + org.label-schema.docker.schema-version="1.0" + RUN addgroup -S app \ && adduser -S -g app app diff --git a/gateway/Gopkg.lock b/gateway/Gopkg.lock index d106e01e..92348a4b 100644 --- a/gateway/Gopkg.lock +++ b/gateway/Gopkg.lock @@ -7,9 +7,19 @@ packages = ["quantile"] revision = "4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9" +[[projects]] + name = "github.com/docker/distribution" + packages = ["uuid"] + revision = "48294d928ced5dd9b378f7fd7c6f5da3ff3f2c89" + version = "v2.6.2" + [[projects]] name = "github.com/gogo/protobuf" - packages = ["gogoproto","proto","protoc-gen-gogo/descriptor"] + packages = [ + "gogoproto", + "proto", + "protoc-gen-gogo/descriptor" + ] revision = "342cbe0a04158f6dcb03ca0079991a51a4248c02" version = "v0.5" @@ -39,15 +49,22 @@ [[projects]] name = "github.com/nats-io/go-nats" - packages = [".","encoders/builtin","util"] - revision = "d66cb54e6b7bdd93f0b28afc8450d84c780dfb68" - version = "v1.4.0" + packages = [ + ".", + "encoders/builtin", + "util" + ] + revision = "062418ea1c2181f52dc0f954f6204370519a868b" + version = "v1.5.0" [[projects]] name = "github.com/nats-io/go-nats-streaming" - packages = [".","pb"] - revision = "6e620057a207bd61e992c1c5b6a2de7b6a4cb010" - version = "v0.3.4" + packages = [ + ".", + "pb" + ] + revision = "e15a53f85e4932540600a16b56f6c4f65f58176f" + version = "v0.4.0" [[projects]] name = "github.com/nats-io/nuid" @@ -55,12 +72,11 @@ revision = "289cccf02c178dc782430d534e3c1f5b72af807f" version = "v1.0.0" - [[projects]] name = "github.com/openfaas/nats-queue-worker" packages = ["handler"] - revision = "c064b78787b00d458fcb96435b0c1fff413126c9" - version = "0.4" + revision = "62e8dcfe87fc01de8b94156f3e4291370c0c84a8" + version = "0.4.6" [[projects]] name = "github.com/prometheus/client_golang" @@ -77,18 +93,25 @@ [[projects]] branch = "master" name = "github.com/prometheus/common" - packages = ["expfmt","internal/bitbucket.org/ww/goautoneg","model"] + packages = [ + "expfmt", + "internal/bitbucket.org/ww/goautoneg", + "model" + ] revision = "2e54d0b93cba2fd133edc32211dcc32c06ef72ca" [[projects]] branch = "master" name = "github.com/prometheus/procfs" - packages = [".","xfs"] + packages = [ + ".", + "xfs" + ] revision = "b15cd069a83443be3154b719d0cc9fe8117f09fb" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "6c22951557e478603b9ee6d67e3787efd5230d52b29b01ad8e136fd3e1ca1bde" + inputs-digest = "181fb3c695e3b12e0a8e967135ef717ea83d9525c7c31b92f641d7a963d26254" solver-name = "gps-cdcl" solver-version = 1 diff --git a/gateway/Gopkg.toml b/gateway/Gopkg.toml index d238cf25..04b106f7 100644 --- a/gateway/Gopkg.toml +++ b/gateway/Gopkg.toml @@ -1,32 +1,21 @@ -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" +ignored = ["github.com/openfaas/faas/gateway/queue"] [[constraint]] name = "github.com/gorilla/mux" version = "1.6.0" [[constraint]] - name = "github.com/openfaas/nats-queue-worker" + name = "github.com/nats-io/go-nats-streaming" version = "0.4.0" +[[override]] + name = "github.com/nats-io/go-nats" + version = "v1.5.0" + +[[constraint]] + name = "github.com/openfaas/nats-queue-worker" + version = "0.4.5" + [[constraint]] name = "github.com/prometheus/client_golang" version = "0.8.0" @@ -34,3 +23,5 @@ [[constraint]] branch = "master" name = "golang.org/x/net" + + diff --git a/gateway/server.go b/gateway/server.go index d920df26..1c656344 100644 --- a/gateway/server.go +++ b/gateway/server.go @@ -88,7 +88,7 @@ func main() { if config.UseNATS() { log.Println("Async enabled: Using NATS Streaming.") - natsQueue, queueErr := natsHandler.CreateNatsQueue(*config.NATSAddress, *config.NATSPort) + natsQueue, queueErr := natsHandler.CreateNatsQueue(*config.NATSAddress, *config.NATSPort, natsHandler.DefaultNatsConfig{}) if queueErr != nil { log.Fatalln(queueErr) } diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/.travis.yml b/gateway/vendor/github.com/nats-io/go-nats-streaming/.travis.yml index 172c65f7..a9708ece 100644 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/.travis.yml +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/.travis.yml @@ -1,22 +1,26 @@ language: go sudo: false go: -- 1.6.4 -- 1.7.4 +- 1.8.x +- 1.9.x +- 1.10.x install: - go get -t ./... - go get github.com/nats-io/nats-streaming-server - go get github.com/mattn/goveralls - go get github.com/wadey/gocovmerge -- go get honnef.co/go/staticcheck/cmd/staticcheck -script: -- go fmt ./... +- go get -u honnef.co/go/tools/cmd/megacheck +- go get -u github.com/client9/misspell/cmd/misspell +before_script: +- $(exit $(go fmt ./... | wc -l)) - go vet ./... +- misspell -error -locale US . +- megacheck ./... +script: - go test -i -race ./... - go test -v -race ./... -- staticcheck ./... after_success: -- if [ "$TRAVIS_GO_VERSION" \> "1.7." ]; then ./scripts/cov.sh TRAVIS; fi +- if [[ "$TRAVIS_GO_VERSION" == 1.9.* ]]; then ./scripts/cov.sh TRAVIS; fi env: global: secure: OoCemKSHHH/SkkamHLWd0qh9qgQDx4/3fGuykYuzW/gjUhLlL0ThyUXOr3HOandoh3wTU8Ntj184WU6Sjh1oXzdDAYcI/ryNQXSmJ/DyGC6ffoj4Je/Rwj3sbwpaFTl1imawL8Lv6+5Dkb2JSbbbqapjbO3BhrrNfqLuQulqrLJKVaOyS5nOByiGFYsgjf/ac7Qrr9AnHhlkWRXoR+q8GlGG7qcKtLlmG5OqxifqfgQ+pcVtyeleT6zGPI0LUyr9gWHRZtMK9nYfxXuQK2d7V+SW4NBW1jdDKBHZbeJRxZ8N8rU8Nk3ka54YHXC2PeD8EloiAr5HkALuHbIdzyy40Y3rJyHfxyY6EYBcZEy+ZCRoqkVJ4NN4R46YE588BpYhT48YHK+lptM7YxrPtf08X+Cugc206X0hk/YFqqsaaNIwMfiTPbapuHxa8S4kgT2vDn3OTI53ZTrDiLVY3ZDp+EdUO1hiYFR6cpu5el/EQN5G0iW6sI69gOv26UmGI369D3fezbYPFPHHDao8xq7s8HdYUZleDNL0oCWK1MgL2g/Irbt5Kr6JjT/tpQOiiagqeR5dlV9mAiOZFr88gg7aqwOuSqmlULWVB4qYncQ6IBoednIHtrLW6H+2RfrZU01cI6tGSrXD+VoFnQ7aZwLxLc71VyN5khYPk0gGvyQhZxk= diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/CODE-OF-CONDUCT.md b/gateway/vendor/github.com/nats-io/go-nats-streaming/CODE-OF-CONDUCT.md new file mode 100644 index 00000000..47ca568c --- /dev/null +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/CODE-OF-CONDUCT.md @@ -0,0 +1,4 @@ +## Community Code of Conduct + +NATS follows the [CNCF Code of Conduct](https://github.com/cncf/foundation/blob/master/code-of-conduct.md). + diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/LICENSE b/gateway/vendor/github.com/nats-io/go-nats-streaming/LICENSE index d5cf6aa5..f49a4e16 100644 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/LICENSE +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/LICENSE @@ -1,20 +1,201 @@ -The MIT License (MIT) + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Copyright (c) 2016 Apcera Inc. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: + 1. Definitions. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/OWNERS b/gateway/vendor/github.com/nats-io/go-nats-streaming/OWNERS new file mode 100644 index 00000000..be422d47 --- /dev/null +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/OWNERS @@ -0,0 +1,9 @@ +reviewers: + - aricart + - ColinSullivan1 + - derekcollison + - kozlovic + - wallyqs +approvers: + - derekcollison + - kozlovic diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/README.md b/gateway/vendor/github.com/nats-io/go-nats-streaming/README.md index 945eb065..bba6d8c0 100644 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/README.md +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/README.md @@ -2,7 +2,7 @@ NATS Streaming is an extremely performant, lightweight reliable streaming platform powered by [NATS](https://nats.io). -[![License MIT](https://img.shields.io/npm/l/express.svg)](http://opensource.org/licenses/MIT) +[![License Apache 2](https://img.shields.io/badge/License-Apache2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![Build Status](https://travis-ci.org/nats-io/go-nats-streaming.svg?branch=master)](http://travis-ci.org/nats-io/go-nats-streaming) [![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) @@ -17,9 +17,6 @@ NATS Streaming provides the following high-level feature set: - Please raise questions/issues via the [Issue Tracker](https://github.com/nats-io/go-nats-streaming/issues). -## Known Issues -- Time- and sequence-based subscriptions are exact. Requesting a time or seqno before the earliest stored message for a subject will result in an error (in SubscriptionRequest.Error) - ## Installation ```bash @@ -59,29 +56,29 @@ The options are described with examples below: // Subscribe starting with most recently published value sub, err := sc.Subscribe("foo", func(m *stan.Msg) { fmt.Printf("Received a message: %s\n", string(m.Data)) -}, StartWithLastReceived()) +}, stan.StartWithLastReceived()) // Receive all stored values in order sub, err := sc.Subscribe("foo", func(m *stan.Msg) { fmt.Printf("Received a message: %s\n", string(m.Data)) -}, DeliverAllAvailable()) +}, stan.DeliverAllAvailable()) // Receive messages starting at a specific sequence number sub, err := sc.Subscribe("foo", func(m *stan.Msg) { fmt.Printf("Received a message: %s\n", string(m.Data)) -}, StartAtSequence(22)) +}, stan.StartAtSequence(22)) // Subscribe starting at a specific time var startTime time.Time ... sub, err := sc.Subscribe("foo", func(m *stan.Msg) { fmt.Printf("Received a message: %s\n", string(m.Data)) -}, StartAtTime(startTime)) +}, stan.StartAtTime(startTime)) // Subscribe starting a specific amount of time in the past (e.g. 30 seconds ago) sub, err := sc.Subscribe("foo", func(m *stan.Msg) { fmt.Printf("Received a message: %s\n", string(m.Data)) -}, StartAtTimeDelta(time.ParseDuration("30s"))) +}, stan.StartAtTimeDelta(time.ParseDuration("30s"))) ``` ### Durable Subscriptions @@ -184,7 +181,7 @@ that is, the start position will take effect and delivery will start from there. ### Durable Queue Groups -As described above, for non durable queue subsribers, when the last member leaves the group, +As described above, for non durable queue subscribers, when the last member leaves the group, that group is removed. A durable queue group allows you to have all members leave but still maintain state. When a member re-joins, it starts at the last position in that group. @@ -220,7 +217,7 @@ The rules for non-durable queue subscribers apply to durable subscribers. As for non-durable queue subscribers, if a member's connection is closed, or if `Unsubscribe` its called, the member leaves the group. Any unacknowledged message -is transfered to remaining members. See *Closing the Group* for important difference +is transferred to remaining members. See *Closing the Group* for important difference with non-durable queue subscribers. #### Closing the Group @@ -242,6 +239,58 @@ NATS Streaming subscriptions **do not** support wildcards. ## Advanced Usage +### Connection Status + +The fact that the NATS Streaming server and clients are not directly connected poses a challenge when it comes to know if a client is still valid. +When a client disconnects, the streaming server is not notified, hence the importance of calling `Close()`. The server sends heartbeats +to the client's private inbox and if it misses a certain number of responses, it will consider the client's connection lost and remove it +from its state. + +Before version `0.4.0`, the client library was not sending PINGs to the streaming server to detect connection failure. This was problematic +especially if an application was never sending data (had only subscriptions for instance). Picture the case where a client connects to a +NATS Server which has a route to a NATS Streaming server (either connecting to a standalone NATS Server or the server it embeds). If the +connection between the streaming server and the client's NATS Server is broken, the client's NATS connection would still be ok, yet, no +communication with the streaming server is possible. This is why relying on `Conn.NatsConn()` to check the status is not helpful. + +Starting version `0.4.0` of this library and server `0.10.0`, the client library will now send PINGs at regular intervals (default is 5 seconds) +and will close the streaming connection after a certain number of PINGs have been sent without any response (default is 3). When that +happens, a callback - if one is registered - will be invoked to notify the user that the connection is permanently lost, and the reason +for the failure. + +Here is how you would specify your own PING values and the callback: + +```go + + // Send PINGs every 10 seconds, and fail after 5 PINGs without any response. + sc, err := stan.Connect(clusterName, clientName, + stan.Pings(10, 5), + stan.SetConnectionLostHandler(func(_ stan.Conn, reason error) { + log.Fatalf("Connection lost, reason: %v", reason) + })) +``` + +Note that the only way to be notified is to set the callback. If the callback is not set, PINGs are still sent and the connection +will be closed if needed, but the application won't know if it has only subscriptions. + +When the connection is lost, your application would have to re-create it and all subscriptions if any. + +When no NATS connection is provided to the `Connect()` call, the library creates its own NATS connection and will now +set the reconnect attempts to "infinite", which was not the case before. It should therefore be possible for the library to +always reconnect, but this does not mean that the streaming connection will not be closed, even if you set a very high +threshold for the PINGs max out value. Keep in mind that while the client is disconnected, the server is sending heartbeats to +the clients too, and when not getting any response, it will remove that client from its state. When the communication is restored, +the PINGs sent to the server will allow to detect this condition and report to the client that the connection is now closed. + +Also, while a client is "disconnected" from the server, another application with connectivity to the streaming server may +connect and uses the same client ID. The server, when detecting the duplicate client ID, will try to contact the first client +to know if it should reject the connect request of the second client. Since the communication between the server and the +first client is broken, the server will not get a response and therefore will replace the first client with the second one. + +Prior to client `0.4.0` and server `0.10.0`, if the communication between the first client and server were to be restored, +and the application would send messages, the server would accept those because the published messages client ID would be +valid, although the client is not. With client at `0.4.0+` and server `0.10.0+`, additional information is sent with each +message to allow the server to reject messages from a client that has been replaced by another client. + ### Asynchronous Publishing 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. @@ -301,7 +350,7 @@ ah := func(nuid string, err error) { } for i := 1; i < 1000; i++ { - // If the server is unable to keep up with the publisher, the number of oustanding acks will eventually + // If the server is unable to keep up with the publisher, the number of outstanding acks will eventually // reach the max and this call will block guid, _ := sc.PublishAsync("foo", []byte("Hello World"), ah) } @@ -327,24 +376,5 @@ sc.Subscribe("foo", func(m *stan.Msg) { ## License -(The MIT License) - -Copyright (c) 2012-2016 Apcera Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. +Unless otherwise noted, the NATS source files are distributed +under the Apache Version 2.0 license found in the LICENSE file. \ No newline at end of file diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/TODO.md b/gateway/vendor/github.com/nats-io/go-nats-streaming/TODO.md deleted file mode 100644 index 581d347b..00000000 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/TODO.md +++ /dev/null @@ -1,15 +0,0 @@ - -- [ ] Retry limits? -- [ ] Server Store Limits (time, msgs, byte) -- [X] Change time to deltas -- [X] Server heartbeat, release dead clients. -- [X] Require clientID for published messages, error if not registered. -- [X] Check for need of ackMap (out of order re-delivery to queue subscribers). -- [X] Redelivered Flag for Msg. -- [X] Queue Subscribers -- [X] Durable Subscribers (survive reconnect, etc) -- [X] Start Positions on Subscribers -- [X] Ack for delivered just Reply? No need on ConnectedResponse? -- [X] PublishWithReply, or option. -- [X] Data Races in Server. -- [X] Manual Ack? diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/benchmark_test.go b/gateway/vendor/github.com/nats-io/go-nats-streaming/benchmark_test.go index acd11855..27b9aa92 100644 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/benchmark_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/benchmark_test.go @@ -1,3 +1,15 @@ +// Copyright 2016-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package stan //////////////////////////////////////////////////////////////////////////////// diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-bench.go b/gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-bench/main.go similarity index 69% rename from gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-bench.go rename to gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-bench/main.go index e6bd4c6d..ae860e58 100644 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-bench.go +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-bench/main.go @@ -1,4 +1,15 @@ -// Copyright 2015 Apcera Inc. All rights reserved. +// Copyright 2016-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package main @@ -29,12 +40,16 @@ const ( ) func usage() { - log.Fatalf("Usage: nats-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) + 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) } var benchmark *bench.Benchmark func main() { + var clusterID string + flag.StringVar(&clusterID, "c", "test-cluster", "The NATS Streaming cluster ID") + flag.StringVar(&clusterID, "cluster", "test-cluster", "The NATS Streaming cluster ID") + var urls = flag.String("s", nats.DefaultURL, "The NATS server URLs (separated by comma") var tls = flag.Bool("tls", false, "Use TLS secure sonnection") var numPubs = flag.Int("np", DefaultNumPubs, "Number of concurrent publishers") @@ -57,7 +72,7 @@ func main() { } // Setup the option block - opts := nats.DefaultOptions + opts := nats.GetDefaultOptions() opts.Servers = strings.Split(*urls, ",") for i, s := range opts.Servers { opts.Servers[i] = strings.Trim(s, " ") @@ -76,7 +91,7 @@ func main() { startwg.Add(*numSubs) for i := 0; i < *numSubs; i++ { subID := fmt.Sprintf("%s-sub-%d", *clientID, i) - go runSubscriber(&startwg, &donewg, opts, *numMsgs, *messageSize, *ignoreOld, subID) + go runSubscriber(&startwg, &donewg, opts, clusterID, *numMsgs, *messageSize, *ignoreOld, subID) } startwg.Wait() @@ -85,7 +100,7 @@ func main() { pubCounts := bench.MsgsPerClient(*numMsgs, *numPubs) for i := 0; i < *numPubs; i++ { pubID := fmt.Sprintf("%s-pub-%d", *clientID, i) - go runPublisher(&startwg, &donewg, opts, pubCounts[i], *messageSize, *async, pubID, *maxPubAcks) + go runPublisher(&startwg, &donewg, opts, clusterID, pubCounts[i], *messageSize, *async, pubID, *maxPubAcks) } log.Printf("Starting benchmark [msgs=%d, msgsize=%d, pubs=%d, subs=%d]\n", *numMsgs, *messageSize, *numPubs, *numSubs) @@ -103,12 +118,15 @@ func main() { } } -func runPublisher(startwg, donewg *sync.WaitGroup, opts nats.Options, numMsgs int, msgSize int, async bool, pubID string, maxPubAcksInflight int) { +func runPublisher(startwg, donewg *sync.WaitGroup, opts nats.Options, clusterID string, numMsgs int, msgSize int, async bool, pubID string, maxPubAcksInflight int) { nc, err := opts.Connect() if err != nil { log.Fatalf("Publisher %s can't connect: %v\n", pubID, err) } - snc, err := stan.Connect("test-cluster", pubID, stan.MaxPubAcksInflight(maxPubAcksInflight), stan.NatsConn(nc)) + snc, err := stan.Connect(clusterID, pubID, stan.MaxPubAcksInflight(maxPubAcksInflight), stan.NatsConn(nc), + stan.SetConnectionLostHandler(func(_ stan.Conn, reason error) { + log.Fatalf("Connection lost, reason: %v", reason) + })) if err != nil { log.Fatalf("Publisher %s can't connect: %v\n", pubID, err) } @@ -128,6 +146,9 @@ func runPublisher(startwg, donewg *sync.WaitGroup, opts nats.Options, numMsgs in if async { ch := make(chan bool) acb := func(lguid string, err error) { + if err != nil { + log.Fatalf("Publisher %q got following error: %v", pubID, err) + } published++ if published >= numMsgs { ch <- true @@ -156,26 +177,31 @@ func runPublisher(startwg, donewg *sync.WaitGroup, opts nats.Options, numMsgs in donewg.Done() } -func runSubscriber(startwg, donewg *sync.WaitGroup, opts nats.Options, numMsgs int, msgSize int, ignoreOld bool, subID string) { +func runSubscriber(startwg, donewg *sync.WaitGroup, opts nats.Options, clusterID string, numMsgs int, msgSize int, ignoreOld bool, subID string) { nc, err := opts.Connect() if err != nil { log.Fatalf("Subscriber %s can't connect: %v\n", subID, err) } - snc, err := stan.Connect("test-cluster", subID, stan.NatsConn(nc)) + snc, err := stan.Connect(clusterID, subID, stan.NatsConn(nc), + stan.SetConnectionLostHandler(func(_ stan.Conn, reason error) { + log.Fatalf("Connection lost, reason: %v", reason) + })) if err != nil { log.Fatalf("Subscriber %s can't connect: %v\n", subID, err) } args := flag.Args() subj := args[0] - ch := make(chan bool) - start := time.Now() + ch := make(chan time.Time, 2) received := 0 mcb := func(msg *stan.Msg) { received++ + if received == 1 { + ch <- time.Now() + } if received >= numMsgs { - ch <- true + ch <- time.Now() } } @@ -186,8 +212,9 @@ func runSubscriber(startwg, donewg *sync.WaitGroup, opts nats.Options, numMsgs i } startwg.Done() - <-ch - benchmark.AddSubSample(bench.NewSample(numMsgs, msgSize, start, time.Now(), snc.NatsConn())) + start := <-ch + end := <-ch + benchmark.AddSubSample(bench.NewSample(numMsgs, msgSize, start, end, snc.NatsConn())) snc.Close() nc.Close() donewg.Done() diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-pub.go b/gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-pub/main.go similarity index 81% rename from gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-pub.go rename to gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-pub/main.go index 32a24308..cdc78ae8 100644 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-pub.go +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-pub/main.go @@ -1,5 +1,15 @@ -// Copyright 2012-2016 Apcera Inc. All rights reserved. -// +build ignore +// Copyright 2016-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package main @@ -79,7 +89,7 @@ func main() { ch <- true } - if async != true { + if !async { err = sc.Publish(subj, msg) if err != nil { log.Fatalf("Error during publish: %v\n", err) diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-sub.go b/gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-sub/main.go similarity index 83% rename from gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-sub.go rename to gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-sub/main.go index 3fef21d8..1f26453c 100644 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-sub.go +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/examples/stan-sub/main.go @@ -1,5 +1,15 @@ -// Copyright 2012-2016 Apcera Inc. All rights reserved. -// +build ignore +// Copyright 2016-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package main @@ -89,7 +99,10 @@ func main() { usage() } - sc, err := stan.Connect(clusterID, clientID, stan.NatsURL(URL)) + sc, err := stan.Connect(clusterID, clientID, stan.NatsURL(URL), + stan.SetConnectionLostHandler(func(_ stan.Conn, reason error) { + log.Fatalf("Connection lost, reason: %v", reason) + })) if err != nil { log.Fatalf("Can't connect: %v.\nMake sure a NATS Streaming Server is running at: %s", err, URL) } @@ -106,9 +119,9 @@ func main() { if startSeq != 0 { startOpt = stan.StartAtSequence(startSeq) - } else if deliverLast == true { + } else if deliverLast { startOpt = stan.StartWithLastReceived() - } else if deliverAll == true { + } else if deliverAll { log.Print("subscribing with DeliverAllAvailable") startOpt = stan.DeliverAllAvailable() } else if startDelta != "" { @@ -138,7 +151,7 @@ func main() { cleanupDone := make(chan bool) signal.Notify(signalChan, os.Interrupt) go func() { - for _ = range signalChan { + for range signalChan { fmt.Printf("\nReceived an interrupt, unsubscribing and closing connection...\n\n") // Do not unsubscribe a durable on exit, except if asked to. if durable == "" || unsubscribe { diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/pb/protocol.pb.go b/gateway/vendor/github.com/nats-io/go-nats-streaming/pb/protocol.pb.go index e0a3da52..2182dc93 100644 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/pb/protocol.pb.go +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/pb/protocol.pb.go @@ -1,6 +1,5 @@ -// Code generated by protoc-gen-gogo. +// Code generated by protoc-gen-gogo. DO NOT EDIT. // source: protocol.proto -// DO NOT EDIT! /* Package pb is a generated protocol buffer package. @@ -15,6 +14,8 @@ Ack ConnectRequest ConnectResponse + Ping + PingResponse SubscriptionRequest SubscriptionResponse UnsubscribeRequest @@ -35,6 +36,12 @@ var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion2 // please upgrade the proto package + // Enum for start position type. type StartPosition int32 @@ -64,6 +71,7 @@ var StartPosition_value = map[string]int32{ func (x StartPosition) String() string { return proto.EnumName(StartPosition_name, int32(x)) } +func (StartPosition) EnumDescriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{0} } // How messages are delivered to the STAN cluster type PubMsg struct { @@ -72,12 +80,14 @@ type PubMsg struct { Subject string `protobuf:"bytes,3,opt,name=subject,proto3" json:"subject,omitempty"` Reply string `protobuf:"bytes,4,opt,name=reply,proto3" json:"reply,omitempty"` Data []byte `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` + ConnID []byte `protobuf:"bytes,6,opt,name=connID,proto3" json:"connID,omitempty"` Sha256 []byte `protobuf:"bytes,10,opt,name=sha256,proto3" json:"sha256,omitempty"` } -func (m *PubMsg) Reset() { *m = PubMsg{} } -func (m *PubMsg) String() string { return proto.CompactTextString(m) } -func (*PubMsg) ProtoMessage() {} +func (m *PubMsg) Reset() { *m = PubMsg{} } +func (m *PubMsg) String() string { return proto.CompactTextString(m) } +func (*PubMsg) ProtoMessage() {} +func (*PubMsg) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{0} } // Used to ACK to publishers type PubAck struct { @@ -85,9 +95,10 @@ type PubAck struct { Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` } -func (m *PubAck) Reset() { *m = PubAck{} } -func (m *PubAck) String() string { return proto.CompactTextString(m) } -func (*PubAck) ProtoMessage() {} +func (m *PubAck) Reset() { *m = PubAck{} } +func (m *PubAck) String() string { return proto.CompactTextString(m) } +func (*PubAck) ProtoMessage() {} +func (*PubAck) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{1} } // Msg struct. Sequence is assigned for global ordering by // the cluster after the publisher has been acknowledged. @@ -101,9 +112,10 @@ type MsgProto struct { CRC32 uint32 `protobuf:"varint,10,opt,name=CRC32,proto3" json:"CRC32,omitempty"` } -func (m *MsgProto) Reset() { *m = MsgProto{} } -func (m *MsgProto) String() string { return proto.CompactTextString(m) } -func (*MsgProto) ProtoMessage() {} +func (m *MsgProto) Reset() { *m = MsgProto{} } +func (m *MsgProto) String() string { return proto.CompactTextString(m) } +func (*MsgProto) ProtoMessage() {} +func (*MsgProto) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{2} } // Ack will deliver an ack for a delivered msg. type Ack struct { @@ -111,19 +123,25 @@ type Ack struct { Sequence uint64 `protobuf:"varint,2,opt,name=sequence,proto3" json:"sequence,omitempty"` } -func (m *Ack) Reset() { *m = Ack{} } -func (m *Ack) String() string { return proto.CompactTextString(m) } -func (*Ack) ProtoMessage() {} +func (m *Ack) Reset() { *m = Ack{} } +func (m *Ack) String() string { return proto.CompactTextString(m) } +func (*Ack) ProtoMessage() {} +func (*Ack) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{3} } // Connection Request type ConnectRequest struct { ClientID string `protobuf:"bytes,1,opt,name=clientID,proto3" json:"clientID,omitempty"` HeartbeatInbox string `protobuf:"bytes,2,opt,name=heartbeatInbox,proto3" json:"heartbeatInbox,omitempty"` + Protocol int32 `protobuf:"varint,3,opt,name=protocol,proto3" json:"protocol,omitempty"` + ConnID []byte `protobuf:"bytes,4,opt,name=connID,proto3" json:"connID,omitempty"` + PingInterval int32 `protobuf:"varint,5,opt,name=pingInterval,proto3" json:"pingInterval,omitempty"` + PingMaxOut int32 `protobuf:"varint,6,opt,name=pingMaxOut,proto3" json:"pingMaxOut,omitempty"` } -func (m *ConnectRequest) Reset() { *m = ConnectRequest{} } -func (m *ConnectRequest) String() string { return proto.CompactTextString(m) } -func (*ConnectRequest) ProtoMessage() {} +func (m *ConnectRequest) Reset() { *m = ConnectRequest{} } +func (m *ConnectRequest) String() string { return proto.CompactTextString(m) } +func (*ConnectRequest) ProtoMessage() {} +func (*ConnectRequest) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{4} } // Response to a client connect type ConnectResponse struct { @@ -133,12 +151,37 @@ type ConnectResponse struct { CloseRequests string `protobuf:"bytes,4,opt,name=closeRequests,proto3" json:"closeRequests,omitempty"` Error string `protobuf:"bytes,5,opt,name=error,proto3" json:"error,omitempty"` SubCloseRequests string `protobuf:"bytes,6,opt,name=subCloseRequests,proto3" json:"subCloseRequests,omitempty"` + PingRequests string `protobuf:"bytes,7,opt,name=pingRequests,proto3" json:"pingRequests,omitempty"` + PingInterval int32 `protobuf:"varint,8,opt,name=pingInterval,proto3" json:"pingInterval,omitempty"` + PingMaxOut int32 `protobuf:"varint,9,opt,name=pingMaxOut,proto3" json:"pingMaxOut,omitempty"` + Protocol int32 `protobuf:"varint,10,opt,name=protocol,proto3" json:"protocol,omitempty"` PublicKey string `protobuf:"bytes,100,opt,name=publicKey,proto3" json:"publicKey,omitempty"` } -func (m *ConnectResponse) Reset() { *m = ConnectResponse{} } -func (m *ConnectResponse) String() string { return proto.CompactTextString(m) } -func (*ConnectResponse) ProtoMessage() {} +func (m *ConnectResponse) Reset() { *m = ConnectResponse{} } +func (m *ConnectResponse) String() string { return proto.CompactTextString(m) } +func (*ConnectResponse) ProtoMessage() {} +func (*ConnectResponse) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{5} } + +// PING from client to server +type Ping struct { + ConnID []byte `protobuf:"bytes,1,opt,name=connID,proto3" json:"connID,omitempty"` +} + +func (m *Ping) Reset() { *m = Ping{} } +func (m *Ping) String() string { return proto.CompactTextString(m) } +func (*Ping) ProtoMessage() {} +func (*Ping) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{6} } + +// PING response from the server +type PingResponse struct { + Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` +} + +func (m *PingResponse) Reset() { *m = PingResponse{} } +func (m *PingResponse) String() string { return proto.CompactTextString(m) } +func (*PingResponse) ProtoMessage() {} +func (*PingResponse) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{7} } // Protocol for a client to subscribe type SubscriptionRequest struct { @@ -154,9 +197,10 @@ type SubscriptionRequest struct { StartTimeDelta int64 `protobuf:"varint,12,opt,name=startTimeDelta,proto3" json:"startTimeDelta,omitempty"` } -func (m *SubscriptionRequest) Reset() { *m = SubscriptionRequest{} } -func (m *SubscriptionRequest) String() string { return proto.CompactTextString(m) } -func (*SubscriptionRequest) ProtoMessage() {} +func (m *SubscriptionRequest) Reset() { *m = SubscriptionRequest{} } +func (m *SubscriptionRequest) String() string { return proto.CompactTextString(m) } +func (*SubscriptionRequest) ProtoMessage() {} +func (*SubscriptionRequest) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{8} } // Response for SubscriptionRequest and UnsubscribeRequests type SubscriptionResponse struct { @@ -164,9 +208,10 @@ type SubscriptionResponse struct { Error string `protobuf:"bytes,3,opt,name=error,proto3" json:"error,omitempty"` } -func (m *SubscriptionResponse) Reset() { *m = SubscriptionResponse{} } -func (m *SubscriptionResponse) String() string { return proto.CompactTextString(m) } -func (*SubscriptionResponse) ProtoMessage() {} +func (m *SubscriptionResponse) Reset() { *m = SubscriptionResponse{} } +func (m *SubscriptionResponse) String() string { return proto.CompactTextString(m) } +func (*SubscriptionResponse) ProtoMessage() {} +func (*SubscriptionResponse) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{9} } // Protocol for a clients to unsubscribe. Will return a SubscriptionResponse type UnsubscribeRequest struct { @@ -176,27 +221,30 @@ type UnsubscribeRequest struct { DurableName string `protobuf:"bytes,4,opt,name=durableName,proto3" json:"durableName,omitempty"` } -func (m *UnsubscribeRequest) Reset() { *m = UnsubscribeRequest{} } -func (m *UnsubscribeRequest) String() string { return proto.CompactTextString(m) } -func (*UnsubscribeRequest) ProtoMessage() {} +func (m *UnsubscribeRequest) Reset() { *m = UnsubscribeRequest{} } +func (m *UnsubscribeRequest) String() string { return proto.CompactTextString(m) } +func (*UnsubscribeRequest) ProtoMessage() {} +func (*UnsubscribeRequest) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{10} } // Protocol for a client to close a connection type CloseRequest struct { ClientID string `protobuf:"bytes,1,opt,name=clientID,proto3" json:"clientID,omitempty"` } -func (m *CloseRequest) Reset() { *m = CloseRequest{} } -func (m *CloseRequest) String() string { return proto.CompactTextString(m) } -func (*CloseRequest) ProtoMessage() {} +func (m *CloseRequest) Reset() { *m = CloseRequest{} } +func (m *CloseRequest) String() string { return proto.CompactTextString(m) } +func (*CloseRequest) ProtoMessage() {} +func (*CloseRequest) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{11} } // Response for CloseRequest type CloseResponse struct { Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` } -func (m *CloseResponse) Reset() { *m = CloseResponse{} } -func (m *CloseResponse) String() string { return proto.CompactTextString(m) } -func (*CloseResponse) ProtoMessage() {} +func (m *CloseResponse) Reset() { *m = CloseResponse{} } +func (m *CloseResponse) String() string { return proto.CompactTextString(m) } +func (*CloseResponse) ProtoMessage() {} +func (*CloseResponse) Descriptor() ([]byte, []int) { return fileDescriptorProtocol, []int{12} } func init() { proto.RegisterType((*PubMsg)(nil), "pb.PubMsg") @@ -205,6 +253,8 @@ func init() { proto.RegisterType((*Ack)(nil), "pb.Ack") proto.RegisterType((*ConnectRequest)(nil), "pb.ConnectRequest") proto.RegisterType((*ConnectResponse)(nil), "pb.ConnectResponse") + proto.RegisterType((*Ping)(nil), "pb.Ping") + proto.RegisterType((*PingResponse)(nil), "pb.PingResponse") proto.RegisterType((*SubscriptionRequest)(nil), "pb.SubscriptionRequest") proto.RegisterType((*SubscriptionResponse)(nil), "pb.SubscriptionResponse") proto.RegisterType((*UnsubscribeRequest)(nil), "pb.UnsubscribeRequest") @@ -212,496 +262,568 @@ func init() { proto.RegisterType((*CloseResponse)(nil), "pb.CloseResponse") proto.RegisterEnum("pb.StartPosition", StartPosition_name, StartPosition_value) } -func (m *PubMsg) Marshal() (data []byte, err error) { +func (m *PubMsg) Marshal() (dAtA []byte, err error) { size := m.Size() - data = make([]byte, size) - n, err := m.MarshalTo(data) + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } - return data[:n], nil + return dAtA[:n], nil } -func (m *PubMsg) MarshalTo(data []byte) (int, error) { +func (m *PubMsg) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l if len(m.ClientID) > 0 { - data[i] = 0xa + dAtA[i] = 0xa i++ - i = encodeVarintProtocol(data, i, uint64(len(m.ClientID))) - i += copy(data[i:], m.ClientID) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.ClientID))) + i += copy(dAtA[i:], m.ClientID) } if len(m.Guid) > 0 { - data[i] = 0x12 + dAtA[i] = 0x12 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Guid))) - i += copy(data[i:], m.Guid) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Guid))) + i += copy(dAtA[i:], m.Guid) } if len(m.Subject) > 0 { - data[i] = 0x1a + dAtA[i] = 0x1a i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Subject))) - i += copy(data[i:], m.Subject) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Subject))) + i += copy(dAtA[i:], m.Subject) } if len(m.Reply) > 0 { - data[i] = 0x22 + dAtA[i] = 0x22 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Reply))) - i += copy(data[i:], m.Reply) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Reply))) + i += copy(dAtA[i:], m.Reply) } - if m.Data != nil { - if len(m.Data) > 0 { - data[i] = 0x2a - i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Data))) - i += copy(data[i:], m.Data) - } + if len(m.Data) > 0 { + dAtA[i] = 0x2a + i++ + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Data))) + i += copy(dAtA[i:], m.Data) } - if m.Sha256 != nil { - if len(m.Sha256) > 0 { - data[i] = 0x52 - i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Sha256))) - i += copy(data[i:], m.Sha256) - } + if len(m.ConnID) > 0 { + dAtA[i] = 0x32 + i++ + i = encodeVarintProtocol(dAtA, i, uint64(len(m.ConnID))) + i += copy(dAtA[i:], m.ConnID) + } + if len(m.Sha256) > 0 { + dAtA[i] = 0x52 + i++ + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Sha256))) + i += copy(dAtA[i:], m.Sha256) } return i, nil } -func (m *PubAck) Marshal() (data []byte, err error) { +func (m *PubAck) Marshal() (dAtA []byte, err error) { size := m.Size() - data = make([]byte, size) - n, err := m.MarshalTo(data) + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } - return data[:n], nil + return dAtA[:n], nil } -func (m *PubAck) MarshalTo(data []byte) (int, error) { +func (m *PubAck) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l if len(m.Guid) > 0 { - data[i] = 0xa + dAtA[i] = 0xa i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Guid))) - i += copy(data[i:], m.Guid) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Guid))) + i += copy(dAtA[i:], m.Guid) } if len(m.Error) > 0 { - data[i] = 0x12 + dAtA[i] = 0x12 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Error))) - i += copy(data[i:], m.Error) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Error))) + i += copy(dAtA[i:], m.Error) } return i, nil } -func (m *MsgProto) Marshal() (data []byte, err error) { +func (m *MsgProto) Marshal() (dAtA []byte, err error) { size := m.Size() - data = make([]byte, size) - n, err := m.MarshalTo(data) + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } - return data[:n], nil + return dAtA[:n], nil } -func (m *MsgProto) MarshalTo(data []byte) (int, error) { +func (m *MsgProto) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l if m.Sequence != 0 { - data[i] = 0x8 + dAtA[i] = 0x8 i++ - i = encodeVarintProtocol(data, i, uint64(m.Sequence)) + i = encodeVarintProtocol(dAtA, i, uint64(m.Sequence)) } if len(m.Subject) > 0 { - data[i] = 0x12 + dAtA[i] = 0x12 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Subject))) - i += copy(data[i:], m.Subject) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Subject))) + i += copy(dAtA[i:], m.Subject) } if len(m.Reply) > 0 { - data[i] = 0x1a + dAtA[i] = 0x1a i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Reply))) - i += copy(data[i:], m.Reply) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Reply))) + i += copy(dAtA[i:], m.Reply) } - if m.Data != nil { - if len(m.Data) > 0 { - data[i] = 0x22 - i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Data))) - i += copy(data[i:], m.Data) - } + if len(m.Data) > 0 { + dAtA[i] = 0x22 + i++ + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Data))) + i += copy(dAtA[i:], m.Data) } if m.Timestamp != 0 { - data[i] = 0x28 + dAtA[i] = 0x28 i++ - i = encodeVarintProtocol(data, i, uint64(m.Timestamp)) + i = encodeVarintProtocol(dAtA, i, uint64(m.Timestamp)) } if m.Redelivered { - data[i] = 0x30 + dAtA[i] = 0x30 i++ if m.Redelivered { - data[i] = 1 + dAtA[i] = 1 } else { - data[i] = 0 + dAtA[i] = 0 } i++ } if m.CRC32 != 0 { - data[i] = 0x50 + dAtA[i] = 0x50 i++ - i = encodeVarintProtocol(data, i, uint64(m.CRC32)) + i = encodeVarintProtocol(dAtA, i, uint64(m.CRC32)) } return i, nil } -func (m *Ack) Marshal() (data []byte, err error) { +func (m *Ack) Marshal() (dAtA []byte, err error) { size := m.Size() - data = make([]byte, size) - n, err := m.MarshalTo(data) + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } - return data[:n], nil + return dAtA[:n], nil } -func (m *Ack) MarshalTo(data []byte) (int, error) { +func (m *Ack) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l if len(m.Subject) > 0 { - data[i] = 0xa + dAtA[i] = 0xa i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Subject))) - i += copy(data[i:], m.Subject) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Subject))) + i += copy(dAtA[i:], m.Subject) } if m.Sequence != 0 { - data[i] = 0x10 + dAtA[i] = 0x10 i++ - i = encodeVarintProtocol(data, i, uint64(m.Sequence)) + i = encodeVarintProtocol(dAtA, i, uint64(m.Sequence)) } return i, nil } -func (m *ConnectRequest) Marshal() (data []byte, err error) { +func (m *ConnectRequest) Marshal() (dAtA []byte, err error) { size := m.Size() - data = make([]byte, size) - n, err := m.MarshalTo(data) + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } - return data[:n], nil + return dAtA[:n], nil } -func (m *ConnectRequest) MarshalTo(data []byte) (int, error) { +func (m *ConnectRequest) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l if len(m.ClientID) > 0 { - data[i] = 0xa + dAtA[i] = 0xa i++ - i = encodeVarintProtocol(data, i, uint64(len(m.ClientID))) - i += copy(data[i:], m.ClientID) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.ClientID))) + i += copy(dAtA[i:], m.ClientID) } if len(m.HeartbeatInbox) > 0 { - data[i] = 0x12 + dAtA[i] = 0x12 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.HeartbeatInbox))) - i += copy(data[i:], m.HeartbeatInbox) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.HeartbeatInbox))) + i += copy(dAtA[i:], m.HeartbeatInbox) + } + if m.Protocol != 0 { + dAtA[i] = 0x18 + i++ + i = encodeVarintProtocol(dAtA, i, uint64(m.Protocol)) + } + if len(m.ConnID) > 0 { + dAtA[i] = 0x22 + i++ + i = encodeVarintProtocol(dAtA, i, uint64(len(m.ConnID))) + i += copy(dAtA[i:], m.ConnID) + } + if m.PingInterval != 0 { + dAtA[i] = 0x28 + i++ + i = encodeVarintProtocol(dAtA, i, uint64(m.PingInterval)) + } + if m.PingMaxOut != 0 { + dAtA[i] = 0x30 + i++ + i = encodeVarintProtocol(dAtA, i, uint64(m.PingMaxOut)) } return i, nil } -func (m *ConnectResponse) Marshal() (data []byte, err error) { +func (m *ConnectResponse) Marshal() (dAtA []byte, err error) { size := m.Size() - data = make([]byte, size) - n, err := m.MarshalTo(data) + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } - return data[:n], nil + return dAtA[:n], nil } -func (m *ConnectResponse) MarshalTo(data []byte) (int, error) { +func (m *ConnectResponse) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l if len(m.PubPrefix) > 0 { - data[i] = 0xa + dAtA[i] = 0xa i++ - i = encodeVarintProtocol(data, i, uint64(len(m.PubPrefix))) - i += copy(data[i:], m.PubPrefix) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.PubPrefix))) + i += copy(dAtA[i:], m.PubPrefix) } if len(m.SubRequests) > 0 { - data[i] = 0x12 + dAtA[i] = 0x12 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.SubRequests))) - i += copy(data[i:], m.SubRequests) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.SubRequests))) + i += copy(dAtA[i:], m.SubRequests) } if len(m.UnsubRequests) > 0 { - data[i] = 0x1a + dAtA[i] = 0x1a i++ - i = encodeVarintProtocol(data, i, uint64(len(m.UnsubRequests))) - i += copy(data[i:], m.UnsubRequests) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.UnsubRequests))) + i += copy(dAtA[i:], m.UnsubRequests) } if len(m.CloseRequests) > 0 { - data[i] = 0x22 + dAtA[i] = 0x22 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.CloseRequests))) - i += copy(data[i:], m.CloseRequests) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.CloseRequests))) + i += copy(dAtA[i:], m.CloseRequests) } if len(m.Error) > 0 { - data[i] = 0x2a + dAtA[i] = 0x2a i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Error))) - i += copy(data[i:], m.Error) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Error))) + i += copy(dAtA[i:], m.Error) } if len(m.SubCloseRequests) > 0 { - data[i] = 0x32 + dAtA[i] = 0x32 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.SubCloseRequests))) - i += copy(data[i:], m.SubCloseRequests) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.SubCloseRequests))) + i += copy(dAtA[i:], m.SubCloseRequests) + } + if len(m.PingRequests) > 0 { + dAtA[i] = 0x3a + i++ + i = encodeVarintProtocol(dAtA, i, uint64(len(m.PingRequests))) + i += copy(dAtA[i:], m.PingRequests) + } + if m.PingInterval != 0 { + dAtA[i] = 0x40 + i++ + i = encodeVarintProtocol(dAtA, i, uint64(m.PingInterval)) + } + if m.PingMaxOut != 0 { + dAtA[i] = 0x48 + i++ + i = encodeVarintProtocol(dAtA, i, uint64(m.PingMaxOut)) + } + if m.Protocol != 0 { + dAtA[i] = 0x50 + i++ + i = encodeVarintProtocol(dAtA, i, uint64(m.Protocol)) } if len(m.PublicKey) > 0 { - data[i] = 0xa2 + dAtA[i] = 0xa2 i++ - data[i] = 0x6 + dAtA[i] = 0x6 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.PublicKey))) - i += copy(data[i:], m.PublicKey) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.PublicKey))) + i += copy(dAtA[i:], m.PublicKey) } return i, nil } -func (m *SubscriptionRequest) Marshal() (data []byte, err error) { +func (m *Ping) Marshal() (dAtA []byte, err error) { size := m.Size() - data = make([]byte, size) - n, err := m.MarshalTo(data) + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } - return data[:n], nil + return dAtA[:n], nil } -func (m *SubscriptionRequest) MarshalTo(data []byte) (int, error) { +func (m *Ping) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.ConnID) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintProtocol(dAtA, i, uint64(len(m.ConnID))) + i += copy(dAtA[i:], m.ConnID) + } + return i, nil +} + +func (m *PingResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *PingResponse) MarshalTo(dAtA []byte) (int, error) { + var i int + _ = i + var l int + _ = l + if len(m.Error) > 0 { + dAtA[i] = 0xa + i++ + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Error))) + i += copy(dAtA[i:], m.Error) + } + return i, nil +} + +func (m *SubscriptionRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *SubscriptionRequest) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l if len(m.ClientID) > 0 { - data[i] = 0xa + dAtA[i] = 0xa i++ - i = encodeVarintProtocol(data, i, uint64(len(m.ClientID))) - i += copy(data[i:], m.ClientID) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.ClientID))) + i += copy(dAtA[i:], m.ClientID) } if len(m.Subject) > 0 { - data[i] = 0x12 + dAtA[i] = 0x12 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Subject))) - i += copy(data[i:], m.Subject) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Subject))) + i += copy(dAtA[i:], m.Subject) } if len(m.QGroup) > 0 { - data[i] = 0x1a + dAtA[i] = 0x1a i++ - i = encodeVarintProtocol(data, i, uint64(len(m.QGroup))) - i += copy(data[i:], m.QGroup) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.QGroup))) + i += copy(dAtA[i:], m.QGroup) } if len(m.Inbox) > 0 { - data[i] = 0x22 + dAtA[i] = 0x22 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Inbox))) - i += copy(data[i:], m.Inbox) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Inbox))) + i += copy(dAtA[i:], m.Inbox) } if m.MaxInFlight != 0 { - data[i] = 0x28 + dAtA[i] = 0x28 i++ - i = encodeVarintProtocol(data, i, uint64(m.MaxInFlight)) + i = encodeVarintProtocol(dAtA, i, uint64(m.MaxInFlight)) } if m.AckWaitInSecs != 0 { - data[i] = 0x30 + dAtA[i] = 0x30 i++ - i = encodeVarintProtocol(data, i, uint64(m.AckWaitInSecs)) + i = encodeVarintProtocol(dAtA, i, uint64(m.AckWaitInSecs)) } if len(m.DurableName) > 0 { - data[i] = 0x3a + dAtA[i] = 0x3a i++ - i = encodeVarintProtocol(data, i, uint64(len(m.DurableName))) - i += copy(data[i:], m.DurableName) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.DurableName))) + i += copy(dAtA[i:], m.DurableName) } if m.StartPosition != 0 { - data[i] = 0x50 + dAtA[i] = 0x50 i++ - i = encodeVarintProtocol(data, i, uint64(m.StartPosition)) + i = encodeVarintProtocol(dAtA, i, uint64(m.StartPosition)) } if m.StartSequence != 0 { - data[i] = 0x58 + dAtA[i] = 0x58 i++ - i = encodeVarintProtocol(data, i, uint64(m.StartSequence)) + i = encodeVarintProtocol(dAtA, i, uint64(m.StartSequence)) } if m.StartTimeDelta != 0 { - data[i] = 0x60 + dAtA[i] = 0x60 i++ - i = encodeVarintProtocol(data, i, uint64(m.StartTimeDelta)) + i = encodeVarintProtocol(dAtA, i, uint64(m.StartTimeDelta)) } return i, nil } -func (m *SubscriptionResponse) Marshal() (data []byte, err error) { +func (m *SubscriptionResponse) Marshal() (dAtA []byte, err error) { size := m.Size() - data = make([]byte, size) - n, err := m.MarshalTo(data) + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } - return data[:n], nil + return dAtA[:n], nil } -func (m *SubscriptionResponse) MarshalTo(data []byte) (int, error) { +func (m *SubscriptionResponse) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l if len(m.AckInbox) > 0 { - data[i] = 0x12 + dAtA[i] = 0x12 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.AckInbox))) - i += copy(data[i:], m.AckInbox) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.AckInbox))) + i += copy(dAtA[i:], m.AckInbox) } if len(m.Error) > 0 { - data[i] = 0x1a + dAtA[i] = 0x1a i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Error))) - i += copy(data[i:], m.Error) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Error))) + i += copy(dAtA[i:], m.Error) } return i, nil } -func (m *UnsubscribeRequest) Marshal() (data []byte, err error) { +func (m *UnsubscribeRequest) Marshal() (dAtA []byte, err error) { size := m.Size() - data = make([]byte, size) - n, err := m.MarshalTo(data) + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } - return data[:n], nil + return dAtA[:n], nil } -func (m *UnsubscribeRequest) MarshalTo(data []byte) (int, error) { +func (m *UnsubscribeRequest) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l if len(m.ClientID) > 0 { - data[i] = 0xa + dAtA[i] = 0xa i++ - i = encodeVarintProtocol(data, i, uint64(len(m.ClientID))) - i += copy(data[i:], m.ClientID) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.ClientID))) + i += copy(dAtA[i:], m.ClientID) } if len(m.Subject) > 0 { - data[i] = 0x12 + dAtA[i] = 0x12 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Subject))) - i += copy(data[i:], m.Subject) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Subject))) + i += copy(dAtA[i:], m.Subject) } if len(m.Inbox) > 0 { - data[i] = 0x1a + dAtA[i] = 0x1a i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Inbox))) - i += copy(data[i:], m.Inbox) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Inbox))) + i += copy(dAtA[i:], m.Inbox) } if len(m.DurableName) > 0 { - data[i] = 0x22 + dAtA[i] = 0x22 i++ - i = encodeVarintProtocol(data, i, uint64(len(m.DurableName))) - i += copy(data[i:], m.DurableName) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.DurableName))) + i += copy(dAtA[i:], m.DurableName) } return i, nil } -func (m *CloseRequest) Marshal() (data []byte, err error) { +func (m *CloseRequest) Marshal() (dAtA []byte, err error) { size := m.Size() - data = make([]byte, size) - n, err := m.MarshalTo(data) + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } - return data[:n], nil + return dAtA[:n], nil } -func (m *CloseRequest) MarshalTo(data []byte) (int, error) { +func (m *CloseRequest) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l if len(m.ClientID) > 0 { - data[i] = 0xa + dAtA[i] = 0xa i++ - i = encodeVarintProtocol(data, i, uint64(len(m.ClientID))) - i += copy(data[i:], m.ClientID) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.ClientID))) + i += copy(dAtA[i:], m.ClientID) } return i, nil } -func (m *CloseResponse) Marshal() (data []byte, err error) { +func (m *CloseResponse) Marshal() (dAtA []byte, err error) { size := m.Size() - data = make([]byte, size) - n, err := m.MarshalTo(data) + dAtA = make([]byte, size) + n, err := m.MarshalTo(dAtA) if err != nil { return nil, err } - return data[:n], nil + return dAtA[:n], nil } -func (m *CloseResponse) MarshalTo(data []byte) (int, error) { +func (m *CloseResponse) MarshalTo(dAtA []byte) (int, error) { var i int _ = i var l int _ = l if len(m.Error) > 0 { - data[i] = 0xa + dAtA[i] = 0xa i++ - i = encodeVarintProtocol(data, i, uint64(len(m.Error))) - i += copy(data[i:], m.Error) + i = encodeVarintProtocol(dAtA, i, uint64(len(m.Error))) + i += copy(dAtA[i:], m.Error) } return i, nil } -func encodeFixed64Protocol(data []byte, offset int, v uint64) int { - data[offset] = uint8(v) - data[offset+1] = uint8(v >> 8) - data[offset+2] = uint8(v >> 16) - data[offset+3] = uint8(v >> 24) - data[offset+4] = uint8(v >> 32) - data[offset+5] = uint8(v >> 40) - data[offset+6] = uint8(v >> 48) - data[offset+7] = uint8(v >> 56) - return offset + 8 -} -func encodeFixed32Protocol(data []byte, offset int, v uint32) int { - data[offset] = uint8(v) - data[offset+1] = uint8(v >> 8) - data[offset+2] = uint8(v >> 16) - data[offset+3] = uint8(v >> 24) - return offset + 4 -} -func encodeVarintProtocol(data []byte, offset int, v uint64) int { +func encodeVarintProtocol(dAtA []byte, offset int, v uint64) int { for v >= 1<<7 { - data[offset] = uint8(v&0x7f | 0x80) + dAtA[offset] = uint8(v&0x7f | 0x80) v >>= 7 offset++ } - data[offset] = uint8(v) + dAtA[offset] = uint8(v) return offset + 1 } func (m *PubMsg) Size() (n int) { @@ -723,17 +845,17 @@ func (m *PubMsg) Size() (n int) { if l > 0 { n += 1 + l + sovProtocol(uint64(l)) } - if m.Data != nil { - l = len(m.Data) - if l > 0 { - n += 1 + l + sovProtocol(uint64(l)) - } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovProtocol(uint64(l)) } - if m.Sha256 != nil { - l = len(m.Sha256) - if l > 0 { - n += 1 + l + sovProtocol(uint64(l)) - } + l = len(m.ConnID) + if l > 0 { + n += 1 + l + sovProtocol(uint64(l)) + } + l = len(m.Sha256) + if l > 0 { + n += 1 + l + sovProtocol(uint64(l)) } return n } @@ -766,11 +888,9 @@ func (m *MsgProto) Size() (n int) { if l > 0 { n += 1 + l + sovProtocol(uint64(l)) } - if m.Data != nil { - l = len(m.Data) - if l > 0 { - n += 1 + l + sovProtocol(uint64(l)) - } + l = len(m.Data) + if l > 0 { + n += 1 + l + sovProtocol(uint64(l)) } if m.Timestamp != 0 { n += 1 + sovProtocol(uint64(m.Timestamp)) @@ -808,6 +928,19 @@ func (m *ConnectRequest) Size() (n int) { if l > 0 { n += 1 + l + sovProtocol(uint64(l)) } + if m.Protocol != 0 { + n += 1 + sovProtocol(uint64(m.Protocol)) + } + l = len(m.ConnID) + if l > 0 { + n += 1 + l + sovProtocol(uint64(l)) + } + if m.PingInterval != 0 { + n += 1 + sovProtocol(uint64(m.PingInterval)) + } + if m.PingMaxOut != 0 { + n += 1 + sovProtocol(uint64(m.PingMaxOut)) + } return n } @@ -838,6 +971,19 @@ func (m *ConnectResponse) Size() (n int) { if l > 0 { n += 1 + l + sovProtocol(uint64(l)) } + l = len(m.PingRequests) + if l > 0 { + n += 1 + l + sovProtocol(uint64(l)) + } + if m.PingInterval != 0 { + n += 1 + sovProtocol(uint64(m.PingInterval)) + } + if m.PingMaxOut != 0 { + n += 1 + sovProtocol(uint64(m.PingMaxOut)) + } + if m.Protocol != 0 { + n += 1 + sovProtocol(uint64(m.Protocol)) + } l = len(m.PublicKey) if l > 0 { n += 2 + l + sovProtocol(uint64(l)) @@ -845,6 +991,26 @@ func (m *ConnectResponse) Size() (n int) { return n } +func (m *Ping) Size() (n int) { + var l int + _ = l + l = len(m.ConnID) + if l > 0 { + n += 1 + l + sovProtocol(uint64(l)) + } + return n +} + +func (m *PingResponse) Size() (n int) { + var l int + _ = l + l = len(m.Error) + if l > 0 { + n += 1 + l + sovProtocol(uint64(l)) + } + return n +} + func (m *SubscriptionRequest) Size() (n int) { var l int _ = l @@ -955,8 +1121,8 @@ func sovProtocol(x uint64) (n int) { func sozProtocol(x uint64) (n int) { return sovProtocol(uint64((x << 1) ^ uint64((int64(x) >> 63)))) } -func (m *PubMsg) Unmarshal(data []byte) error { - l := len(data) +func (m *PubMsg) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -968,7 +1134,7 @@ func (m *PubMsg) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -996,7 +1162,7 @@ func (m *PubMsg) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1011,7 +1177,7 @@ func (m *PubMsg) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ClientID = string(data[iNdEx:postIndex]) + m.ClientID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { @@ -1025,7 +1191,7 @@ func (m *PubMsg) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1040,7 +1206,7 @@ func (m *PubMsg) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Guid = string(data[iNdEx:postIndex]) + m.Guid = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { @@ -1054,7 +1220,7 @@ func (m *PubMsg) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1069,7 +1235,7 @@ func (m *PubMsg) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Subject = string(data[iNdEx:postIndex]) + m.Subject = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 2 { @@ -1083,7 +1249,7 @@ func (m *PubMsg) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1098,7 +1264,7 @@ func (m *PubMsg) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Reply = string(data[iNdEx:postIndex]) + m.Reply = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 5: if wireType != 2 { @@ -1112,7 +1278,7 @@ func (m *PubMsg) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ byteLen |= (int(b) & 0x7F) << shift if b < 0x80 { @@ -1126,11 +1292,42 @@ func (m *PubMsg) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Data = append(m.Data[:0], data[iNdEx:postIndex]...) + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) if m.Data == nil { m.Data = []byte{} } iNdEx = postIndex + case 6: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnID", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProtocol + } + postIndex := iNdEx + byteLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConnID = append(m.ConnID[:0], dAtA[iNdEx:postIndex]...) + if m.ConnID == nil { + m.ConnID = []byte{} + } + iNdEx = postIndex case 10: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field Sha256", wireType) @@ -1143,7 +1340,7 @@ func (m *PubMsg) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ byteLen |= (int(b) & 0x7F) << shift if b < 0x80 { @@ -1157,14 +1354,14 @@ func (m *PubMsg) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Sha256 = append(m.Sha256[:0], data[iNdEx:postIndex]...) + m.Sha256 = append(m.Sha256[:0], dAtA[iNdEx:postIndex]...) if m.Sha256 == nil { m.Sha256 = []byte{} } iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipProtocol(data[iNdEx:]) + skippy, err := skipProtocol(dAtA[iNdEx:]) if err != nil { return err } @@ -1183,8 +1380,8 @@ func (m *PubMsg) Unmarshal(data []byte) error { } return nil } -func (m *PubAck) Unmarshal(data []byte) error { - l := len(data) +func (m *PubAck) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -1196,7 +1393,7 @@ func (m *PubAck) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1224,7 +1421,7 @@ func (m *PubAck) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1239,7 +1436,7 @@ func (m *PubAck) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Guid = string(data[iNdEx:postIndex]) + m.Guid = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { @@ -1253,7 +1450,7 @@ func (m *PubAck) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1268,11 +1465,11 @@ func (m *PubAck) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Error = string(data[iNdEx:postIndex]) + m.Error = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipProtocol(data[iNdEx:]) + skippy, err := skipProtocol(dAtA[iNdEx:]) if err != nil { return err } @@ -1291,8 +1488,8 @@ func (m *PubAck) Unmarshal(data []byte) error { } return nil } -func (m *MsgProto) Unmarshal(data []byte) error { - l := len(data) +func (m *MsgProto) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -1304,7 +1501,7 @@ func (m *MsgProto) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1332,7 +1529,7 @@ func (m *MsgProto) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ m.Sequence |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1351,7 +1548,7 @@ func (m *MsgProto) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1366,7 +1563,7 @@ func (m *MsgProto) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Subject = string(data[iNdEx:postIndex]) + m.Subject = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { @@ -1380,7 +1577,7 @@ func (m *MsgProto) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1395,7 +1592,7 @@ func (m *MsgProto) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Reply = string(data[iNdEx:postIndex]) + m.Reply = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 2 { @@ -1409,7 +1606,7 @@ func (m *MsgProto) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ byteLen |= (int(b) & 0x7F) << shift if b < 0x80 { @@ -1423,7 +1620,7 @@ func (m *MsgProto) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Data = append(m.Data[:0], data[iNdEx:postIndex]...) + m.Data = append(m.Data[:0], dAtA[iNdEx:postIndex]...) if m.Data == nil { m.Data = []byte{} } @@ -1440,7 +1637,7 @@ func (m *MsgProto) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ m.Timestamp |= (int64(b) & 0x7F) << shift if b < 0x80 { @@ -1459,7 +1656,7 @@ func (m *MsgProto) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ v |= (int(b) & 0x7F) << shift if b < 0x80 { @@ -1479,7 +1676,7 @@ func (m *MsgProto) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ m.CRC32 |= (uint32(b) & 0x7F) << shift if b < 0x80 { @@ -1488,7 +1685,7 @@ func (m *MsgProto) Unmarshal(data []byte) error { } default: iNdEx = preIndex - skippy, err := skipProtocol(data[iNdEx:]) + skippy, err := skipProtocol(dAtA[iNdEx:]) if err != nil { return err } @@ -1507,8 +1704,8 @@ func (m *MsgProto) Unmarshal(data []byte) error { } return nil } -func (m *Ack) Unmarshal(data []byte) error { - l := len(data) +func (m *Ack) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -1520,7 +1717,7 @@ func (m *Ack) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1548,7 +1745,7 @@ func (m *Ack) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1563,7 +1760,7 @@ func (m *Ack) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Subject = string(data[iNdEx:postIndex]) + m.Subject = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 0 { @@ -1577,7 +1774,7 @@ func (m *Ack) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ m.Sequence |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1586,7 +1783,7 @@ func (m *Ack) Unmarshal(data []byte) error { } default: iNdEx = preIndex - skippy, err := skipProtocol(data[iNdEx:]) + skippy, err := skipProtocol(dAtA[iNdEx:]) if err != nil { return err } @@ -1605,8 +1802,8 @@ func (m *Ack) Unmarshal(data []byte) error { } return nil } -func (m *ConnectRequest) Unmarshal(data []byte) error { - l := len(data) +func (m *ConnectRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -1618,7 +1815,7 @@ func (m *ConnectRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1646,7 +1843,7 @@ func (m *ConnectRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1661,7 +1858,7 @@ func (m *ConnectRequest) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ClientID = string(data[iNdEx:postIndex]) + m.ClientID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { @@ -1675,7 +1872,7 @@ func (m *ConnectRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1690,11 +1887,99 @@ func (m *ConnectRequest) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.HeartbeatInbox = string(data[iNdEx:postIndex]) + m.HeartbeatInbox = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 3: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Protocol", wireType) + } + m.Protocol = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Protocol |= (int32(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + case 4: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnID", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProtocol + } + postIndex := iNdEx + byteLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConnID = append(m.ConnID[:0], dAtA[iNdEx:postIndex]...) + if m.ConnID == nil { + m.ConnID = []byte{} + } + iNdEx = postIndex + case 5: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PingInterval", wireType) + } + m.PingInterval = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PingInterval |= (int32(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + case 6: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PingMaxOut", wireType) + } + m.PingMaxOut = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PingMaxOut |= (int32(b) & 0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex - skippy, err := skipProtocol(data[iNdEx:]) + skippy, err := skipProtocol(dAtA[iNdEx:]) if err != nil { return err } @@ -1713,8 +1998,8 @@ func (m *ConnectRequest) Unmarshal(data []byte) error { } return nil } -func (m *ConnectResponse) Unmarshal(data []byte) error { - l := len(data) +func (m *ConnectResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -1726,7 +2011,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1754,7 +2039,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1769,7 +2054,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.PubPrefix = string(data[iNdEx:postIndex]) + m.PubPrefix = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { @@ -1783,7 +2068,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1798,7 +2083,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.SubRequests = string(data[iNdEx:postIndex]) + m.SubRequests = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { @@ -1812,7 +2097,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1827,7 +2112,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.UnsubRequests = string(data[iNdEx:postIndex]) + m.UnsubRequests = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 2 { @@ -1841,7 +2126,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1856,7 +2141,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.CloseRequests = string(data[iNdEx:postIndex]) + m.CloseRequests = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 5: if wireType != 2 { @@ -1870,7 +2155,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1885,7 +2170,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Error = string(data[iNdEx:postIndex]) + m.Error = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 6: if wireType != 2 { @@ -1899,7 +2184,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1914,8 +2199,94 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.SubCloseRequests = string(data[iNdEx:postIndex]) + m.SubCloseRequests = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex + case 7: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field PingRequests", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthProtocol + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.PingRequests = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 8: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PingInterval", wireType) + } + m.PingInterval = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PingInterval |= (int32(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + case 9: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field PingMaxOut", wireType) + } + m.PingMaxOut = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.PingMaxOut |= (int32(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + case 10: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field Protocol", wireType) + } + m.Protocol = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.Protocol |= (int32(b) & 0x7F) << shift + if b < 0x80 { + break + } + } case 100: if wireType != 2 { return fmt.Errorf("proto: wrong wireType = %d for field PublicKey", wireType) @@ -1928,7 +2299,7 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -1943,11 +2314,11 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.PublicKey = string(data[iNdEx:postIndex]) + m.PublicKey = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipProtocol(data[iNdEx:]) + skippy, err := skipProtocol(dAtA[iNdEx:]) if err != nil { return err } @@ -1966,8 +2337,8 @@ func (m *ConnectResponse) Unmarshal(data []byte) error { } return nil } -func (m *SubscriptionRequest) Unmarshal(data []byte) error { - l := len(data) +func (m *Ping) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -1979,7 +2350,167 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: Ping: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: Ping: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConnID", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProtocol + } + postIndex := iNdEx + byteLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConnID = append(m.ConnID[:0], dAtA[iNdEx:postIndex]...) + if m.ConnID == nil { + m.ConnID = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProtocol(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProtocol + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *PingResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: PingResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: PingResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Error", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthProtocol + } + postIndex := iNdEx + intStringLen + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Error = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProtocol(dAtA[iNdEx:]) + if err != nil { + return err + } + if skippy < 0 { + return ErrInvalidLengthProtocol + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *SubscriptionRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProtocol + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2007,7 +2538,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2022,7 +2553,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ClientID = string(data[iNdEx:postIndex]) + m.ClientID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { @@ -2036,7 +2567,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2051,7 +2582,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Subject = string(data[iNdEx:postIndex]) + m.Subject = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { @@ -2065,7 +2596,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2080,7 +2611,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.QGroup = string(data[iNdEx:postIndex]) + m.QGroup = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 2 { @@ -2094,7 +2625,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2109,7 +2640,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Inbox = string(data[iNdEx:postIndex]) + m.Inbox = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 5: if wireType != 0 { @@ -2123,7 +2654,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ m.MaxInFlight |= (int32(b) & 0x7F) << shift if b < 0x80 { @@ -2142,7 +2673,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ m.AckWaitInSecs |= (int32(b) & 0x7F) << shift if b < 0x80 { @@ -2161,7 +2692,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2176,7 +2707,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.DurableName = string(data[iNdEx:postIndex]) + m.DurableName = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 10: if wireType != 0 { @@ -2190,7 +2721,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ m.StartPosition |= (StartPosition(b) & 0x7F) << shift if b < 0x80 { @@ -2209,7 +2740,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ m.StartSequence |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2228,7 +2759,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ m.StartTimeDelta |= (int64(b) & 0x7F) << shift if b < 0x80 { @@ -2237,7 +2768,7 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { } default: iNdEx = preIndex - skippy, err := skipProtocol(data[iNdEx:]) + skippy, err := skipProtocol(dAtA[iNdEx:]) if err != nil { return err } @@ -2256,8 +2787,8 @@ func (m *SubscriptionRequest) Unmarshal(data []byte) error { } return nil } -func (m *SubscriptionResponse) Unmarshal(data []byte) error { - l := len(data) +func (m *SubscriptionResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -2269,7 +2800,7 @@ func (m *SubscriptionResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2297,7 +2828,7 @@ func (m *SubscriptionResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2312,7 +2843,7 @@ func (m *SubscriptionResponse) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.AckInbox = string(data[iNdEx:postIndex]) + m.AckInbox = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { @@ -2326,7 +2857,7 @@ func (m *SubscriptionResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2341,11 +2872,11 @@ func (m *SubscriptionResponse) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Error = string(data[iNdEx:postIndex]) + m.Error = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipProtocol(data[iNdEx:]) + skippy, err := skipProtocol(dAtA[iNdEx:]) if err != nil { return err } @@ -2364,8 +2895,8 @@ func (m *SubscriptionResponse) Unmarshal(data []byte) error { } return nil } -func (m *UnsubscribeRequest) Unmarshal(data []byte) error { - l := len(data) +func (m *UnsubscribeRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -2377,7 +2908,7 @@ func (m *UnsubscribeRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2405,7 +2936,7 @@ func (m *UnsubscribeRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2420,7 +2951,7 @@ func (m *UnsubscribeRequest) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ClientID = string(data[iNdEx:postIndex]) + m.ClientID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 2: if wireType != 2 { @@ -2434,7 +2965,7 @@ func (m *UnsubscribeRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2449,7 +2980,7 @@ func (m *UnsubscribeRequest) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Subject = string(data[iNdEx:postIndex]) + m.Subject = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 3: if wireType != 2 { @@ -2463,7 +2994,7 @@ func (m *UnsubscribeRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2478,7 +3009,7 @@ func (m *UnsubscribeRequest) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Inbox = string(data[iNdEx:postIndex]) + m.Inbox = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex case 4: if wireType != 2 { @@ -2492,7 +3023,7 @@ func (m *UnsubscribeRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2507,11 +3038,11 @@ func (m *UnsubscribeRequest) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.DurableName = string(data[iNdEx:postIndex]) + m.DurableName = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipProtocol(data[iNdEx:]) + skippy, err := skipProtocol(dAtA[iNdEx:]) if err != nil { return err } @@ -2530,8 +3061,8 @@ func (m *UnsubscribeRequest) Unmarshal(data []byte) error { } return nil } -func (m *CloseRequest) Unmarshal(data []byte) error { - l := len(data) +func (m *CloseRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -2543,7 +3074,7 @@ func (m *CloseRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2571,7 +3102,7 @@ func (m *CloseRequest) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2586,11 +3117,11 @@ func (m *CloseRequest) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.ClientID = string(data[iNdEx:postIndex]) + m.ClientID = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipProtocol(data[iNdEx:]) + skippy, err := skipProtocol(dAtA[iNdEx:]) if err != nil { return err } @@ -2609,8 +3140,8 @@ func (m *CloseRequest) Unmarshal(data []byte) error { } return nil } -func (m *CloseResponse) Unmarshal(data []byte) error { - l := len(data) +func (m *CloseResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) iNdEx := 0 for iNdEx < l { preIndex := iNdEx @@ -2622,7 +3153,7 @@ func (m *CloseResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2650,7 +3181,7 @@ func (m *CloseResponse) Unmarshal(data []byte) error { if iNdEx >= l { return io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ stringLen |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2665,11 +3196,11 @@ func (m *CloseResponse) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Error = string(data[iNdEx:postIndex]) + m.Error = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex default: iNdEx = preIndex - skippy, err := skipProtocol(data[iNdEx:]) + skippy, err := skipProtocol(dAtA[iNdEx:]) if err != nil { return err } @@ -2688,8 +3219,8 @@ func (m *CloseResponse) Unmarshal(data []byte) error { } return nil } -func skipProtocol(data []byte) (n int, err error) { - l := len(data) +func skipProtocol(dAtA []byte) (n int, err error) { + l := len(dAtA) iNdEx := 0 for iNdEx < l { var wire uint64 @@ -2700,7 +3231,7 @@ func skipProtocol(data []byte) (n int, err error) { if iNdEx >= l { return 0, io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ wire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2718,7 +3249,7 @@ func skipProtocol(data []byte) (n int, err error) { return 0, io.ErrUnexpectedEOF } iNdEx++ - if data[iNdEx-1] < 0x80 { + if dAtA[iNdEx-1] < 0x80 { break } } @@ -2735,7 +3266,7 @@ func skipProtocol(data []byte) (n int, err error) { if iNdEx >= l { return 0, io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ length |= (int(b) & 0x7F) << shift if b < 0x80 { @@ -2758,7 +3289,7 @@ func skipProtocol(data []byte) (n int, err error) { if iNdEx >= l { return 0, io.ErrUnexpectedEOF } - b := data[iNdEx] + b := dAtA[iNdEx] iNdEx++ innerWire |= (uint64(b) & 0x7F) << shift if b < 0x80 { @@ -2769,7 +3300,7 @@ func skipProtocol(data []byte) (n int, err error) { if innerWireType == 4 { break } - next, err := skipProtocol(data[start:]) + next, err := skipProtocol(dAtA[start:]) if err != nil { return 0, err } @@ -2792,3 +3323,61 @@ var ( ErrInvalidLengthProtocol = fmt.Errorf("proto: negative length found during unmarshaling") ErrIntOverflowProtocol = fmt.Errorf("proto: integer overflow") ) + +func init() { proto.RegisterFile("protocol.proto", fileDescriptorProtocol) } + +var fileDescriptorProtocol = []byte{ + // 823 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xc1, 0x8e, 0xe3, 0x44, + 0x10, 0x1d, 0xc7, 0x76, 0x26, 0x53, 0x93, 0x84, 0x6c, 0x13, 0xad, 0xac, 0x08, 0x45, 0x23, 0x6b, + 0x41, 0xab, 0x91, 0xc8, 0x4a, 0x59, 0x01, 0x07, 0x4e, 0x90, 0xd1, 0x42, 0x04, 0xb3, 0x1b, 0x39, + 0x20, 0xae, 0xb4, 0x9d, 0x5e, 0xa7, 0x19, 0xa7, 0xed, 0x75, 0xb7, 0x87, 0xcc, 0x11, 0xbe, 0x80, + 0x0f, 0xe1, 0x23, 0x38, 0xee, 0x81, 0x03, 0x9f, 0x00, 0xc3, 0x8d, 0xaf, 0x40, 0x5d, 0x76, 0x9c, + 0x76, 0x86, 0x1d, 0x90, 0xb8, 0xf5, 0x7b, 0xa9, 0x6e, 0xd7, 0x7b, 0xaf, 0x2a, 0xd0, 0xcf, 0xf2, + 0x54, 0xa5, 0x51, 0x9a, 0x4c, 0xf0, 0x40, 0x5a, 0x59, 0x38, 0x7a, 0x3f, 0xe6, 0x6a, 0x5d, 0x84, + 0x93, 0x28, 0xdd, 0x3c, 0x89, 0xd3, 0x38, 0x7d, 0x82, 0x3f, 0x85, 0xc5, 0x4b, 0x44, 0x08, 0xf0, + 0x54, 0x5e, 0xf1, 0x7f, 0xb6, 0xa0, 0xbd, 0x28, 0xc2, 0x4b, 0x19, 0x93, 0x11, 0x74, 0xa2, 0x84, + 0x33, 0xa1, 0xe6, 0x17, 0x9e, 0x75, 0x66, 0x3d, 0x3e, 0x09, 0x6a, 0x4c, 0x08, 0x38, 0x71, 0xc1, + 0x57, 0x5e, 0x0b, 0x79, 0x3c, 0x13, 0x0f, 0x8e, 0x65, 0x11, 0x7e, 0xc7, 0x22, 0xe5, 0xd9, 0x48, + 0xef, 0x20, 0x19, 0x82, 0x9b, 0xb3, 0x2c, 0xb9, 0xf1, 0x1c, 0xe4, 0x4b, 0xa0, 0xdf, 0x58, 0x51, + 0x45, 0x3d, 0xf7, 0xcc, 0x7a, 0xdc, 0x0d, 0xf0, 0x4c, 0x1e, 0x42, 0x3b, 0x4a, 0x85, 0x98, 0x5f, + 0x78, 0x6d, 0x64, 0x2b, 0xa4, 0x79, 0xb9, 0xa6, 0xd3, 0x0f, 0x3e, 0xf4, 0xa0, 0xe4, 0x4b, 0xe4, + 0x4f, 0xb1, 0xdb, 0x4f, 0xa2, 0xab, 0xba, 0x23, 0xcb, 0xe8, 0x68, 0x08, 0x2e, 0xcb, 0xf3, 0x34, + 0xaf, 0xda, 0x2c, 0x81, 0xff, 0x8b, 0x05, 0x9d, 0x4b, 0x19, 0x2f, 0xd0, 0xa2, 0x11, 0x74, 0x24, + 0x7b, 0x55, 0x30, 0x11, 0x31, 0xbc, 0xea, 0x04, 0x35, 0x36, 0x05, 0xb5, 0xde, 0x20, 0xc8, 0xfe, + 0x27, 0x41, 0x8e, 0x21, 0xe8, 0x1d, 0x38, 0x51, 0x7c, 0xc3, 0xa4, 0xa2, 0x9b, 0x0c, 0x95, 0xda, + 0xc1, 0x9e, 0x20, 0x67, 0x70, 0x9a, 0xb3, 0x15, 0x4b, 0xf8, 0x35, 0xcb, 0xd9, 0x0a, 0x35, 0x77, + 0x02, 0x93, 0xd2, 0x5f, 0x9a, 0x05, 0xb3, 0xa7, 0x53, 0xd4, 0xdd, 0x0b, 0x4a, 0xe0, 0x7f, 0x0c, + 0xb6, 0xd6, 0x6c, 0x34, 0x68, 0x35, 0x1b, 0x34, 0x65, 0xb5, 0x9a, 0xb2, 0xfc, 0x5f, 0x2d, 0xe8, + 0xcf, 0x52, 0x21, 0x58, 0xa4, 0x02, 0xcd, 0x49, 0x75, 0x6f, 0xd4, 0xef, 0x41, 0x7f, 0xcd, 0x68, + 0xae, 0x42, 0x46, 0xd5, 0x5c, 0x84, 0xe9, 0xb6, 0x32, 0xe3, 0x80, 0xd5, 0x6f, 0xec, 0xc6, 0x0f, + 0x6d, 0x71, 0x83, 0x1a, 0x1b, 0xb1, 0x3a, 0x8d, 0x58, 0x7d, 0xe8, 0x66, 0x5c, 0xc4, 0x73, 0xa1, + 0x58, 0x7e, 0x4d, 0x13, 0x34, 0xc8, 0x0d, 0x1a, 0x1c, 0x19, 0x03, 0x68, 0x7c, 0x49, 0xb7, 0x2f, + 0x0a, 0x85, 0x16, 0xb9, 0x81, 0xc1, 0xf8, 0x3f, 0xd8, 0xf0, 0x56, 0x2d, 0x47, 0x66, 0xa9, 0x90, + 0x4c, 0xbb, 0x9e, 0x15, 0xe1, 0x22, 0x67, 0x2f, 0xf9, 0xb6, 0x12, 0xb4, 0x27, 0xb4, 0xeb, 0xb2, + 0x08, 0x2b, 0xed, 0xb2, 0x92, 0x63, 0x52, 0xe4, 0x11, 0xf4, 0x0a, 0x61, 0xd6, 0x94, 0x39, 0x37, + 0x49, 0x5d, 0x15, 0x25, 0xa9, 0x64, 0x75, 0x55, 0x39, 0xde, 0x4d, 0x72, 0x3f, 0x84, 0xae, 0x31, + 0x84, 0xe4, 0x1c, 0x06, 0xb2, 0x08, 0x67, 0x8d, 0xeb, 0x6d, 0x2c, 0xb8, 0xc3, 0xef, 0x5c, 0xaa, + 0xeb, 0x8e, 0xb1, 0xae, 0xc1, 0xdd, 0x71, 0xb2, 0xf3, 0xaf, 0x4e, 0x9e, 0x1c, 0x3a, 0xd9, 0x48, + 0x10, 0x0e, 0x12, 0x2c, 0x1d, 0x4d, 0x78, 0xf4, 0x05, 0xbb, 0xf1, 0x56, 0xb5, 0xa3, 0x25, 0xe1, + 0x8f, 0xc1, 0x59, 0x70, 0x11, 0x1b, 0x39, 0x5b, 0x66, 0xce, 0xfe, 0x23, 0xe8, 0x2e, 0xb0, 0xdb, + 0x2a, 0x9f, 0xda, 0x13, 0xcb, 0x5c, 0xcc, 0xbf, 0x5a, 0xf0, 0xf6, 0xb2, 0x08, 0x65, 0x94, 0xf3, + 0x4c, 0xf1, 0x54, 0xfc, 0x97, 0xe9, 0x7c, 0xf3, 0x8e, 0x3e, 0x84, 0xf6, 0xab, 0xcf, 0xf2, 0xb4, + 0xc8, 0xaa, 0xf0, 0x2a, 0xa4, 0xbf, 0xcd, 0x71, 0x8c, 0xab, 0x3f, 0x23, 0x04, 0x7a, 0x26, 0x36, + 0x74, 0x3b, 0x17, 0xcf, 0x12, 0x1e, 0xaf, 0x55, 0x35, 0x88, 0x26, 0xa5, 0xd3, 0xa6, 0xd1, 0xd5, + 0x37, 0x94, 0xab, 0xb9, 0x58, 0xb2, 0x48, 0x56, 0xa3, 0xd8, 0x24, 0xf5, 0x3b, 0xab, 0x22, 0xa7, + 0x61, 0xc2, 0x9e, 0xd3, 0x0d, 0xab, 0xa2, 0x32, 0x29, 0xf2, 0x11, 0xf4, 0xa4, 0xa2, 0xb9, 0x5a, + 0xa4, 0x92, 0x6b, 0x95, 0x68, 0x75, 0x7f, 0xfa, 0x60, 0x92, 0x85, 0x93, 0xa5, 0xf9, 0x43, 0xd0, + 0xac, 0xd3, 0x0d, 0x20, 0xb1, 0xdc, 0x2d, 0xf6, 0x29, 0x2e, 0x76, 0x93, 0xd4, 0xeb, 0x8a, 0xc4, + 0x57, 0x7c, 0xc3, 0x2e, 0x58, 0xa2, 0xa8, 0xd7, 0xc5, 0x7f, 0x9d, 0x03, 0xd6, 0xff, 0x1c, 0x86, + 0x4d, 0xaf, 0xab, 0x68, 0x46, 0xd0, 0xa1, 0xd1, 0x95, 0xb9, 0xe8, 0x35, 0xde, 0xc7, 0x66, 0x9b, + 0xb1, 0xfd, 0x68, 0x01, 0xf9, 0x5a, 0x2f, 0x86, 0x7e, 0x2c, 0x64, 0xff, 0x2f, 0xb5, 0x3a, 0x1d, + 0xfb, 0x20, 0x1d, 0xd3, 0x55, 0xe7, 0x8e, 0xab, 0xfe, 0x39, 0x74, 0xcd, 0xa5, 0xb9, 0xef, 0xeb, + 0xfe, 0xbb, 0xd0, 0xab, 0x6a, 0xef, 0x1b, 0xc7, 0xf3, 0x6f, 0xa1, 0xd7, 0xc8, 0x83, 0x9c, 0xc2, + 0xf1, 0x73, 0xf6, 0xfd, 0x0b, 0x91, 0xdc, 0x0c, 0x8e, 0xc8, 0x00, 0xba, 0x5f, 0x52, 0xa9, 0x02, + 0x16, 0x31, 0x7e, 0xcd, 0x56, 0x03, 0x8b, 0x10, 0xe8, 0xd7, 0xf6, 0xe2, 0xc5, 0x41, 0x8b, 0x3c, + 0x80, 0xde, 0x2e, 0x99, 0x92, 0xb2, 0xc9, 0x09, 0xb8, 0xcf, 0x78, 0x2e, 0xd5, 0xc0, 0xf9, 0x74, + 0xf8, 0xfa, 0x8f, 0xf1, 0xd1, 0xeb, 0xdb, 0xb1, 0xf5, 0xdb, 0xed, 0xd8, 0xfa, 0xfd, 0x76, 0x6c, + 0xfd, 0xf4, 0xe7, 0xf8, 0x28, 0x6c, 0xe3, 0xd2, 0x3d, 0xfd, 0x3b, 0x00, 0x00, 0xff, 0xff, 0x66, + 0xcd, 0xb9, 0x27, 0xce, 0x07, 0x00, 0x00, +} diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/pb/protocol.proto b/gateway/vendor/github.com/nats-io/go-nats-streaming/pb/protocol.proto index a1eea67a..20da0e8c 100644 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/pb/protocol.proto +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/pb/protocol.proto @@ -1,4 +1,15 @@ -// Copyright 2016 Apcera Inc. All rights reserved. +// Copyright 2016-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // // Uses https://github.com/gogo/protobuf // compiled via `protoc -I=. -I=$GOPATH/src --gogofaster_out=. protocol.proto` @@ -20,6 +31,7 @@ message PubMsg { string subject = 3; // subject string reply = 4; // optional reply bytes data = 5; // payload + bytes connID = 6; // Connection ID. For servers that know about this field, clientID can be omitted bytes sha256 = 10; // optional sha256 of data } @@ -53,6 +65,10 @@ message Ack { message ConnectRequest { string clientID = 1; // Client name/identifier. string heartbeatInbox = 2; // Inbox for server initiated heartbeats. + int32 protocol = 3; // Protocol the client is at. + bytes connID = 4; // Connection ID, a way to uniquely identify a connection (no connection should ever have the same) + int32 pingInterval = 5; // Interval at which client wishes to send PINGs (expressed in seconds). + int32 pingMaxOut = 6; // Maximum number of PINGs without a response after which the connection can be considered lost. } // Response to a client connect @@ -63,10 +79,24 @@ message ConnectResponse { string closeRequests = 4; // Subject for closing the stan connection string error = 5; // err string, empty/omitted if no error string subCloseRequests = 6; // Subject to use for subscription close requests + string pingRequests = 7; // Subject to use for PING requests + int32 pingInterval = 8; // Interval at which client should send PINGs (expressed in seconds). + int32 pingMaxOut = 9; // Maximum number of PINGs without a response after which the connection can be considered lost + int32 protocol = 10; // Protocol version the server is at string publicKey = 100; // Possibly used to sign acks, etc. } +// PING from client to server +message Ping { + bytes connID = 1; // Connection ID +} + +// PING response from the server +message PingResponse { + string error = 1; // Error string, empty/omitted if no error +} + // Enum for start position type. enum StartPosition { NewOnly = 0; diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/stan.go b/gateway/vendor/github.com/nats-io/go-nats-streaming/stan.go index 248f5ee9..167ab6dd 100644 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/stan.go +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/stan.go @@ -1,4 +1,15 @@ -// Copyright 2016 Apcera Inc. All rights reserved. +// Copyright 2016-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // Package stan is a Go client for the NATS Streaming messaging system (https://nats.io). package stan @@ -16,7 +27,7 @@ import ( ) // Version is the NATS Streaming Go Client version -const Version = "0.3.4" +const Version = "0.4.0" const ( // DefaultNatsURL is the default URL the client connects to @@ -30,6 +41,10 @@ const ( // DefaultMaxPubAcksInflight is the default maximum number of published messages // without outstanding ACKs from the server DefaultMaxPubAcksInflight = 16384 + // DefaultPingInterval is the default interval (in seconds) at which a connection sends a PING to the server + DefaultPingInterval = 5 + // DefaultPingMaxOut is the number of PINGs without a response before the connection is considered lost. + DefaultPingMaxOut = 3 ) // Conn represents a connection to the NATS Streaming subsystem. It can Publish and @@ -54,6 +69,13 @@ type Conn interface { NatsConn() *nats.Conn } +const ( + // Client send connID in ConnectRequest and PubMsg, and server + // listens and responds to client PINGs. The validity of the + // connection (based on connID) is checked on incoming PINGs. + protocolOne = int32(1) +) + // Errors var ( ErrConnectReqTimeout = errors.New("stan: connect request timeout") @@ -68,13 +90,20 @@ var ( ErrManualAck = errors.New("stan: cannot manually ack in auto-ack mode") ErrNilMsg = errors.New("stan: nil message") ErrNoServerSupport = errors.New("stan: not supported by server") + ErrMaxPings = errors.New("stan: connection lost due to PING failure") ) +var testAllowMillisecInPings = false + // AckHandler is used for Async Publishing to provide status of the ack. -// The func will be passed teh GUID and any error state. No error means the +// The func will be passed the GUID and any error state. No error means the // message was successfully received by NATS Streaming. type AckHandler func(string, error) +// ConnectionLostHandler is used to be notified if the Streaming connection +// is closed due to unexpected errors. +type ConnectionLostHandler func(Conn, error) + // Options can be used to a create a customized connection. type Options struct { NatsURL string @@ -83,6 +112,9 @@ type Options struct { AckTimeout time.Duration DiscoverPrefix string MaxPubAcksInflight int + PingIterval int // In seconds + PingMaxOut int + ConnectionLostCB ConnectionLostHandler } // DefaultOptions are the NATS Streaming client's default options @@ -92,6 +124,8 @@ var DefaultOptions = Options{ AckTimeout: DefaultAckWait, DiscoverPrefix: DefaultDiscoverPrefix, MaxPubAcksInflight: DefaultMaxPubAcksInflight, + PingIterval: DefaultPingInterval, + PingMaxOut: DefaultPingMaxOut, } // Option is a function on the options for a connection. @@ -140,11 +174,45 @@ func NatsConn(nc *nats.Conn) Option { } } +// Pings is an Option to set the ping interval and max out values. +// The interval needs to be at least 1 and represents the number +// of seconds. +// The maxOut needs to be at least 2, since the count of sent PINGs +// increase whenever a PING is sent and reset to 0 when a response +// is received. Setting to 1 would cause the library to close the +// connection right away. +func Pings(interval, maxOut int) Option { + return func(o *Options) error { + // For tests, we may pass negative value that will be interpreted + // by the library as milliseconds. If this test boolean is set, + // do not check values. + if !testAllowMillisecInPings { + if interval < 1 || maxOut <= 2 { + return fmt.Errorf("Invalid ping values: interval=%v (min>0) maxOut=%v (min=2)", interval, maxOut) + } + } + o.PingIterval = interval + o.PingMaxOut = maxOut + return nil + } +} + +// SetConnectionLostHandler is an Option to set the connection lost handler. +// This callback will be invoked should the client permanently lose +// contact with the server (or another client replaces it while being +// disconnected). The callback will not be invoked on normal Conn.Close(). +func SetConnectionLostHandler(handler ConnectionLostHandler) Option { + return func(o *Options) error { + o.ConnectionLostCB = handler + return nil + } +} + // A conn represents a bare connection to a stan cluster. type conn struct { sync.RWMutex clientID string - serverID string + connID []byte // This is a NUID that uniquely identify connections. pubPrefix string // Publish prefix set by stan, append our subject. subRequests string // Subject to send subscription requests. unsubRequests string // Subject to send unsubscribe requests. @@ -158,7 +226,19 @@ type conn struct { pubAckChan chan (struct{}) opts Options nc *nats.Conn - ncOwned bool // NATS Streaming created the connection, so needs to close it. + ncOwned bool // NATS Streaming created the connection, so needs to close it. + pubNUID *nuid.NUID // NUID generator for published messages. + connLostCB ConnectionLostHandler + + pingMu sync.Mutex + pingSub *nats.Subscription + pingTimer *time.Timer + pingBytes []byte + pingRequests string + pingInbox string + pingInterval time.Duration + pingMaxOut int + pingOut int } // Closure for ack contexts. @@ -169,9 +249,10 @@ type ack struct { } // Connect will form a connection to the NATS Streaming subsystem. +// Note that clientID can contain only alphanumeric and `-` or `_` characters. func Connect(stanClusterID, clientID string, options ...Option) (Conn, error) { // Process Options - c := conn{clientID: clientID, opts: DefaultOptions} + c := conn{clientID: clientID, opts: DefaultOptions, connID: []byte(nuid.Next()), pubNUID: nuid.New()} for _, opt := range options { if err := opt(&c.opts); err != nil { return nil, err @@ -181,7 +262,15 @@ func Connect(stanClusterID, clientID string, options ...Option) (Conn, error) { c.nc = c.opts.NatsConn // Create a NATS connection if it doesn't exist. if c.nc == nil { - nc, err := nats.Connect(c.opts.NatsURL) + // We will set the max reconnect attempts to -1 (infinite) + // and the reconnect buffer to -1 to prevent any buffering + // (which may cause a published message to be flushed on + // reconnect while the API may have returned an error due + // to PubAck timeout. + nc, err := nats.Connect(c.opts.NatsURL, + nats.Name(clientID), + nats.MaxReconnects(-1), + nats.ReconnectBufSize(-1)) if err != nil { return nil, err } @@ -200,9 +289,25 @@ func Connect(stanClusterID, clientID string, options ...Option) (Conn, error) { return nil, err } + // Prepare a subscription on ping responses, even if we are not + // going to need it, so that if that fails, it fails before initiating + // a connection. + pingSub, err := c.nc.Subscribe(nats.NewInbox(), c.processPingResponse) + if err != nil { + c.Close() + return nil, err + } + // Send Request to discover the cluster discoverSubject := c.opts.DiscoverPrefix + "." + stanClusterID - req := &pb.ConnectRequest{ClientID: clientID, HeartbeatInbox: hbInbox} + req := &pb.ConnectRequest{ + ClientID: clientID, + HeartbeatInbox: hbInbox, + ConnID: c.connID, + Protocol: protocolOne, + PingInterval: int32(c.opts.PingIterval), + PingMaxOut: int32(c.opts.PingMaxOut), + } b, _ := req.Marshal() reply, err := c.nc.Request(discoverSubject, b, c.opts.ConnectTimeout) if err != nil { @@ -245,18 +350,172 @@ func Connect(stanClusterID, clientID string, options ...Option) (Conn, error) { c.pubAckChan = make(chan struct{}, c.opts.MaxPubAcksInflight) + // Capture the connection error cb + c.connLostCB = c.opts.ConnectionLostCB + + unsubPingSub := true + // Do this with servers which are at least at protcolOne. + if cr.Protocol >= protocolOne { + // Note that in the future server may override client ping + // interval value sent in ConnectRequest, so use the + // value in ConnectResponse to decide if we send PINGs + // and at what interval. + // In tests, the interval could be negative to indicate + // milliseconds. + if cr.PingInterval != 0 { + unsubPingSub = false + + // These will be immutable. + c.pingRequests = cr.PingRequests + c.pingInbox = pingSub.Subject + // In test, it is possible that we get a negative value + // to represent milliseconds. + if testAllowMillisecInPings && cr.PingInterval < 0 { + c.pingInterval = time.Duration(cr.PingInterval*-1) * time.Millisecond + } else { + // PingInterval is otherwise assumed to be in seconds. + c.pingInterval = time.Duration(cr.PingInterval) * time.Second + } + c.pingMaxOut = int(cr.PingMaxOut) + c.pingBytes, _ = (&pb.Ping{ConnID: c.connID}).Marshal() + c.pingSub = pingSub + // Set the timer now that we are set. Use lock to create + // synchronization point. + c.pingMu.Lock() + c.pingTimer = time.AfterFunc(c.pingInterval, c.pingServer) + c.pingMu.Unlock() + } + } + if unsubPingSub { + pingSub.Unsubscribe() + } + // Attach a finalizer runtime.SetFinalizer(&c, func(sc *conn) { sc.Close() }) return &c, nil } +// Sends a PING (containing the connection's ID) to the server at intervals +// specified by PingInterval option when connection is created. +// Everytime a PING is sent, the number of outstanding PINGs is increased. +// If the total number is > than the PingMaxOut option, then the connection +// is closed, and connection error callback invoked if one was specified. +func (sc *conn) pingServer() { + sc.pingMu.Lock() + // In case the timer fired while we were stopping it. + if sc.pingTimer == nil { + sc.pingMu.Unlock() + return + } + sc.pingOut++ + if sc.pingOut > sc.pingMaxOut { + sc.pingMu.Unlock() + sc.closeDueToPing(ErrMaxPings) + return + } + sc.pingTimer.Reset(sc.pingInterval) + nc := sc.nc + sc.pingMu.Unlock() + // Send the PING now. If the NATS connection is reported closed, + // we are done. + if err := nc.PublishRequest(sc.pingRequests, sc.pingInbox, sc.pingBytes); err == nats.ErrConnectionClosed { + sc.closeDueToPing(err) + } +} + +// Receives PING responses from the server. +// If the response contains an error message, the connection is closed +// and the connection error callback is invoked (if one is specified). +// If no error, the number of ping out is reset to 0. There is no +// decrement by one since for a given PING, the client may received +// many responses when servers are running in channel partitioning mode. +// Regardless, any positive response from the server ought to signal +// that the connection is ok. +func (sc *conn) processPingResponse(m *nats.Msg) { + // No data means OK (we don't have to call Unmarshal) + if len(m.Data) > 0 { + pingResp := &pb.PingResponse{} + if err := pingResp.Unmarshal(m.Data); err != nil { + return + } + if pingResp.Error != "" { + sc.closeDueToPing(errors.New(pingResp.Error)) + return + } + } + // Do not attempt to decrement, simply reset to 0. + sc.pingMu.Lock() + sc.pingOut = 0 + sc.pingMu.Unlock() +} + +// Closes a connection and invoke the connection error callback if one +// was registered when the connection was created. +func (sc *conn) closeDueToPing(err error) { + sc.Lock() + if sc.nc == nil { + sc.Unlock() + return + } + // Stop timer, unsubscribe, fail the pubs, etc.. + sc.cleanupOnClose(err) + // No need to send Close prototol, so simply close the underlying + // NATS connection (if we own it, and if not already closed) + if sc.ncOwned && !sc.nc.IsClosed() { + sc.nc.Close() + } + // Mark this streaming connection as closed. Do this under pingMu lock. + sc.pingMu.Lock() + sc.nc = nil + sc.pingMu.Unlock() + // Capture callback (even though this is immutable). + cb := sc.connLostCB + sc.Unlock() + if cb != nil { + // Execute in separate go routine. + go cb(sc, err) + } +} + +// Do some cleanup when connection is lost or closed. +// Connection lock is held on entry, and sc.nc is guaranteed not to be nil. +func (sc *conn) cleanupOnClose(err error) { + sc.pingMu.Lock() + if sc.pingTimer != nil { + sc.pingTimer.Stop() + sc.pingTimer = nil + } + sc.pingMu.Unlock() + + // Unsubscribe only if the NATS connection is not already closed... + if !sc.nc.IsClosed() { + if sc.ackSubscription != nil { + sc.ackSubscription.Unsubscribe() + } + if sc.pingSub != nil { + sc.pingSub.Unsubscribe() + } + } + // Fail all pending pubs + for guid, pubAck := range sc.pubAckMap { + if pubAck.t != nil { + pubAck.t.Stop() + } + if pubAck.ah != nil { + pubAck.ah(guid, err) + } else if pubAck.ch != nil { + pubAck.ch <- err + } + delete(sc.pubAckMap, guid) + if len(sc.pubAckChan) > 0 { + <-sc.pubAckChan + } + } +} + // Close a connection to the stan system. func (sc *conn) Close() error { - if sc == nil { - return ErrBadConnection - } - sc.Lock() defer sc.Unlock() @@ -271,13 +530,15 @@ func (sc *conn) Close() error { defer nc.Close() } - // Signals we are closed. - sc.nc = nil - // Now close ourselves. - if sc.ackSubscription != nil { - sc.ackSubscription.Unsubscribe() - } + sc.cleanupOnClose(ErrConnectionClosed) + + // Signals we are closed. + // Do this also under pingMu lock so that we don't need + // to grab sc's lock in pingServer. + sc.pingMu.Lock() + sc.nc = nil + sc.pingMu.Unlock() req := &pb.CloseRequest{ClientID: sc.clientID} b, _ := req.Marshal() @@ -303,7 +564,10 @@ func (sc *conn) Close() error { // closing the wrapped NATS conn will put the NATS Streaming Conn in an invalid // state. func (sc *conn) NatsConn() *nats.Conn { - return sc.nc + sc.RLock() + nc := sc.nc + sc.RUnlock() + return nc } // Process a heartbeat from the NATS Streaming cluster @@ -322,9 +586,7 @@ func (sc *conn) processAck(m *nats.Msg) { pa := &pb.PubAck{} err := pa.Unmarshal(m.Data) if err != nil { - // FIXME, make closure to have context? - fmt.Printf("Error processing unmarshal\n") - return + panic(fmt.Errorf("Error during ack unmarshal: %v", err)) } // Remove @@ -346,7 +608,10 @@ func (sc *conn) processAck(m *nats.Msg) { // Publish will publish to the cluster and wait for an ACK. func (sc *conn) Publish(subject string, data []byte) error { - ch := make(chan error) + // Need to make this a buffered channel of 1 in case + // a publish call is blocked in pubAckChan but cleanupOnClose() + // is trying to push the error to this channel. + ch := make(chan error, 1) _, err := sc.publishAsync(subject, data, nil, ch) if err == nil { err = <-ch @@ -370,9 +635,11 @@ func (sc *conn) publishAsync(subject string, data []byte, ah AckHandler, ch chan subj := sc.pubPrefix + "." + subject // This is only what we need from PubMsg in the timer below, - // so do this so that pe doesn't escape (and we same on new object) - peGUID := nuid.Next() - pe := &pb.PubMsg{ClientID: sc.clientID, Guid: peGUID, Subject: subject, Data: data} + // so do this so that pe doesn't escape. + peGUID := sc.pubNUID.Next() + // We send connID regardless of server we connect to. Older server + // will simply not decode it. + pe := &pb.PubMsg{ClientID: sc.clientID, Guid: peGUID, Subject: subject, Data: data, ConnID: sc.connID} b, _ := pe.Marshal() // Map ack to guid. @@ -381,25 +648,44 @@ func (sc *conn) publishAsync(subject string, data []byte, ah AckHandler, ch chan ackSubject := sc.ackSubject ackTimeout := sc.opts.AckTimeout pac := sc.pubAckChan + nc := sc.nc sc.Unlock() // Use the buffered channel to control the number of outstanding acks. pac <- struct{}{} - err := sc.nc.PublishRequest(subj, ackSubject, b) - if err != nil { - sc.removeAck(peGUID) - return "", err - } + err := nc.PublishRequest(subj, ackSubject, b) // Setup the timer for expiration. sc.Lock() + if err != nil || sc.nc == nil { + sc.Unlock() + // If we got and error on publish or the connection has been closed, + // we need to return an error only if: + // - we can remove the pubAck from the map + // - we can't, but this is an async pub with no provided AckHandler + removed := sc.removeAck(peGUID) != nil + if removed || (ch == nil && ah == nil) { + if err == nil { + err = ErrConnectionClosed + } + return "", err + } + // pubAck was removed from cleanupOnClose() and error will be sent + // to appropriate go channel (ah or ch). + return peGUID, nil + } a.t = time.AfterFunc(ackTimeout, func() { - sc.removeAck(peGUID) - if a.ah != nil { - ah(peGUID, ErrTimeout) + pubAck := sc.removeAck(peGUID) + // processAck could get here before and handle the ack. + // If that's the case, we would get nil here and simply return. + if pubAck == nil { + return + } + if pubAck.ah != nil { + pubAck.ah(peGUID, ErrTimeout) } else if a.ch != nil { - a.ch <- ErrTimeout + pubAck.ch <- ErrTimeout } }) sc.Unlock() @@ -436,7 +722,7 @@ func (sc *conn) processMsg(raw *nats.Msg) { msg := &Msg{} err := msg.Unmarshal(raw.Data) if err != nil { - panic("Error processing unmarshal for msg") + panic(fmt.Errorf("Error processing unmarshal for msg: %v", err)) } // Lookup the subscription sc.RLock() @@ -465,12 +751,11 @@ func (sc *conn) processMsg(raw *nats.Msg) { cb(msg) } - // Proces auto-ack + // Process auto-ack if !isManualAck && nc != nil { ack := &pb.Ack{Subject: msg.Subject, Sequence: msg.Sequence} b, _ := ack.Marshal() - if err := nc.Publish(ackSubject, b); err != nil { - // FIXME(dlc) - Async error handler? Retry? - } + // FIXME(dlc) - Async error handler? Retry? + nc.Publish(ackSubject, b) } } diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/stan_test.go b/gateway/vendor/github.com/nats-io/go-nats-streaming/stan_test.go index 6020af99..8c8d42ac 100644 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/stan_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/stan_test.go @@ -1,3 +1,15 @@ +// Copyright 2016-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package stan //////////////////////////////////////////////////////////////////////////////// @@ -8,8 +20,8 @@ import ( "bytes" "errors" "fmt" - "math" "math/rand" + "net" "runtime" "strconv" "strings" @@ -21,13 +33,23 @@ import ( natsd "github.com/nats-io/gnatsd/test" "github.com/nats-io/go-nats" "github.com/nats-io/go-nats-streaming/pb" - natstest "github.com/nats-io/go-nats/test" "github.com/nats-io/nats-streaming-server/server" - "github.com/nats-io/nats-streaming-server/test" ) func RunServer(ID string) *server.StanServer { - return test.RunServer(ID) + s, err := server.RunServer(ID) + if err != nil { + panic(err) + } + return s +} + +func runServerWithOpts(sOpts *server.Options) *server.StanServer { + s, err := server.RunServerWithOpts(sOpts, nil) + if err != nil { + panic(err) + } + return s } // Dumb wait program to sync on callbacks, etc... Will timeout @@ -84,7 +106,7 @@ func stackFatalf(t tLogger, f string, args ...interface{}) { // Generate the Stack of callers: for i := 1; true; i++ { _, file, line, ok := runtime.Caller(i) - if ok == false { + if !ok { break } msg := fmt.Sprintf("%d - %s:%d", i, file, line) @@ -201,16 +223,23 @@ func TestBasicPublishAsync(t *testing.T) { } } -func TestTimeoutPublishAsync(t *testing.T) { - // Run a NATS Streaming server - s := RunServer(clusterName) - defer s.Shutdown() +func TestTimeoutPublish(t *testing.T) { + ns := natsd.RunDefaultServer() + defer ns.Shutdown() + opts := server.GetDefaultOptions() + opts.NATSServerURL = nats.DefaultURL + opts.ID = clusterName + s := runServerWithOpts(opts) + defer s.Shutdown() sc, err := Connect(clusterName, clientName, PubAckWait(50*time.Millisecond)) + if err != nil { t.Fatalf("Expected to connect correctly, got err %v\n", err) } - defer sc.Close() + // Do not defer the connection close because we are going to + // shutdown the server before the client connection is closed, + // which would cause a 2 seconds delay on test exit. ch := make(chan bool) var glock sync.Mutex @@ -237,6 +266,38 @@ func TestTimeoutPublishAsync(t *testing.T) { if err := Wait(ch); err != nil { t.Fatal("Did not receive our ack callback with a timeout err") } + // Publish synchronously + if err := sc.Publish("foo", []byte("hello")); err == nil || err != ErrTimeout { + t.Fatalf("Expected Timeout error on publish, got %v", err) + } +} + +func TestPublishWithClosedNATSConn(t *testing.T) { + // Run a NATS Streaming server + s := RunServer(clusterName) + defer s.Shutdown() + + nc, err := nats.Connect(nats.DefaultURL) + if err != nil { + t.Fatalf("Unexpected error on connect: %v", err) + } + defer nc.Close() + sc, err := Connect(clusterName, clientName, NatsConn(nc)) + if err != nil { + t.Fatalf("Unexpected error on connect: %v", err) + } + defer sc.Close() + // Close the NATS Connection + nc.Close() + msg := []byte("hello") + // Publish should fail + if err := sc.Publish("foo", msg); err == nil { + t.Fatal("Expected error on publish") + } + // Even PublishAsync should fail right away + if _, err := sc.PublishAsync("foo", msg, nil); err == nil { + t.Fatal("Expected error on publish") + } } func TestBasicSubscription(t *testing.T) { @@ -252,6 +313,17 @@ func TestBasicSubscription(t *testing.T) { t.Fatalf("Unexpected error on Subscribe, got %v", err) } defer sub.Unsubscribe() + + // Close connection + sc.Close() + + // Expect ErrConnectionClosed on subscribe + if _, err := sc.Subscribe("foo", func(m *Msg) {}); err == nil || err != ErrConnectionClosed { + t.Fatalf("Expected ErrConnectionClosed on subscribe, got %v", err) + } + if _, err := sc.QueueSubscribe("foo", "bar", func(m *Msg) {}); err == nil || err != ErrConnectionClosed { + t.Fatalf("Expected ErrConnectionClosed on subscribe, got %v", err) + } } func TestBasicQueueSubscription(t *testing.T) { @@ -329,11 +401,6 @@ func TestDurableQueueSubscriber(t *testing.T) { if err := Wait(ch); err != nil { t.Fatal("Did not get our message") } - // Give a chance to ACKs to make it to the server. - // This step is not necessary. Worse could happen is that messages - // are redelivered. This is why we check on !m.Redelivered in the - // callback to validate the counts. - time.Sleep(500 * time.Millisecond) // Close connection sc.Close() @@ -638,7 +705,7 @@ func TestSubscriptionStartAtTime(t *testing.T) { } // Now test Ago helper - delta := time.Now().Sub(startTime) + delta := time.Since(startTime) sub, err = sc.Subscribe("foo", mcb, StartAtTimeDelta(delta)) if err != nil { @@ -651,7 +718,7 @@ func TestSubscriptionStartAtTime(t *testing.T) { } } -func TestSubscriptionStartAtWithEmptyStore(t *testing.T) { +func TestSubscriptionStartAt(t *testing.T) { // Run a NATS Streaming server s := RunServer(clusterName) defer s.Shutdown() @@ -659,34 +726,37 @@ func TestSubscriptionStartAtWithEmptyStore(t *testing.T) { sc := NewDefaultConnection(t) defer sc.Close() - startTime := time.Now() + // Publish ten messages + for i := 1; i <= 10; i++ { + sc.Publish("foo", []byte("hello")) + } + ch := make(chan bool) + received := 0 mcb := func(m *Msg) { + received++ + if received == 10 { + ch <- true + } } - sub, err := sc.Subscribe("foo", mcb, StartAtTime(startTime)) + // Now subscribe and set start position to sequence. It should be + // sequence 0 + sub, err := sc.Subscribe("foo", mcb, StartAt(pb.StartPosition_SequenceStart)) if err != nil { - t.Fatalf("Unexpected error on subscribe: %v", err) + t.Fatalf("Expected no error on Subscribe, got %v", err) } - sub.Unsubscribe() + defer sub.Unsubscribe() - sub, err = sc.Subscribe("foo", mcb, StartAtSequence(0)) - if err != nil { - t.Fatalf("Unexpected error on subscribe: %v", err) + // Check for sub setup + rsub := sub.(*subscription) + if rsub.opts.StartAt != pb.StartPosition_SequenceStart { + t.Fatalf("Incorrect StartAt state: %s\n", rsub.opts.StartAt) } - sub.Unsubscribe() - sub, err = sc.Subscribe("foo", mcb, StartWithLastReceived()) - if err != nil { - t.Fatalf("Unexpected error on subscribe: %v", err) + if err := Wait(ch); err != nil { + t.Fatal("Did not receive our messages") } - sub.Unsubscribe() - - sub, err = sc.Subscribe("foo", mcb) - if err != nil { - t.Fatalf("Unexpected error on subscribe: %v", err) - } - sub.Unsubscribe() } func TestSubscriptionStartAtFirst(t *testing.T) { @@ -762,13 +832,6 @@ func TestUnsubscribe(t *testing.T) { sc := NewDefaultConnection(t) defer sc.Close() - // test nil - var nsub *subscription - err := nsub.Unsubscribe() - if err == nil || err != ErrBadSubscription { - t.Fatalf("Expected a bad subscription err, got %v\n", err) - } - // Create a valid one sc.Subscribe("foo", nil) @@ -798,6 +861,28 @@ func TestUnsubscribe(t *testing.T) { data := []byte(fmt.Sprintf("%d", i)) sc.Publish("foo", data) } + + sc.Close() + sc = NewDefaultConnection(t) + defer sc.Close() + sub1, err := sc.Subscribe("foo", func(_ *Msg) {}) + if err != nil { + t.Fatalf("Unexpected error on subscribe: %v", err) + } + sub2, err := sc.Subscribe("foo", func(_ *Msg) {}) + if err != nil { + t.Fatalf("Unexpected error on subscribe: %v", err) + } + // Override clientID to get an error on Subscription.Close() and Unsubscribe() + sc.(*conn).Lock() + sc.(*conn).clientID = "foobar" + sc.(*conn).Unlock() + if err := sub1.Close(); err == nil || !strings.Contains(err.Error(), "unknown") { + t.Fatalf("Expected error about unknown clientID, got %v", err) + } + if err := sub2.Close(); err == nil || !strings.Contains(err.Error(), "unknown") { + t.Fatalf("Expected error about unknown clientID, got %v", err) + } } func TestUnsubscribeWhileConnClosing(t *testing.T) { @@ -831,33 +916,6 @@ func TestUnsubscribeWhileConnClosing(t *testing.T) { wg.Wait() } -func TestSubscribeShrink(t *testing.T) { - // Run a NATS Streaming server - s := RunServer(clusterName) - defer s.Shutdown() - - sc := NewDefaultConnection(t) - defer sc.Close() - - nsubs := 1000 - subs := make([]Subscription, 0, nsubs) - for i := 1; i <= nsubs; i++ { - // Create a valid one - sub, err := sc.Subscribe("foo", nil) - if err != nil { - t.Fatalf("Got an error on subscribe: %v\n", err) - } - subs = append(subs, sub) - } - // Now unsubsribe them all - for _, sub := range subs { - err := sub.Unsubscribe() - if err != nil { - t.Fatalf("Got an error on unsubscribe: %v\n", err) - } - } -} - func TestDupClientID(t *testing.T) { // Run a NATS Streaming server s := RunServer(clusterName) @@ -866,9 +924,8 @@ func TestDupClientID(t *testing.T) { sc := NewDefaultConnection(t) defer sc.Close() - _, err := Connect(clusterName, clientName, PubAckWait(50*time.Millisecond)) - if err == nil { - t.Fatalf("Expected to get an error for duplicate clientID\n") + if _, err := Connect(clusterName, clientName); err == nil { + t.Fatal("Expected to get an error for duplicate clientID") } } @@ -892,16 +949,25 @@ func TestClose(t *testing.T) { t.Fatalf("Did not expect error on Close(), got %v\n", err) } - for i := 0; i < 10; i++ { - sc.Publish("foo", []byte("ok")) + if _, err := sc.PublishAsync("foo", []byte("Hello World!"), nil); err == nil || err != ErrConnectionClosed { + t.Fatalf("Expected an ErrConnectionClosed on publish async to a closed connection, got %v", err) } if err := sc.Publish("foo", []byte("Hello World!")); err == nil || err != ErrConnectionClosed { - t.Fatalf("Expected an ErrConnectionClosed error on publish to a closed connection, got %v\n", err) + t.Fatalf("Expected an ErrConnectionClosed error on publish to a closed connection, got %v", err) } if err := sub.Unsubscribe(); err == nil || err != ErrConnectionClosed { - t.Fatalf("Expected an ErrConnectionClosed error on unsubscribe to a closed connection, got %v\n", err) + t.Fatalf("Expected an ErrConnectionClosed error on unsubscribe to a closed connection, got %v", err) + } + + sc = NewDefaultConnection(t) + // Override the clientID so that we get an error on close + sc.(*conn).Lock() + sc.(*conn).clientID = "foobar" + sc.(*conn).Unlock() + if err := sc.Close(); err == nil || !strings.Contains(err.Error(), "unknown") { + t.Fatalf("Expected error about unknown clientID, got %v", err) } } @@ -999,6 +1065,24 @@ func TestManualAck(t *testing.T) { if nr := atomic.LoadInt32(&received); nr != toSend+1 { t.Fatalf("Did not receive correct number of messages: %d vs %d\n", nr, toSend+1) } + + // Close connection + sc.Close() + if err := msgs[0].Ack(); err != ErrBadConnection { + t.Fatalf("Expected ErrBadConnection, got %v", err) + } + + // Close the subscription + sub.Unsubscribe() + if err := msgs[0].Ack(); err != ErrBadSubscription { + t.Fatalf("Expected ErrBadSubscription, got %v", err) + } + + // Test nil msg Ack + var m *Msg + if err := m.Ack(); err != ErrNilMsg { + t.Fatalf("Expected ErrNilMsg, got %v", err) + } } func TestRedelivery(t *testing.T) { @@ -1054,125 +1138,6 @@ func TestRedelivery(t *testing.T) { } } -func checkTime(t *testing.T, label string, time1, time2 time.Time, expected time.Duration, tolerance time.Duration) { - duration := time2.Sub(time1) - - if duration < (expected-tolerance) || duration > (expected+tolerance) { - t.Fatalf("%s not in range: %v (expected %v +/- %v)", label, duration, expected, tolerance) - } -} - -func testRedelivery(t *testing.T, count int, queueSub bool) { - // Run a NATS Streaming server - s := RunServer(clusterName) - defer s.Shutdown() - - sc := NewDefaultConnection(t) - defer sc.Close() - - toSend := int32(count) - hw := []byte("Hello World") - - ch := make(chan bool) - acked := int32(0) - secondRedelivery := false - firstDeliveryCount := int32(0) - firstRedeliveryCount := int32(0) - var startDelivery time.Time - var startFirstRedelivery time.Time - var startSecondRedelivery time.Time - - ackRedeliverTime := 1 * time.Second - - recvCb := func(m *Msg) { - if m.Redelivered { - if secondRedelivery { - if startSecondRedelivery.IsZero() { - startSecondRedelivery = time.Now() - } - acks := atomic.AddInt32(&acked, 1) - if acks <= toSend { - m.Ack() - if acks == toSend { - ch <- true - } - } - } else { - if startFirstRedelivery.IsZero() { - startFirstRedelivery = time.Now() - } - if atomic.AddInt32(&firstRedeliveryCount, 1) == toSend { - secondRedelivery = true - } - } - } else { - if startDelivery.IsZero() { - startDelivery = time.Now() - } - atomic.AddInt32(&firstDeliveryCount, 1) - } - } - - var sub Subscription - var err error - if queueSub { - sub, err = sc.QueueSubscribe("foo", "bar", recvCb, AckWait(ackRedeliverTime), SetManualAckMode()) - } else { - sub, err = sc.Subscribe("foo", recvCb, AckWait(ackRedeliverTime), SetManualAckMode()) - } - if err != nil { - t.Fatalf("Unexpected error on Subscribe, got %v\n", err) - } - defer sub.Unsubscribe() - - for i := int32(0); i < toSend; i++ { - sc.Publish("foo", hw) - } - - // If this succeeds, it means that we got all messages first delivered, - // and then at least 2 * toSend messages received as redelivered. - if err := Wait(ch); err != nil { - t.Fatal("Did not ack all expected messages") - } - - // Wait a period and bit more to make sure that no more message are - // redelivered (acked will then be > toSend) - time.Sleep(ackRedeliverTime + 100*time.Millisecond) - - // Verify first redelivery happens when expected - checkTime(t, "First redelivery", startDelivery, startFirstRedelivery, ackRedeliverTime, ackRedeliverTime/2) - - // Verify second redelivery happens when expected - checkTime(t, "Second redelivery", startFirstRedelivery, startSecondRedelivery, ackRedeliverTime, ackRedeliverTime/2) - - // Check counts - if delivered := atomic.LoadInt32(&firstDeliveryCount); delivered != toSend { - t.Fatalf("Did not receive all messages during delivery: %v vs %v", delivered, toSend) - } - if firstRedelivered := atomic.LoadInt32(&firstRedeliveryCount); firstRedelivered != toSend { - t.Fatalf("Did not receive all messages during first redelivery: %v vs %v", firstRedelivered, toSend) - } - if acks := atomic.LoadInt32(&acked); acks != toSend { - t.Fatalf("Did not get expected acks: %v vs %v", acks, toSend) - } -} - -func TestLowRedeliveryToSubMoreThanOnce(t *testing.T) { - testRedelivery(t, 10, false) -} - -func TestHighRedeliveryToSubMoreThanOnce(t *testing.T) { - testRedelivery(t, 100, false) -} - -func TestLowRedeliveryToQueueSubMoreThanOnce(t *testing.T) { - testRedelivery(t, 10, true) -} - -func TestHighRedeliveryToQueueSubMoreThanOnce(t *testing.T) { - testRedelivery(t, 100, true) -} - func TestDurableSubscriber(t *testing.T) { // Run a NATS Streaming server s := RunServer(clusterName) @@ -1197,9 +1162,6 @@ func TestDurableSubscriber(t *testing.T) { _, err := sc.Subscribe("foo", func(m *Msg) { if nr := atomic.AddInt32(&received, 1); nr == 10 { - // Reduce risk of test failure by allowing server to - // process acks before processing Close() requesting - time.Sleep(time.Second) sc.Close() ch <- true } else { @@ -1283,300 +1245,6 @@ func TestDurableSubscriber(t *testing.T) { } } -func TestPubMultiQueueSub(t *testing.T) { - // Run a NATS Streaming server - s := RunServer(clusterName) - defer s.Shutdown() - - sc := NewDefaultConnection(t) - defer sc.Close() - - ch := make(chan bool) - received := int32(0) - s1Received := int32(0) - s2Received := int32(0) - toSend := int32(1000) - - var s1, s2 Subscription - - msgMapLock := &sync.Mutex{} - msgMap := make(map[uint64]struct{}) - - mcb := func(m *Msg) { - // Remember the message sequence. - msgMapLock.Lock() - if _, ok := msgMap[m.Sequence]; ok { - t.Fatalf("Detected duplicate for sequence: %d\n", m.Sequence) - } - msgMap[m.Sequence] = struct{}{} - msgMapLock.Unlock() - // Track received for each receiver. - if m.Sub == s1 { - atomic.AddInt32(&s1Received, 1) - } else if m.Sub == s2 { - atomic.AddInt32(&s2Received, 1) - } else { - t.Fatalf("Received message on unknown subscription") - } - // Track total - if nr := atomic.AddInt32(&received, 1); nr == int32(toSend) { - ch <- true - } - } - - s1, err := sc.QueueSubscribe("foo", "bar", mcb) - if err != nil { - t.Fatalf("Unexpected error on Subscribe, got %v", err) - } - defer s1.Unsubscribe() - - s2, err = sc.QueueSubscribe("foo", "bar", mcb) - if err != nil { - t.Fatalf("Unexpected error on Subscribe, got %v", err) - } - defer s2.Unsubscribe() - - // Publish out the messages. - for i := int32(0); i < toSend; i++ { - data := []byte(fmt.Sprintf("%d", i)) - sc.Publish("foo", data) - } - if err := WaitTime(ch, 10*time.Second); err != nil { - t.Fatal("Did not receive our messages") - } - - if nr := atomic.LoadInt32(&received); nr != toSend { - t.Fatalf("Did not receive correct number of messages: %d vs %d\n", nr, toSend) - } - - s1r := atomic.LoadInt32(&s1Received) - s2r := atomic.LoadInt32(&s2Received) - - v := uint(float32(toSend) * 0.25) // 25 percent - expected := toSend / 2 - d1 := uint(math.Abs(float64(expected - s1r))) - d2 := uint(math.Abs(float64(expected - s2r))) - if d1 > v || d2 > v { - t.Fatalf("Too much variance in totals: %d, %d > %d", d1, d2, v) - } -} - -func TestPubMultiQueueSubWithSlowSubscriber(t *testing.T) { - // Run a NATS Streaming server - s := RunServer(clusterName) - defer s.Shutdown() - - sc := NewDefaultConnection(t) - defer sc.Close() - - ch := make(chan bool) - s2BlockedCh := make(chan bool) - received := int32(0) - s1Received := int32(0) - s2Received := int32(0) - toSend := int32(100) - - var s1, s2 Subscription - - msgMapLock := &sync.Mutex{} - msgMap := make(map[uint64]struct{}) - - mcb := func(m *Msg) { - // Remember the message sequence. - msgMapLock.Lock() - if _, ok := msgMap[m.Sequence]; ok { - t.Fatalf("Detected duplicate for sequence: %d\n", m.Sequence) - } - msgMap[m.Sequence] = struct{}{} - msgMapLock.Unlock() - // Track received for each receiver. - if m.Sub == s1 { - atomic.AddInt32(&s1Received, 1) - } else if m.Sub == s2 { - // Block this subscriber - <-s2BlockedCh - atomic.AddInt32(&s2Received, 1) - } else { - t.Fatalf("Received message on unknown subscription") - } - // Track total - if nr := atomic.AddInt32(&received, 1); nr == int32(toSend) { - ch <- true - } - } - - s1, err := sc.QueueSubscribe("foo", "bar", mcb) - if err != nil { - t.Fatalf("Unexpected error on Subscribe, got %v", err) - } - defer s1.Unsubscribe() - - s2, err = sc.QueueSubscribe("foo", "bar", mcb) - if err != nil { - t.Fatalf("Unexpected error on Subscribe, got %v", err) - } - defer s2.Unsubscribe() - - // Publish out the messages. - for i := int32(0); i < toSend; i++ { - data := []byte(fmt.Sprintf("%d", i)) - sc.Publish("foo", data) - } - - close(s2BlockedCh) - - if err := WaitTime(ch, 10*time.Second); err != nil { - t.Fatal("Did not receive our messages") - } - - if nr := atomic.LoadInt32(&received); nr != toSend { - t.Fatalf("Did not receive correct number of messages: %d vs %d\n", nr, toSend) - } - - s1r := atomic.LoadInt32(&s1Received) - s2r := atomic.LoadInt32(&s2Received) - - // We have no guarantee that s2 received only 1 or 2 messages, but it should - // not have received more than half - if s2r > toSend/2 { - t.Fatalf("Expected sub2 to receive no more than half, got %d\n", s2r) - } - - if s1r != toSend-s2r { - t.Fatalf("Expected %d msgs for sub1, got %d\n", toSend-s2r, s1r) - } -} - -func TestPubMultiQueueSubWithRedelivery(t *testing.T) { - // Run a NATS Streaming server - s := RunServer(clusterName) - defer s.Shutdown() - - sc := NewDefaultConnection(t) - defer sc.Close() - - ch := make(chan bool) - received := int32(0) - s1Received := int32(0) - toSend := int32(50) - - var s1, s2 Subscription - - mcb := func(m *Msg) { - // Track received for each receiver. - - if m.Sub == s1 { - m.Ack() - atomic.AddInt32(&s1Received, 1) - - // Track total only for sub1 - if nr := atomic.AddInt32(&received, 1); nr == int32(toSend) { - ch <- true - } - } else if m.Sub == s2 { - // We will not ack this subscriber - } else { - t.Fatalf("Received message on unknown subscription") - } - } - - s1, err := sc.QueueSubscribe("foo", "bar", mcb, SetManualAckMode()) - if err != nil { - t.Fatalf("Unexpected error on Subscribe, got %v", err) - } - defer s1.Unsubscribe() - - s2, err = sc.QueueSubscribe("foo", "bar", mcb, SetManualAckMode(), AckWait(1*time.Second)) - if err != nil { - t.Fatalf("Unexpected error on Subscribe, got %v", err) - } - defer s2.Unsubscribe() - - // Publish out the messages. - for i := int32(0); i < toSend; i++ { - data := []byte(fmt.Sprintf("%d", i)) - sc.Publish("foo", data) - } - if err := WaitTime(ch, 30*time.Second); err != nil { - t.Fatal("Did not receive our messages") - } - - if nr := atomic.LoadInt32(&received); nr != toSend { - t.Fatalf("Did not receive correct number of messages: %d vs %d\n", nr, toSend) - } -} - -func TestPubMultiQueueSubWithDelayRedelivery(t *testing.T) { - // Run a NATS Streaming server - s := RunServer(clusterName) - defer s.Shutdown() - - sc := NewDefaultConnection(t) - defer sc.Close() - - ch := make(chan bool) - toSend := int32(500) - ackCount := int32(0) - - var s1, s2 Subscription - - mcb := func(m *Msg) { - // Track received for each receiver. - if m.Sub == s1 { - - m.Ack() - - // if we've acked everything, signal - nr := atomic.AddInt32(&ackCount, 1) - - if nr == int32(toSend) { - ch <- true - } - - if nr > 0 && nr%(toSend/2) == 0 { - - // This depends on the internal algorithm where the - // best resend subscriber is the one with the least number - // of outstanding acks. - // - // Sleep to allow the acks to back up, so s2 will look - // like a better subscriber to send messages to. - time.Sleep(time.Millisecond * 200) - } - } else if m.Sub == s2 { - // We will not ack this subscriber - } else { - t.Fatalf("Received message on unknown subscription") - } - } - - s1, err := sc.QueueSubscribe("foo", "bar", mcb, SetManualAckMode()) - if err != nil { - t.Fatalf("Unexpected error on Subscribe, got %v", err) - } - defer s1.Unsubscribe() - - s2, err = sc.QueueSubscribe("foo", "bar", mcb, SetManualAckMode(), AckWait(1*time.Second)) - if err != nil { - t.Fatalf("Unexpected error on Subscribe, got %v", err) - } - defer s2.Unsubscribe() - - // Publish out the messages. - for i := int32(0); i < toSend; i++ { - data := []byte(fmt.Sprintf("%d", i)) - sc.Publish("foo", data) - } - - if err := WaitTime(ch, 30*time.Second); err != nil { - t.Fatalf("Did not ack expected count of messages: %v", toSend) - } - - if nr := atomic.LoadInt32(&ackCount); nr != toSend { - t.Fatalf("Did not ack the correct number of messages: %d vs %d\n", nr, toSend) - } -} - func TestRedeliveredFlag(t *testing.T) { // Run a NATS Streaming server s := RunServer(clusterName) @@ -1715,7 +1383,7 @@ func TestMaxChannels(t *testing.T) { opts.MaxChannels = 10 // Run a NATS Streaming server - s := server.RunServerWithOpts(opts, nil) + s := runServerWithOpts(opts) defer s.Shutdown() sc := NewDefaultConnection(t) @@ -1731,7 +1399,7 @@ func TestMaxChannels(t *testing.T) { } // This one should error if err := sc.Publish("CHAN_MAX", hw); err == nil { - t.Fatalf("Expected an error signalling too many channels\n") + t.Fatalf("Expected an error signaling too many channels\n") } } @@ -1797,32 +1465,37 @@ func TestNatsConn(t *testing.T) { } // Bail if we have a custom connection but not connected - cnc := nats.Conn{Opts: nats.DefaultOptions} - sc, err := Connect(clusterName, clientName, NatsConn(&cnc)) - if err != ErrBadConnection { - stackFatalf(t, "Expected to get an invalid connection error, got %v", err) + cnc := nats.Conn{Opts: nats.GetDefaultOptions()} + if _, err := Connect(clusterName, clientName, NatsConn(&cnc)); err != ErrBadConnection { + t.Fatalf("Expected to get an invalid connection error, got %v", err) } // Allow custom conn only if already connected - opts := nats.DefaultOptions - nc, err = opts.Connect() + opts := nats.GetDefaultOptions() + nc, err := opts.Connect() if err != nil { - stackFatalf(t, "Expected to connect correctly, got err %v", err) + t.Fatalf("Expected to connect correctly, got err %v", err) } sc, err = Connect(clusterName, clientName, NatsConn(nc)) if err != nil { - stackFatalf(t, "Expected to connect correctly, got err %v", err) + t.Fatalf("Expected to connect correctly, got err %v", err) } nc.Close() if nc.Status() != nats.CLOSED { t.Fatal("Should have status set to CLOSED") } + sc.Close() // Make sure we can get the Conn we provide. - nc = natstest.NewDefaultConnection(t) + opts = nats.GetDefaultOptions() + nc, err = opts.Connect() + if err != nil { + t.Fatalf("Expected to connect correctly, got err %v", err) + } + defer nc.Close() sc, err = Connect(clusterName, clientName, NatsConn(nc)) if err != nil { - stackFatalf(t, "Expected to connect correctly, got err %v", err) + t.Fatalf("Expected to connect correctly, got err %v", err) } defer sc.Close() if sc.NatsConn() != nc { @@ -1881,6 +1554,89 @@ func TestNatsURLOption(t *testing.T) { } } +func TestSubscriptionPending(t *testing.T) { + // Run a NATS Streaming server + s := RunServer(clusterName) + defer s.Shutdown() + + sc := NewDefaultConnection(t) + defer sc.Close() + + nc := sc.NatsConn() + + total := 100 + msg := []byte("0123456789") + + inCb := make(chan bool) + block := make(chan bool) + cb := func(m *Msg) { + inCb <- true + <-block + } + + sub, _ := sc.QueueSubscribe("foo", "bar", cb) + defer sub.Unsubscribe() + + // Publish five messages + for i := 0; i < total; i++ { + sc.Publish("foo", msg) + } + nc.Flush() + + // Wait for our first message + if err := Wait(inCb); err != nil { + t.Fatal("No message received") + } + + m, b, _ := sub.Pending() + // FIXME(jack0) - nats streaming appends clientid, guid, and subject to messages so bytes pending is greater than message size + mlen := len(msg) + 19 + totalSize := total * mlen + + if m != total && m != total-1 { + t.Fatalf("Expected msgs of %d or %d, got %d\n", total, total-1, m) + } + if b != totalSize && b != totalSize-mlen { + t.Fatalf("Expected bytes of %d or %d, got %d\n", + totalSize, totalSize-mlen, b) + } + + // Make sure max has been set. Since we block after the first message is + // received, MaxPending should be >= total - 1 and <= total + mm, bm, _ := sub.MaxPending() + if mm < total-1 || mm > total { + t.Fatalf("Expected max msgs (%d) to be between %d and %d\n", + mm, total-1, total) + } + if bm < totalSize-mlen || bm > totalSize { + t.Fatalf("Expected max bytes (%d) to be between %d and %d\n", + bm, totalSize, totalSize-mlen) + } + // Check that clear works. + sub.ClearMaxPending() + mm, bm, _ = sub.MaxPending() + if mm != 0 { + t.Fatalf("Expected max msgs to be 0 vs %d after clearing\n", mm) + } + if bm != 0 { + t.Fatalf("Expected max bytes to be 0 vs %d after clearing\n", bm) + } + + close(block) + sub.Unsubscribe() + + // These calls should fail once the subscription is closed. + if _, _, err := sub.Pending(); err == nil { + t.Fatal("Calling Pending() on closed subscription should fail") + } + if _, _, err := sub.MaxPending(); err == nil { + t.Fatal("Calling MaxPending() on closed subscription should fail") + } + if err := sub.ClearMaxPending(); err == nil { + t.Fatal("Calling ClearMaxPending() on closed subscription should fail") + } +} + func TestTimeoutOnRequests(t *testing.T) { ns := natsd.RunDefaultServer() defer ns.Shutdown() @@ -1888,7 +1644,7 @@ func TestTimeoutOnRequests(t *testing.T) { opts := server.GetDefaultOptions() opts.ID = clusterName opts.NATSServerURL = nats.DefaultURL - s := server.RunServerWithOpts(opts, nil) + s := runServerWithOpts(opts) defer s.Shutdown() sc := NewDefaultConnection(t) @@ -1938,6 +1694,68 @@ func TestTimeoutOnRequests(t *testing.T) { } } +func TestSlowAsyncSubscriber(t *testing.T) { + // Run a NATS Streaming server + s := RunServer(clusterName) + defer s.Shutdown() + + sc := NewDefaultConnection(t) + defer sc.Close() + + nc := sc.NatsConn() + + bch := make(chan bool) + + sub, _ := sc.Subscribe("foo", func(_ *Msg) { + // block to back us up.. + <-bch + }) + // Make sure these are the defaults + pm, pb, _ := sub.PendingLimits() + if pm != nats.DefaultSubPendingMsgsLimit { + t.Fatalf("Pending limit for number of msgs incorrect, expected %d, got %d\n", nats.DefaultSubPendingMsgsLimit, pm) + } + if pb != nats.DefaultSubPendingBytesLimit { + t.Fatalf("Pending limit for number of bytes incorrect, expected %d, got %d\n", nats.DefaultSubPendingBytesLimit, pb) + } + + // Set new limits + pml := 100 + pbl := 1024 * 1024 + + sub.SetPendingLimits(pml, pbl) + + // Make sure the set is correct + pm, pb, _ = sub.PendingLimits() + if pm != pml { + t.Fatalf("Pending limit for number of msgs incorrect, expected %d, got %d\n", pml, pm) + } + if pb != pbl { + t.Fatalf("Pending limit for number of bytes incorrect, expected %d, got %d\n", pbl, pb) + } + + for i := 0; i < (int(pml) + 100); i++ { + sc.Publish("foo", []byte("Hello")) + } + + timeout := 5 * time.Second + start := time.Now() + err := nc.FlushTimeout(timeout) + elapsed := time.Since(start) + if elapsed >= timeout { + t.Fatalf("Flush did not return before timeout") + } + // We want flush to work, so expect no error for it. + if err != nil { + t.Fatalf("Expected no error from Flush()\n") + } + if nc.LastError() != nats.ErrSlowConsumer { + t.Fatal("Expected LastError to indicate slow consumer") + } + // release the sub + bch <- true +} + func TestSubscriberClose(t *testing.T) { s := RunServer(clusterName) defer s.Shutdown() @@ -1948,27 +1766,62 @@ func TestSubscriberClose(t *testing.T) { // If old server, Close() is expected to fail. supported := sc.(*conn).subCloseRequests != "" + checkClose := func(sub Subscription) { + err := sub.Close() + if supported && err != nil { + t.Fatalf("Unexpected error on close: %v", err) + } else if !supported && err != ErrNoServerSupport { + t.Fatalf("Expected %v, got %v", ErrNoServerSupport, err) + } + } + + count := 1 + if supported { + count = 2 + } + for i := 0; i < count; i++ { + sub, err := sc.Subscribe("foo", func(_ *Msg) {}) + if err != nil { + t.Fatalf("Unexpected error on subscribe: %v", err) + } + checkClose(sub) + + qsub, err := sc.QueueSubscribe("foo", "group", func(_ *Msg) {}) + if err != nil { + t.Fatalf("Unexpected error on subscribe: %v", err) + } + checkClose(qsub) + + if supported { + // Repeat the tests but pretend server does not support close + sc.(*conn).Lock() + sc.(*conn).subCloseRequests = "" + sc.(*conn).Unlock() + supported = false + } + } + sub, err := sc.Subscribe("foo", func(_ *Msg) {}) if err != nil { t.Fatalf("Unexpected error on subscribe: %v", err) } - err = sub.Close() - if supported && err != nil { - t.Fatalf("Unexpected error on close: %v", err) - } else if !supported && err != ErrNoServerSupport { - t.Fatalf("Expected %v, got %v", ErrNoServerSupport, err) - } - - sub, err = sc.QueueSubscribe("foo", "group", func(_ *Msg) {}) + closedNC, err := nats.Connect(nats.DefaultURL) if err != nil { - t.Fatalf("Unexpected error on subscribe: %v", err) + t.Fatalf("Unexpected error on connect: %v", err) } - err = sub.Close() - if supported && err != nil { - t.Fatalf("Unexpected error on close: %v", err) - } else if !supported && err != ErrNoServerSupport { - t.Fatalf("Expected %v, got %v", ErrNoServerSupport, err) + closedNC.Close() + // Swap current NATS connection with this closed connection + sc.(*conn).Lock() + savedNC := sc.(*conn).nc + sc.(*conn).nc = closedNC + sc.(*conn).Unlock() + if err := sub.Unsubscribe(); err == nil { + t.Fatal("Expected error on close") } + // Restore NATS connection + sc.(*conn).Lock() + sc.(*conn).nc = savedNC + sc.(*conn).Unlock() sc.Close() @@ -1976,6 +1829,20 @@ func TestSubscriberClose(t *testing.T) { closeSubscriber(t, "durqueuesub", "queue") } +func TestOptionNatsName(t *testing.T) { + s := RunServer(clusterName) + defer s.Shutdown() + sc := NewDefaultConnection(t) + defer sc.Close() + + // Make sure we can get the STAN-created Conn. + nc := sc.NatsConn() + + if n := nc.Opts.Name; n != clientName { + t.Fatalf("Unexpected nats client name: %s", n) + } +} + func closeSubscriber(t *testing.T, channel, subType string) { sc := NewDefaultConnection(t) defer sc.Close() @@ -2051,3 +1918,574 @@ func closeSubscriber(t *testing.T, channel, subType string) { stackFatalf(t, "Timeout waiting for messages") } } + +func TestDuplicateProcessingOfPubAck(t *testing.T) { + // We run our tests on Windows VM and this test would fail because + // server would be a slow consumer. So skipping for now. + if runtime.GOOS == "windows" { + t.SkipNow() + } + s := RunServer(clusterName) + defer s.Shutdown() + + // Use a very small timeout purposely + sc, err := Connect(clusterName, clientName, PubAckWait(time.Millisecond)) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + defer sc.Close() + + total := 10000 + pubAcks := make(map[string]struct{}, total) + gotBug := false + errCh := make(chan error) + msg := []byte("msg") + count := 0 + done := make(chan bool) + mu := &sync.Mutex{} + + ackHandler := func(guid string, err error) { + mu.Lock() + if gotBug { + mu.Unlock() + return + } + if _, exist := pubAcks[guid]; exist { + gotBug = true + errCh <- fmt.Errorf("Duplicate processing of PubAck %d guid=%v", (count + 1), guid) + mu.Unlock() + return + } + pubAcks[guid] = struct{}{} + count++ + if count == total { + done <- true + } + mu.Unlock() + } + for i := 0; i < total; i++ { + sc.PublishAsync("foo", msg, ackHandler) + } + select { + case <-done: + case e := <-errCh: + t.Fatal(e) + case <-time.After(10 * time.Second): + t.Fatal("Test took too long") + } + // If we are here is that we have published `total` messages. + // Since the bug is about processing duplicate PubAck, + // wait a bit more. + select { + case e := <-errCh: + t.Fatal(e) + case <-time.After(100 * time.Millisecond): + // This is more than the PubAckWait, so we should be good now. + } +} + +func TestSubDelivered(t *testing.T) { + s := RunServer(clusterName) + defer s.Shutdown() + + sc := NewDefaultConnection(t) + defer sc.Close() + + total := 10 + count := 0 + ch := make(chan bool) + sub, err := sc.Subscribe("foo", func(_ *Msg) { + count++ + if count == total { + ch <- true + } + }) + if err != nil { + t.Fatalf("Unexpected error on subscriber: %v", err) + } + defer sub.Unsubscribe() + + for i := 0; i < total; i++ { + if err := sc.Publish("foo", []byte("hello")); err != nil { + t.Fatalf("Unexpected error on publish: %v", err) + } + } + // Wait for all messages + if err := Wait(ch); err != nil { + t.Fatal("Did not get our messages") + } + if n, err := sub.Delivered(); err != nil || n != int64(total) { + t.Fatalf("Expected %d messages delivered, got %d, err=%v", total, n, err) + } + sub.Unsubscribe() + if n, err := sub.Delivered(); err != ErrBadSubscription || n != int64(-1) { + t.Fatalf("Expected ErrBadSubscription, got %d, err=%v", n, err) + } +} + +func TestSubDropped(t *testing.T) { + s := RunServer(clusterName) + defer s.Shutdown() + + sc := NewDefaultConnection(t) + defer sc.Close() + + total := 1000 + count := 0 + ch := make(chan bool) + blocked := make(chan bool) + ready := make(chan bool) + sub, err := sc.Subscribe("foo", func(_ *Msg) { + count++ + if count == 1 { + ready <- true + <-blocked + ch <- true + } + }) + if err != nil { + t.Fatalf("Unexpected error on subscriber: %v", err) + } + defer sub.Unsubscribe() + + // Set low pending limits + sub.SetPendingLimits(1, -1) + + for i := 0; i < total; i++ { + if err := sc.Publish("foo", []byte("hello")); err != nil { + t.Fatalf("Unexpected error on publish: %v", err) + } + } + // Wait for sub to receive first message and block + if err := Wait(ready); err != nil { + t.Fatal("Did not get our first message") + } + + // Messages should be dropped + if n, err := sub.Dropped(); err != nil || n == 0 { + t.Fatalf("Messages should have been dropped, got %d, err=%v", n, err) + } + + // Unblock and wait for end + close(blocked) + if err := Wait(ch); err != nil { + t.Fatal("Callback did not return") + } + sub.Unsubscribe() + // Now subscription is closed, this should return error + if n, err := sub.Dropped(); err != ErrBadSubscription || n != -1 { + t.Fatalf("Expected ErrBadSubscription, got %d, err=%v", n, err) + } +} + +func TestSubIsValid(t *testing.T) { + s := RunServer(clusterName) + defer s.Shutdown() + + sc := NewDefaultConnection(t) + defer sc.Close() + + sub, err := sc.Subscribe("foo", func(_ *Msg) {}) + if err != nil { + t.Fatalf("Unexpected error on subscriber: %v", err) + } + defer sub.Unsubscribe() + if !sub.IsValid() { + t.Fatal("Subscription should be valid") + } + sub.Unsubscribe() + if sub.IsValid() { + t.Fatal("Subscription should not be valid") + } +} + +func TestPingsInvalidOptions(t *testing.T) { + s := RunServer(clusterName) + defer s.Shutdown() + for _, test := range []struct { + name string + opt Option + }{ + { + "Negative interval", + Pings(-1, 10), + }, + { + "Zero interval", + Pings(-1, 10), + }, + { + "Negative maxOut ", + Pings(1, -1), + }, + { + "Too small maxOut", + Pings(1, 1), + }, + } { + t.Run(test.name, func(t *testing.T) { + sc, err := Connect(clusterName, clientName, test.opt) + if sc != nil { + sc.Close() + } + if err == nil { + t.Fatalf("Expected error") + } + }) + } +} + +func pingInMillis(interval int) int { + return interval * -1 +} + +func TestPings(t *testing.T) { + s := RunServer(clusterName) + defer s.Shutdown() + + testAllowMillisecInPings = true + defer func() { testAllowMillisecInPings = false }() + + // Create a sub on the subject the pings are sent to + nc, err := nats.Connect(nats.DefaultURL) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + count := 0 + ch := make(chan bool, 1) + nc.Subscribe(DefaultDiscoverPrefix+"."+clusterName+".pings", func(m *nats.Msg) { + count++ + // Wait more than the number of maxOut + if count == 10 { + ch <- true + } + }) + + errCh := make(chan error, 1) + sc, err := Connect(clusterName, clientName, + Pings(pingInMillis(50), 5), + SetConnectionLostHandler(func(sc Conn, err error) { + errCh <- err + })) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + defer sc.Close() + + if err := Wait(ch); err != nil { + t.Fatal("Did not get our pings") + } + // Kill the server and expect the error callback to fire + s.Shutdown() + select { + case e := <-errCh: + if e != ErrMaxPings { + t.Fatalf("Expected error %v, got %v", ErrMaxPings, e) + } + case <-time.After(2 * time.Second): + t.Fatalf("Error callback should have fired") + } + // Check that connection is closed. + c := sc.(*conn) + c.RLock() + c.pingMu.Lock() + timerIsNil := c.pingTimer == nil + c.pingMu.Unlock() + c.RUnlock() + if !timerIsNil { + t.Fatalf("Expected timer to be nil") + } + if sc.NatsConn() != nil { + t.Fatalf("Expected nats conn to be nil") + } + + s = RunServer(clusterName) + defer s.Shutdown() + + sc, err = Connect(clusterName, clientName, + Pings(pingInMillis(50), 100), + SetConnectionLostHandler(func(sc Conn, err error) { + errCh <- err + })) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + defer sc.Close() + + // Kill NATS connection, expect different error + sc.NatsConn().Close() + select { + case e := <-errCh: + if e != nats.ErrConnectionClosed { + t.Fatalf("Expected error %v, got %v", nats.ErrConnectionClosed, e) + } + case <-time.After(2 * time.Second): + t.Fatalf("Error callback should have fired") + } +} + +func TestPingsCloseUnlockPubCalls(t *testing.T) { + ns := natsd.RunDefaultServer() + defer ns.Shutdown() + + testAllowMillisecInPings = true + defer func() { testAllowMillisecInPings = false }() + + opts := server.GetDefaultOptions() + opts.NATSServerURL = nats.DefaultURL + opts.ID = clusterName + s := runServerWithOpts(opts) + defer s.Shutdown() + + sc, err := Connect(clusterName, clientName, + MaxPubAcksInflight(1), + Pings(pingInMillis(50), 10)) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + defer sc.Close() + + s.Shutdown() + + total := 100 + ch := make(chan bool, 1) + ec := int32(0) + ah := func(g string, e error) { + if c := atomic.AddInt32(&ec, 1); c == int32(total) { + ch <- true + } + } + wg := sync.WaitGroup{} + wg.Add(total) + for i := 0; i < total/2; i++ { + go func() { + sc.PublishAsync("foo", []byte("hello"), ah) + wg.Done() + }() + go func() { + if err := sc.Publish("foo", []byte("hello")); err != nil { + if c := atomic.AddInt32(&ec, 1); c == int32(total) { + ch <- true + } + } + wg.Done() + }() + } + if err := Wait(ch); err != nil { + t.Fatal("Did not get all the expected failures") + } + wg.Wait() +} + +func TestConnErrHandlerNotCalledOnNormalClose(t *testing.T) { + s := RunServer(clusterName) + defer s.Shutdown() + + errCh := make(chan error, 1) + sc, err := Connect(clusterName, clientName, + SetConnectionLostHandler(func(_ Conn, err error) { + errCh <- err + })) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + sc.Close() + select { + case <-errCh: + t.Fatalf("ConnErrHandler should not have been invoked in normal close") + case <-time.After(250 * time.Millisecond): + // ok + } +} + +type pubFailsOnClientReplacedDialer struct { + sync.Mutex + conn net.Conn + fail bool + ch chan bool +} + +func (d *pubFailsOnClientReplacedDialer) Dial(network, address string) (net.Conn, error) { + d.Lock() + defer d.Unlock() + if d.fail { + return nil, fmt.Errorf("error on purpose") + } + c, err := net.Dial(network, address) + if err != nil { + return nil, err + } + d.conn = c + d.ch <- true + return c, nil +} + +func TestPubFailsOnClientReplaced(t *testing.T) { + s := RunServer(clusterName) + defer s.Shutdown() + + cd := &pubFailsOnClientReplacedDialer{ch: make(chan bool, 1)} + + nc, err := nats.Connect(nats.DefaultURL, + nats.MaxReconnects(-1), + nats.ReconnectWait(50*time.Millisecond), + nats.SetCustomDialer(cd)) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + defer nc.Close() + + // Consume dial success notification + <-cd.ch + + sc, err := Connect(clusterName, clientName, NatsConn(nc)) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + // Send a message and ensure it is ok. + if err := sc.Publish("foo", []byte("hello")); err != nil { + t.Fatalf("Error on publish: %v", err) + } + + // Cause failure of client connection + cd.Lock() + cd.fail = true + cd.conn.Close() + cd.Unlock() + + // Create new client with same client ID + sc2, err := Connect(clusterName, clientName) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + // Verify that this client can publish + if err := sc2.Publish("foo", []byte("hello")); err != nil { + t.Fatalf("Error on publish: %v", err) + } + + // Allow first client to "reconnect" + cd.Lock() + cd.fail = false + cd.Unlock() + + // Wait for the reconnect + <-cd.ch + + // Wait a bit and try to publish + time.Sleep(50 * time.Millisecond) + // It should fail + if err := sc.Publish("foo", []byte("hello")); err == nil { + t.Fatalf("Publish of first client should have failed") + } +} + +func TestPingsResponseError(t *testing.T) { + s := RunServer(clusterName) + defer s.Shutdown() + + testAllowMillisecInPings = true + defer func() { testAllowMillisecInPings = false }() + + cd := &pubFailsOnClientReplacedDialer{ch: make(chan bool, 1)} + + nc, err := nats.Connect(nats.DefaultURL, + nats.MaxReconnects(-1), + nats.ReconnectWait(50*time.Millisecond), + nats.SetCustomDialer(cd)) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + defer nc.Close() + + // Consume dial success notification + <-cd.ch + + errCh := make(chan error, 1) + sc, err := Connect(clusterName, clientName, + NatsConn(nc), + // Make it big enough so that we get the response error before we reach the max + Pings(pingInMillis(50), 100), + SetConnectionLostHandler(func(_ Conn, err error) { + errCh <- err + })) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + // Send a message and ensure it is ok. + if err := sc.Publish("foo", []byte("hello")); err != nil { + t.Fatalf("Error on publish: %v", err) + } + + // Cause failure of client connection + cd.Lock() + cd.fail = true + cd.conn.Close() + cd.Unlock() + + // Create new client with same client ID + sc2, err := Connect(clusterName, clientName) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + // Verify that this client can publish + if err := sc2.Publish("foo", []byte("hello")); err != nil { + t.Fatalf("Error on publish: %v", err) + } + + // Allow first client to "reconnect" + cd.Lock() + cd.fail = false + cd.Unlock() + + // Wait for the reconnect + <-cd.ch + + // Wait for the error callback + select { + case e := <-errCh: + if !strings.Contains(e.Error(), "replaced") { + t.Fatalf("Expected error saying that client was replaced, got %v", e) + } + case <-time.After(2 * time.Second): + t.Fatalf("Error callback not invoked") + } +} + +func TestClientIDAndConnIDInPubMsg(t *testing.T) { + s := RunServer(clusterName) + defer s.Shutdown() + + // By default, when connecting to a 0.10.0+ server, the PubMsg + // now only contains a connection ID, not the publish call. + sc := NewDefaultConnection(t) + defer sc.Close() + + c := sc.(*conn) + c.RLock() + pubSubj := c.pubPrefix + connID := c.connID + c.RUnlock() + + nc, err := nats.Connect(nats.DefaultURL) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + defer nc.Close() + ch := make(chan bool, 1) + nc.Subscribe(pubSubj+".foo", func(m *nats.Msg) { + pubMsg := &pb.PubMsg{} + pubMsg.Unmarshal(m.Data) + if pubMsg.ClientID == clientName && bytes.Equal(pubMsg.ConnID, connID) { + ch <- true + } + }) + nc.Flush() + + if sc.Publish("foo", []byte("hello")); err != nil { + t.Fatalf("Error on publish: %v", err) + } + // Verify that client ID and ConnID are properly set + if err := Wait(ch); err != nil { + t.Fatal("Invalid ClientID and/or ConnID") + } +} diff --git a/gateway/vendor/github.com/nats-io/go-nats-streaming/sub.go b/gateway/vendor/github.com/nats-io/go-nats-streaming/sub.go index b545ac7f..f35763a5 100644 --- a/gateway/vendor/github.com/nats-io/go-nats-streaming/sub.go +++ b/gateway/vendor/github.com/nats-io/go-nats-streaming/sub.go @@ -1,4 +1,15 @@ -// Copyright 2016 Apcera Inc. All rights reserved. +// Copyright 2016-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // Package stan is a Go client for the NATS Streaming messaging system (https://nats.io). package stan @@ -30,6 +41,14 @@ type Msg struct { // Subscription represents a subscription within the NATS Streaming cluster. Subscriptions // will be rate matched and follow at-least delivery semantics. type Subscription interface { + ClearMaxPending() error + Delivered() (int64, error) + Dropped() (int, error) + IsValid() bool + MaxPending() (int, int, error) + Pending() (int, int, error) + PendingLimits() (int, int, error) + SetPendingLimits(msgLimit, bytesLimit int) error // Unsubscribe removes interest in the subscription. // For durables, it means that the durable interest is also removed from // the server. Restarting a durable with the same name will not resume @@ -256,12 +275,97 @@ func (sc *conn) subscribe(subject, qgroup string, cb MsgHandler, options ...Subs return sub, nil } +// ClearMaxPending resets the maximums seen so far. +func (sub *subscription) ClearMaxPending() error { + sub.Lock() + defer sub.Unlock() + if sub.inboxSub == nil { + return ErrBadSubscription + } + return sub.inboxSub.ClearMaxPending() +} + +// Delivered returns the number of delivered messages for this subscription. +func (sub *subscription) Delivered() (int64, error) { + sub.Lock() + defer sub.Unlock() + if sub.inboxSub == nil { + return -1, ErrBadSubscription + } + return sub.inboxSub.Delivered() +} + +// Dropped returns the number of known dropped messages for this subscription. +// This will correspond to messages dropped by violations of PendingLimits. If +// the server declares the connection a SlowConsumer, this number may not be +// valid. +func (sub *subscription) Dropped() (int, error) { + sub.Lock() + defer sub.Unlock() + if sub.inboxSub == nil { + return -1, ErrBadSubscription + } + return sub.inboxSub.Dropped() +} + +// IsValid returns a boolean indicating whether the subscription +// is still active. This will return false if the subscription has +// already been closed. +func (sub *subscription) IsValid() bool { + sub.Lock() + defer sub.Unlock() + if sub.inboxSub == nil { + return false + } + return sub.inboxSub.IsValid() +} + +// MaxPending returns the maximum number of queued messages and queued bytes seen so far. +func (sub *subscription) MaxPending() (int, int, error) { + sub.Lock() + defer sub.Unlock() + if sub.inboxSub == nil { + return -1, -1, ErrBadSubscription + } + return sub.inboxSub.MaxPending() +} + +// Pending returns the number of queued messages and queued bytes in the client for this subscription. +func (sub *subscription) Pending() (int, int, error) { + sub.Lock() + defer sub.Unlock() + if sub.inboxSub == nil { + return -1, -1, ErrBadSubscription + } + return sub.inboxSub.Pending() +} + +// PendingLimits returns the current limits for this subscription. +// If no error is returned, a negative value indicates that the +// given metric is not limited. +func (sub *subscription) PendingLimits() (int, int, error) { + sub.Lock() + defer sub.Unlock() + if sub.inboxSub == nil { + return -1, -1, ErrBadSubscription + } + return sub.inboxSub.PendingLimits() +} + +// SetPendingLimits sets the limits for pending msgs and bytes for this subscription. +// Zero is not allowed. Any negative value means that the given metric is not limited. +func (sub *subscription) SetPendingLimits(msgLimit, bytesLimit int) error { + sub.Lock() + defer sub.Unlock() + if sub.inboxSub == nil { + return ErrBadSubscription + } + return sub.inboxSub.SetPendingLimits(msgLimit, bytesLimit) +} + // closeOrUnsubscribe performs either close or unsubsribe based on // given boolean. func (sub *subscription) closeOrUnsubscribe(doClose bool) error { - if sub == nil { - return ErrBadSubscription - } sub.Lock() sc := sub.sc if sc == nil { @@ -274,10 +378,6 @@ func (sub *subscription) closeOrUnsubscribe(doClose bool) error { sub.inboxSub = nil sub.Unlock() - if sc == nil { - return ErrBadSubscription - } - sc.Lock() if sc.nc == nil { sc.Unlock() @@ -342,12 +442,8 @@ func (msg *Msg) Ack() error { if msg == nil { return ErrNilMsg } - // Look up subscription + // Look up subscription (cannot be nil) sub := msg.Sub.(*subscription) - if sub == nil { - return ErrBadSubscription - } - sub.RLock() ackSubject := sub.ackInbox isManualAck := sub.opts.ManualAcks @@ -355,6 +451,9 @@ func (msg *Msg) Ack() error { sub.RUnlock() // Check for error conditions. + if !isManualAck { + return ErrManualAck + } if sc == nil { return ErrBadSubscription } @@ -365,9 +464,6 @@ func (msg *Msg) Ack() error { if nc == nil { return ErrBadConnection } - if !isManualAck { - return ErrManualAck - } // Ack here. ack := &pb.Ack{Subject: msg.Subject, Sequence: msg.Sequence} diff --git a/gateway/vendor/github.com/nats-io/go-nats/.travis.yml b/gateway/vendor/github.com/nats-io/go-nats/.travis.yml index e3bbae52..24c08c28 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/.travis.yml +++ b/gateway/vendor/github.com/nats-io/go-nats/.travis.yml @@ -1,9 +1,9 @@ language: go sudo: false go: +- 1.10.x - 1.9.x - 1.8.x -- 1.7.x install: - go get -t ./... - go get github.com/nats-io/gnatsd @@ -18,4 +18,4 @@ before_script: - megacheck -ignore "$(cat staticcheck.ignore)" ./... script: - go test -i -race ./... -- if [[ "$TRAVIS_GO_VERSION" == 1.7.* ]]; then ./scripts/cov.sh TRAVIS; else go test -v -race ./...; fi +- if [[ "$TRAVIS_GO_VERSION" == 1.9.* ]]; then ./scripts/cov.sh TRAVIS; else go test -v -race ./...; fi diff --git a/gateway/vendor/github.com/nats-io/go-nats/LICENSE b/gateway/vendor/github.com/nats-io/go-nats/LICENSE index 9798d4ef..261eeb9e 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/LICENSE +++ b/gateway/vendor/github.com/nats-io/go-nats/LICENSE @@ -1,20 +1,201 @@ -The MIT License (MIT) + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ -Copyright (c) 2012-2017 Apcera Inc. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: + 1. Definitions. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/gateway/vendor/github.com/nats-io/go-nats/OWNERS b/gateway/vendor/github.com/nats-io/go-nats/OWNERS new file mode 100644 index 00000000..a2530668 --- /dev/null +++ b/gateway/vendor/github.com/nats-io/go-nats/OWNERS @@ -0,0 +1,7 @@ +reviewers: + - derekcollison + - kozlovic + - wallyqs +approvers: + - derekcollison + - kozlovic diff --git a/gateway/vendor/github.com/nats-io/go-nats/README.md b/gateway/vendor/github.com/nats-io/go-nats/README.md index ae6868c5..5b898021 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/README.md +++ b/gateway/vendor/github.com/nats-io/go-nats/README.md @@ -1,7 +1,7 @@ # NATS - Go Client A [Go](http://golang.org) client for the [NATS messaging system](https://nats.io). -[![License MIT](https://img.shields.io/badge/License-MIT-blue.svg)](http://opensource.org/licenses/MIT) +[![License Apache 2](https://img.shields.io/badge/License-Apache2-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0) [![Go Report Card](https://goreportcard.com/badge/github.com/nats-io/go-nats)](https://goreportcard.com/report/github.com/nats-io/go-nats) [![Build Status](https://travis-ci.org/nats-io/go-nats.svg?branch=master)](http://travis-ci.org/nats-io/go-nats) [![GoDoc](https://godoc.org/github.com/nats-io/go-nats?status.svg)](http://godoc.org/github.com/nats-io/go-nats) [![Coverage Status](https://coveralls.io/repos/nats-io/go-nats/badge.svg?branch=master)](https://coveralls.io/r/nats-io/go-nats?branch=master) ## Installation @@ -327,24 +327,5 @@ err := c.RequestWithContext(ctx, "foo", req, resp) ## License -(The MIT License) - -Copyright (c) 2012-2017 Apcera Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to -deal in the Software without restriction, including without limitation the -rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -sell copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. +Unless otherwise noted, the NATS source files are distributed +under the Apache Version 2.0 license found in the LICENSE file. diff --git a/gateway/vendor/github.com/nats-io/go-nats/bench/bench.go b/gateway/vendor/github.com/nats-io/go-nats/bench/bench.go index 54511ce1..2dc496bf 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/bench/bench.go +++ b/gateway/vendor/github.com/nats-io/go-nats/bench/bench.go @@ -1,4 +1,15 @@ -// Copyright 2016 Apcera Inc. All rights reserved. +// Copyright 2016-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package bench diff --git a/gateway/vendor/github.com/nats-io/go-nats/bench/benchlib_test.go b/gateway/vendor/github.com/nats-io/go-nats/bench/benchlib_test.go index 6d7dddca..2fa43a50 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/bench/benchlib_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/bench/benchlib_test.go @@ -1,3 +1,16 @@ +// Copyright 2016-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package bench import ( diff --git a/gateway/vendor/github.com/nats-io/go-nats/context.go b/gateway/vendor/github.com/nats-io/go-nats/context.go index be6ada4a..4f9ec67d 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/context.go +++ b/gateway/vendor/github.com/nats-io/go-nats/context.go @@ -1,4 +1,15 @@ -// Copyright 2012-2017 Apcera Inc. All rights reserved. +// Copyright 2016-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // +build go1.7 diff --git a/gateway/vendor/github.com/nats-io/go-nats/enc.go b/gateway/vendor/github.com/nats-io/go-nats/enc.go index 291b7826..08edfe53 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/enc.go +++ b/gateway/vendor/github.com/nats-io/go-nats/enc.go @@ -1,4 +1,15 @@ -// Copyright 2012-2015 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package nats diff --git a/gateway/vendor/github.com/nats-io/go-nats/enc_test.go b/gateway/vendor/github.com/nats-io/go-nats/enc_test.go index ada5b024..ca170e8b 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/enc_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/enc_test.go @@ -1,3 +1,16 @@ +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package nats_test import ( diff --git a/gateway/vendor/github.com/nats-io/go-nats/encoders/builtin/default_enc.go b/gateway/vendor/github.com/nats-io/go-nats/encoders/builtin/default_enc.go index 82467ce7..46d918ee 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/encoders/builtin/default_enc.go +++ b/gateway/vendor/github.com/nats-io/go-nats/encoders/builtin/default_enc.go @@ -1,4 +1,15 @@ -// Copyright 2012-2015 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package builtin diff --git a/gateway/vendor/github.com/nats-io/go-nats/encoders/builtin/gob_enc.go b/gateway/vendor/github.com/nats-io/go-nats/encoders/builtin/gob_enc.go index 988ff42f..632bcbd3 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/encoders/builtin/gob_enc.go +++ b/gateway/vendor/github.com/nats-io/go-nats/encoders/builtin/gob_enc.go @@ -1,4 +1,15 @@ -// Copyright 2013-2015 Apcera Inc. All rights reserved. +// Copyright 2013-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package builtin diff --git a/gateway/vendor/github.com/nats-io/go-nats/encoders/builtin/json_enc.go b/gateway/vendor/github.com/nats-io/go-nats/encoders/builtin/json_enc.go index 3b269ef0..c9670f31 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/encoders/builtin/json_enc.go +++ b/gateway/vendor/github.com/nats-io/go-nats/encoders/builtin/json_enc.go @@ -1,4 +1,15 @@ -// Copyright 2012-2015 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package builtin diff --git a/gateway/vendor/github.com/nats-io/go-nats/encoders/protobuf/protobuf_enc.go b/gateway/vendor/github.com/nats-io/go-nats/encoders/protobuf/protobuf_enc.go index e44466d9..1a731056 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/encoders/protobuf/protobuf_enc.go +++ b/gateway/vendor/github.com/nats-io/go-nats/encoders/protobuf/protobuf_enc.go @@ -1,4 +1,15 @@ -// Copyright 2015 Apcera Inc. All rights reserved. +// Copyright 2015-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package protobuf diff --git a/gateway/vendor/github.com/nats-io/go-nats/example_test.go b/gateway/vendor/github.com/nats-io/go-nats/example_test.go index 64a65867..f0101763 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/example_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/example_test.go @@ -1,3 +1,16 @@ +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package nats_test import ( diff --git a/gateway/vendor/github.com/nats-io/go-nats/examples/nats-bench.go b/gateway/vendor/github.com/nats-io/go-nats/examples/nats-bench.go index 82d9c8f8..e24151c3 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/examples/nats-bench.go +++ b/gateway/vendor/github.com/nats-io/go-nats/examples/nats-bench.go @@ -1,4 +1,15 @@ -// Copyright 2015 Apcera Inc. All rights reserved. +// Copyright 2015-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package main diff --git a/gateway/vendor/github.com/nats-io/go-nats/examples/nats-pub.go b/gateway/vendor/github.com/nats-io/go-nats/examples/nats-pub.go index 4eaedb25..c129f504 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/examples/nats-pub.go +++ b/gateway/vendor/github.com/nats-io/go-nats/examples/nats-pub.go @@ -1,4 +1,16 @@ -// Copyright 2012-2016 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // +build ignore package main diff --git a/gateway/vendor/github.com/nats-io/go-nats/examples/nats-qsub.go b/gateway/vendor/github.com/nats-io/go-nats/examples/nats-qsub.go index 2262dba6..05e72671 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/examples/nats-qsub.go +++ b/gateway/vendor/github.com/nats-io/go-nats/examples/nats-qsub.go @@ -1,4 +1,16 @@ -// Copyright 2012-2016 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // +build ignore package main diff --git a/gateway/vendor/github.com/nats-io/go-nats/examples/nats-req.go b/gateway/vendor/github.com/nats-io/go-nats/examples/nats-req.go index 711be5e7..680d77bb 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/examples/nats-req.go +++ b/gateway/vendor/github.com/nats-io/go-nats/examples/nats-req.go @@ -1,4 +1,16 @@ -// Copyright 2012-2016 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // +build ignore package main diff --git a/gateway/vendor/github.com/nats-io/go-nats/examples/nats-rply.go b/gateway/vendor/github.com/nats-io/go-nats/examples/nats-rply.go index be284bb5..8ea09e23 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/examples/nats-rply.go +++ b/gateway/vendor/github.com/nats-io/go-nats/examples/nats-rply.go @@ -1,4 +1,16 @@ -// Copyright 2012-2016 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // +build ignore package main diff --git a/gateway/vendor/github.com/nats-io/go-nats/examples/nats-sub.go b/gateway/vendor/github.com/nats-io/go-nats/examples/nats-sub.go index 048a0d96..68c19837 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/examples/nats-sub.go +++ b/gateway/vendor/github.com/nats-io/go-nats/examples/nats-sub.go @@ -1,4 +1,16 @@ -// Copyright 2012-2016 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // +build ignore package main diff --git a/gateway/vendor/github.com/nats-io/go-nats/nats.go b/gateway/vendor/github.com/nats-io/go-nats/nats.go index b3ba1f7b..225b5400 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/nats.go +++ b/gateway/vendor/github.com/nats-io/go-nats/nats.go @@ -1,4 +1,15 @@ -// Copyright 2012-2017 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // A Go client for the NATS messaging system (https://nats.io). package nats @@ -11,15 +22,16 @@ import ( "encoding/json" "errors" "fmt" + "io" "io/ioutil" "math/rand" "net" "net/url" - "regexp" "runtime" "strconv" "strings" "sync" + "sync/atomic" "time" "github.com/nats-io/go-nats/util" @@ -28,7 +40,7 @@ import ( // Default Constants const ( - Version = "1.3.1" + Version = "1.5.0" DefaultURL = "nats://localhost:4222" DefaultPort = 4222 DefaultMaxReconnect = 60 @@ -351,6 +363,12 @@ type Msg struct { Data []byte Sub *Subscription next *Msg + barrier *barrierInfo +} + +type barrierInfo struct { + refs int64 + f func() } // Tracks various stats received and sent on this connection, @@ -528,6 +546,14 @@ func MaxReconnects(max int) Option { } } +// ReconnectBufSize sets the buffer size of messages kept while busy reconnecting +func ReconnectBufSize(size int) Option { + return func(o *Options) error { + o.ReconnectBufSize = size + return nil + } +} + // Timeout is an Option to set the timeout for Dial on a connection. func Timeout(t time.Duration) Option { return func(o *Options) error { @@ -568,7 +594,7 @@ func DiscoveredServersHandler(cb ConnHandler) Option { } } -// ErrHandler is an Option to set the async error handler. +// ErrorHandler is an Option to set the async error handler. func ErrorHandler(cb ErrHandler) Option { return func(o *Options) error { o.AsyncErrorCB = cb @@ -615,7 +641,7 @@ func SetCustomDialer(dialer CustomDialer) Option { } } -// UseOldRequestyStyle is an Option to force usage of the old Request style. +// UseOldRequestStyle is an Option to force usage of the old Request style. func UseOldRequestStyle() Option { return func(o *Options) error { o.UseOldRequestStyle = true @@ -665,7 +691,7 @@ func (nc *Conn) SetClosedHandler(cb ConnHandler) { nc.Opts.ClosedCB = cb } -// SetErrHandler will set the async error handler. +// SetErrorHandler will set the async error handler. func (nc *Conn) SetErrorHandler(cb ErrHandler) { if nc == nil { return @@ -1094,7 +1120,7 @@ func (nc *Conn) connect() error { } else { // Cancel out default connection refused, will trigger the // No servers error conditional - if matched, _ := regexp.Match(`connection refused`, []byte(err.Error())); matched { + if strings.Contains(err.Error(), "connection refused") { returnedErr = nil } } @@ -1229,38 +1255,40 @@ func (nc *Conn) sendConnect() error { return err } - // Now read the response from the server. - br := bufio.NewReaderSize(nc.conn, defaultBufSize) - line, err := br.ReadString('\n') + // We don't want to read more than we need here, otherwise + // we would need to transfer the excess read data to the readLoop. + // Since in normal situations we just are looking for a PONG\r\n, + // reading byte-by-byte here is ok. + proto, err := nc.readProto() if err != nil { return err } // If opts.Verbose is set, handle +OK - if nc.Opts.Verbose && line == okProto { + if nc.Opts.Verbose && proto == okProto { // Read the rest now... - line, err = br.ReadString('\n') + proto, err = nc.readProto() if err != nil { return err } } // We expect a PONG - if line != pongProto { + if proto != pongProto { // But it could be something else, like -ERR // Since we no longer use ReadLine(), trim the trailing "\r\n" - line = strings.TrimRight(line, "\r\n") + proto = strings.TrimRight(proto, "\r\n") // If it's a server error... - if strings.HasPrefix(line, _ERR_OP_) { + if strings.HasPrefix(proto, _ERR_OP_) { // Remove -ERR, trim spaces and quotes, and convert to lower case. - line = normalizeErr(line) - return errors.New("nats: " + line) + proto = normalizeErr(proto) + return errors.New("nats: " + proto) } // Notify that we got an unexpected protocol. - return fmt.Errorf("nats: expected '%s', got '%s'", _PONG_OP_, line) + return fmt.Errorf("nats: expected '%s', got '%s'", _PONG_OP_, proto) } // This is where we are truly connected. @@ -1269,6 +1297,29 @@ func (nc *Conn) sendConnect() error { return nil } +// reads a protocol one byte at a time. +func (nc *Conn) readProto() (string, error) { + var ( + _buf = [10]byte{} + buf = _buf[:0] + b = [1]byte{} + protoEnd = byte('\n') + ) + for { + if _, err := nc.conn.Read(b[:1]); err != nil { + // Do not report EOF error + if err == io.EOF { + return string(buf), nil + } + return "", err + } + buf = append(buf, b[0]) + if b[0] == protoEnd { + return string(buf), nil + } + } +} + // A control protocol line. type control struct { op, args string @@ -1460,10 +1511,12 @@ func (nc *Conn) processOpErr(err error) { nc.conn = nil } - // Create a new pending buffer to underpin the bufio Writer while - // we are reconnecting. - nc.pending = &bytes.Buffer{} - nc.bw = bufio.NewWriterSize(nc.pending, nc.Opts.ReconnectBufSize) + // Reset pending buffers before reconnecting. + if nc.pending == nil { + nc.pending = new(bytes.Buffer) + } + nc.pending.Reset() + nc.bw.Reset(nc.pending) go nc.doReconnect() nc.mu.Unlock() @@ -1571,6 +1624,13 @@ func (nc *Conn) waitForMsgs(s *Subscription) { if s.pHead == nil { s.pTail = nil } + if m.barrier != nil { + s.mu.Unlock() + if atomic.AddInt64(&m.barrier.refs, -1) == 0 { + m.barrier.f() + } + continue + } s.pMsgs-- s.pBytes -= len(m.Data) } @@ -1599,6 +1659,19 @@ func (nc *Conn) waitForMsgs(s *Subscription) { break } } + // Check for barrier messages + s.mu.Lock() + for m := s.pHead; m != nil; m = s.pHead { + if m.barrier != nil { + s.mu.Unlock() + if atomic.AddInt64(&m.barrier.refs, -1) == 0 { + m.barrier.f() + } + s.mu.Lock() + } + s.pHead = m.next + } + s.mu.Unlock() } // processMsg is called by parse and will place the msg on the @@ -1812,32 +1885,67 @@ func (nc *Conn) processInfo(info string) error { if info == _EMPTY_ { return nil } - if err := json.Unmarshal([]byte(info), &nc.info); err != nil { + ncInfo := serverInfo{} + if err := json.Unmarshal([]byte(info), &ncInfo); err != nil { return err } + // Copy content into connection's info structure. + nc.info = ncInfo + // The array could be empty/not present on initial connect, + // if advertise is disabled on that server, or servers that + // did not include themselves in the async INFO protocol. + // If empty, do not remove the implicit servers from the pool. + if len(ncInfo.ConnectURLs) == 0 { + return nil + } + // Note about pool randomization: when the pool was first created, + // it was randomized (if allowed). We keep the order the same (removing + // implicit servers that are no longer sent to us). New URLs are sent + // to us in no specific order so don't need extra randomization. + hasNew := false + // This is what we got from the server we are connected to. urls := nc.info.ConnectURLs - if len(urls) > 0 { - added := false - // If randomization is allowed, shuffle the received array, not the - // entire pool. We want to preserve the pool's order up to this point - // (this would otherwise be problematic for the (re)connect loop). - if !nc.Opts.NoRandomize { - for i := range urls { - j := rand.Intn(i + 1) - urls[i], urls[j] = urls[j], urls[i] - } + // Transform that to a map for easy lookups + tmp := make(map[string]struct{}, len(urls)) + for _, curl := range urls { + tmp[curl] = struct{}{} + } + // Walk the pool and removed the implicit servers that are no longer in the + // given array/map + sp := nc.srvPool + for i := 0; i < len(sp); i++ { + srv := sp[i] + curl := srv.url.Host + // Check if this URL is in the INFO protocol + _, inInfo := tmp[curl] + // Remove from the temp map so that at the end we are left with only + // new (or restarted) servers that need to be added to the pool. + delete(tmp, curl) + // Keep servers that were set through Options, but also the one that + // we are currently connected to (even if it is a discovered server). + if !srv.isImplicit || srv.url == nc.url { + continue } - for _, curl := range urls { - if _, present := nc.urls[curl]; !present { - if err := nc.addURLToPool(fmt.Sprintf("nats://%s", curl), true); err != nil { - continue - } - added = true - } + if !inInfo { + // Remove from server pool. Keep current order. + copy(sp[i:], sp[i+1:]) + nc.srvPool = sp[:len(sp)-1] + sp = nc.srvPool + i-- } - if added && !nc.initc && nc.Opts.DiscoveredServersCB != nil { - nc.ach <- func() { nc.Opts.DiscoveredServersCB(nc) } + } + // If there are any left in the tmp map, these are new (or restarted) servers + // and need to be added to the pool. + for curl := range tmp { + // Before adding, check if this is a new (as in never seen) URL. + // This is used to figure out if we invoke the DiscoveredServersCB + if _, present := nc.urls[curl]; !present { + hasNew = true } + nc.addURLToPool(fmt.Sprintf("nats://%s", curl), true) + } + if hasNew && !nc.initc && nc.Opts.DiscoveredServersCB != nil { + nc.ach <- func() { nc.Opts.DiscoveredServersCB(nc) } } return nil } @@ -3006,3 +3114,51 @@ func (nc *Conn) TLSRequired() bool { defer nc.mu.Unlock() return nc.info.TLSRequired } + +// Barrier schedules the given function `f` to all registered asynchronous +// subscriptions. +// Only the last subscription to see this barrier will invoke the function. +// If no subscription is registered at the time of this call, `f()` is invoked +// right away. +// ErrConnectionClosed is returned if the connection is closed prior to +// the call. +func (nc *Conn) Barrier(f func()) error { + nc.mu.Lock() + if nc.isClosed() { + nc.mu.Unlock() + return ErrConnectionClosed + } + nc.subsMu.Lock() + // Need to figure out how many non chan subscriptions there are + numSubs := 0 + for _, sub := range nc.subs { + if sub.typ == AsyncSubscription { + numSubs++ + } + } + if numSubs == 0 { + nc.subsMu.Unlock() + nc.mu.Unlock() + f() + return nil + } + barrier := &barrierInfo{refs: int64(numSubs), f: f} + for _, sub := range nc.subs { + sub.mu.Lock() + if sub.mch == nil { + msg := &Msg{barrier: barrier} + // Push onto the async pList + if sub.pTail != nil { + sub.pTail.next = msg + } else { + sub.pHead = msg + sub.pCond.Signal() + } + sub.pTail = msg + } + sub.mu.Unlock() + } + nc.subsMu.Unlock() + nc.mu.Unlock() + return nil +} diff --git a/gateway/vendor/github.com/nats-io/go-nats/nats_test.go b/gateway/vendor/github.com/nats-io/go-nats/nats_test.go index cbd95632..4c19dec3 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/nats_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/nats_test.go @@ -1,3 +1,16 @@ +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package nats //////////////////////////////////////////////////////////////////////////////// @@ -10,6 +23,7 @@ import ( "encoding/json" "errors" "fmt" + "os" "reflect" "runtime" "strings" @@ -40,7 +54,7 @@ func stackFatalf(t *testing.T, f string, args ...interface{}) { lines = append(lines, msg) // Generate the Stack of callers: Skip us and verify* frames. - for i := 2; true; i++ { + for i := 1; true; i++ { _, file, line, ok := runtime.Caller(i) if !ok { break @@ -51,6 +65,23 @@ func stackFatalf(t *testing.T, f string, args ...interface{}) { t.Fatalf("%s", strings.Join(lines, "\n")) } +func TestVersionMatchesTag(t *testing.T) { + tag := os.Getenv("TRAVIS_TAG") + if tag == "" { + t.SkipNow() + } + // We expect a tag of the form vX.Y.Z. If that's not the case, + // we need someone to have a look. So fail if first letter is not + // a `v` + if tag[0] != 'v' { + t.Fatalf("Expect tag to start with `v`, tag is: %s", tag) + } + // Strip the `v` from the tag for the version comparison. + if Version != tag[1:] { + t.Fatalf("Version (%s) does not match tag (%s)", Version, tag[1:]) + } +} + //////////////////////////////////////////////////////////////////////////////// // Reconnect tests //////////////////////////////////////////////////////////////////////////////// @@ -935,7 +966,7 @@ func TestAsyncINFO(t *testing.T) { } } - checkPool := func(inThatOrder bool, urls ...string) { + checkPool := func(urls ...string) { // Check both pool and urls map if len(c.srvPool) != len(urls) { stackFatalf(t, "Pool should have %d elements, has %d", len(urls), len(c.srvPool)) @@ -943,35 +974,27 @@ func TestAsyncINFO(t *testing.T) { if len(c.urls) != len(urls) { stackFatalf(t, "Map should have %d elements, has %d", len(urls), len(c.urls)) } - for i, url := range urls { - if inThatOrder { - if c.srvPool[i].url.Host != url { - stackFatalf(t, "Pool should have %q at index %q, has %q", url, i, c.srvPool[i].url.Host) - } - } else { - if _, present := c.urls[url]; !present { - stackFatalf(t, "Pool should have %q", url) - } + for _, url := range urls { + if _, present := c.urls[url]; !present { + stackFatalf(t, "Pool should have %q", url) } } } // Now test the decoding of "connect_urls" - // No randomize for now - c.Opts.NoRandomize = true // Reset the pool c.setupServerPool() // Reinitialize the parser c.ps = &parseState{} - info = []byte("INFO {\"connect_urls\":[\"localhost:5222\"]}\r\n") + info = []byte("INFO {\"connect_urls\":[\"localhost:4222\", \"localhost:5222\"]}\r\n") err = c.parse(info) if err != nil || c.ps.state != OP_START { t.Fatalf("Unexpected: %d : %v\n", c.ps.state, err) } // Pool now should contain localhost:4222 (the default URL) and localhost:5222 - checkPool(true, "localhost:4222", "localhost:5222") + checkPool("localhost:4222", "localhost:5222") // Make sure that if client receives the same, it is not added again. err = c.parse(info) @@ -979,84 +1002,16 @@ func TestAsyncINFO(t *testing.T) { t.Fatalf("Unexpected: %d : %v\n", c.ps.state, err) } // Pool should still contain localhost:4222 (the default URL) and localhost:5222 - checkPool(true, "localhost:4222", "localhost:5222") + checkPool("localhost:4222", "localhost:5222") // Receive a new URL - info = []byte("INFO {\"connect_urls\":[\"localhost:6222\"]}\r\n") + info = []byte("INFO {\"connect_urls\":[\"localhost:4222\", \"localhost:5222\", \"localhost:6222\"]}\r\n") err = c.parse(info) if err != nil || c.ps.state != OP_START { t.Fatalf("Unexpected: %d : %v\n", c.ps.state, err) } // Pool now should contain localhost:4222 (the default URL) localhost:5222 and localhost:6222 - checkPool(true, "localhost:4222", "localhost:5222", "localhost:6222") - - // Receive more than 1 URL at once - info = []byte("INFO {\"connect_urls\":[\"localhost:7222\", \"localhost:8222\"]}\r\n") - err = c.parse(info) - if err != nil || c.ps.state != OP_START { - t.Fatalf("Unexpected: %d : %v\n", c.ps.state, err) - } - // Pool now should contain localhost:4222 (the default URL) localhost:5222, localhost:6222 - // localhost:7222 and localhost:8222 - checkPool(true, "localhost:4222", "localhost:5222", "localhost:6222", "localhost:7222", "localhost:8222") - - // Test with pool randomization now. Note that with randominzation, - // the initial pool is randomize, then each array of urls that the - // client gets from the INFO protocol is randomized, but added to - // the end of the pool. - c.Opts.NoRandomize = false - c.setupServerPool() - - info = []byte("INFO {\"connect_urls\":[\"localhost:5222\"]}\r\n") - err = c.parse(info) - if err != nil || c.ps.state != OP_START { - t.Fatalf("Unexpected: %d : %v\n", c.ps.state, err) - } - // Pool now should contain localhost:4222 (the default URL) and localhost:5222 - checkPool(true, "localhost:4222", "localhost:5222") - - // Make sure that if client receives the same, it is not added again. - err = c.parse(info) - if err != nil || c.ps.state != OP_START { - t.Fatalf("Unexpected: %d : %v\n", c.ps.state, err) - } - // Pool should still contain localhost:4222 (the default URL) and localhost:5222 - checkPool(true, "localhost:4222", "localhost:5222") - - // Receive a new URL - info = []byte("INFO {\"connect_urls\":[\"localhost:6222\"]}\r\n") - err = c.parse(info) - if err != nil || c.ps.state != OP_START { - t.Fatalf("Unexpected: %d : %v\n", c.ps.state, err) - } - // Pool now should contain localhost:4222 (the default URL) localhost:5222 and localhost:6222 - checkPool(true, "localhost:4222", "localhost:5222", "localhost:6222") - - // Receive more than 1 URL at once. Add more than 2 to increase the chance of - // the array being shuffled. - info = []byte("INFO {\"connect_urls\":[\"localhost:7222\", \"localhost:8222\", " + - "\"localhost:9222\", \"localhost:10222\", \"localhost:11222\"]}\r\n") - err = c.parse(info) - if err != nil || c.ps.state != OP_START { - t.Fatalf("Unexpected: %d : %v\n", c.ps.state, err) - } - // Pool now should contain localhost:4222 (the default URL) localhost:5222, localhost:6222 - // localhost:7222, localhost:8222, localhost:9222, localhost:10222 and localhost:11222 - checkPool(false, "localhost:4222", "localhost:5222", "localhost:6222", "localhost:7222", "localhost:8222", - "localhost:9222", "localhost:10222", "localhost:11222") - - // Finally, check that (part of) the pool should be randomized. - allUrls := []string{"localhost:4222", "localhost:5222", "localhost:6222", "localhost:7222", "localhost:8222", - "localhost:9222", "localhost:10222", "localhost:11222"} - same := 0 - for i, url := range c.srvPool { - if url.url.Host == allUrls[i] { - same++ - } - } - if same == len(allUrls) { - t.Fatal("Pool does not seem to be randomized") - } + checkPool("localhost:4222", "localhost:5222", "localhost:6222") // Check that pool may be randomized on setup, but new URLs are always // added at end of pool. diff --git a/gateway/vendor/github.com/nats-io/go-nats/netchan.go b/gateway/vendor/github.com/nats-io/go-nats/netchan.go index 0608fd7a..75479be3 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/netchan.go +++ b/gateway/vendor/github.com/nats-io/go-nats/netchan.go @@ -1,4 +1,15 @@ -// Copyright 2013-2017 Apcera Inc. All rights reserved. +// Copyright 2013-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package nats diff --git a/gateway/vendor/github.com/nats-io/go-nats/parser.go b/gateway/vendor/github.com/nats-io/go-nats/parser.go index 8359b8bc..a4b3ea0e 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/parser.go +++ b/gateway/vendor/github.com/nats-io/go-nats/parser.go @@ -1,4 +1,15 @@ -// Copyright 2012-2017 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package nats diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/auth_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/auth_test.go index d5180e2b..769dfc73 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/auth_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/auth_test.go @@ -1,3 +1,16 @@ +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package test import ( diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/basic_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/basic_test.go index af61d0b1..050dc531 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/basic_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/basic_test.go @@ -1,3 +1,16 @@ +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package test import ( diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/bench_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/bench_test.go index 233e8c0f..d97a1662 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/bench_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/bench_test.go @@ -1,3 +1,16 @@ +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package test import ( diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/cluster_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/cluster_test.go index c404d9dc..24c27f8a 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/cluster_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/cluster_test.go @@ -1,7 +1,22 @@ +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package test import ( + "fmt" "math" + "net" "regexp" "runtime" "strings" @@ -9,6 +24,7 @@ import ( "testing" "time" + "github.com/nats-io/gnatsd/server" "github.com/nats-io/gnatsd/test" "github.com/nats-io/go-nats" ) @@ -25,6 +41,17 @@ var testServers = []string{ var servers = strings.Join(testServers, ",") +func serverVersionAtLeast(major, minor, update int) error { + var ( + ma, mi, up int + ) + fmt.Sscanf(server.VERSION, "%d.%d.%d", &ma, &mi, &up) + if ma > major || (ma == major && mi > minor) || (ma == major && mi == minor && up >= update) { + return nil + } + return fmt.Errorf("Server version is %v, requires %d.%d.%d+", server.VERSION, major, minor, update) +} + func TestServersOption(t *testing.T) { opts := nats.GetDefaultOptions() opts.NoRandomize = true @@ -604,3 +631,230 @@ func TestPingReconnect(t *testing.T) { } } } + +type checkPoolUpdatedDialer struct { + conn net.Conn + first, final bool + ra int +} + +func (d *checkPoolUpdatedDialer) Dial(network, address string) (net.Conn, error) { + doReal := false + if d.first { + d.first = false + doReal = true + } else if d.final { + d.ra++ + return nil, fmt.Errorf("On purpose") + } else { + d.ra++ + if d.ra == 15 { + d.ra = 0 + doReal = true + } + } + if doReal { + c, err := net.Dial(network, address) + if err != nil { + return nil, err + } + d.conn = c + return c, nil + } + return nil, fmt.Errorf("On purpose") +} + +func TestServerPoolUpdatedWhenRouteGoesAway(t *testing.T) { + if err := serverVersionAtLeast(1, 0, 7); err != nil { + t.Skipf(err.Error()) + } + s1Opts := test.DefaultTestOptions + s1Opts.Host = "127.0.0.1" + s1Opts.Port = 4222 + s1Opts.Cluster.Host = "127.0.0.1" + s1Opts.Cluster.Port = 6222 + s1Opts.Routes = server.RoutesFromStr("nats://127.0.0.1:6223,nats://127.0.0.1:6224") + s1 := test.RunServer(&s1Opts) + defer s1.Shutdown() + + s1Url := "nats://127.0.0.1:4222" + s2Url := "nats://127.0.0.1:4223" + s3Url := "nats://127.0.0.1:4224" + + ch := make(chan bool, 1) + chch := make(chan bool, 1) + connHandler := func(_ *nats.Conn) { + chch <- true + } + nc, err := nats.Connect(s1Url, + nats.ReconnectHandler(connHandler), + nats.DiscoveredServersHandler(func(_ *nats.Conn) { + ch <- true + })) + if err != nil { + t.Fatalf("Error on connect") + } + + s2Opts := test.DefaultTestOptions + s2Opts.Host = "127.0.0.1" + s2Opts.Port = s1Opts.Port + 1 + s2Opts.Cluster.Host = "127.0.0.1" + s2Opts.Cluster.Port = 6223 + s2Opts.Routes = server.RoutesFromStr("nats://127.0.0.1:6222,nats://127.0.0.1:6224") + s2 := test.RunServer(&s2Opts) + defer s2.Shutdown() + + // Wait to be notified + if err := Wait(ch); err != nil { + t.Fatal("New server callback was not invoked") + } + + checkPool := func(expected []string) { + // Don't use discovered here, but Servers to have the full list. + // Also, there may be cases where the mesh is not formed yet, + // so try again on failure. + var ( + ds []string + timeout = time.Now().Add(5 * time.Second) + ) + for time.Now().Before(timeout) { + ds = nc.Servers() + if len(ds) == len(expected) { + m := make(map[string]struct{}, len(ds)) + for _, url := range ds { + m[url] = struct{}{} + } + ok := true + for _, url := range expected { + if _, present := m[url]; !present { + ok = false + break + } + } + if ok { + return + } + } + time.Sleep(50 * time.Millisecond) + } + stackFatalf(t, "Expected %v, got %v", expected, ds) + } + // Verify that we now know about s2 + checkPool([]string{s1Url, s2Url}) + + s3Opts := test.DefaultTestOptions + s3Opts.Host = "127.0.0.1" + s3Opts.Port = s2Opts.Port + 1 + s3Opts.Cluster.Host = "127.0.0.1" + s3Opts.Cluster.Port = 6224 + s3Opts.Routes = server.RoutesFromStr("nats://127.0.0.1:6222,nats://127.0.0.1:6223") + s3 := test.RunServer(&s3Opts) + defer s3.Shutdown() + + // Wait to be notified + if err := Wait(ch); err != nil { + t.Fatal("New server callback was not invoked") + } + // Verify that we now know about s3 + checkPool([]string{s1Url, s2Url, s3Url}) + + // Stop s1. Since this was passed to the Connect() call, this one should + // still be present. + s1.Shutdown() + // Wait for reconnect + if err := Wait(chch); err != nil { + t.Fatal("Reconnect handler not invoked") + } + checkPool([]string{s1Url, s2Url, s3Url}) + + // Check the server we reconnected to. + reConnectedTo := nc.ConnectedUrl() + expected := []string{s1Url} + restartS2 := false + if reConnectedTo == s2Url { + restartS2 = true + s2.Shutdown() + expected = append(expected, s3Url) + } else if reConnectedTo == s3Url { + s3.Shutdown() + expected = append(expected, s2Url) + } else { + t.Fatalf("Unexpected server client has reconnected to: %v", reConnectedTo) + } + // Wait for reconnect + if err := Wait(chch); err != nil { + t.Fatal("Reconnect handler not invoked") + } + // The implicit server that we just shutdown should have been removed from the pool + checkPool(expected) + + // Restart the one that was shutdown and check that it is now back in the pool + if restartS2 { + s2 = test.RunServer(&s2Opts) + defer s2.Shutdown() + expected = append(expected, s2Url) + } else { + s3 = test.RunServer(&s3Opts) + defer s3.Shutdown() + expected = append(expected, s3Url) + } + // Since this is not a "new" server, the DiscoveredServersCB won't be invoked. + checkPool(expected) + + nc.Close() + + // Restart s1 + s1 = test.RunServer(&s1Opts) + defer s1.Shutdown() + + // We should have all 3 servers running now... + + // Create a client connection with special dialer. + d := &checkPoolUpdatedDialer{first: true} + nc, err = nats.Connect(s1Url, + nats.MaxReconnects(10), + nats.ReconnectWait(15*time.Millisecond), + nats.SetCustomDialer(d), + nats.ReconnectHandler(connHandler), + nats.ClosedHandler(connHandler)) + if err != nil { + t.Fatalf("Error on connect") + } + defer nc.Close() + + // Make sure that we have all 3 servers in the pool (this will wait if required) + checkPool(expected) + + // Cause disconnection between client and server. We are going to reconnect + // and we want to check that when we get the INFO again with the list of + // servers, we don't lose the knowledge of how many times we tried to + // reconnect. + d.conn.Close() + + // Wait for client to reconnect to a server + if err := Wait(chch); err != nil { + t.Fatal("Reconnect handler not invoked") + } + // At this point, we should have tried to reconnect 5 times to each server. + // For the one we reconnected to, its max reconnect attempts should have been + // cleared, not for the other ones. + + // Cause a disconnect again and ensure we won't reconnect. + d.final = true + d.conn.Close() + + // Wait for Close callback to be invoked. + if err := Wait(chch); err != nil { + t.Fatal("Close handler not invoked") + } + + // Since MaxReconnect is 10, after trying 5 more times on 2 of the servers, + // these should have been removed. We have still 5 more tries for the server + // we did previously reconnect to. + // So total of reconnect attempt should be: 2*5+1*10=20 + if d.ra != 20 { + t.Fatalf("Should have tried to reconnect 20 more times, got %v", d.ra) + } + + nc.Close() +} diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/configs/tls.conf b/gateway/vendor/github.com/nats-io/go-nats/test/configs/tls.conf index 06394b1b..02754ec8 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/configs/tls.conf +++ b/gateway/vendor/github.com/nats-io/go-nats/test/configs/tls.conf @@ -1,4 +1,3 @@ - # Simple TLS config file port: 4443 diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/configs/tlsverify.conf b/gateway/vendor/github.com/nats-io/go-nats/test/configs/tlsverify.conf index 29e6a77f..12c904c1 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/configs/tlsverify.conf +++ b/gateway/vendor/github.com/nats-io/go-nats/test/configs/tlsverify.conf @@ -1,4 +1,3 @@ - # Simple TLS config file port: 4443 @@ -11,7 +10,7 @@ tls { # Optional certificate authority for clients ca_file: "./configs/certs/ca.pem" - + # Require a client certificate verify: true } diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/conn_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/conn_test.go index 6d2a77d4..72163a20 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/conn_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/conn_test.go @@ -1,3 +1,16 @@ +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package test import ( @@ -11,6 +24,7 @@ import ( "runtime" "strconv" "strings" + "sync" "sync/atomic" "testing" "time" @@ -701,6 +715,7 @@ func TestCallbacksOrder(t *testing.T) { nats.ErrorHandler(ech), nats.ReconnectWait(50*time.Millisecond), nats.DontRandomize()) + if err != nil { t.Fatalf("Unable to connect: %v\n", err) } @@ -1476,12 +1491,16 @@ func TestCustomFlusherTimeout(t *testing.T) { func TestNewServers(t *testing.T) { s1Opts := test.DefaultTestOptions + s1Opts.Host = "127.0.0.1" + s1Opts.Port = 4222 s1Opts.Cluster.Host = "localhost" s1Opts.Cluster.Port = 6222 s1 := test.RunServer(&s1Opts) defer s1.Shutdown() s2Opts := test.DefaultTestOptions + s2Opts.Host = "127.0.0.1" + s2Opts.Port = 4223 s2Opts.Port = s1Opts.Port + 1 s2Opts.Cluster.Host = "localhost" s2Opts.Cluster.Port = 6223 @@ -1525,6 +1544,8 @@ func TestNewServers(t *testing.T) { // Start a new server. s3Opts := test.DefaultTestOptions + s1Opts.Host = "127.0.0.1" + s1Opts.Port = 4224 s3Opts.Port = s2Opts.Port + 1 s3Opts.Cluster.Host = "localhost" s3Opts.Cluster.Port = 6224 @@ -1543,3 +1564,400 @@ func TestNewServers(t *testing.T) { t.Fatal("Did not get our callback") } } + +func TestBarrier(t *testing.T) { + s := RunDefaultServer() + defer s.Shutdown() + + nc := NewDefaultConnection(t) + defer nc.Close() + + pubMsgs := int32(0) + ch := make(chan bool, 1) + + sub1, err := nc.Subscribe("pub", func(_ *nats.Msg) { + atomic.AddInt32(&pubMsgs, 1) + time.Sleep(250 * time.Millisecond) + }) + if err != nil { + t.Fatalf("Error on subscribe: %v", err) + } + + sub2, err := nc.Subscribe("close", func(_ *nats.Msg) { + // The "close" message was sent/received lat, but + // because we are dealing with different subscriptions, + // which are dispatched by different dispatchers, and + // because the "pub" subscription is delayed, this + // callback is likely to be invoked before the sub1's + // second callback is invoked. Using the Barrier call + // here will ensure that the given function will be invoked + // after the preceding messages have been dispatched. + nc.Barrier(func() { + res := atomic.LoadInt32(&pubMsgs) == 2 + ch <- res + }) + }) + if err != nil { + t.Fatalf("Error on subscribe: %v", err) + } + + // Send 2 "pub" messages followed by a "close" message + for i := 0; i < 2; i++ { + if err := nc.Publish("pub", []byte("pub msg")); err != nil { + t.Fatalf("Error on publish: %v", err) + } + } + if err := nc.Publish("close", []byte("closing")); err != nil { + t.Fatalf("Error on publish: %v", err) + } + + select { + case ok := <-ch: + if !ok { + t.Fatal("The barrier function was invoked before the second message") + } + case <-time.After(2 * time.Second): + t.Fatal("Waited for too long...") + } + + // Remove all subs + sub1.Unsubscribe() + sub2.Unsubscribe() + + // Barrier should be invoked in place. Since we use buffered channel + // we are ok. + nc.Barrier(func() { ch <- true }) + if err := Wait(ch); err != nil { + t.Fatal("Barrier function was not invoked") + } + + if _, err := nc.Subscribe("foo", func(m *nats.Msg) { + // To check that the Barrier() function works if the subscription + // is unsubscribed after the call was made, sleep a bit here. + time.Sleep(250 * time.Millisecond) + m.Sub.Unsubscribe() + }); err != nil { + t.Fatalf("Error on subscribe: %v", err) + } + if err := nc.Publish("foo", []byte("hello")); err != nil { + t.Fatalf("Error on publish: %v", err) + } + // We need to Flush here to make sure that message has been received + // and posted to subscription's internal queue before calling Barrier. + if err := nc.Flush(); err != nil { + t.Fatalf("Error on flush: %v", err) + } + nc.Barrier(func() { ch <- true }) + if err := Wait(ch); err != nil { + t.Fatal("Barrier function was not invoked") + } + + // Test with AutoUnsubscribe now... + sub1, err = nc.Subscribe("foo", func(m *nats.Msg) { + // Since we auto-unsubscribe with 1, there should not be another + // invocation of this callback, but the Barrier should still be + // invoked. + nc.Barrier(func() { ch <- true }) + + }) + if err != nil { + t.Fatalf("Error on subscribe: %v", err) + } + sub1.AutoUnsubscribe(1) + // Send 2 messages and flush + for i := 0; i < 2; i++ { + if err := nc.Publish("foo", []byte("hello")); err != nil { + t.Fatalf("Error on publish: %v", err) + } + } + if err := nc.Flush(); err != nil { + t.Fatalf("Error on flush: %v", err) + } + // Check barrier was invoked + if err := Wait(ch); err != nil { + t.Fatal("Barrier function was not invoked") + } + + // Check that Barrier only affects asynchronous subscriptions + sub1, err = nc.Subscribe("foo", func(m *nats.Msg) { + nc.Barrier(func() { ch <- true }) + }) + if err != nil { + t.Fatalf("Error on subscribe: %v", err) + } + syncSub, err := nc.SubscribeSync("foo") + if err != nil { + t.Fatalf("Error on subscribe: %v", err) + } + msgChan := make(chan *nats.Msg, 1) + chanSub, err := nc.ChanSubscribe("foo", msgChan) + if err != nil { + t.Fatalf("Error on subscribe: %v", err) + } + if err := nc.Publish("foo", []byte("hello")); err != nil { + t.Fatalf("Error on publish: %v", err) + } + if err := nc.Flush(); err != nil { + t.Fatalf("Error on flush: %v", err) + } + // Check barrier was invoked even if we did not yet consume + // from the 2 other type of subscriptions + if err := Wait(ch); err != nil { + t.Fatal("Barrier function was not invoked") + } + if _, err := syncSub.NextMsg(time.Second); err != nil { + t.Fatalf("Sync sub did not receive the message") + } + select { + case <-msgChan: + case <-time.After(time.Second): + t.Fatal("Chan sub did not receive the message") + } + chanSub.Unsubscribe() + syncSub.Unsubscribe() + sub1.Unsubscribe() + + atomic.StoreInt32(&pubMsgs, 0) + // Check barrier does not prevent new messages to be delivered. + sub1, err = nc.Subscribe("foo", func(_ *nats.Msg) { + if pm := atomic.AddInt32(&pubMsgs, 1); pm == 1 { + nc.Barrier(func() { + nc.Publish("foo", []byte("second")) + nc.Flush() + }) + } else if pm == 2 { + ch <- true + } + }) + if err != nil { + t.Fatalf("Error on subscribe: %v", err) + } + if err := nc.Publish("foo", []byte("first")); err != nil { + t.Fatalf("Error on publish: %v", err) + } + if err := Wait(ch); err != nil { + t.Fatal("Barrier function was not invoked") + } + sub1.Unsubscribe() + + // Check that barrier works if called before connection + // is closed. + if _, err := nc.Subscribe("bar", func(_ *nats.Msg) { + nc.Barrier(func() { ch <- true }) + nc.Close() + }); err != nil { + t.Fatalf("Error on subscribe: %v", err) + } + if err := nc.Publish("bar", []byte("hello")); err != nil { + t.Fatalf("Error on publish: %v", err) + } + if err := nc.Flush(); err != nil { + t.Fatalf("Error on flush: %v", err) + } + if err := Wait(ch); err != nil { + t.Fatal("Barrier function was not invoked") + } + + // Finally, check that if connection is closed, Barrier returns + // an error. + if err := nc.Barrier(func() { ch <- true }); err != nats.ErrConnectionClosed { + t.Fatalf("Expected error %v, got %v", nats.ErrConnectionClosed, err) + } + + // Check that one can call connection methods from Barrier + // when there is no async subscriptions + nc = NewDefaultConnection(t) + defer nc.Close() + + if err := nc.Barrier(func() { + ch <- nc.TLSRequired() + }); err != nil { + t.Fatalf("Error on Barrier: %v", err) + } + if err := Wait(ch); err != nil { + t.Fatal("Barrier was blocked") + } +} + +func TestReceiveInfoRightAfterFirstPong(t *testing.T) { + l, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("Error on listen: %v", err) + } + tl := l.(*net.TCPListener) + defer tl.Close() + addr := tl.Addr().(*net.TCPAddr) + + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + defer wg.Done() + + c, err := tl.Accept() + if err != nil { + return + } + defer c.Close() + // Send the initial INFO + c.Write([]byte("INFO {}\r\n")) + buf := make([]byte, 0, 100) + b := make([]byte, 100) + for { + n, err := c.Read(b) + if err != nil { + return + } + buf = append(buf, b[:n]...) + if bytes.Contains(buf, []byte("PING\r\n")) { + break + } + } + // Send PONG and following INFO in one go (or at least try). + // The processing of PONG in sendConnect() should leave the + // rest for the readLoop to process. + c.Write([]byte(fmt.Sprintf("PONG\r\nINFO {\"connect_urls\":[\"127.0.0.1:%d\", \"me:1\"]}\r\n", addr.Port))) + // Wait for client to disconnect + for { + if _, err := c.Read(buf); err != nil { + return + } + } + }() + + nc, err := nats.Connect(fmt.Sprintf("nats://127.0.0.1:%d", addr.Port)) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + defer nc.Close() + var ( + ds []string + timeout = time.Now().Add(2 * time.Second) + ok = false + ) + for time.Now().Before(timeout) { + ds = nc.DiscoveredServers() + if len(ds) == 1 && ds[0] == "nats://me:1" { + ok = true + break + } + time.Sleep(50 * time.Millisecond) + } + nc.Close() + wg.Wait() + if !ok { + t.Fatalf("Unexpected discovered servers: %v", ds) + } +} + +func TestReceiveInfoWithEmptyConnectURLs(t *testing.T) { + ready := make(chan bool, 2) + ch := make(chan bool, 1) + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + defer wg.Done() + + ports := []int{4222, 4223} + for i := 0; i < 2; i++ { + l, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", ports[i])) + if err != nil { + t.Fatalf("Error on listen: %v", err) + } + tl := l.(*net.TCPListener) + defer tl.Close() + + ready <- true + + c, err := tl.Accept() + if err != nil { + return + } + defer c.Close() + + // Send the initial INFO + c.Write([]byte(fmt.Sprintf("INFO {\"server_id\":\"server%d\"}\r\n", (i + 1)))) + buf := make([]byte, 0, 100) + b := make([]byte, 100) + for { + n, err := c.Read(b) + if err != nil { + return + } + buf = append(buf, b[:n]...) + if bytes.Contains(buf, []byte("PING\r\n")) { + break + } + } + if i == 0 { + // Send PONG and following INFO in one go (or at least try). + // The processing of PONG in sendConnect() should leave the + // rest for the readLoop to process. + c.Write([]byte("PONG\r\nINFO {\"server_id\":\"server1\",\"connect_urls\":[\"127.0.0.1:4222\", \"127.0.0.1:4223\", \"127.0.0.1:4224\"]}\r\n")) + // Wait for the notication + <-ch + // Close the connection in our side and go back into accept + c.Close() + } else { + // Send no connect ULRs (as if this was an older server that could in some cases + // send an empty array) + c.Write([]byte(fmt.Sprintf("PONG\r\nINFO {\"server_id\":\"server2\"}\r\n"))) + // Wait for client to disconnect + for { + if _, err := c.Read(buf); err != nil { + return + } + } + } + } + }() + + // Wait for listener to be up and running + if err := Wait(ready); err != nil { + t.Fatal("Listener not ready") + } + + rch := make(chan bool) + nc, err := nats.Connect("nats://127.0.0.1:4222", + nats.ReconnectWait(50*time.Millisecond), + nats.ReconnectHandler(func(_ *nats.Conn) { + rch <- true + })) + if err != nil { + t.Fatalf("Error on connect: %v", err) + } + defer nc.Close() + var ( + ds []string + timeout = time.Now().Add(2 * time.Second) + ok = false + ) + for time.Now().Before(timeout) { + ds = nc.DiscoveredServers() + if len(ds) == 2 { + if (ds[0] == "nats://127.0.0.1:4223" && ds[1] == "nats://127.0.0.1:4224") || + (ds[0] == "nats://127.0.0.1:4224" && ds[1] == "nats://127.0.0.1:4223") { + ok = true + break + } + } + time.Sleep(50 * time.Millisecond) + } + if !ok { + t.Fatalf("Unexpected discovered servers: %v", ds) + } + // Make the server close our connection + ch <- true + // Wait for the reconnect + if err := Wait(rch); err != nil { + t.Fatal("Did not reconnect") + } + // Discovered servers should still contain nats://me:1 + ds = nc.DiscoveredServers() + if len(ds) != 2 || + !((ds[0] == "nats://127.0.0.1:4223" && ds[1] == "nats://127.0.0.1:4224") || + (ds[0] == "nats://127.0.0.1:4224" && ds[1] == "nats://127.0.0.1:4223")) { + t.Fatalf("Unexpected discovered servers list: %v", ds) + } + nc.Close() + wg.Wait() +} diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/context_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/context_test.go index 00397700..64a9b297 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/context_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/context_test.go @@ -1,4 +1,15 @@ -// Copyright 2012-2017 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. // +build go1.7 diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/enc_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/enc_test.go index 8f580177..03ff6e63 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/enc_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/enc_test.go @@ -1,4 +1,15 @@ -// Copyright 2012-2017 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package test diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/gob_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/gob_test.go index 97456901..72992f86 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/gob_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/gob_test.go @@ -1,4 +1,15 @@ -// Copyright 2012-2017 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package test diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/helper_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/helper_test.go index ec4fd1db..e7775742 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/helper_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/helper_test.go @@ -1,10 +1,23 @@ -// Copyright 2015 Apcera Inc. All rights reserved. +// Copyright 2015-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package test import ( "errors" "fmt" + "runtime" + "strings" "time" "github.com/nats-io/gnatsd/server" @@ -37,6 +50,23 @@ func WaitTime(ch chan bool, timeout time.Duration) error { return errors.New("timeout") } +func stackFatalf(t tLogger, f string, args ...interface{}) { + lines := make([]string, 0, 32) + msg := fmt.Sprintf(f, args...) + lines = append(lines, msg) + + // Generate the Stack of callers: Skip us and verify* frames. + for i := 1; true; i++ { + _, file, line, ok := runtime.Caller(i) + if !ok { + break + } + msg := fmt.Sprintf("%d - %s:%d", i, file, line) + lines = append(lines, msg) + } + t.Fatalf("%s", strings.Join(lines, "\n")) +} + //////////////////////////////////////////////////////////////////////////////// // Creating client connections //////////////////////////////////////////////////////////////////////////////// diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/json_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/json_test.go index 36bfa200..67cbc99c 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/json_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/json_test.go @@ -1,4 +1,15 @@ -// Copyright 2012-2017 Apcera Inc. All rights reserved. +// Copyright 2012-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package test diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/main.go b/gateway/vendor/github.com/nats-io/go-nats/test/main.go index c1d4dc0d..3277158a 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/main.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/main.go @@ -1,4 +1,15 @@ -// Copyright 2017 Apcera Inc. All rights reserved. +// Copyright 2017-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. package test diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/netchan_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/netchan_test.go index 88b66cb6..bea821a7 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/netchan_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/netchan_test.go @@ -1,3 +1,16 @@ +// Copyright 2013-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package test import ( diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/protobuf_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/protobuf_test.go index 7227461a..03c95d59 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/protobuf_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/protobuf_test.go @@ -1,3 +1,16 @@ +// Copyright 2015-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package test import ( diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/reconnect_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/reconnect_test.go index 0b9040e7..ed779113 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/reconnect_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/reconnect_test.go @@ -1,3 +1,16 @@ +// Copyright 2013-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package test import ( @@ -576,6 +589,21 @@ func TestReconnectVerbose(t *testing.T) { } } +func TestReconnectBufSizeOption(t *testing.T) { + s := RunDefaultServer() + defer s.Shutdown() + + nc, err := nats.Connect("nats://localhost:4222", nats.ReconnectBufSize(32)) + if err != nil { + t.Fatalf("Should have connected ok: %v", err) + } + defer nc.Close() + + if nc.Opts.ReconnectBufSize != 32 { + t.Fatalf("ReconnectBufSize should be 32 but it is %d", nc.Opts.ReconnectBufSize) + } +} + func TestReconnectBufSize(t *testing.T) { s := RunDefaultServer() defer s.Shutdown() diff --git a/gateway/vendor/github.com/nats-io/go-nats/test/sub_test.go b/gateway/vendor/github.com/nats-io/go-nats/test/sub_test.go index 1703edbb..3fa5a141 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/test/sub_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/test/sub_test.go @@ -1,3 +1,16 @@ +// Copyright 2013-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package test import ( diff --git a/gateway/vendor/github.com/nats-io/go-nats/timer.go b/gateway/vendor/github.com/nats-io/go-nats/timer.go index 1b96fd52..1216762d 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/timer.go +++ b/gateway/vendor/github.com/nats-io/go-nats/timer.go @@ -1,3 +1,16 @@ +// Copyright 2017-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package nats import ( diff --git a/gateway/vendor/github.com/nats-io/go-nats/timer_test.go b/gateway/vendor/github.com/nats-io/go-nats/timer_test.go index fb02a769..d561f967 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/timer_test.go +++ b/gateway/vendor/github.com/nats-io/go-nats/timer_test.go @@ -1,3 +1,16 @@ +// Copyright 2017-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + package nats import ( diff --git a/gateway/vendor/github.com/nats-io/go-nats/util/tls.go b/gateway/vendor/github.com/nats-io/go-nats/util/tls.go index 15bed9b1..53ff9aa2 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/util/tls.go +++ b/gateway/vendor/github.com/nats-io/go-nats/util/tls.go @@ -1,4 +1,16 @@ -// Copyright 2017 Apcera Inc. All rights reserved. +// Copyright 2017-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // +build go1.8 package util diff --git a/gateway/vendor/github.com/nats-io/go-nats/util/tls_go17.go b/gateway/vendor/github.com/nats-io/go-nats/util/tls_go17.go index 3e38fc4d..fd646d31 100644 --- a/gateway/vendor/github.com/nats-io/go-nats/util/tls_go17.go +++ b/gateway/vendor/github.com/nats-io/go-nats/util/tls_go17.go @@ -1,4 +1,16 @@ -// Copyright 2016 Apcera Inc. All rights reserved. +// Copyright 2016-2018 The NATS Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // +build go1.7,!go1.8 package util diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/.DEREK.yml b/gateway/vendor/github.com/openfaas/nats-queue-worker/.DEREK.yml new file mode 100644 index 00000000..c075190d --- /dev/null +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/.DEREK.yml @@ -0,0 +1,16 @@ +maintainers: + - alexellis + - rgee0 + - johnmccabe + - jockdarock + - ericstoekl + - austinfrey + - itscaro + - rorpage + - kenfdev + - BurtonR + +features: + - dco_check + - comments + diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/.github/ISSUE_TEMPLATE.md b/gateway/vendor/github.com/openfaas/nats-queue-worker/.github/ISSUE_TEMPLATE.md new file mode 100644 index 00000000..dce0abc5 --- /dev/null +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,35 @@ + + +## Expected Behaviour + + + +## Current Behaviour + + + +## Possible Solution + + + +## Steps to Reproduce (for bugs) + + +1. +2. +3. +4. + +## Context + + + +## Your Environment + +* Docker version `docker version` (e.g. Docker 17.0.05 ): + +* Are you using Docker Swarm or Kubernetes (FaaS-netes)? + +* Operating System and version (e.g. Linux, Windows, MacOS): + +* Link to your project or a code example to reproduce issue: diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/.github/PULL_REQUEST_TEMPLATE.md b/gateway/vendor/github.com/openfaas/nats-queue-worker/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..8de3247e --- /dev/null +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,31 @@ + + +## Description + + +## Motivation and Context + + +- [ ] I have raised an issue to propose this change ([required](https://github.com/openfaas/faas/blob/master/CONTRIBUTING.md)) + +## How Has This Been Tested? + + + + +## Types of changes + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) + +## Checklist: + + +- [ ] My code follows the code style of this project. +- [ ] My change requires a change to the documentation. +- [ ] I have updated the documentation accordingly. +- [ ] I've read the [CONTRIBUTION](https://github.com/openfaas/faas/blob/master/CONTRIBUTING.md) guide +- [ ] I have signed-off my commits with `git commit -s` +- [ ] I have added tests to cover my changes. +- [ ] All new and existing tests passed. diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/.gitignore b/gateway/vendor/github.com/openfaas/nats-queue-worker/.gitignore index 1cd9dda5..02fffa44 100644 --- a/gateway/vendor/github.com/openfaas/nats-queue-worker/.gitignore +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/.gitignore @@ -15,3 +15,4 @@ .idea .DS_Store +nats-queue-worker diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/.travis.yml b/gateway/vendor/github.com/openfaas/nats-queue-worker/.travis.yml index 8c2a8fb1..d4683af3 100644 --- a/gateway/vendor/github.com/openfaas/nats-queue-worker/.travis.yml +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/.travis.yml @@ -4,14 +4,29 @@ language: go go: - 1.9.x -install: - - echo "Please don't go get" services: - docker -before_script: - - curl -sSL test.docker.com | sudo -E sh +addons: + apt: + packages: + - docker-ce + +install: + - echo "Please don't go get" script: - cd queue-worker && ./build.sh + +after_success: + - if [ ! -z "$TRAVIS_TAG" ] ; then + + if [ -z $DOCKER_NS ] ; then + export DOCKER_NS=functions; + fi + + docker tag $DOCKER_NS/queue-worker:latest-dev $DOCKER_NS/queue-worker:$TRAVIS_TAG; + echo $DOCKER_PASSWORD | docker login -u=$DOCKER_USERNAME --password-stdin; + docker push $DOCKER_NS/queue-worker:$TRAVIS_TAG; + fi \ No newline at end of file diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/Dockerfile b/gateway/vendor/github.com/openfaas/nats-queue-worker/Dockerfile similarity index 58% rename from gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/Dockerfile rename to gateway/vendor/github.com/openfaas/nats-queue-worker/Dockerfile index 7213c68b..26cdf337 100644 --- a/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/Dockerfile +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/Dockerfile @@ -1,14 +1,20 @@ -FROM golang:1.9.2-alpine as golang +FROM golang:1.9.7-alpine as golang WORKDIR /go/src/github.com/openfaas/nats-queue-worker COPY vendor vendor +COPY handler handler COPY main.go . +RUN go test -v ./handler/ RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM alpine:3.7 -RUN apk add --no-cache ca-certificates -WORKDIR /root/ + +RUN addgroup -S app \ + && adduser -S -g app app \ + && apk add --no-cache ca-certificates + +WORKDIR /home/app EXPOSE 8080 ENV http_proxy "" @@ -16,4 +22,7 @@ ENV https_proxy "" COPY --from=golang /go/src/github.com/openfaas/nats-queue-worker/app . +RUN chown -R app:app ./ + +USER app CMD ["./app"] diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/Dockerfile.armhf b/gateway/vendor/github.com/openfaas/nats-queue-worker/Dockerfile.armhf similarity index 61% rename from gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/Dockerfile.armhf rename to gateway/vendor/github.com/openfaas/nats-queue-worker/Dockerfile.armhf index 7213c68b..df9dac6f 100644 --- a/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/Dockerfile.armhf +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/Dockerfile.armhf @@ -1,14 +1,19 @@ -FROM golang:1.9.2-alpine as golang +FROM golang:1.9.7-alpine as golang WORKDIR /go/src/github.com/openfaas/nats-queue-worker COPY vendor vendor +COPY handler handler COPY main.go . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . FROM alpine:3.7 -RUN apk add --no-cache ca-certificates -WORKDIR /root/ + +RUN addgroup -S app \ + && adduser -S -g app app \ + && apk add --no-cache ca-certificates + +WORKDIR /home/app EXPOSE 8080 ENV http_proxy "" @@ -16,4 +21,7 @@ ENV https_proxy "" COPY --from=golang /go/src/github.com/openfaas/nats-queue-worker/app . +RUN chown -R app:app ./ + +USER app CMD ["./app"] diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/Gopkg.lock b/gateway/vendor/github.com/openfaas/nats-queue-worker/Gopkg.lock new file mode 100644 index 00000000..70bf744a --- /dev/null +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/Gopkg.lock @@ -0,0 +1,50 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/gogo/protobuf" + packages = [ + "gogoproto", + "proto", + "protoc-gen-gogo/descriptor" + ] + revision = "1adfc126b41513cc696b209667c8656ea7aac67c" + version = "v1.0.0" + +[[projects]] + name = "github.com/nats-io/go-nats" + packages = [ + ".", + "encoders/builtin", + "util" + ] + revision = "062418ea1c2181f52dc0f954f6204370519a868b" + version = "v1.5.0" + +[[projects]] + name = "github.com/nats-io/go-nats-streaming" + packages = [ + ".", + "pb" + ] + revision = "e15a53f85e4932540600a16b56f6c4f65f58176f" + version = "v0.4.0" + +[[projects]] + name = "github.com/nats-io/nuid" + packages = ["."] + revision = "289cccf02c178dc782430d534e3c1f5b72af807f" + version = "v1.0.0" + +[[projects]] + name = "github.com/openfaas/faas" + packages = ["gateway/queue"] + revision = "81334141832d6c4fc9b78e6b5e17e5330eca7606" + version = "0.8.2" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "fb873f03ba109e6e479b9133d610f50d7fd6cbcdc0fe7dcf947ae70a1eade465" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/Gopkg.toml b/gateway/vendor/github.com/openfaas/nats-queue-worker/Gopkg.toml new file mode 100644 index 00000000..e8532211 --- /dev/null +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/Gopkg.toml @@ -0,0 +1,38 @@ +# Gopkg.toml example +# +# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" +# +# [prune] +# non-go = false +# go-tests = true +# unused-packages = true + + +[[constraint]] + name = "github.com/nats-io/go-nats-streaming" + version = "0.4.0" + +[[constraint]] + name = "github.com/openfaas/faas" + version = "0.8.2" + +[prune] + go-tests = true + unused-packages = true diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/Makefile b/gateway/vendor/github.com/openfaas/nats-queue-worker/Makefile new file mode 100644 index 00000000..a7a4981b --- /dev/null +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/Makefile @@ -0,0 +1,9 @@ +TAG?=latest + +build: + docker build --build-arg http_proxy="${http_proxy}" --build-arg https_proxy="${https_proxy}" -t functions/queue-worker:$(TAG) . + +push: + docker push functions/queue-worker:$(TAG) + +all: build diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/README.md b/gateway/vendor/github.com/openfaas/nats-queue-worker/README.md index 616592ba..ab515e39 100644 --- a/gateway/vendor/github.com/openfaas/nats-queue-worker/README.md +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/README.md @@ -6,7 +6,7 @@ This is a queue-worker to enable asynchronous processing of function requests. * [Read more in the async guide](https://github.com/openfaas/faas/blob/master/guide/asynchronous.md) -Hub image: [functions/queue-worker:0.1.1](https://hub.docker.com/r/functions/queue-worker/) +Hub image: [functions/queue-worker](https://hub.docker.com/r/functions/queue-worker/) License: MIT diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/build.sh b/gateway/vendor/github.com/openfaas/nats-queue-worker/build.sh similarity index 99% rename from gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/build.sh rename to gateway/vendor/github.com/openfaas/nats-queue-worker/build.sh index 1d05f3c6..e9e4d4af 100755 --- a/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/build.sh +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/build.sh @@ -9,4 +9,3 @@ fi echo Building functions/queue-worker:$eTAG docker build --build-arg http_proxy=$http_proxy -t functions/queue-worker:$eTAG . - diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/handler/handler.go b/gateway/vendor/github.com/openfaas/nats-queue-worker/handler/handler.go index 34af8534..c34fc0ae 100644 --- a/gateway/vendor/github.com/openfaas/nats-queue-worker/handler/handler.go +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/handler/handler.go @@ -15,15 +15,26 @@ type NatsQueue struct { nc stan.Conn } +type NatsConfig interface { + GetClientID() string +} + +type DefaultNatsConfig struct { +} + +func (DefaultNatsConfig) GetClientID() string { + val, _ := os.Hostname() + return "faas-publisher-" + val +} + // CreateNatsQueue ready for asynchronous processing -func CreateNatsQueue(address string, port int) (*NatsQueue, error) { +func CreateNatsQueue(address string, port int, clientConfig NatsConfig) (*NatsQueue, error) { queue1 := NatsQueue{} var err error natsURL := fmt.Sprintf("nats://%s:%d", address, port) log.Printf("Opening connection to %s\n", natsURL) - val, _ := os.Hostname() - clientID := "faas-publisher-" + val + clientID := clientConfig.GetClientID() clusterID := "faas-cluster" nc, err := stan.Connect(clusterID, clientID, stan.NatsURL(natsURL)) diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/handler/handler_test.go b/gateway/vendor/github.com/openfaas/nats-queue-worker/handler/handler_test.go new file mode 100644 index 00000000..f1c3a972 --- /dev/null +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/handler/handler_test.go @@ -0,0 +1,19 @@ +package handler + +import ( + "os" + "strings" + "testing" +) + +func Test_GetClientID_ContainsHostname(t *testing.T) { + c := DefaultNatsConfig{} + + val := c.GetClientID() + + hostname, _ := os.Hostname() + if !strings.HasSuffix(val, hostname) { + t.Errorf("GetClientID should contain hostname as suffix, got: %s", val) + t.Fail() + } +} diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/main.go b/gateway/vendor/github.com/openfaas/nats-queue-worker/main.go similarity index 87% rename from gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/main.go rename to gateway/vendor/github.com/openfaas/nats-queue-worker/main.go index 0b30be0d..014f2b03 100644 --- a/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/main.go +++ b/gateway/vendor/github.com/openfaas/nats-queue-worker/main.go @@ -98,6 +98,7 @@ func main() { req := queue.Request{} unmarshalErr := json.Unmarshal(msg.Data, &req) + if unmarshalErr != nil { log.Printf("Unmarshal error: %s with data %s", unmarshalErr, msg.Data) return @@ -115,12 +116,10 @@ func main() { functionURL := fmt.Sprintf("http://%s%s:8080/%s", req.Function, functionSuffix, queryString) - request, err := http.NewRequest("POST", functionURL, bytes.NewReader(req.Body)) + request, err := http.NewRequest(http.MethodPost, functionURL, bytes.NewReader(req.Body)) defer request.Body.Close() - for k, v := range req.Header { - request.Header[k] = v - } + copyHeaders(request.Header, &req.Header) res, err := client.Do(request) var status int @@ -135,7 +134,7 @@ func main() { if req.CallbackURL != nil { log.Printf("Callback to: %s\n", req.CallbackURL.String()) - resultStatusCode, resultErr := postResult(&client, req, functionResult, status) + resultStatusCode, resultErr := postResult(&client, res, functionResult, req.CallbackURL.String()) if resultErr != nil { log.Println(resultErr) } else { @@ -170,7 +169,7 @@ func main() { if req.CallbackURL != nil { log.Printf("Callback to: %s\n", req.CallbackURL.String()) - resultStatusCode, resultErr := postResult(&client, req, functionResult, res.StatusCode) + resultStatusCode, resultErr := postResult(&client, res, functionResult, req.CallbackURL.String()) if resultErr != nil { log.Println(resultErr) } else { @@ -238,18 +237,21 @@ func main() { <-cleanupDone } -func postResult(client *http.Client, req queue.Request, result []byte, statusCode int) (int, error) { +func postResult(client *http.Client, functionRes *http.Response, result []byte, callbackURL string) (int, error) { var reader io.Reader if result != nil { reader = bytes.NewReader(result) } - request, err := http.NewRequest("POST", req.CallbackURL.String(), reader) + request, err := http.NewRequest(http.MethodPost, callbackURL, reader) + + copyHeaders(request.Header, &functionRes.Header) + res, err := client.Do(request) if err != nil { - return http.StatusBadGateway, fmt.Errorf("error posting result to URL %s %s", req.CallbackURL.String(), err.Error()) + return http.StatusBadGateway, fmt.Errorf("error posting result to URL %s %s", callbackURL, err.Error()) } if request.Body != nil { @@ -262,6 +264,14 @@ func postResult(client *http.Client, req queue.Request, result []byte, statusCod return res.StatusCode, nil } +func copyHeaders(destination http.Header, source *http.Header) { + for k, v := range *source { + vClone := make([]string, len(v)) + copy(vClone, v) + (destination)[k] = vClone + } +} + func postReport(client *http.Client, function string, statusCode int, timeTaken float64, gatewayAddress string) (int, error) { req := AsyncReport{ FunctionName: function, @@ -271,7 +281,7 @@ func postReport(client *http.Client, function string, statusCode int, timeTaken targetPostback := "http://" + gatewayAddress + ":8080/system/async-report" reqBytes, _ := json.Marshal(req) - request, err := http.NewRequest("POST", targetPostback, bytes.NewReader(reqBytes)) + request, err := http.NewRequest(http.MethodPost, targetPostback, bytes.NewReader(reqBytes)) defer request.Body.Close() res, err := client.Do(request) diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/.gitignore b/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/.gitignore deleted file mode 100644 index e0236d0f..00000000 --- a/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/.gitignore +++ /dev/null @@ -1 +0,0 @@ -queue-worker diff --git a/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/vendor.conf b/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/vendor.conf deleted file mode 100644 index e2ab03e6..00000000 --- a/gateway/vendor/github.com/openfaas/nats-queue-worker/queue-worker/vendor.conf +++ /dev/null @@ -1,5 +0,0 @@ -github.com/openfaas/faas 4cc299d4c84e7ce10c6a5117e918c5a5b4aeb2ae -github.com/nats-io/go-nats-streaming bf8654e90f5296da96eab1e85808eb5c4b7b5541 -github.com/nats-io/go-nats 34c8842105ac0b69c838a9998a239d482936c466 -github.com/nats-io/nuid 3cf34f9fca4e88afa9da8eabd75e3326c9941b44 -github.com/gogo/protobuf dda3e8acadcc9affc16faf33fbb229db78399245