[
  {
    "path": ".github/workflows/PR.yaml",
    "content": "on:\n  pull_request:\n    branches:\n      - master\n\njobs:\n  build:\n    name: test\n    runs-on: ubuntu-latest\n    container:\n      image: golang:1.14-buster\n      volumes:\n        - \"/home/runner/work/$GITHUB_REPOSITORY:/go/src/github.com/$GITHUB_REPOSITORY\"\n    steps:\n      - uses: actions/checkout@v1\n\n      - name: restore from cache\n        uses: actions/cache@v1\n        with:\n          path: /go/pkg/mod\n          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}\n          restore-keys: |\n            ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}\n\n      - name: download dependencies if not cached\n        run: |\n          if [ ! -d \"/go/pkg/mod\" ]; then\n            go mod tidy\n          fi\n\n      - name: test\n        run: make test\n        env:\n          CGO_ENABLED: 1\n"
  },
  {
    "path": ".github/workflows/master.yaml",
    "content": "on:\n  push:\n    branches:\n      - master\n\njobs:\n  build:\n    name: build\n    runs-on: ubuntu-latest\n    container:\n      image: golang:1.14-buster\n      volumes:\n        - \"/home/runner/work/$GITHUB_REPOSITORY:/go/src/github.com/$GITHUB_REPOSITORY\"\n    steps:\n      - uses: actions/checkout@v1\n\n      - name: restore from cache\n        uses: actions/cache@v1\n        with:\n          path: /go/pkg/mod\n          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}\n          restore-keys: |\n            ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}\n\n      - name: build\n        run: |\n          go install github.com/mitchellh/gox\n          make build\n\n      - name: compress build binary\n        run: |\n          cd bin && tar -czvf ../dist.tar.gz cete\n\n      - name: upload compressed dist to artifacts\n        uses: actions/upload-artifact@v1\n        with:\n          name: distribution\n          path: dist.tar.gz\n\n  docker:\n    name: docker\n    runs-on: ubuntu-latest\n    needs:\n      - build\n    steps:\n      - uses: actions/checkout@v1\n\n      - name: downloads compressed dist\n        uses: actions/download-artifact@v1\n        with:\n          name: distribution\n\n      - name: untar dist.tar.gz\n        run: |\n          if [ ! -d \"$(pwd)/bin\" ]; then\n            mkdir bin\n          fi\n          tar -xzvf distribution/dist.tar.gz -C bin\n          rm -rf distribution/\n\n      - name: build docker image\n        run: |\n          docker build . --file Dockerfile --tag $(dirname $GITHUB_REPOSITORY)/$(basename $GITHUB_REPOSITORY)\n          docker tag $(dirname $GITHUB_REPOSITORY)/$(basename $GITHUB_REPOSITORY) $(dirname $GITHUB_REPOSITORY)/$(basename $GITHUB_REPOSITORY):${{ github.sha }}\n\n      - name: log into docker registry\n        run: echo \"${{ secrets.DOCKER_PSW }}\" | docker login -u ${{ secrets.DOCKER_USR }} --password-stdin\n\n      - name: push image to docker registry\n        run: |\n          # pushes unique commit sha based tag\n          docker push $(dirname $GITHUB_REPOSITORY)/$(basename $GITHUB_REPOSITORY)\n          docker push $(dirname $GITHUB_REPOSITORY)/$(basename $GITHUB_REPOSITORY):${{ github.sha }}\n"
  },
  {
    "path": ".github/workflows/tags.yaml",
    "content": "on:\n  push:\n    tags:\n      - \"v*\"\n\njobs:\n  build:\n    name: build\n    runs-on: ubuntu-latest\n    container:\n      image: golang:1.14-buster\n      volumes:\n        - \"/home/runner/work/$GITHUB_REPOSITORY:/go/src/github.com/$GITHUB_REPOSITORY\"\n    steps:\n      - uses: actions/checkout@v1\n\n      - name: restore from cache\n        uses: actions/cache@v1\n        with:\n          path: /go/pkg/mod\n          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}\n          restore-keys: |\n            ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}\n\n      - name: create multiple OS dists\n        run: |\n          go install github.com/mitchellh/gox\n          VERSION=$(basename $GITHUB_REF) make dist\n\n      - name: compress build binary\n        run: |\n          tar -czvf dist.tar.gz dist\n\n      - name: upload compressed dist to artifacts\n        uses: actions/upload-artifact@v1\n        with:\n          name: distribution\n          path: dist.tar.gz\n\n  docker:\n    name: docker\n    runs-on: ubuntu-latest\n    needs:\n      - build\n    steps:\n      - uses: actions/checkout@v1\n\n      - name: downloads compressed dist\n        uses: actions/download-artifact@v1\n        with:\n          name: distribution\n\n      - name: untar dist.tar.gz\n        run: |\n          if [ ! -d \"$(pwd)/bin\" ]; then\n            mkdir bin\n          fi\n          tar -xzvf distribution/dist.tar.gz\n          mv dist/cete_linux_amd64 bin/cete\n          rm -rf distribution/ dist/\n\n      - name: build docker image\n        run: docker build . --file Dockerfile --tag $(dirname $GITHUB_REPOSITORY)/$(basename $GITHUB_REPOSITORY):$(basename $GITHUB_REF)\n\n      - name: log into docker registry\n        run: echo \"${{ secrets.DOCKER_PSW }}\" | docker login -u ${{ secrets.DOCKER_USR }} --password-stdin\n\n      - name: push image to docker registry\n        run: |\n          # pushes unique commit sha based tag\n          docker push $(dirname $GITHUB_REPOSITORY)/$(basename $GITHUB_REPOSITORY):$(basename $GITHUB_REF)\n\n  release:\n    name: release\n    runs-on: ubuntu-latest\n    needs:\n      - docker\n    steps:\n      - uses: actions/checkout@v2\n\n      - name: downloads compressed dist\n        uses: actions/download-artifact@v1\n        with:\n          name: distribution\n\n      - name: create dists .tar.gz\n        run: |\n          tar -xzvf distribution/dist.tar.gz\n          for dist_file in $(ls dist);\n          do\n            (cd dist && tar -czvf ../$(basename -- \"${dist_file%.*}\").tar.gz $dist_file) || exit 1\n          done\n          rm -rf distribution/ dist/\n\n      - run: |\n          set -x\n          assets=()\n          for asset in $(ls *.tar.gz); do\n            assets+=(\"-a\" \"$asset\")\n          done\n          tag_name=$(basename $GITHUB_REF)\n          hub release create \"${assets[@]}\" -m \"$tag_name\" \"$tag_name\"\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n"
  },
  {
    "path": ".gitignore",
    "content": ".DS_Store\n\n.classpath\n.project\n\n.idea/\n\nbin/\ndist/\n\n*.pem\n*.csr\n\ncover.out\ncover.html\n"
  },
  {
    "path": "CHANGES.md",
    "content": "# Change Log\n\nAll notable changes to this project will be documented in this file.\n\nThe format is based on [Keep a Changelog](http://keepachangelog.com/)\nand this project adheres to [Semantic Versioning](http://semver.org/).\n\n## [Unreleased]\n\n- Fix go.mod dependency due to a change in the case #50 @mosuka\n- Add garbage collector for badger #48 @christian-roggia\n- adds cicd #41 @vniche\n- adds scan endpoint #35 @vniche\n- Fix bug in getting leader ID #34 @mosuka\n\n## [v0.3.1] 2020-04-01\n\n- Update protobuf #33 @mosuka\n\n## [v0.3.0] 2020-03-31\n\n- Add health check endpoints #32 @mosuka\n- Add some metrics #31 @mosuka\n- Allow CLI options to be read from the configuration file #29 @mosuka\n- Fix gateway bug #26 @mosuka\n- Support TLS #25 @mosuka\n- Add keepalive options #24 @mosuka\n- Improve cluster watching #22 @mosuka\n- Refactoring #21 @mosuka\n- Update Makefile #20 @mosuka\n\n## [v0.2.0] 2020-03-19\n\n- Add join endpoint #19 @mosuka\n- Add leave endpoint #18 @mosuka\n- Add snapshot endpoint #17 @mosuka\n- Disable raft-badgerdb logging #16 @mosuka\n- Migrate to grpc-gateway #15 @mosuka\n- Add metrics command #14 @mosuka\n- Use raft-badger #13 @mosuka\n- Refactoring #12 @mosuka\n- Refactoring #11 @mosuka\n- Refactoring #10 @mosuka\n- Upgrade Badger #9 @mosuka\n- Upgrade Raft #8 @mosuka\n- Refactoring #7 @mosuka\n\n## [v0.1.1] 2019-11-05\n\n- Fix bugs in defer #5 @mosuka\n\n## [v0.1.0] 2019-03-30\n\n- First release @mosuka\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM alpine:3.11\n\nLABEL maintainer=\"Minoru Osuka minoru.osuka@gmail.com\"\nLABEL maintainer=\"Vinícius Niche Correa viniciusnichecorrea@gmail.com\"\n\nRUN apk update && \\\n    rm -rf /var/cache/apk/*\n\nRUN\taddgroup cete \\\n    && adduser -S cete -u 1000 -G cete\n\nUSER cete\n\nCOPY --chown=cete:cete bin/cete /usr/bin/\n\nEXPOSE 7000 8000 9000\n\nENTRYPOINT [ \"/usr/bin/cete\" ]\nCMD        [ \"start\" ]\n"
  },
  {
    "path": "LICENSE",
    "content": "                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright 2019 Minoru Osuka\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n"
  },
  {
    "path": "Makefile",
    "content": "GOOS ?=\nGOARCH ?=\nGO111MODULE ?= on\nCGO_ENABLED ?= 0\nCGO_CFLAGS ?=\nCGO_LDFLAGS ?=\nBUILD_TAGS ?=\nVERSION ?=\nBIN_EXT ?=\nDOCKER_REPOSITORY ?= mosuka\n\nPACKAGES = $(shell $(GO) list ./... | grep -v '/vendor/')\n\nPROTOBUFS = $(shell find . -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq | grep -v /vendor/)\n\nTARGET_PACKAGES = $(shell find $(CURDIR) -name 'main.go' -print0 | xargs -0 -n1 dirname | sort | uniq | grep -v /vendor/)\n\nGRPC_GATEWAY_PATH = $(shell $(GO) list -m -f \"{{.Dir}}\" github.com/grpc-ecosystem/grpc-gateway)\n\nifeq ($(GOOS),)\n  GOOS = $(shell go version | awk -F ' ' '{print $$NF}' | awk -F '/' '{print $$1}')\nendif\n\nifeq ($(GOARCH),)\n  GOARCH = $(shell go version | awk -F ' ' '{print $$NF}' | awk -F '/' '{print $$2}')\nendif\n\nifeq ($(VERSION),)\n  VERSION = latest\nendif\nLDFLAGS = -ldflags \"-X \\\"github.com/mosuka/cete/version.Version=$(VERSION)\\\"\"\n\nifeq ($(GOOS),windows)\n  BIN_EXT = .exe\nendif\n\nBUILD_FLAGS := GOOS=$(GOOS) GOARCH=$(GOARCH) CGO_ENABLED=$(CGO_ENABLED) CGO_CFLAGS=$(CGO_CFLAGS) CGO_LDFLAGS=$(CGO_LDFLAGS) GO111MODULE=$(GO111MODULE)\n\nGO := $(BUILD_FLAGS) go\nGOX := $(BUILD_FLAGS) gox\n\n.DEFAULT_GOAL := build\n\n.PHONY: show-env\nshow-env:\n\t@echo \">> show env\"\n\t@echo \"   GOOS              = $(GOOS)\"\n\t@echo \"   GOARCH            = $(GOARCH)\"\n\t@echo \"   GO111MODULE       = $(GO111MODULE)\"\n\t@echo \"   CGO_ENABLED       = $(CGO_ENABLED)\"\n\t@echo \"   CGO_CFLAGS        = $(CGO_CFLAGS)\"\n\t@echo \"   CGO_LDFLAGS       = $(CGO_LDFLAGS)\"\n\t@echo \"   BUILD_TAGS        = $(BUILD_TAGS)\"\n\t@echo \"   VERSION           = $(VERSION)\"\n\t@echo \"   BIN_EXT           = $(BIN_EXT)\"\n\t@echo \"   DOCKER_REPOSITORY = $(DOCKER_REPOSITORY)\"\n\t@echo \"   LDFLAGS           = $(LDFLAGS)\"\n\t@echo \"   PACKAGES          = $(PACKAGES)\"\n\t@echo \"   PROTOBUFS         = $(PROTOBUFS)\"\n\t@echo \"   TARGET_PACKAGES   = $(TARGET_PACKAGES)\"\n\t@echo \"   GRPC_GATEWAY_PATH = $(GRPC_GATEWAY_PATH)\"\n\n.PHONY: protoc\nprotoc: show-env\n\t@echo \">> generating proto3 code\"\n\tfor proto_dir in $(PROTOBUFS); do echo $$proto_dir; protoc --proto_path=. --proto_path=$$proto_dir --proto_path=${GRPC_GATEWAY_PATH} --proto_path=${GRPC_GATEWAY_PATH}/third_party/googleapis --go_out=plugins=grpc:$(GOPATH)/src $$proto_dir/*.proto || exit 1; done\n\tfor proto_dir in $(PROTOBUFS); do echo $$proto_dir; protoc --proto_path=. --proto_path=$$proto_dir --proto_path=${GRPC_GATEWAY_PATH} --proto_path=${GRPC_GATEWAY_PATH}/third_party/googleapis --grpc-gateway_out=logtostderr=true,allow_delete_body=true:$(GOPATH)/src $$proto_dir/*.proto || exit 1; done\n\n.PHONY: format\nformat: show-env\n\t@echo \">> formatting code\"\n\t$(GO) fmt $(PACKAGES)\n\n.PHONY: test\ntest: show-env\n\t@echo \">> testing all packages\"\n\t$(GO) test -covermode=atomic -v -tags=\"$(BUILD_TAGS)\" $(PACKAGES)\n\n.PHONY: coverage\ncoverage: show-env\n\t@echo \">> checking coverage of all packages\"\n\t$(GO) test -covermode=atomic -coverprofile cover.out -tags=\"$(BUILD_TAGS)\" $(PACKAGES)\n\t$(GO) tool cover -html=cover.out -o cover.html\n\n.PHONY: clean\nclean: show-env\n\t@echo \">> cleaning binaries\"\n\trm -rf ./bin\n\trm -rf ./data\n\trm -rf ./dist\n\n.PHONY: build\nbuild: show-env\n\t@echo \">> building binaries\"\n\tmkdir -p bin\n\t$(GOX) -osarch=\"$(GOOS)/amd64\" -tags=\"$(BUILD_TAGS)\" $(LDFLAGS) -output bin/cete\n\n.PHONY: install\ninstall: show-env\n\t@echo \">> installing binaries\"\n\tfor target_pkg in $(TARGET_PACKAGES); do echo $$target_pkg; $(GO) install -tags=\"$(BUILD_TAGS)\" $(LDFLAGS) $$target_pkg || exit 1; done\n\n.PHONY: dist\ndist: show-env\n\t@echo \">> packaging binaries\"\n\tmkdir dist\n\t$(GOX) -osarch=\"linux/amd64\" -osarch=\"darwin/amd64\" -osarch=\"windows/amd64\" -tags=\"$(BUILD_TAGS)\" $(LDFLAGS) -output \"dist/{{.Dir}}_{{.OS}}_{{.Arch}}\"\n\n.PHONY: list-tag\nlist-tag:\n\t@echo \">> listing github tags\"\n\tgit tag -l --sort=-v:refname\n\n.PHONY: tag\ntag: show-env\n\t@echo \">> tagging github\"\nifeq ($(VERSION),$(filter $(VERSION),latest master \"\"))\n\t@echo \"please specify VERSION\"\nelse\n\tgit tag -a $(VERSION) -m \"Release $(VERSION)\"\n\tgit push origin $(VERSION)\nendif\n\n.PHONY: docker-build\ndocker-build: show-env\n\t@echo \">> building docker container image\"\n\tdocker build -t $(DOCKER_REPOSITORY)/cete:latest --build-arg VERSION=$(VERSION) .\n\tdocker tag $(DOCKER_REPOSITORY)/cete:latest $(DOCKER_REPOSITORY)/cete:$(VERSION)\n\n.PHONY: docker-push\ndocker-push: show-env\n\t@echo \">> pushing docker container image\"\n\tdocker push $(DOCKER_REPOSITORY)/cete:latest\n\tdocker push $(DOCKER_REPOSITORY)/cete:$(VERSION)\n\n.PHONY: docker-clean\ndocker-clean: show-env\n\tdocker rmi -f $(shell docker images --filter \"dangling=true\" -q --no-trunc)\n\n.PHONY: cert\ncert: show-env\n\t@echo \">> generating certification\"\n\topenssl req -x509 -nodes -newkey rsa:4096 -keyout ./etc/cete-key.pem -out ./etc/cete-cert.pem -days 365 -subj '/CN=localhost'\n"
  },
  {
    "path": "README.md",
    "content": "# Cete\n\nCete is a distributed key value store server written in [Go](https://golang.org) built on top of [BadgerDB](https://blog.dgraph.io/post/badger/).  \nIt provides functions through [gRPC](http://www.grpc.io) ([HTTP/2](https://en.wikipedia.org/wiki/HTTP/2) + [Protocol Buffers](https://developers.google.com/protocol-buffers/)) or traditional [RESTful](https://en.wikipedia.org/wiki/Representational_state_transfer) API ([HTTP/1.1](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol) + [JSON](http://www.json.org)).  \nCete implements [Raft consensus algorithm](https://raft.github.io/) by [hashicorp/raft](https://github.com/hashicorp/raft). It achieve consensus across all the instances of the nodes, ensuring that every change made to the system is made to a quorum of nodes, or none at all.  \nCete makes it easy bringing up a cluster of BadgerDB (a cete of badgers) .\n\n\n## Features\n\n- Easy deployment\n- Bringing up cluster\n- Database replication\n- An easy-to-use HTTP API\n- CLI is also available\n- Docker container image is available\n\n\n## Building Cete\n\nWhen you satisfied dependencies, let's build Cete for Linux as following:\n\n```bash\n$ mkdir -p ${GOPATH}/src/github.com/mosuka\n$ cd ${GOPATH}/src/github.com/mosuka\n$ git clone https://github.com/mosuka/cete.git\n$ cd cete\n$ make build\n```\n\nIf you want to build for other platform, set `GOOS`, `GOARCH` environment variables. For example, build for macOS like following:\n\n```bash\n$ make GOOS=darwin build\n```\n\n### Binaries\n\nYou can see the binary file when build successful like so:\n\n```bash\n$ ls ./bin\ncete\n```\n\n\n## Testing Cete\n\nIf you want to test your changes, run command like following:\n\n```bash\n$ make test\n```\n\n\n## Packaging Cete\n\n###  Linux\n\n```bash\n$ make GOOS=linux dist\n```\n\n### macOS\n\n```bash\n$ make GOOS=darwin dist\n```\n\n## Configure Cete\n\n| CLI Flag | Environment variable | Configuration File | Description |\n| --- | --- | --- | --- |\n| --config-file | - | - | config file. if omitted, cete.yaml in /etc and home directory will be searched |\n| --id | CETE_ID | id | node ID |\n| --raft-address | CETE_RAFT_ADDRESS | raft_address | Raft server listen address |\n| --grpc-address | CETE_GRPC_ADDRESS | grpc_address | gRPC server listen address |\n| --http-address | CETE_HTTP_ADDRESS | http_address | HTTP server listen address |\n| --data-directory | CETE_DATA_DIRECTORY | data_directory | data directory which store the key-value store data and Raft logs |\n| --peer-grpc-address | CETE_PEER_GRPC_ADDRESS | peer_grpc_address | listen address of the existing gRPC server in the joining cluster |\n| --certificate-file | CETE_CERTIFICATE_FILE | certificate_file | path to the client server TLS certificate file |\n| --key-file | CETE_KEY_FILE | key_file | path to the client server TLS key file |\n| --common-name | CETE_COMMON_NAME | common_name | certificate common name |\n| --log-level | CETE_LOG_LEVEL | log_level | log level |\n| --log-file | CETE_LOG_FILE | log_file | log file |\n| --log-max-size | CETE_LOG_MAX_SIZE | log_max_size | max size of a log file in megabytes |\n| --log-max-backups | CETE_LOG_MAX_BACKUPS | log_max_backups | max backup count of log files |\n| --log-max-age | CETE_LOG_MAX_AGE | log_max_age | max age of a log file in days |\n| --log-compress | CETE_LOG_COMPRESS | log_compress | compress a log file |\n\n\n## Starting Cete node\n\nStarting cete is easy as follows:\n\n```bash\n$ ./bin/cete start --id=node1 --raft-address=:7000 --grpc-address=:9000 --http-address=:8000 --data-directory=/tmp/cete/node1\n```\n\nYou can get the node information with the following command:\n\n```bash\n$ ./bin/cete node | jq .\n```\n\nor the following URL:\n\n```bash\n$ curl -X GET http://localhost:8000/v1/node | jq .\n```\n\nThe result of the above command is:\n\n```json\n{\n  \"node\": {\n    \"raft_address\": \":7000\",\n    \"metadata\": {\n      \"grpc_address\": \":9000\",\n      \"http_address\": \":8000\"\n    },\n    \"state\": \"Leader\"\n  }\n}\n```\n\n## Health check\n\nYou can check the health status of the node.\n\n```bash\n$ ./bin/cete healthcheck | jq .\n```\n\nAlso provides the following REST APIs\n\n### Liveness prove\n\nThis endpoint always returns 200 and should be used to check Cete health.\n\n```bash\n$ curl -X GET http://localhost:8000/v1/liveness_check | jq .\n```\n\n### Readiness probe\n\nThis endpoint returns 200 when Cete is ready to serve traffic (i.e. respond to queries).\n\n```bash\n$ curl -X GET http://localhost:8000/v1/readiness_check | jq .\n```\n\n## Putting a key-value\n\nTo put a key-value, execute the following command:\n\n```bash\n$ ./bin/cete set 1 value1\n```\n\nor, you can use the RESTful API as follows:\n\n```bash\n$ curl -X PUT 'http://127.0.0.1:8000/v1/data/1' --data-binary value1\n$ curl -X PUT 'http://127.0.0.1:8000/v1/data/2' -H \"Content-Type: image/jpeg\" --data-binary @/path/to/photo.jpg\n```\n\n## Getting a key-value\n\nTo get a key-value, execute the following command:\n\n```bash\n$ ./bin/cete get 1\n```\n\nor, you can use the RESTful API as follows:\n\n```bash\n$ curl -X GET 'http://127.0.0.1:8000/v1/data/1'\n```\n\nYou can see the result. The result of the above command is:\n\n```text\nvalue1\n```\n\n## Deleting a key-value\n\nDeleting a value by key, execute the following command:\n\n```bash\n$ ./bin/cete delete 1\n```\n\nor, you can use the RESTful API as follows:\n\n```bash\n$ curl -X DELETE 'http://127.0.0.1:8000/v1/data/1'\n```\n\n\n## Bringing up a cluster\n\nCete is easy to bring up the cluster. Cete node is already running, but that is not fault tolerant. If you need to increase the fault tolerance, bring up 2 more data nodes like so:\n\n```bash\n$ ./bin/cete start --id=node2 --raft-address=:7001 --grpc-address=:9001 --http-address=:8001 --data-directory=/tmp/cete/node2 --peer-grpc-address=:9000\n$ ./bin/cete start --id=node3 --raft-address=:7002 --grpc-address=:9002 --http-address=:8002 --data-directory=/tmp/cete/node3 --peer-grpc-address=:9000\n```\n\n_Above example shows each Cete node running on the same host, so each node must listen on different ports. This would not be necessary if each node ran on a different host._\n\nThis instructs each new node to join an existing node, each node recognizes the joining clusters when started.\nSo you have a 3-node cluster. That way you can tolerate the failure of 1 node. You can check the cluster with the following command:\n\n```bash\n$ ./bin/cete cluster | jq .\n```\n\nor, you can use the RESTful API as follows:\n\n```bash\n$ curl -X GET 'http://127.0.0.1:8000/v1/cluster' | jq .\n```\n\nYou can see the result in JSON format. The result of the above command is:\n\n```json\n{\n  \"cluster\": {\n    \"nodes\": {\n      \"node1\": {\n        \"raft_address\": \":7000\",\n        \"metadata\": {\n          \"grpc_address\": \":9000\",\n          \"http_address\": \":8000\"\n        },\n        \"state\": \"Leader\"\n      },\n      \"node2\": {\n        \"raft_address\": \":7001\",\n        \"metadata\": {\n          \"grpc_address\": \":9001\",\n          \"http_address\": \":8001\"\n        },\n        \"state\": \"Follower\"\n      },\n      \"node3\": {\n        \"raft_address\": \":7002\",\n        \"metadata\": {\n          \"grpc_address\": \":9002\",\n          \"http_address\": \":8002\"\n        },\n        \"state\": \"Follower\"\n      }\n    },\n    \"leader\": \"node1\"\n  }\n}\n```\n\nRecommend 3 or more odd number of nodes in the cluster. In failure scenarios, data loss is inevitable, so avoid deploying single nodes.\n\nThe above example, the node joins to the cluster at startup, but you can also join the node that already started on standalone mode to the cluster later, as follows:\n\n```bash\n$ ./bin/cete join --grpc-addr=:9000 node2 127.0.0.1:9001\n```\n\nor, you can use the RESTful API as follows:\n\n```bash\n$ curl -X PUT 'http://127.0.0.1:8000/v1/cluster/node2' --data-binary '\n{\n  \"raft_address\": \":7001\",\n  \"metadata\": {\n    \"grpc_address\": \":9001\",\n    \"http_address\": \":8001\"\n  }\n}\n'\n```\n\nTo remove a node from the cluster, execute the following command:\n\n```bash\n$ ./bin/cete leave --grpc-addr=:9000 node2\n```\n\nor, you can use the RESTful API as follows:\n\n```bash\n$ curl -X DELETE 'http://127.0.0.1:8000/v1/cluster/node2'\n```\n\nThe following command indexes documents to any node in the cluster:\n\n```bash\n$ ./bin/cete set 1 value1 --grpc-address=:9000 \n```\n\nSo, you can get the document from the node specified by the above command as follows:\n\n```bash\n$ ./bin/cete get 1 --grpc-address=:9000\n```\n\nYou can see the result. The result of the above command is:\n\n```text\nvalue1\n```\n\nYou can also get the same document from other nodes in the cluster as follows:\n\n```bash\n$ ./bin/cete get 1 --grpc-address=:9001\n$ ./bin/cete get 1 --grpc-address=:9002\n```\n\nYou can see the result. The result of the above command is:\n\n```text\nvalue1\n```\n\n\n## Cete on Docker\n\n### Building Cete Docker container image on localhost\n\nYou can build the Docker container image like so:\n\n```bash\n$ make docker-build\n```\n\n### Pulling Cete Docker container image from docker.io\n\nYou can also use the Docker container image already registered in docker.io like so:\n\n```bash\n$ docker pull mosuka/cete:latest\n```\n\nSee https://hub.docker.com/r/mosuka/cete/tags/\n\n\n### Pulling Cete Docker container image from docker.io\n\nYou can also use the Docker container image already registered in docker.io like so:\n\n```bash\n$ docker pull mosuka/cete:latest\n```\n\n\n### Running Cete node on Docker\n\nRunning a Cete data node on Docker. Start Cete node like so:\n\n```bash\n$ docker run --rm --name cete-node1 \\\n    -p 7000:7000 \\\n    -p 8000:8000 \\\n    -p 9000:9000 \\\n    mosuka/cete:latest cete start \\\n      --id=node1 \\\n      --raft-address=:7000 \\\n      --grpc-address=:9000 \\\n      --http-address=:8000 \\\n      --data-directory=/tmp/cete/node1\n```\n\nYou can execute the command in docker container as follows:\n\n```bash\n$ docker exec -it cete-node1 cete node --grpc-address=:9000\n```\n\n## Securing Cete\n\nCete supports HTTPS access, ensuring that all communication between clients and a cluster is encrypted.\n\n### Generating a certificate and private key\n\nOne way to generate the necessary resources is via [openssl](https://www.openssl.org/). For example:\n\n```bash\n$ openssl req -x509 -nodes -newkey rsa:4096 -keyout ./etc/cete-key.pem -out ./etc/cete-cert.pem -days 365 -subj '/CN=localhost'\nGenerating a 4096 bit RSA private key\n............................++\n........++\nwriting new private key to 'key.pem'\n```\n\n### Secure cluster example\n\nStarting a node with HTTPS enabled, node-to-node encryption, and with the above configuration file. It is assumed the HTTPS X.509 certificate and key are at the paths server.crt and key.pem respectively.\n\n```bash\n$ ./bin/cete start --id=node1 --raft-address=:7000 --grpc-address=:9000 --http-address=:8000 --data-directory=/tmp/cete/node1 --peer-grpc-address=:9000 --certificate-file=./etc/cert.pem --key-file=./etc/key.pem --common-name=localhost\n$ ./bin/cete start --id=node2 --raft-address=:7001 --grpc-address=:9001 --http-address=:8001 --data-directory=/tmp/cete/node2 --peer-grpc-address=:9000 --certificate-file=./etc/cert.pem --key-file=./etc/key.pem --common-name=localhost\n$ ./bin/cete start --id=node3 --raft-address=:7002 --grpc-address=:9002 --http-address=:8002 --data-directory=/tmp/cete/node3 --peer-grpc-address=:9000 --certificate-file=./etc/cert.pem --key-file=./etc/key.pem --common-name=localhost\n```\n\nYou can access the cluster by adding a flag, such as the following command:\n\n```bash\n$ ./bin/cete cluster --grpc-address=:9000 --certificate-file=./cert.pem --common-name=localhost | jq .\n```\n\nor\n\n```bash\n$ curl -X GET https://localhost:8000/v1/cluster --cacert ./cert.pem | jq .\n```\n"
  },
  {
    "path": "client/grpc_client.go",
    "content": "package client\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"math\"\n\t\"time\"\n\n\t\"github.com/golang/protobuf/ptypes/empty\"\n\t\"github.com/mosuka/cete/errors\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/keepalive\"\n\t\"google.golang.org/grpc/status\"\n)\n\ntype GRPCClient struct {\n\tctx    context.Context\n\tcancel context.CancelFunc\n\tconn   *grpc.ClientConn\n\tclient protobuf.KVSClient\n\n\tlogger *log.Logger\n}\n\nfunc NewGRPCClient(grpc_address string) (*GRPCClient, error) {\n\treturn NewGRPCClientWithContext(grpc_address, context.Background())\n}\n\nfunc NewGRPCClientWithContext(grpc_address string, baseCtx context.Context) (*GRPCClient, error) {\n\treturn NewGRPCClientWithContextTLS(grpc_address, baseCtx, \"\", \"\")\n}\n\nfunc NewGRPCClientWithContextTLS(grpcAddress string, baseCtx context.Context, certificateFile string, commonName string) (*GRPCClient, error) {\n\tdialOpts := []grpc.DialOption{\n\t\tgrpc.WithDefaultCallOptions(\n\t\t\tgrpc.MaxCallSendMsgSize(math.MaxInt64),\n\t\t\tgrpc.MaxCallRecvMsgSize(math.MaxInt64),\n\t\t),\n\t\tgrpc.WithKeepaliveParams(\n\t\t\tkeepalive.ClientParameters{\n\t\t\t\tTime:                1 * time.Second,\n\t\t\t\tTimeout:             5 * time.Second,\n\t\t\t\tPermitWithoutStream: true,\n\t\t\t},\n\t\t),\n\t}\n\n\tctx, cancel := context.WithCancel(baseCtx)\n\n\tif certificateFile == \"\" {\n\t\tdialOpts = append(dialOpts, grpc.WithInsecure())\n\t} else {\n\t\tcreds, err := credentials.NewClientTLSFromFile(certificateFile, commonName)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdialOpts = append(dialOpts, grpc.WithTransportCredentials(creds))\n\t}\n\n\tconn, err := grpc.DialContext(ctx, grpcAddress, dialOpts...)\n\tif err != nil {\n\t\tcancel()\n\t\treturn nil, err\n\t}\n\n\treturn &GRPCClient{\n\t\tctx:    ctx,\n\t\tcancel: cancel,\n\t\tconn:   conn,\n\t\tclient: protobuf.NewKVSClient(conn),\n\t}, nil\n}\n\nfunc (c *GRPCClient) Close() error {\n\tc.cancel()\n\tif c.conn != nil {\n\t\treturn c.conn.Close()\n\t}\n\n\treturn c.ctx.Err()\n}\n\nfunc (c *GRPCClient) Target() string {\n\treturn c.conn.Target()\n}\n\nfunc (c *GRPCClient) LivenessCheck(opts ...grpc.CallOption) (*protobuf.LivenessCheckResponse, error) {\n\tif resp, err := c.client.LivenessCheck(c.ctx, &empty.Empty{}, opts...); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\treturn resp, nil\n\t}\n}\n\nfunc (c *GRPCClient) ReadinessCheck(opts ...grpc.CallOption) (*protobuf.ReadinessCheckResponse, error) {\n\tif resp, err := c.client.ReadinessCheck(c.ctx, &empty.Empty{}, opts...); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\treturn resp, nil\n\t}\n}\n\nfunc (c *GRPCClient) Join(req *protobuf.JoinRequest, opts ...grpc.CallOption) error {\n\tif _, err := c.client.Join(c.ctx, req, opts...); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (c *GRPCClient) Leave(req *protobuf.LeaveRequest, opts ...grpc.CallOption) error {\n\tif _, err := c.client.Leave(c.ctx, req, opts...); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (c *GRPCClient) Node(opts ...grpc.CallOption) (*protobuf.NodeResponse, error) {\n\tif resp, err := c.client.Node(c.ctx, &empty.Empty{}, opts...); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\treturn resp, nil\n\t}\n}\n\nfunc (c *GRPCClient) Cluster(opts ...grpc.CallOption) (*protobuf.ClusterResponse, error) {\n\tif resp, err := c.client.Cluster(c.ctx, &empty.Empty{}, opts...); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\treturn resp, nil\n\t}\n}\n\nfunc (c *GRPCClient) Snapshot(opts ...grpc.CallOption) error {\n\tif _, err := c.client.Snapshot(c.ctx, &empty.Empty{}); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (c *GRPCClient) Get(req *protobuf.GetRequest, opts ...grpc.CallOption) (*protobuf.GetResponse, error) {\n\tif resp, err := c.client.Get(c.ctx, req, opts...); err != nil {\n\t\tst, _ := status.FromError(err)\n\t\tswitch st.Code() {\n\t\tcase codes.NotFound:\n\t\t\treturn nil, errors.ErrNotFound\n\t\tdefault:\n\t\t\treturn nil, err\n\t\t}\n\t} else {\n\t\treturn resp, nil\n\t}\n}\n\nfunc (c *GRPCClient) Set(req *protobuf.SetRequest, opts ...grpc.CallOption) error {\n\tif _, err := c.client.Set(c.ctx, req, opts...); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (c *GRPCClient) Delete(req *protobuf.DeleteRequest, opts ...grpc.CallOption) error {\n\tif _, err := c.client.Delete(c.ctx, req, opts...); err != nil {\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (c *GRPCClient) Watch(req *empty.Empty, opts ...grpc.CallOption) (protobuf.KVS_WatchClient, error) {\n\treturn c.client.Watch(c.ctx, req, opts...)\n}\n\nfunc (c *GRPCClient) Metrics(opts ...grpc.CallOption) (*protobuf.MetricsResponse, error) {\n\tif resp, err := c.client.Metrics(c.ctx, &empty.Empty{}, opts...); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\treturn resp, nil\n\t}\n}\n"
  },
  {
    "path": "cmd/cluster.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar (\n\tclusterCmd = &cobra.Command{\n\t\tUse:   \"cluster\",\n\t\tShort: \"Get the cluster info\",\n\t\tLong:  \"Get the cluster info\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tgrpcAddress = viper.GetString(\"grpc_address\")\n\n\t\t\tcertificateFile = viper.GetString(\"certificate_file\")\n\t\t\tcommonName = viper.GetString(\"common_name\")\n\n\t\t\tc, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = c.Close()\n\t\t\t}()\n\n\t\t\tresp, err := c.Cluster()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\trespBytes, err := json.Marshal(resp)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfmt.Println(string(respBytes))\n\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(clusterCmd)\n\n\tcobra.OnInitialize(func() {\n\t\tif configFile != \"\" {\n\t\t\tviper.SetConfigFile(configFile)\n\t\t} else {\n\t\t\thome, err := homedir.Dir()\n\t\t\tif err != nil {\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tviper.AddConfigPath(\"/etc\")\n\t\t\tviper.AddConfigPath(home)\n\t\t\tviper.SetConfigName(\"cete\")\n\n\t\t}\n\n\t\tviper.SetEnvPrefix(\"CETE\")\n\t\tviper.AutomaticEnv()\n\n\t\tif err := viper.ReadInConfig(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase viper.ConfigFileNotFoundError:\n\t\t\t\t// cete.yaml does not found in config search path\n\t\t\tdefault:\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t})\n\n\tclusterCmd.PersistentFlags().StringVar(&configFile, \"config-file\", \"\", \"config file. if omitted, cete.yaml in /etc and home directory will be searched\")\n\tclusterCmd.PersistentFlags().StringVar(&grpcAddress, \"grpc-address\", \":9000\", \"gRPC server listen address\")\n\tclusterCmd.PersistentFlags().StringVar(&certificateFile, \"certificate-file\", \"\", \"path to the client server TLS certificate file\")\n\tclusterCmd.PersistentFlags().StringVar(&commonName, \"common-name\", \"\", \"certificate common name\")\n\n\t_ = viper.BindPFlag(\"grpc_address\", clusterCmd.PersistentFlags().Lookup(\"grpc-address\"))\n\t_ = viper.BindPFlag(\"certificate_file\", clusterCmd.PersistentFlags().Lookup(\"certificate-file\"))\n\t_ = viper.BindPFlag(\"common_name\", clusterCmd.PersistentFlags().Lookup(\"common-name\"))\n}\n"
  },
  {
    "path": "cmd/delete.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar (\n\tdeleteCmd = &cobra.Command{\n\t\tUse:   \"delete KEY\",\n\t\tArgs:  cobra.ExactArgs(1),\n\t\tShort: \"Delete a key-value\",\n\t\tLong:  \"Delete a key-value\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tgrpcAddress = viper.GetString(\"grpc_address\")\n\n\t\t\tcertificateFile = viper.GetString(\"certificate_file\")\n\t\t\tcommonName = viper.GetString(\"common_name\")\n\n\t\t\tkey := args[0]\n\n\t\t\tc, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = c.Close()\n\t\t\t}()\n\n\t\t\treq := &protobuf.DeleteRequest{\n\t\t\t\tKey: key,\n\t\t\t}\n\n\t\t\tif err := c.Delete(req); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(deleteCmd)\n\n\tcobra.OnInitialize(func() {\n\t\tif configFile != \"\" {\n\t\t\tviper.SetConfigFile(configFile)\n\t\t} else {\n\t\t\thome, err := homedir.Dir()\n\t\t\tif err != nil {\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tviper.AddConfigPath(\"/etc\")\n\t\t\tviper.AddConfigPath(home)\n\t\t\tviper.SetConfigName(\"cete\")\n\n\t\t}\n\n\t\tviper.SetEnvPrefix(\"CETE\")\n\t\tviper.AutomaticEnv()\n\n\t\tif err := viper.ReadInConfig(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase viper.ConfigFileNotFoundError:\n\t\t\t\t// cete.yaml does not found in config search path\n\t\t\tdefault:\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t})\n\n\tdeleteCmd.PersistentFlags().StringVar(&configFile, \"config-file\", \"\", \"config file. if omitted, cete.yaml in /etc and home directory will be searched\")\n\tdeleteCmd.PersistentFlags().StringVar(&grpcAddress, \"grpc-address\", \":9000\", \"gRPC server listen address\")\n\tdeleteCmd.PersistentFlags().StringVar(&certificateFile, \"certificate-file\", \"\", \"path to the client server TLS certificate file\")\n\tdeleteCmd.PersistentFlags().StringVar(&commonName, \"common-name\", \"\", \"certificate common name\")\n\n\t_ = viper.BindPFlag(\"grpc_address\", deleteCmd.PersistentFlags().Lookup(\"grpc-address\"))\n\t_ = viper.BindPFlag(\"certificate_file\", deleteCmd.PersistentFlags().Lookup(\"certificate-file\"))\n\t_ = viper.BindPFlag(\"common_name\", deleteCmd.PersistentFlags().Lookup(\"common-name\"))\n}\n"
  },
  {
    "path": "cmd/get.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar (\n\tgetCmd = &cobra.Command{\n\t\tUse:   \"get KEY\",\n\t\tArgs:  cobra.ExactArgs(1),\n\t\tShort: \"Get a key-value\",\n\t\tLong:  \"Get a key-value\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tgrpcAddress = viper.GetString(\"grpc_address\")\n\n\t\t\tcertificateFile = viper.GetString(\"certificate_file\")\n\t\t\tcommonName = viper.GetString(\"common_name\")\n\n\t\t\tkey := args[0]\n\n\t\t\tc, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = c.Close()\n\t\t\t}()\n\n\t\t\treq := &protobuf.GetRequest{\n\t\t\t\tKey: key,\n\t\t\t}\n\n\t\t\tresp, err := c.Get(req)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfmt.Println(string(resp.Value))\n\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(getCmd)\n\n\tcobra.OnInitialize(func() {\n\t\tif configFile != \"\" {\n\t\t\tviper.SetConfigFile(configFile)\n\t\t} else {\n\t\t\thome, err := homedir.Dir()\n\t\t\tif err != nil {\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tviper.AddConfigPath(\"/etc\")\n\t\t\tviper.AddConfigPath(home)\n\t\t\tviper.SetConfigName(\"cete\")\n\n\t\t}\n\n\t\tviper.SetEnvPrefix(\"CETE\")\n\t\tviper.AutomaticEnv()\n\n\t\tif err := viper.ReadInConfig(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase viper.ConfigFileNotFoundError:\n\t\t\t\t// cete.yaml does not found in config search path\n\t\t\tdefault:\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t})\n\n\tgetCmd.PersistentFlags().StringVar(&configFile, \"config-file\", \"\", \"config file. if omitted, cete.yaml in /etc and home directory will be searched\")\n\tgetCmd.PersistentFlags().StringVar(&grpcAddress, \"grpc-address\", \":9000\", \"gRPC server listen address\")\n\tgetCmd.PersistentFlags().StringVar(&certificateFile, \"certificate-file\", \"\", \"path to the client server TLS certificate file\")\n\tgetCmd.PersistentFlags().StringVar(&commonName, \"common-name\", \"\", \"certificate common name\")\n\n\t_ = viper.BindPFlag(\"grpc_address\", getCmd.PersistentFlags().Lookup(\"grpc-address\"))\n\t_ = viper.BindPFlag(\"certificate_file\", getCmd.PersistentFlags().Lookup(\"certificate-file\"))\n\t_ = viper.BindPFlag(\"common_name\", getCmd.PersistentFlags().Lookup(\"common-name\"))\n}\n"
  },
  {
    "path": "cmd/healthcheck.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar (\n\thealthCheckCmd = &cobra.Command{\n\t\tUse:   \"healthcheck\",\n\t\tShort: \"Health check a node\",\n\t\tLong:  \"Health check a node\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tgrpcAddress = viper.GetString(\"grpc_address\")\n\n\t\t\tcertificateFile = viper.GetString(\"certificate_file\")\n\t\t\tcommonName = viper.GetString(\"common_name\")\n\n\t\t\tc, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = c.Close()\n\t\t\t}()\n\n\t\t\tlResp, err := c.LivenessCheck()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\trResp, err := c.ReadinessCheck()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tresp := map[string]bool{\n\t\t\t\t\"liveness\":   lResp.Alive,\n\t\t\t\t\"readiness:\": rResp.Ready,\n\t\t\t}\n\n\t\t\trespBytes, err := json.Marshal(resp)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfmt.Println(string(respBytes))\n\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(healthCheckCmd)\n\n\tcobra.OnInitialize(func() {\n\t\tif configFile != \"\" {\n\t\t\tviper.SetConfigFile(configFile)\n\t\t} else {\n\t\t\thome, err := homedir.Dir()\n\t\t\tif err != nil {\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tviper.AddConfigPath(\"/etc\")\n\t\t\tviper.AddConfigPath(home)\n\t\t\tviper.SetConfigName(\"cete\")\n\n\t\t}\n\n\t\tviper.SetEnvPrefix(\"CETE\")\n\t\tviper.AutomaticEnv()\n\n\t\tif err := viper.ReadInConfig(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase viper.ConfigFileNotFoundError:\n\t\t\t\t// cete.yaml does not found in config search path\n\t\t\tdefault:\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t})\n\n\thealthCheckCmd.PersistentFlags().StringVar(&configFile, \"config-file\", \"\", \"config file. if omitted, cete.yaml in /etc and home directory will be searched\")\n\thealthCheckCmd.PersistentFlags().StringVar(&grpcAddress, \"grpc-address\", \":9000\", \"gRPC server listen address\")\n\thealthCheckCmd.PersistentFlags().StringVar(&certificateFile, \"certificate-file\", \"\", \"path to the client server TLS certificate file\")\n\thealthCheckCmd.PersistentFlags().StringVar(&commonName, \"common-name\", \"\", \"certificate common name\")\n\n\t_ = viper.BindPFlag(\"grpc_address\", healthCheckCmd.PersistentFlags().Lookup(\"grpc-address\"))\n\t_ = viper.BindPFlag(\"certificate_file\", healthCheckCmd.PersistentFlags().Lookup(\"certificate-file\"))\n\t_ = viper.BindPFlag(\"common_name\", healthCheckCmd.PersistentFlags().Lookup(\"common-name\"))\n}\n"
  },
  {
    "path": "cmd/join.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar (\n\tjoinCmd = &cobra.Command{\n\t\tUse:   \"join ID GRPC_ADDRESS\",\n\t\tArgs:  cobra.ExactArgs(2),\n\t\tShort: \"Join a node to the cluster\",\n\t\tLong:  \"Join a node to the cluster\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tgrpcAddress = viper.GetString(\"grpc_address\")\n\n\t\t\tcertificateFile = viper.GetString(\"certificate_file\")\n\t\t\tcommonName = viper.GetString(\"common_name\")\n\n\t\t\tid := args[0]\n\t\t\ttargetGrpcAddress := args[1]\n\n\t\t\tt, err := client.NewGRPCClientWithContextTLS(targetGrpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = t.Close()\n\t\t\t}()\n\n\t\t\tnodeResp, err := t.Node()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tc, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = c.Close()\n\t\t\t}()\n\n\t\t\treq := &protobuf.JoinRequest{\n\t\t\t\tId:   id,\n\t\t\t\tNode: nodeResp.Node,\n\t\t\t}\n\n\t\t\tif err := c.Join(req); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(joinCmd)\n\n\tcobra.OnInitialize(func() {\n\t\tif configFile != \"\" {\n\t\t\tviper.SetConfigFile(configFile)\n\t\t} else {\n\t\t\thome, err := homedir.Dir()\n\t\t\tif err != nil {\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tviper.AddConfigPath(\"/etc\")\n\t\t\tviper.AddConfigPath(home)\n\t\t\tviper.SetConfigName(\"cete\")\n\n\t\t}\n\n\t\tviper.SetEnvPrefix(\"CETE\")\n\t\tviper.AutomaticEnv()\n\n\t\tif err := viper.ReadInConfig(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase viper.ConfigFileNotFoundError:\n\t\t\t\t// cete.yaml does not found in config search path\n\t\t\tdefault:\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t})\n\n\tjoinCmd.PersistentFlags().StringVar(&configFile, \"config-file\", \"\", \"config file. if omitted, cete.yaml in /etc and home directory will be searched\")\n\tjoinCmd.PersistentFlags().StringVar(&grpcAddress, \"grpc-address\", \":9000\", \"gRPC server listen address\")\n\tjoinCmd.PersistentFlags().StringVar(&certificateFile, \"certificate-file\", \"\", \"path to the client server TLS certificate file\")\n\tjoinCmd.PersistentFlags().StringVar(&commonName, \"common-name\", \"\", \"certificate common name\")\n\n\t_ = viper.BindPFlag(\"grpc_address\", joinCmd.PersistentFlags().Lookup(\"grpc-address\"))\n\t_ = viper.BindPFlag(\"certificate_file\", joinCmd.PersistentFlags().Lookup(\"certificate-file\"))\n\t_ = viper.BindPFlag(\"common_name\", joinCmd.PersistentFlags().Lookup(\"common-name\"))\n}\n"
  },
  {
    "path": "cmd/leave.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar (\n\tleaveCmd = &cobra.Command{\n\t\tUse:   \"leave ID\",\n\t\tArgs:  cobra.ExactArgs(1),\n\t\tShort: \"Leave a node from the cluster\",\n\t\tLong:  \"Leave a node from the cluster\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tgrpcAddress = viper.GetString(\"grpc_address\")\n\n\t\t\tcertificateFile = viper.GetString(\"certificate_file\")\n\t\t\tcommonName = viper.GetString(\"common_name\")\n\n\t\t\tid := args[0]\n\n\t\t\tc, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = c.Close()\n\t\t\t}()\n\n\t\t\treq := &protobuf.LeaveRequest{\n\t\t\t\tId: id,\n\t\t\t}\n\n\t\t\tif err := c.Leave(req); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(leaveCmd)\n\n\tcobra.OnInitialize(func() {\n\t\tif configFile != \"\" {\n\t\t\tviper.SetConfigFile(configFile)\n\t\t} else {\n\t\t\thome, err := homedir.Dir()\n\t\t\tif err != nil {\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tviper.AddConfigPath(\"/etc\")\n\t\t\tviper.AddConfigPath(home)\n\t\t\tviper.SetConfigName(\"cete\")\n\n\t\t}\n\n\t\tviper.SetEnvPrefix(\"CETE\")\n\t\tviper.AutomaticEnv()\n\n\t\tif err := viper.ReadInConfig(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase viper.ConfigFileNotFoundError:\n\t\t\t\t// cete.yaml does not found in config search path\n\t\t\tdefault:\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t})\n\n\tleaveCmd.PersistentFlags().StringVar(&configFile, \"config-file\", \"\", \"config file. if omitted, cete.yaml in /etc and home directory will be searched\")\n\tleaveCmd.PersistentFlags().StringVar(&grpcAddress, \"grpc-address\", \":9000\", \"gRPC server listen address\")\n\tleaveCmd.PersistentFlags().StringVar(&certificateFile, \"certificate-file\", \"\", \"path to the client server TLS certificate file\")\n\tleaveCmd.PersistentFlags().StringVar(&commonName, \"common-name\", \"\", \"certificate common name\")\n\n\t_ = viper.BindPFlag(\"grpc_address\", leaveCmd.PersistentFlags().Lookup(\"grpc-address\"))\n\t_ = viper.BindPFlag(\"certificate_file\", leaveCmd.PersistentFlags().Lookup(\"certificate-file\"))\n\t_ = viper.BindPFlag(\"common_name\", leaveCmd.PersistentFlags().Lookup(\"common-name\"))\n}\n"
  },
  {
    "path": "cmd/metrics.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar (\n\tmetricsCmd = &cobra.Command{\n\t\tUse:   \"metrics\",\n\t\tShort: \"Get the node metrics\",\n\t\tLong:  \"Get the node metrics in Prometheus exposition format\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tgrpcAddress = viper.GetString(\"grpc_address\")\n\n\t\t\tcertificateFile = viper.GetString(\"certificate_file\")\n\t\t\tcommonName = viper.GetString(\"common_name\")\n\n\t\t\tc, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = c.Close()\n\t\t\t}()\n\n\t\t\tresp, err := c.Metrics()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfmt.Println(string(resp.Metrics))\n\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(metricsCmd)\n\n\tcobra.OnInitialize(func() {\n\t\tif configFile != \"\" {\n\t\t\tviper.SetConfigFile(configFile)\n\t\t} else {\n\t\t\thome, err := homedir.Dir()\n\t\t\tif err != nil {\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tviper.AddConfigPath(\"/etc\")\n\t\t\tviper.AddConfigPath(home)\n\t\t\tviper.SetConfigName(\"cete\")\n\n\t\t}\n\n\t\tviper.SetEnvPrefix(\"CETE\")\n\t\tviper.AutomaticEnv()\n\n\t\tif err := viper.ReadInConfig(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase viper.ConfigFileNotFoundError:\n\t\t\t\t// cete.yaml does not found in config search path\n\t\t\tdefault:\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t})\n\n\tmetricsCmd.PersistentFlags().StringVar(&configFile, \"config-file\", \"\", \"config file. if omitted, cete.yaml in /etc and home directory will be searched\")\n\tmetricsCmd.PersistentFlags().StringVar(&grpcAddress, \"grpc-address\", \":9000\", \"gRPC server listen address\")\n\tmetricsCmd.PersistentFlags().StringVar(&certificateFile, \"certificate-file\", \"\", \"path to the client server TLS certificate file\")\n\tmetricsCmd.PersistentFlags().StringVar(&commonName, \"common-name\", \"\", \"certificate common name\")\n\n\t_ = viper.BindPFlag(\"grpc_address\", metricsCmd.PersistentFlags().Lookup(\"grpc-address\"))\n\t_ = viper.BindPFlag(\"certificate_file\", metricsCmd.PersistentFlags().Lookup(\"certificate-file\"))\n\t_ = viper.BindPFlag(\"common_name\", metricsCmd.PersistentFlags().Lookup(\"common-name\"))\n}\n"
  },
  {
    "path": "cmd/node.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar (\n\tnodeCmd = &cobra.Command{\n\t\tUse:   \"node\",\n\t\tShort: \"Get the node info\",\n\t\tLong:  \"Get the node info\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tgrpcAddress = viper.GetString(\"grpc_address\")\n\n\t\t\tcertificateFile = viper.GetString(\"certificate_file\")\n\t\t\tcommonName = viper.GetString(\"common_name\")\n\n\t\t\tc, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = c.Close()\n\t\t\t}()\n\n\t\t\tresp, err := c.Node()\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\trespBytes, err := json.Marshal(resp)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tfmt.Println(string(respBytes))\n\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(nodeCmd)\n\n\tcobra.OnInitialize(func() {\n\t\tif configFile != \"\" {\n\t\t\tviper.SetConfigFile(configFile)\n\t\t} else {\n\t\t\thome, err := homedir.Dir()\n\t\t\tif err != nil {\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tviper.AddConfigPath(\"/etc\")\n\t\t\tviper.AddConfigPath(home)\n\t\t\tviper.SetConfigName(\"cete\")\n\n\t\t}\n\n\t\tviper.SetEnvPrefix(\"CETE\")\n\t\tviper.AutomaticEnv()\n\n\t\tif err := viper.ReadInConfig(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase viper.ConfigFileNotFoundError:\n\t\t\t\t// cete.yaml does not found in config search path\n\t\t\tdefault:\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t})\n\n\tnodeCmd.PersistentFlags().StringVar(&configFile, \"config-file\", \"\", \"config file. if omitted, cete.yaml in /etc and home directory will be searched\")\n\tnodeCmd.PersistentFlags().StringVar(&grpcAddress, \"grpc-address\", \":9000\", \"gRPC server listen address\")\n\tnodeCmd.PersistentFlags().StringVar(&certificateFile, \"certificate-file\", \"\", \"path to the client server TLS certificate file\")\n\tnodeCmd.PersistentFlags().StringVar(&commonName, \"common-name\", \"\", \"certificate common name\")\n\n\t_ = viper.BindPFlag(\"grpc_address\", nodeCmd.PersistentFlags().Lookup(\"grpc-address\"))\n\t_ = viper.BindPFlag(\"certificate_file\", nodeCmd.PersistentFlags().Lookup(\"certificate-file\"))\n\t_ = viper.BindPFlag(\"common_name\", nodeCmd.PersistentFlags().Lookup(\"common-name\"))\n}\n"
  },
  {
    "path": "cmd/root.go",
    "content": "package cmd\n\nimport (\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\trootCmd = &cobra.Command{\n\t\tUse:   \"cete\",\n\t\tShort: \"The lightweight distributed key value store server\",\n\t\tLong:  \"The lightweight distributed key value store server\",\n\t}\n)\n\nfunc Execute() error {\n\treturn rootCmd.Execute()\n}\n"
  },
  {
    "path": "cmd/set.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar (\n\tsetCmd = &cobra.Command{\n\t\tUse:   \"set KEY VALUE\",\n\t\tArgs:  cobra.ExactArgs(2),\n\t\tShort: \"Set a key-value\",\n\t\tLong:  \"Set a key-value\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tgrpcAddress = viper.GetString(\"grpc_address\")\n\n\t\t\tcertificateFile = viper.GetString(\"certificate_file\")\n\t\t\tcommonName = viper.GetString(\"common_name\")\n\n\t\t\tkey := args[0]\n\t\t\tvalue := args[1]\n\n\t\t\tc, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = c.Close()\n\t\t\t}()\n\n\t\t\treq := &protobuf.SetRequest{\n\t\t\t\tKey:   key,\n\t\t\t\tValue: []byte(value),\n\t\t\t}\n\n\t\t\tif err := c.Set(req); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(setCmd)\n\n\tcobra.OnInitialize(func() {\n\t\tif configFile != \"\" {\n\t\t\tviper.SetConfigFile(configFile)\n\t\t} else {\n\t\t\thome, err := homedir.Dir()\n\t\t\tif err != nil {\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tviper.AddConfigPath(\"/etc\")\n\t\t\tviper.AddConfigPath(home)\n\t\t\tviper.SetConfigName(\"cete\")\n\n\t\t}\n\n\t\tviper.SetEnvPrefix(\"CETE\")\n\t\tviper.AutomaticEnv()\n\n\t\tif err := viper.ReadInConfig(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase viper.ConfigFileNotFoundError:\n\t\t\t\t// cete.yaml does not found in config search path\n\t\t\tdefault:\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t})\n\n\tsetCmd.PersistentFlags().StringVar(&configFile, \"config-file\", \"\", \"config file. if omitted, cete.yaml in /etc and home directory will be searched\")\n\tsetCmd.PersistentFlags().StringVar(&grpcAddress, \"grpc-address\", \":9000\", \"gRPC server listen address\")\n\tsetCmd.PersistentFlags().StringVar(&certificateFile, \"certificate-file\", \"\", \"path to the client server TLS certificate file\")\n\tsetCmd.PersistentFlags().StringVar(&commonName, \"common-name\", \"\", \"certificate common name\")\n\n\t_ = viper.BindPFlag(\"grpc_address\", setCmd.PersistentFlags().Lookup(\"grpc-address\"))\n\t_ = viper.BindPFlag(\"certificate_file\", setCmd.PersistentFlags().Lookup(\"certificate-file\"))\n\t_ = viper.BindPFlag(\"common_name\", setCmd.PersistentFlags().Lookup(\"common-name\"))\n}\n"
  },
  {
    "path": "cmd/snapshot.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar (\n\tsnapshotCmd = &cobra.Command{\n\t\tUse:   \"snapshot\",\n\t\tShort: \"Create a snapshot\",\n\t\tLong:  \"Create a snapshot which is full-volume copy of data stored on the node\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tgrpcAddress = viper.GetString(\"grpc_address\")\n\n\t\t\tcertificateFile = viper.GetString(\"certificate_file\")\n\t\t\tcommonName = viper.GetString(\"common_name\")\n\n\t\t\tc, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = c.Close()\n\t\t\t}()\n\n\t\t\tif err := c.Snapshot(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(snapshotCmd)\n\n\tcobra.OnInitialize(func() {\n\t\tif configFile != \"\" {\n\t\t\tviper.SetConfigFile(configFile)\n\t\t} else {\n\t\t\thome, err := homedir.Dir()\n\t\t\tif err != nil {\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tviper.AddConfigPath(\"/etc\")\n\t\t\tviper.AddConfigPath(home)\n\t\t\tviper.SetConfigName(\"cete\")\n\n\t\t}\n\n\t\tviper.SetEnvPrefix(\"CETE\")\n\t\tviper.AutomaticEnv()\n\n\t\tif err := viper.ReadInConfig(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase viper.ConfigFileNotFoundError:\n\t\t\t\t// cete.yaml does not found in config search path\n\t\t\tdefault:\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t})\n\n\tsnapshotCmd.PersistentFlags().StringVar(&configFile, \"config-file\", \"\", \"config file. if omitted, cete.yaml in /etc and home directory will be searched\")\n\tsnapshotCmd.PersistentFlags().StringVar(&grpcAddress, \"grpc-address\", \":9000\", \"gRPC server listen address\")\n\tsnapshotCmd.PersistentFlags().StringVar(&certificateFile, \"certificate-file\", \"\", \"path to the client server TLS certificate file\")\n\tsnapshotCmd.PersistentFlags().StringVar(&commonName, \"common-name\", \"\", \"certificate common name\")\n\n\t_ = viper.BindPFlag(\"grpc_address\", snapshotCmd.PersistentFlags().Lookup(\"grpc-address\"))\n\t_ = viper.BindPFlag(\"certificate_file\", snapshotCmd.PersistentFlags().Lookup(\"certificate-file\"))\n\t_ = viper.BindPFlag(\"common_name\", snapshotCmd.PersistentFlags().Lookup(\"common-name\"))\n}\n"
  },
  {
    "path": "cmd/start.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\t\"time\"\n\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/mosuka/cete/log\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"github.com/mosuka/cete/server\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar (\n\tstartCmd = &cobra.Command{\n\t\tUse:   \"start\",\n\t\tShort: \"Start the key value store server\",\n\t\tLong:  \"Start the key value store server\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tid = viper.GetString(\"id\")\n\t\t\traftAddress = viper.GetString(\"raft_address\")\n\t\t\tgrpcAddress = viper.GetString(\"grpc_address\")\n\t\t\thttpAddress = viper.GetString(\"http_address\")\n\t\t\tdataDirectory = viper.GetString(\"data_directory\")\n\t\t\tpeerGrpcAddress = viper.GetString(\"peer_grpc_address\")\n\n\t\t\tcertificateFile = viper.GetString(\"certificate_file\")\n\t\t\tkeyFile = viper.GetString(\"key_file\")\n\t\t\tcommonName = viper.GetString(\"common_name\")\n\n\t\t\tlogLevel = viper.GetString(\"log_level\")\n\t\t\tlogFile = viper.GetString(\"log_file\")\n\t\t\tlogMaxSize = viper.GetInt(\"log_max_size\")\n\t\t\tlogMaxBackups = viper.GetInt(\"log_max_backups\")\n\t\t\tlogMaxAge = viper.GetInt(\"log_max_age\")\n\t\t\tlogCompress = viper.GetBool(\"log_compress\")\n\n\t\t\tlogger := log.NewLogger(\n\t\t\t\tlogLevel,\n\t\t\t\tlogFile,\n\t\t\t\tlogMaxSize,\n\t\t\t\tlogMaxBackups,\n\t\t\t\tlogMaxAge,\n\t\t\t\tlogCompress,\n\t\t\t)\n\n\t\t\tbootstrap := peerGrpcAddress == \"\" || peerGrpcAddress == grpcAddress\n\n\t\t\traftServer, err := server.NewRaftServer(id, raftAddress, dataDirectory, bootstrap, logger)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tgrpcServer, err := server.NewGRPCServer(grpcAddress, raftServer, certificateFile, keyFile, commonName, logger)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tgrpcGateway, err := server.NewGRPCGateway(httpAddress, grpcAddress, certificateFile, keyFile, commonName, logger)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tquitCh := make(chan os.Signal, 1)\n\t\t\tsignal.Notify(quitCh, os.Kill, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)\n\n\t\t\tif err := raftServer.Start(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := grpcServer.Start(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tif err := grpcGateway.Start(); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// wait for detect leader if it's bootstrap\n\t\t\tif bootstrap {\n\t\t\t\ttimeout := 60 * time.Second\n\t\t\t\tif err := raftServer.WaitForDetectLeader(timeout); err != nil {\n\t\t\t\t\treturn err\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// create gRPC client for joining node\n\t\t\tvar joinGrpcAddress string\n\t\t\tif bootstrap {\n\t\t\t\tjoinGrpcAddress = grpcAddress\n\t\t\t} else {\n\t\t\t\tjoinGrpcAddress = peerGrpcAddress\n\t\t\t}\n\n\t\t\tc, err := client.NewGRPCClientWithContextTLS(joinGrpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = c.Close()\n\t\t\t}()\n\n\t\t\t// join this node to the existing cluster\n\t\t\tjoinRequest := &protobuf.JoinRequest{\n\t\t\t\tId: id,\n\t\t\t\tNode: &protobuf.Node{\n\t\t\t\t\tRaftAddress: raftAddress,\n\t\t\t\t\tMetadata: &protobuf.Metadata{\n\t\t\t\t\t\tGrpcAddress: grpcAddress,\n\t\t\t\t\t\tHttpAddress: httpAddress,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t\tif err = c.Join(joinRequest); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\t// wait for receiving signal\n\t\t\t<-quitCh\n\n\t\t\t_ = grpcGateway.Stop()\n\t\t\t_ = grpcServer.Stop()\n\t\t\t_ = raftServer.Stop()\n\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(startCmd)\n\n\tcobra.OnInitialize(func() {\n\t\tif configFile != \"\" {\n\t\t\tviper.SetConfigFile(configFile)\n\t\t} else {\n\t\t\thome, err := homedir.Dir()\n\t\t\tif err != nil {\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tviper.AddConfigPath(\"/etc\")\n\t\t\tviper.AddConfigPath(home)\n\t\t\tviper.SetConfigName(\"cete\")\n\n\t\t}\n\n\t\tviper.SetEnvPrefix(\"CETE\")\n\t\tviper.AutomaticEnv()\n\n\t\tif err := viper.ReadInConfig(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase viper.ConfigFileNotFoundError:\n\t\t\t\t// cete.yaml does not found in config search path\n\t\t\tdefault:\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t})\n\n\tstartCmd.PersistentFlags().StringVar(&configFile, \"config-file\", \"\", \"config file. if omitted, cete.yaml in /etc and home directory will be searched\")\n\tstartCmd.PersistentFlags().StringVar(&id, \"id\", \"node1\", \"node ID\")\n\tstartCmd.PersistentFlags().StringVar(&raftAddress, \"raft-address\", \":7000\", \"Raft server listen address\")\n\tstartCmd.PersistentFlags().StringVar(&grpcAddress, \"grpc-address\", \":9000\", \"gRPC server listen address\")\n\tstartCmd.PersistentFlags().StringVar(&httpAddress, \"http-address\", \":8000\", \"HTTP server listen address\")\n\tstartCmd.PersistentFlags().StringVar(&dataDirectory, \"data-directory\", \"/tmp/cete/data\", \"data directory which store the key-value store data and Raft logs\")\n\tstartCmd.PersistentFlags().StringVar(&peerGrpcAddress, \"peer-grpc-address\", \"\", \"listen address of the existing gRPC server in the joining cluster\")\n\tstartCmd.PersistentFlags().StringVar(&certificateFile, \"certificate-file\", \"\", \"path to the client server TLS certificate file\")\n\tstartCmd.PersistentFlags().StringVar(&keyFile, \"key-file\", \"\", \"path to the client server TLS key file\")\n\tstartCmd.PersistentFlags().StringVar(&commonName, \"common-name\", \"\", \"certificate common name\")\n\tstartCmd.PersistentFlags().StringVar(&logLevel, \"log-level\", \"INFO\", \"log level\")\n\tstartCmd.PersistentFlags().StringVar(&logFile, \"log-file\", os.Stderr.Name(), \"log file\")\n\tstartCmd.PersistentFlags().IntVar(&logMaxSize, \"log-max-size\", 500, \"max size of a log file in megabytes\")\n\tstartCmd.PersistentFlags().IntVar(&logMaxBackups, \"log-max-backups\", 3, \"max backup count of log files\")\n\tstartCmd.PersistentFlags().IntVar(&logMaxAge, \"log-max-age\", 30, \"max age of a log file in days\")\n\tstartCmd.PersistentFlags().BoolVar(&logCompress, \"log-compress\", false, \"compress a log file\")\n\n\t_ = viper.BindPFlag(\"id\", startCmd.PersistentFlags().Lookup(\"id\"))\n\t_ = viper.BindPFlag(\"raft_address\", startCmd.PersistentFlags().Lookup(\"raft-address\"))\n\t_ = viper.BindPFlag(\"grpc_address\", startCmd.PersistentFlags().Lookup(\"grpc-address\"))\n\t_ = viper.BindPFlag(\"http_address\", startCmd.PersistentFlags().Lookup(\"http-address\"))\n\t_ = viper.BindPFlag(\"data_directory\", startCmd.PersistentFlags().Lookup(\"data-directory\"))\n\t_ = viper.BindPFlag(\"peer_grpc_address\", startCmd.PersistentFlags().Lookup(\"peer-grpc-address\"))\n\t_ = viper.BindPFlag(\"certificate_file\", startCmd.PersistentFlags().Lookup(\"certificate-file\"))\n\t_ = viper.BindPFlag(\"key_file\", startCmd.PersistentFlags().Lookup(\"key-file\"))\n\t_ = viper.BindPFlag(\"common_name\", startCmd.PersistentFlags().Lookup(\"common-name\"))\n\t_ = viper.BindPFlag(\"log_level\", startCmd.PersistentFlags().Lookup(\"log-level\"))\n\t_ = viper.BindPFlag(\"log_max_size\", startCmd.PersistentFlags().Lookup(\"log-max-size\"))\n\t_ = viper.BindPFlag(\"log_max_backups\", startCmd.PersistentFlags().Lookup(\"log-max-backups\"))\n\t_ = viper.BindPFlag(\"log_max_age\", startCmd.PersistentFlags().Lookup(\"log-max-age\"))\n\t_ = viper.BindPFlag(\"log_compress\", startCmd.PersistentFlags().Lookup(\"log-compress\"))\n}\n"
  },
  {
    "path": "cmd/variables.go",
    "content": "package cmd\n\nvar (\n\tconfigFile      string\n\tid              string\n\traftAddress     string\n\tgrpcAddress     string\n\thttpAddress     string\n\tdataDirectory   string\n\tpeerGrpcAddress string\n\tcertificateFile string\n\tkeyFile         string\n\tcommonName      string\n\tlogLevel        string\n\tlogFile         string\n\tlogMaxSize      int\n\tlogMaxBackups   int\n\tlogMaxAge       int\n\tlogCompress     bool\n)\n"
  },
  {
    "path": "cmd/version.go",
    "content": "package cmd\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/mosuka/cete/version\"\n\t\"github.com/spf13/cobra\"\n)\n\nvar (\n\tversionCmd = &cobra.Command{\n\t\tUse:   \"version\",\n\t\tShort: \"Print the version number\",\n\t\tLong:  \"Print the version number\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tfmt.Printf(\"cete version: %s\\n\", version.Version)\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(versionCmd)\n}\n"
  },
  {
    "path": "cmd/watch.go",
    "content": "package cmd\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"os\"\n\t\"os/signal\"\n\t\"syscall\"\n\n\t\"github.com/golang/protobuf/ptypes/empty\"\n\t\"github.com/mitchellh/go-homedir\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/mosuka/cete/marshaler\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"github.com/spf13/cobra\"\n\t\"github.com/spf13/viper\"\n)\n\nvar (\n\twatchCmd = &cobra.Command{\n\t\tUse:   \"watch\",\n\t\tShort: \"Watch a node updates\",\n\t\tLong:  \"Watch a node updates\",\n\t\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\t\tgrpcAddress = viper.GetString(\"grpc_address\")\n\n\t\t\tcertificateFile = viper.GetString(\"certificate_file\")\n\t\t\tcommonName = viper.GetString(\"common_name\")\n\n\t\t\tc, err := client.NewGRPCClientWithContextTLS(grpcAddress, context.Background(), certificateFile, commonName)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer func() {\n\t\t\t\t_ = c.Close()\n\t\t\t}()\n\n\t\t\treq := &empty.Empty{}\n\t\t\twatchClient, err := c.Watch(req)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tgo func() {\n\t\t\t\tfor {\n\t\t\t\t\tresp, err := watchClient.Recv()\n\t\t\t\t\tif err == io.EOF {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\n\t\t\t\t\tswitch resp.Event.Type {\n\t\t\t\t\tcase protobuf.Event_Join:\n\t\t\t\t\t\teventReq := &protobuf.SetMetadataRequest{}\n\t\t\t\t\t\tif eventData, err := marshaler.MarshalAny(resp.Event.Data); err != nil {\n\t\t\t\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(\"%s, %v\", resp.Event.Type.String(), err))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif eventData == nil {\n\t\t\t\t\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(\"%s, nil\", resp.Event.Type.String()))\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\teventReq = eventData.(*protobuf.SetMetadataRequest)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfmt.Printf(\"%s, %v\\n\", resp.Event.Type.String(), eventReq)\n\t\t\t\t\tcase protobuf.Event_Leave:\n\t\t\t\t\t\teventReq := &protobuf.DeleteMetadataRequest{}\n\t\t\t\t\t\tif eventData, err := marshaler.MarshalAny(resp.Event.Data); err != nil {\n\t\t\t\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(\"%s, %v\", resp.Event.Type.String(), err))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif eventData == nil {\n\t\t\t\t\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(\"%s, nil\", resp.Event.Type.String()))\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\teventReq = eventData.(*protobuf.DeleteMetadataRequest)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfmt.Printf(\"%s, %v\\n\", resp.Event.Type.String(), eventReq)\n\t\t\t\t\tcase protobuf.Event_Set:\n\t\t\t\t\t\tputRequest := &protobuf.SetRequest{}\n\t\t\t\t\t\tif putRequestInstance, err := marshaler.MarshalAny(resp.Event.Data); err != nil {\n\t\t\t\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(\"%s, %v\", resp.Event.Type.String(), err))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif putRequestInstance == nil {\n\t\t\t\t\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(\"%s, nil\", resp.Event.Type.String()))\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tputRequest = putRequestInstance.(*protobuf.SetRequest)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfmt.Printf(\"%s, %v\\n\", resp.Event.Type.String(), putRequest)\n\t\t\t\t\tcase protobuf.Event_Delete:\n\t\t\t\t\t\tdeleteRequest := &protobuf.DeleteRequest{}\n\t\t\t\t\t\tif deleteRequestInstance, err := marshaler.MarshalAny(resp.Event.Data); err != nil {\n\t\t\t\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(\"%s, %v\", resp.Event.Type.String(), err))\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif deleteRequestInstance == nil {\n\t\t\t\t\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, fmt.Sprintf(\"%s, nil\", resp.Event.Type.String()))\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tdeleteRequest = deleteRequestInstance.(*protobuf.DeleteRequest)\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfmt.Printf(\"%s, %v\\n\", resp.Event.Type.String(), deleteRequest)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}()\n\n\t\t\tquitCh := make(chan os.Signal, 1)\n\t\t\tsignal.Notify(quitCh, os.Kill, os.Interrupt, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)\n\n\t\t\t<-quitCh\n\n\t\t\treturn nil\n\t\t},\n\t}\n)\n\nfunc init() {\n\trootCmd.AddCommand(watchCmd)\n\n\tcobra.OnInitialize(func() {\n\t\tif configFile != \"\" {\n\t\t\tviper.SetConfigFile(configFile)\n\t\t} else {\n\t\t\thome, err := homedir.Dir()\n\t\t\tif err != nil {\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\n\t\t\tviper.AddConfigPath(\"/etc\")\n\t\t\tviper.AddConfigPath(home)\n\t\t\tviper.SetConfigName(\"cete\")\n\n\t\t}\n\n\t\tviper.SetEnvPrefix(\"CETE\")\n\t\tviper.AutomaticEnv()\n\n\t\tif err := viper.ReadInConfig(); err != nil {\n\t\t\tswitch err.(type) {\n\t\t\tcase viper.ConfigFileNotFoundError:\n\t\t\t\t// cete.yaml does not found in config search path\n\t\t\tdefault:\n\t\t\t\t_, _ = fmt.Fprintln(os.Stderr, err)\n\t\t\t\tos.Exit(1)\n\t\t\t}\n\t\t}\n\t})\n\n\twatchCmd.PersistentFlags().StringVar(&configFile, \"config-file\", \"\", \"config file. if omitted, cete.yaml in /etc and home directory will be searched\")\n\twatchCmd.PersistentFlags().StringVar(&grpcAddress, \"grpc-address\", \":9000\", \"gRPC server listen address\")\n\twatchCmd.PersistentFlags().StringVar(&certificateFile, \"certificate-file\", \"\", \"path to the client server TLS certificate file\")\n\twatchCmd.PersistentFlags().StringVar(&commonName, \"common-name\", \"\", \"certificate common name\")\n\n\t_ = viper.BindPFlag(\"grpc_address\", watchCmd.PersistentFlags().Lookup(\"grpc-address\"))\n\t_ = viper.BindPFlag(\"certificate_file\", watchCmd.PersistentFlags().Lookup(\"certificate-file\"))\n\t_ = viper.BindPFlag(\"common_name\", watchCmd.PersistentFlags().Lookup(\"common-name\"))\n}\n"
  },
  {
    "path": "docker-entrypoint.sh",
    "content": "#!/bin/sh\n\nset -e\n\nexec \"$@\"\n"
  },
  {
    "path": "errors/errors.go",
    "content": "package errors\n\nimport \"errors\"\n\nvar (\n\tErrNotFoundLeader    = errors.New(\"does not found leader\")\n\tErrNodeAlreadyExists = errors.New(\"node already exists\")\n\tErrNodeNotReady      = errors.New(\"node not ready\")\n\tErrNotFound          = errors.New(\"not found\")\n\tErrTimeout           = errors.New(\"timeout\")\n)\n"
  },
  {
    "path": "etc/cete.yaml",
    "content": "id: \"node1\"\nraft_address: \":7000\"\ngrpc_address: \":9000\"\nhttp_address: \":8000\"\ndata_directory: \"/tmp/cete/node1/data\"\npeer_grpc_address: \"\"\n#certificate_file: \"./etc/cete-cert.pem\"\n#key_file: \"./etc/cete-key.pem\"\n#common_name: \"localhost\"\nlog_level: \"INFO\"\nlog_file: \"\"\n#log_max_size: 500\n#log_max_backups: 3\n#log_max_age: 30\n#log_compress: false\n"
  },
  {
    "path": "go.mod",
    "content": "module github.com/mosuka/cete\n\ngo 1.14\n\nrequire (\n\tgithub.com/BBVA/raft-badger v1.0.2\n\tgithub.com/dgraph-io/badger/v2 v2.0.3\n\tgithub.com/golang/protobuf v1.3.5\n\tgithub.com/grpc-ecosystem/go-grpc-middleware v1.2.0\n\tgithub.com/grpc-ecosystem/go-grpc-prometheus v1.2.0\n\tgithub.com/grpc-ecosystem/grpc-gateway v1.14.3\n\tgithub.com/hashicorp/raft v1.1.2\n\tgithub.com/mash/go-accesslog v1.1.0\n\tgithub.com/mitchellh/go-homedir v1.1.0\n\tgithub.com/natefinch/lumberjack v2.0.0+incompatible\n\tgithub.com/prometheus/client_golang v1.5.1\n\tgithub.com/prometheus/common v0.9.1\n\tgithub.com/spf13/cobra v0.0.7\n\tgithub.com/spf13/viper v1.4.0\n\tgo.uber.org/zap v1.14.1\n\tgoogle.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c\n\tgoogle.golang.org/grpc v1.28.0\n\tgopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect\n)\n"
  },
  {
    "path": "go.sum",
    "content": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ngithub.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=\ngithub.com/BBVA/raft-badger v1.0.2 h1:FGSzkfr2iyfEretWvU2v7y34KEorWH+XSKssnWRdrBg=\ngithub.com/BBVA/raft-badger v1.0.2/go.mod h1:zsjAa/3jFfMR+ZR+XCMGhVqr9Zz7fBqT8LOuGpPzzDw=\ngithub.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=\ngithub.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=\ngithub.com/DataDog/datadog-go v2.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=\ngithub.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=\ngithub.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=\ngithub.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=\ngithub.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=\ngithub.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=\ngithub.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=\ngithub.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=\ngithub.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=\ngithub.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878 h1:EFSB7Zo9Eg91v7MJPVsifUysc/wPdN+NOnVe6bWbdBM=\ngithub.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQhVx52RsWOnlkpikZr01T/yAVN2gn0861vByNg=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=\ngithub.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=\ngithub.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=\ngithub.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=\ngithub.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=\ngithub.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=\ngithub.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=\ngithub.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=\ngithub.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=\ngithub.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=\ngithub.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=\ngithub.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=\ngithub.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=\ngithub.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=\ngithub.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=\ngithub.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=\ngithub.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=\ngithub.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=\ngithub.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=\ngithub.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=\ngithub.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=\ngithub.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=\ngithub.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=\ngithub.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=\ngithub.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=\ngithub.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=\ngithub.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=\ngithub.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=\ngithub.com/dgraph-io/badger/v2 v2.0.3 h1:inzdf6VF/NZ+tJ8RwwYMjJMvsOALTHYdozn0qSl6XJI=\ngithub.com/dgraph-io/badger/v2 v2.0.3/go.mod h1:3KY8+bsP8wI0OEnQJAKpd4wIJW/Mm32yw2j/9FUVnIM=\ngithub.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3 h1:MQLRM35Pp0yAyBYksjbj1nZI/w6eyRY/mWoM1sFf4kU=\ngithub.com/dgraph-io/ristretto v0.0.2-0.20200115201040-8f368f2f2ab3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=\ngithub.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=\ngithub.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=\ngithub.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=\ngithub.com/dgryski/go-farm v0.0.0-20191112170834-c2139c5d712b h1:SeiGBzKrEtuDddnBABHkp4kq9sBGE9nuYmk6FPTg0zg=\ngithub.com/dgryski/go-farm v0.0.0-20191112170834-c2139c5d712b/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=\ngithub.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=\ngithub.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=\ngithub.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=\ngithub.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=\ngithub.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=\ngithub.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=\ngithub.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=\ngithub.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=\ngithub.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=\ngithub.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=\ngithub.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=\ngithub.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=\ngithub.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=\ngithub.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=\ngithub.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=\ngithub.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=\ngithub.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=\ngithub.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=\ngithub.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=\ngithub.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=\ngithub.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=\ngithub.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=\ngithub.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=\ngithub.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=\ngithub.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=\ngithub.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=\ngithub.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=\ngithub.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=\ngithub.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=\ngithub.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=\ngithub.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=\ngithub.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=\ngithub.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=\ngithub.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.2.0 h1:0IKlLyQ3Hs9nDaiK5cSHAGmcQEIC8l2Ts1u6x5Dfrqg=\ngithub.com/grpc-ecosystem/go-grpc-middleware v1.2.0/go.mod h1:mJzapYve32yjrKlk9GbyCZHuPgZsrbyIbyKhSzOpg6s=\ngithub.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=\ngithub.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=\ngithub.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=\ngithub.com/grpc-ecosystem/grpc-gateway v1.14.3 h1:OCJlWkOUoTnl0neNGlf4fUm3TmbEtguw7vR+nGtnDjY=\ngithub.com/grpc-ecosystem/grpc-gateway v1.14.3/go.mod h1:6CwZWGDSPRJidgKAtJVvND6soZe6fT7iteq8wDPdhb0=\ngithub.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=\ngithub.com/hashicorp/go-hclog v0.9.1 h1:9PZfAcVEvez4yhLH2TBU64/h/z4xlFI80cWXRrxuKuM=\ngithub.com/hashicorp/go-hclog v0.9.1/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=\ngithub.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=\ngithub.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=\ngithub.com/hashicorp/go-msgpack v0.5.5 h1:i9R9JSrqIz0QVLz3sz+i3YJdT7TTSLcfLLzJi9aZTuI=\ngithub.com/hashicorp/go-msgpack v0.5.5/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=\ngithub.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=\ngithub.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM=\ngithub.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=\ngithub.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=\ngithub.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=\ngithub.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=\ngithub.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=\ngithub.com/hashicorp/raft v1.1.1/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=\ngithub.com/hashicorp/raft v1.1.2 h1:oxEL5DDeurYxLd3UbcY/hccgSPhLLpiBZ1YxtWEq59c=\ngithub.com/hashicorp/raft v1.1.2/go.mod h1:vPAJM8Asw6u8LxC3eJCUZmRP/E4QmUGE1R7g7k8sG/8=\ngithub.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea h1:xykPFhrBAS2J0VBzVa5e80b5ZtYuNQtgXjN40qBZlD4=\ngithub.com/hashicorp/raft-boltdb v0.0.0-20171010151810-6e5ba93211ea/go.mod h1:pNv7Wc3ycL6F5oOWn+tPGo2gWD4a5X+yp/ntwdKLjRk=\ngithub.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=\ngithub.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=\ngithub.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=\ngithub.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=\ngithub.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=\ngithub.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=\ngithub.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=\ngithub.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=\ngithub.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=\ngithub.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=\ngithub.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=\ngithub.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=\ngithub.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=\ngithub.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=\ngithub.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=\ngithub.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=\ngithub.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=\ngithub.com/mash/go-accesslog v1.1.0 h1:y22583qP3s+SePBs6mv8ZTz5D1UffPrSg+WFEW2Rf/c=\ngithub.com/mash/go-accesslog v1.1.0/go.mod h1:DAbGQzio0KX16krP/3uouoTPxGbzcPjFAb948zazOgg=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=\ngithub.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=\ngithub.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=\ngithub.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=\ngithub.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=\ngithub.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=\ngithub.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=\ngithub.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=\ngithub.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=\ngithub.com/natefinch/lumberjack v2.0.0+incompatible h1:4QJd3OLAMgj7ph+yZTuX13Ld4UpgHp07nNdFX7mqFfM=\ngithub.com/natefinch/lumberjack v2.0.0+incompatible/go.mod h1:Wi9p2TTF5DG5oU+6YfsmYQpsTIOm0B1VNzQg9Mw6nPk=\ngithub.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=\ngithub.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=\ngithub.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY=\ngithub.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=\ngithub.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=\ngithub.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=\ngithub.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=\ngithub.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=\ngithub.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=\ngithub.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=\ngithub.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=\ngithub.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740=\ngithub.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=\ngithub.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=\ngithub.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=\ngithub.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA=\ngithub.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f05m9MGOsuEi1ATq9shN03HrxNkD/luQvxCv8=\ngithub.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=\ngithub.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=\ngithub.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=\ngithub.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=\ngithub.com/prometheus/common v0.0.0-20181126121408-4724e9255275 h1:PnBWHBf+6L0jOqq0gIVUe6Yk0/QMZ640k6NvkxcBf+8=\ngithub.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=\ngithub.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=\ngithub.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=\ngithub.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=\ngithub.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nLJdBg+pBmGgkJlSaKC2KaQmTCk1XDtE=\ngithub.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=\ngithub.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=\ngithub.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=\ngithub.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=\ngithub.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=\ngithub.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=\ngithub.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=\ngithub.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=\ngithub.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=\ngithub.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=\ngithub.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=\ngithub.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=\ngithub.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=\ngithub.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=\ngithub.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=\ngithub.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=\ngithub.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=\ngithub.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=\ngithub.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=\ngithub.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=\ngithub.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=\ngithub.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=\ngithub.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=\ngithub.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=\ngithub.com/spf13/cobra v0.0.7 h1:FfTH+vuMXOas8jmfb5/M7dzEYx7LpcLb7a0LPe34uOU=\ngithub.com/spf13/cobra v0.0.7/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=\ngithub.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=\ngithub.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=\ngithub.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=\ngithub.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=\ngithub.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=\ngithub.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=\ngithub.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=\ngithub.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=\ngithub.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=\ngithub.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=\ngithub.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=\ngithub.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=\ngithub.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=\ngithub.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=\ngithub.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=\ngithub.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=\ngithub.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=\ngithub.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=\ngithub.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=\ngithub.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=\ngo.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=\ngo.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=\ngo.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=\ngo.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=\ngo.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=\ngo.uber.org/multierr v1.5.0 h1:KCa4XfM8CWFCpxXRGok+Q0SS/0XBhMDbHHGABQLvD2A=\ngo.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=\ngo.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=\ngo.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=\ngo.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=\ngo.uber.org/zap v1.14.1 h1:nYDKopTbvAPq/NrUVZwT15y2lpROBiLLyoRTbXOYWOo=\ngo.uber.org/zap v1.14.1/go.mod h1:Mb2vm2krFEG5DV0W9qcHBYFtp/Wku1cvYaqPsS/WYfc=\ngolang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=\ngolang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=\ngolang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=\ngolang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=\ngolang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=\ngolang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=\ngolang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs=\ngolang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=\ngolang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=\ngolang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0=\ngolang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=\ngolang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=\ngolang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=\ngolang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=\ngolang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/net v0.0.0-20191002035440-2ec189313ef0 h1:2mqDk8w/o6UmeUCu5Qiq2y7iMf6anbx+YA8d1JFoFrs=\ngolang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=\ngolang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=\ngolang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522 h1:Ve1ORMCxvRmSXBwJK+t3Oy+V2vRW2OetUQBq4rJIkZE=\ngolang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=\ngolang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5 h1:sM3evRHxE/1RuMe1FYAL3j7C7fUfIjkbE+NiDAYUF8U=\ngolang.org/x/sys v0.0.0-20190523142557-0e01d883c5c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20190626221950-04f50cda93cb h1:fgwFCsaw9buMuxNd6+DQfAuSFqbNiQZpcgJQAgJsK6k=\ngolang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU=\ngolang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=\ngolang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=\ngolang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=\ngolang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=\ngolang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=\ngolang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=\ngolang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=\ngolang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=\ngolang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=\ngolang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5 h1:hKsoRgsbwY1NafxrwTs+k64bikrLBkAgPir1TNCj3Zs=\ngolang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=\ngolang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=\ngolang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=\ngoogle.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=\ngoogle.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=\ngoogle.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=\ngoogle.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=\ngoogle.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c h1:hrpEMCZ2O7DR5gC1n2AJGVhrwiEjOi35+jxtIuZpTMo=\ngoogle.golang.org/genproto v0.0.0-20190927181202-20e1ac93f88c/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=\ngoogle.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=\ngoogle.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=\ngoogle.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=\ngoogle.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=\ngoogle.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=\ngoogle.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=\ngoogle.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=\ngopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=\ngopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=\ngopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=\ngopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=\ngopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=\ngopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=\ngopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=\ngopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=\ngopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=\ngopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\ngopkg.in/yaml.v2 v2.2.5 h1:ymVxjfMaHvXD8RqPRmzHHsB3VvucivSkIAvJFDI5O3c=\ngopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=\nhonnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=\nhonnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=\nhonnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=\n"
  },
  {
    "path": "log/log.go",
    "content": "package log\n\nimport (\n\t\"os\"\n\t\"strconv\"\n\n\t\"github.com/mash/go-accesslog\"\n\t\"github.com/natefinch/lumberjack\"\n\t\"go.uber.org/zap\"\n\t\"go.uber.org/zap/zapcore\"\n)\n\nfunc NewLogger(logLevel string, logFilename string, logMaxSize int, logMaxBackups int, logMaxAge int, logCompress bool) *zap.Logger {\n\tvar ll zapcore.Level\n\tswitch logLevel {\n\tcase \"DEBUG\":\n\t\tll = zap.DebugLevel\n\tcase \"INFO\":\n\t\tll = zap.InfoLevel\n\tcase \"WARN\", \"WARNING\":\n\t\tll = zap.WarnLevel\n\tcase \"ERR\", \"ERROR\":\n\t\tll = zap.WarnLevel\n\tcase \"DPANIC\":\n\t\tll = zap.DPanicLevel\n\tcase \"PANIC\":\n\t\tll = zap.PanicLevel\n\tcase \"FATAL\":\n\t\tll = zap.FatalLevel\n\t}\n\n\tvar ws zapcore.WriteSyncer\n\tswitch logFilename {\n\tcase \"\", os.Stderr.Name():\n\t\tws = zapcore.AddSync(os.Stderr)\n\tcase os.Stdout.Name():\n\t\tws = zapcore.AddSync(os.Stdout)\n\tdefault:\n\t\tws = zapcore.AddSync(\n\t\t\t&lumberjack.Logger{\n\t\t\t\tFilename:   logFilename,\n\t\t\t\tMaxSize:    logMaxSize, // megabytes\n\t\t\t\tMaxBackups: logMaxBackups,\n\t\t\t\tMaxAge:     logMaxAge, // days\n\t\t\t\tCompress:   logCompress,\n\t\t\t},\n\t\t)\n\t}\n\n\tec := zap.NewProductionEncoderConfig()\n\tec.TimeKey = \"_timestamp_\"\n\tec.LevelKey = \"_level_\"\n\tec.NameKey = \"_name_\"\n\tec.CallerKey = \"_caller_\"\n\tec.MessageKey = \"_message_\"\n\tec.StacktraceKey = \"_stacktrace_\"\n\tec.EncodeTime = zapcore.ISO8601TimeEncoder\n\tec.EncodeCaller = zapcore.ShortCallerEncoder\n\n\tlogger := zap.New(\n\t\tzapcore.NewCore(\n\t\t\tzapcore.NewJSONEncoder(ec),\n\t\t\tws,\n\t\t\tll,\n\t\t),\n\t\tzap.AddCaller(),\n\t\t//zap.AddStacktrace(ll),\n\t).Named(\"cete\")\n\n\treturn logger\n}\n\ntype HTTPLogger struct {\n\tLogger *zap.Logger\n}\n\nfunc (l HTTPLogger) Log(record accesslog.LogRecord) {\n\t// Output log that formatted Apache combined.\n\tsize := \"-\"\n\tif record.Size > 0 {\n\t\tsize = strconv.FormatInt(record.Size, 10)\n\t}\n\n\treferer := \"-\"\n\tif record.RequestHeader.Get(\"Referer\") != \"\" {\n\t\treferer = record.RequestHeader.Get(\"Referer\")\n\t}\n\n\tuserAgent := \"-\"\n\tif record.RequestHeader.Get(\"User-Agent\") != \"\" {\n\t\tuserAgent = record.RequestHeader.Get(\"User-Agent\")\n\t}\n\n\tl.Logger.Info(\n\t\t\"\",\n\t\tzap.String(\"ip\", record.Ip),\n\t\tzap.String(\"username\", record.Username),\n\t\tzap.String(\"time\", record.Time.Format(\"02/Jan/2006 03:04:05 +0000\")),\n\t\tzap.String(\"method\", record.Method),\n\t\tzap.String(\"uri\", record.Uri),\n\t\tzap.String(\"protocol\", record.Protocol),\n\t\tzap.Int(\"status\", record.Status),\n\t\tzap.String(\"size\", size),\n\t\tzap.String(\"referer\", referer),\n\t\tzap.String(\"user_agent\", userAgent),\n\t)\n}\n"
  },
  {
    "path": "main.go",
    "content": "package main\n\nimport (\n\t\"os\"\n\n\t\"github.com/mosuka/cete/cmd\"\n)\n\nfunc main() {\n\tif err := cmd.Execute(); err != nil {\n\t\tos.Exit(1)\n\t}\n\n\tos.Exit(0)\n}\n"
  },
  {
    "path": "marshaler/marshaler.go",
    "content": "package marshaler\n\nimport (\n\t\"encoding/json\"\n\t\"io\"\n\t\"io/ioutil\"\n\n\t\"github.com/grpc-ecosystem/grpc-gateway/runtime\"\n\t\"github.com/mosuka/cete/protobuf\"\n)\n\nvar (\n\tDefaultContentType = \"application/json\"\n)\n\ntype CeteMarshaler struct{}\n\nfunc (*CeteMarshaler) ContentType() string {\n\treturn DefaultContentType\n}\n\nfunc (j *CeteMarshaler) Marshal(v interface{}) ([]byte, error) {\n\tswitch v.(type) {\n\tcase *protobuf.GetResponse:\n\t\tvalue := v.(*protobuf.GetResponse).Value\n\t\treturn value, nil\n\tcase *protobuf.MetricsResponse:\n\t\tvalue := v.(*protobuf.MetricsResponse).Metrics\n\t\treturn value, nil\n\tdefault:\n\t\treturn json.Marshal(v)\n\t}\n}\n\nfunc (j *CeteMarshaler) Unmarshal(data []byte, v interface{}) error {\n\treturn json.Unmarshal(data, v)\n}\n\nfunc (j *CeteMarshaler) NewDecoder(r io.Reader) runtime.Decoder {\n\treturn runtime.DecoderFunc(\n\t\tfunc(v interface{}) error {\n\t\t\tbuffer, err := ioutil.ReadAll(r)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tswitch v.(type) {\n\t\t\tcase *protobuf.SetRequest:\n\t\t\t\tv.(*protobuf.SetRequest).Value = buffer\n\t\t\t\treturn nil\n\t\t\tdefault:\n\t\t\t\treturn json.Unmarshal(buffer, v)\n\t\t\t}\n\t\t},\n\t)\n}\n\nfunc (j *CeteMarshaler) NewEncoder(w io.Writer) runtime.Encoder {\n\treturn json.NewEncoder(w)\n}\n\nfunc (j *CeteMarshaler) Delimiter() []byte {\n\treturn []byte(\"\\n\")\n}\n"
  },
  {
    "path": "marshaler/util.go",
    "content": "package marshaler\n\nimport (\n\t\"encoding/json\"\n\t\"reflect\"\n\n\t\"github.com/golang/protobuf/ptypes/any\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"github.com/mosuka/cete/registry\"\n)\n\nfunc init() {\n\tregistry.RegisterType(\"protobuf.LivenessCheckResponse\", reflect.TypeOf(protobuf.LivenessCheckResponse{}))\n\tregistry.RegisterType(\"protobuf.ReadinessCheckResponse\", reflect.TypeOf(protobuf.ReadinessCheckResponse{}))\n\tregistry.RegisterType(\"protobuf.Metadata\", reflect.TypeOf(protobuf.Metadata{}))\n\tregistry.RegisterType(\"protobuf.Node\", reflect.TypeOf(protobuf.Node{}))\n\tregistry.RegisterType(\"protobuf.Cluster\", reflect.TypeOf(protobuf.Cluster{}))\n\tregistry.RegisterType(\"protobuf.JoinRequest\", reflect.TypeOf(protobuf.JoinRequest{}))\n\tregistry.RegisterType(\"protobuf.LeaveRequest\", reflect.TypeOf(protobuf.LeaveRequest{}))\n\tregistry.RegisterType(\"protobuf.NodeResponse\", reflect.TypeOf(protobuf.NodeResponse{}))\n\tregistry.RegisterType(\"protobuf.ClusterResponse\", reflect.TypeOf(protobuf.ClusterResponse{}))\n\tregistry.RegisterType(\"protobuf.GetRequest\", reflect.TypeOf(protobuf.GetRequest{}))\n\tregistry.RegisterType(\"protobuf.GetResponse\", reflect.TypeOf(protobuf.GetResponse{}))\n\tregistry.RegisterType(\"protobuf.SetRequest\", reflect.TypeOf(protobuf.SetRequest{}))\n\tregistry.RegisterType(\"protobuf.DeleteRequest\", reflect.TypeOf(protobuf.DeleteRequest{}))\n\tregistry.RegisterType(\"protobuf.SetMetadataRequest\", reflect.TypeOf(protobuf.SetMetadataRequest{}))\n\tregistry.RegisterType(\"protobuf.DeleteMetadataRequest\", reflect.TypeOf(protobuf.DeleteMetadataRequest{}))\n\tregistry.RegisterType(\"protobuf.Event\", reflect.TypeOf(protobuf.Event{}))\n\tregistry.RegisterType(\"protobuf.WatchResponse\", reflect.TypeOf(protobuf.WatchResponse{}))\n\tregistry.RegisterType(\"protobuf.MetricsResponse\", reflect.TypeOf(protobuf.MetricsResponse{}))\n\tregistry.RegisterType(\"protobuf.KeyValuePair\", reflect.TypeOf(protobuf.KeyValuePair{}))\n\tregistry.RegisterType(\"map[string]interface {}\", reflect.TypeOf((map[string]interface{})(nil)))\n}\n\nfunc MarshalAny(message *any.Any) (interface{}, error) {\n\tif message == nil {\n\t\treturn nil, nil\n\t}\n\n\ttypeUrl := message.TypeUrl\n\tvalue := message.Value\n\n\tinstance := registry.TypeInstanceByName(typeUrl)\n\n\tif err := json.Unmarshal(value, instance); err != nil {\n\t\treturn nil, err\n\t} else {\n\t\treturn instance, nil\n\t}\n\n}\n\nfunc UnmarshalAny(instance interface{}, message *any.Any) error {\n\tif instance == nil {\n\t\treturn nil\n\t}\n\n\tvalue, err := json.Marshal(instance)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tmessage.TypeUrl = registry.TypeNameByInstance(instance)\n\tmessage.Value = value\n\n\treturn nil\n}\n"
  },
  {
    "path": "marshaler/util_test.go",
    "content": "package marshaler\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n\n\t\"github.com/golang/protobuf/ptypes/any\"\n\t\"github.com/mosuka/cete/protobuf\"\n)\n\nfunc TestMarshalAny(t *testing.T) {\n\t// test map[string]interface{}\n\tdata := map[string]interface{}{\"a\": 1, \"b\": 2, \"c\": 3}\n\n\tmapAny := &any.Any{}\n\terr := UnmarshalAny(data, mapAny)\n\tif err != nil {\n\t\tt.Errorf(\"%v\", err)\n\t}\n\n\texpectedType := \"map[string]interface {}\"\n\tactualType := mapAny.TypeUrl\n\tif expectedType != actualType {\n\t\tt.Errorf(\"expected content to see %s, saw %s\", expectedType, actualType)\n\t}\n\n\texpectedValue := []byte(`{\"a\":1,\"b\":2,\"c\":3}`)\n\tactualValue := mapAny.Value\n\tif !bytes.Equal(expectedValue, actualValue) {\n\t\tt.Errorf(\"expected content to see %v, saw %v\", expectedValue, actualValue)\n\t}\n\n\t// test kvs.Node\n\tnode := &protobuf.Node{\n\t\tRaftAddress: \":7000\",\n\t\tState:       \"Leader\",\n\t\tMetadata: &protobuf.Metadata{\n\t\t\tGrpcAddress: \":9000\",\n\t\t\tHttpAddress: \":8000\",\n\t\t},\n\t}\n\n\tnodeAny := &any.Any{}\n\terr = UnmarshalAny(node, nodeAny)\n\tif err != nil {\n\t\tt.Errorf(\"%v\", err)\n\t}\n\n\texpectedType = \"protobuf.Node\"\n\tactualType = nodeAny.TypeUrl\n\tif expectedType != actualType {\n\t\tt.Errorf(\"expected content to see %s, saw %s\", expectedType, actualType)\n\t}\n\n\texpectedValue = []byte(`{\"raft_address\":\":7000\",\"metadata\":{\"grpc_address\":\":9000\",\"http_address\":\":8000\"},\"state\":\"Leader\"}`)\n\tactualValue = nodeAny.Value\n\tif !bytes.Equal(expectedValue, actualValue) {\n\t\tt.Errorf(\"expected content to see %v, saw %v\", expectedValue, actualValue)\n\t}\n}\n\nfunc TestUnmarshalAny(t *testing.T) {\n\t// test map[string]interface{}\n\tdataAny := &any.Any{\n\t\tTypeUrl: \"map[string]interface {}\",\n\t\tValue:   []byte(`{\"a\":1,\"b\":2,\"c\":3}`),\n\t}\n\n\tdata, err := MarshalAny(dataAny)\n\tif err != nil {\n\t\tt.Errorf(\"%v\", err)\n\t}\n\tdataMap := *data.(*map[string]interface{})\n\n\tif dataMap[\"a\"] != float64(1) {\n\t\tt.Errorf(\"expected content to see %v, saw %v\", 1, dataMap[\"a\"])\n\t}\n\tif dataMap[\"b\"] != float64(2) {\n\t\tt.Errorf(\"expected content to see %v, saw %v\", 2, dataMap[\"b\"])\n\t}\n\tif dataMap[\"c\"] != float64(3) {\n\t\tt.Errorf(\"expected content to see %v, saw %v\", 3, dataMap[\"c\"])\n\t}\n\n\t// raft.Node\n\tdataAny = &any.Any{\n\t\tTypeUrl: \"protobuf.Node\",\n\t\tValue:   []byte(`{\"raft_address\":\":7000\",\"metadata\":{\"grpc_address\":\":9000\",\"http_address\":\":8000\"},\"state\":\"Leader\"}`),\n\t}\n\n\tdata, err = MarshalAny(dataAny)\n\tif err != nil {\n\t\tt.Errorf(\"%v\", err)\n\t}\n\tnode := data.(*protobuf.Node)\n\n\tif node.RaftAddress != \":7000\" {\n\t\tt.Errorf(\"expected content to see %v, saw %v\", \":7000\", node.RaftAddress)\n\t}\n\tif node.Metadata.GrpcAddress != \":9000\" {\n\t\tt.Errorf(\"expected content to see %v, saw %v\", \":9000\", node.Metadata.GrpcAddress)\n\t}\n\tif node.Metadata.HttpAddress != \":8000\" {\n\t\tt.Errorf(\"expected content to see %v, saw %v\", \":8000\", node.Metadata.HttpAddress)\n\t}\n\tif node.State != \"Leader\" {\n\t\tt.Errorf(\"expected content to see %v, saw %v\", \"Leader\", node.State)\n\t}\n}\n"
  },
  {
    "path": "metric/metric.go",
    "content": "package metric\n\nimport (\n\tgrpcprometheus \"github.com/grpc-ecosystem/go-grpc-prometheus\"\n\t\"github.com/prometheus/client_golang/prometheus\"\n)\n\nvar (\n\t// Create a metrics registry.\n\tRegistry = prometheus.NewRegistry()\n\n\t// Create some standard server metrics.\n\tGrpcMetrics = grpcprometheus.NewServerMetrics(\n\t\tfunc(o *prometheus.CounterOpts) {\n\t\t\to.Namespace = \"cete\"\n\t\t},\n\t)\n\n\t// Raft node state metric\n\tRaftStateMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"state\",\n\t\tHelp:      \"Node state. 0:Follower, 1:Candidate, 2:Leader, 3:Shutdown\",\n\t}, []string{\"id\"})\n\n\tRaftTermMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"term\",\n\t\tHelp:      \"Term.\",\n\t}, []string{\"id\"})\n\n\tRaftLastLogIndexMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"last_log_index\",\n\t\tHelp:      \"Last log index.\",\n\t}, []string{\"id\"})\n\n\tRaftLastLogTermMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"last_log_term\",\n\t\tHelp:      \"Last log term.\",\n\t}, []string{\"id\"})\n\n\tRaftCommitIndexMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"commit_index\",\n\t\tHelp:      \"Commit index.\",\n\t}, []string{\"id\"})\n\n\tRaftAppliedIndexMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"applied_index\",\n\t\tHelp:      \"Applied index.\",\n\t}, []string{\"id\"})\n\n\tRaftFsmPendingMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"fsm_pending\",\n\t\tHelp:      \"FSM pending.\",\n\t}, []string{\"id\"})\n\n\tRaftLastSnapshotIndexMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"last_snapshot_index\",\n\t\tHelp:      \"Last snapshot index.\",\n\t}, []string{\"id\"})\n\n\tRaftLastSnapshotTermMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"last_snapshot_term\",\n\t\tHelp:      \"Last snapshot term.\",\n\t}, []string{\"id\"})\n\n\tRaftLatestConfigurationIndexMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"latest_configuration_index\",\n\t\tHelp:      \"Latest configuration index.\",\n\t}, []string{\"id\"})\n\n\tRaftNumPeersMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"num_peers\",\n\t\tHelp:      \"Number of peers.\",\n\t}, []string{\"id\"})\n\n\tRaftLastContactMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"last_copntact\",\n\t\tHelp:      \"Last contact.\",\n\t}, []string{\"id\"})\n\n\tRaftNumNodesMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"raft\",\n\t\tName:      \"num_nodes\",\n\t\tHelp:      \"Number of nodes.\",\n\t}, []string{\"id\"})\n\n\tKvsNumReadsMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"num_reads\",\n\t\tHelp:      \"Number of reads.\",\n\t}, []string{\"id\"})\n\n\tKvsNumWritesMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"num_writes\",\n\t\tHelp:      \"Number of writes.\",\n\t}, []string{\"id\"})\n\n\tKvsNumBytesReadMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"num_bytes_read\",\n\t\tHelp:      \"Number of bytes read.\",\n\t}, []string{\"id\"})\n\n\tKvsNumBytesWrittenMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"num_bytes_written\",\n\t\tHelp:      \"Number of bytes written.\",\n\t}, []string{\"id\"})\n\n\tKvsNumLSMGetsMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"num_lsm_gets\",\n\t\tHelp:      \"Number of LSM gets.\",\n\t}, []string{\"id\"})\n\n\tKvsNumLSMBloomHitsMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"num_lsm_bloom_Hits\",\n\t\tHelp:      \"Number of LSM bloom hits.\",\n\t}, []string{\"id\"})\n\n\tKvsNumGetsMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"num_gets\",\n\t\tHelp:      \"Number of gets.\",\n\t}, []string{\"id\"})\n\n\tKvsNumPutsMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"num_puts\",\n\t\tHelp:      \"Number of puts.\",\n\t}, []string{\"id\"})\n\n\tKvsNumBlockedPutsMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"num_blocked_puts\",\n\t\tHelp:      \"Number of blocked puts.\",\n\t}, []string{\"id\"})\n\n\tKvsNumMemtablesGetsMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"num_memtables_gets\",\n\t\tHelp:      \"Number of memtables gets.\",\n\t}, []string{\"id\"})\n\n\tKvsLSMSizeMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"lsm_size\",\n\t\tHelp:      \"LSM size.\",\n\t}, []string{\"id\", \"path\"})\n\n\tKvsVlogSizeMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"vlog_size\",\n\t\tHelp:      \"Vlog size.\",\n\t}, []string{\"id\", \"path\"})\n\n\tKvsPendingWritesMetric = prometheus.NewGaugeVec(prometheus.GaugeOpts{\n\t\tNamespace: \"cete\",\n\t\tSubsystem: \"kvs\",\n\t\tName:      \"pending_writes\",\n\t\tHelp:      \"Pending writes.\",\n\t}, []string{\"id\", \"path\"})\n)\n\nfunc init() {\n\t// Register standard server metrics and customized metrics to registry.\n\tRegistry.MustRegister(\n\t\tGrpcMetrics,\n\t\tRaftStateMetric,\n\t\tRaftTermMetric,\n\t\tRaftLastLogIndexMetric,\n\t\tRaftLastLogTermMetric,\n\t\tRaftCommitIndexMetric,\n\t\tRaftAppliedIndexMetric,\n\t\tRaftFsmPendingMetric,\n\t\tRaftLastSnapshotIndexMetric,\n\t\tRaftLastSnapshotTermMetric,\n\t\tRaftLatestConfigurationIndexMetric,\n\t\tRaftNumPeersMetric,\n\t\tRaftLastContactMetric,\n\t\tRaftNumNodesMetric,\n\t\tKvsNumReadsMetric,\n\t\tKvsNumWritesMetric,\n\t\tKvsNumBytesReadMetric,\n\t\tKvsNumBytesWrittenMetric,\n\t\tKvsNumLSMGetsMetric,\n\t\tKvsNumLSMBloomHitsMetric,\n\t\tKvsNumGetsMetric,\n\t\tKvsNumPutsMetric,\n\t\tKvsNumBlockedPutsMetric,\n\t\tKvsNumMemtablesGetsMetric,\n\t\tKvsLSMSizeMetric,\n\t\tKvsVlogSizeMetric,\n\t\tKvsPendingWritesMetric,\n\t)\n\tGrpcMetrics.EnableHandlingTimeHistogram(\n\t\tfunc(o *prometheus.HistogramOpts) {\n\t\t\to.Namespace = \"cete\"\n\t\t},\n\t)\n}\n"
  },
  {
    "path": "protobuf/kvs.pb.go",
    "content": "// Code generated by protoc-gen-go. DO NOT EDIT.\n// source: protobuf/kvs.proto\n\npackage protobuf\n\nimport (\n\tcontext \"context\"\n\tfmt \"fmt\"\n\tproto \"github.com/golang/protobuf/proto\"\n\tany \"github.com/golang/protobuf/ptypes/any\"\n\tempty \"github.com/golang/protobuf/ptypes/empty\"\n\t_ \"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger/options\"\n\t_ \"google.golang.org/genproto/googleapis/api/annotations\"\n\tgrpc \"google.golang.org/grpc\"\n\tcodes \"google.golang.org/grpc/codes\"\n\tstatus \"google.golang.org/grpc/status\"\n\tmath \"math\"\n)\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ = proto.Marshal\nvar _ = fmt.Errorf\nvar _ = math.Inf\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the proto package it is being compiled against.\n// A compilation error at this line likely means your copy of the\n// proto package needs to be updated.\nconst _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package\n\ntype Event_Type int32\n\nconst (\n\tEvent_Unknown Event_Type = 0\n\tEvent_Join    Event_Type = 1\n\tEvent_Leave   Event_Type = 2\n\tEvent_Set     Event_Type = 3\n\tEvent_Delete  Event_Type = 4\n)\n\nvar Event_Type_name = map[int32]string{\n\t0: \"Unknown\",\n\t1: \"Join\",\n\t2: \"Leave\",\n\t3: \"Set\",\n\t4: \"Delete\",\n}\n\nvar Event_Type_value = map[string]int32{\n\t\"Unknown\": 0,\n\t\"Join\":    1,\n\t\"Leave\":   2,\n\t\"Set\":     3,\n\t\"Delete\":  4,\n}\n\nfunc (x Event_Type) String() string {\n\treturn proto.EnumName(Event_Type_name, int32(x))\n}\n\nfunc (Event_Type) EnumDescriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{17, 0}\n}\n\ntype LivenessCheckResponse struct {\n\tAlive                bool     `protobuf:\"varint,1,opt,name=alive,proto3\" json:\"alive,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *LivenessCheckResponse) Reset()         { *m = LivenessCheckResponse{} }\nfunc (m *LivenessCheckResponse) String() string { return proto.CompactTextString(m) }\nfunc (*LivenessCheckResponse) ProtoMessage()    {}\nfunc (*LivenessCheckResponse) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{0}\n}\n\nfunc (m *LivenessCheckResponse) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_LivenessCheckResponse.Unmarshal(m, b)\n}\nfunc (m *LivenessCheckResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_LivenessCheckResponse.Marshal(b, m, deterministic)\n}\nfunc (m *LivenessCheckResponse) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_LivenessCheckResponse.Merge(m, src)\n}\nfunc (m *LivenessCheckResponse) XXX_Size() int {\n\treturn xxx_messageInfo_LivenessCheckResponse.Size(m)\n}\nfunc (m *LivenessCheckResponse) XXX_DiscardUnknown() {\n\txxx_messageInfo_LivenessCheckResponse.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_LivenessCheckResponse proto.InternalMessageInfo\n\nfunc (m *LivenessCheckResponse) GetAlive() bool {\n\tif m != nil {\n\t\treturn m.Alive\n\t}\n\treturn false\n}\n\ntype ReadinessCheckResponse struct {\n\tReady                bool     `protobuf:\"varint,1,opt,name=ready,proto3\" json:\"ready,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *ReadinessCheckResponse) Reset()         { *m = ReadinessCheckResponse{} }\nfunc (m *ReadinessCheckResponse) String() string { return proto.CompactTextString(m) }\nfunc (*ReadinessCheckResponse) ProtoMessage()    {}\nfunc (*ReadinessCheckResponse) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{1}\n}\n\nfunc (m *ReadinessCheckResponse) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_ReadinessCheckResponse.Unmarshal(m, b)\n}\nfunc (m *ReadinessCheckResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_ReadinessCheckResponse.Marshal(b, m, deterministic)\n}\nfunc (m *ReadinessCheckResponse) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_ReadinessCheckResponse.Merge(m, src)\n}\nfunc (m *ReadinessCheckResponse) XXX_Size() int {\n\treturn xxx_messageInfo_ReadinessCheckResponse.Size(m)\n}\nfunc (m *ReadinessCheckResponse) XXX_DiscardUnknown() {\n\txxx_messageInfo_ReadinessCheckResponse.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_ReadinessCheckResponse proto.InternalMessageInfo\n\nfunc (m *ReadinessCheckResponse) GetReady() bool {\n\tif m != nil {\n\t\treturn m.Ready\n\t}\n\treturn false\n}\n\ntype Metadata struct {\n\tGrpcAddress          string   `protobuf:\"bytes,1,opt,name=grpc_address,json=grpcAddress,proto3\" json:\"grpc_address,omitempty\"`\n\tHttpAddress          string   `protobuf:\"bytes,2,opt,name=http_address,json=httpAddress,proto3\" json:\"http_address,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *Metadata) Reset()         { *m = Metadata{} }\nfunc (m *Metadata) String() string { return proto.CompactTextString(m) }\nfunc (*Metadata) ProtoMessage()    {}\nfunc (*Metadata) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{2}\n}\n\nfunc (m *Metadata) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_Metadata.Unmarshal(m, b)\n}\nfunc (m *Metadata) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_Metadata.Marshal(b, m, deterministic)\n}\nfunc (m *Metadata) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_Metadata.Merge(m, src)\n}\nfunc (m *Metadata) XXX_Size() int {\n\treturn xxx_messageInfo_Metadata.Size(m)\n}\nfunc (m *Metadata) XXX_DiscardUnknown() {\n\txxx_messageInfo_Metadata.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_Metadata proto.InternalMessageInfo\n\nfunc (m *Metadata) GetGrpcAddress() string {\n\tif m != nil {\n\t\treturn m.GrpcAddress\n\t}\n\treturn \"\"\n}\n\nfunc (m *Metadata) GetHttpAddress() string {\n\tif m != nil {\n\t\treturn m.HttpAddress\n\t}\n\treturn \"\"\n}\n\ntype Node struct {\n\tRaftAddress          string    `protobuf:\"bytes,1,opt,name=raft_address,json=raftAddress,proto3\" json:\"raft_address,omitempty\"`\n\tMetadata             *Metadata `protobuf:\"bytes,2,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tState                string    `protobuf:\"bytes,3,opt,name=state,proto3\" json:\"state,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{}  `json:\"-\"`\n\tXXX_unrecognized     []byte    `json:\"-\"`\n\tXXX_sizecache        int32     `json:\"-\"`\n}\n\nfunc (m *Node) Reset()         { *m = Node{} }\nfunc (m *Node) String() string { return proto.CompactTextString(m) }\nfunc (*Node) ProtoMessage()    {}\nfunc (*Node) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{3}\n}\n\nfunc (m *Node) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_Node.Unmarshal(m, b)\n}\nfunc (m *Node) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_Node.Marshal(b, m, deterministic)\n}\nfunc (m *Node) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_Node.Merge(m, src)\n}\nfunc (m *Node) XXX_Size() int {\n\treturn xxx_messageInfo_Node.Size(m)\n}\nfunc (m *Node) XXX_DiscardUnknown() {\n\txxx_messageInfo_Node.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_Node proto.InternalMessageInfo\n\nfunc (m *Node) GetRaftAddress() string {\n\tif m != nil {\n\t\treturn m.RaftAddress\n\t}\n\treturn \"\"\n}\n\nfunc (m *Node) GetMetadata() *Metadata {\n\tif m != nil {\n\t\treturn m.Metadata\n\t}\n\treturn nil\n}\n\nfunc (m *Node) GetState() string {\n\tif m != nil {\n\t\treturn m.State\n\t}\n\treturn \"\"\n}\n\ntype Cluster struct {\n\tNodes                map[string]*Node `protobuf:\"bytes,1,rep,name=nodes,proto3\" json:\"nodes,omitempty\" protobuf_key:\"bytes,1,opt,name=key,proto3\" protobuf_val:\"bytes,2,opt,name=value,proto3\"`\n\tLeader               string           `protobuf:\"bytes,2,opt,name=leader,proto3\" json:\"leader,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{}         `json:\"-\"`\n\tXXX_unrecognized     []byte           `json:\"-\"`\n\tXXX_sizecache        int32            `json:\"-\"`\n}\n\nfunc (m *Cluster) Reset()         { *m = Cluster{} }\nfunc (m *Cluster) String() string { return proto.CompactTextString(m) }\nfunc (*Cluster) ProtoMessage()    {}\nfunc (*Cluster) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{4}\n}\n\nfunc (m *Cluster) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_Cluster.Unmarshal(m, b)\n}\nfunc (m *Cluster) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_Cluster.Marshal(b, m, deterministic)\n}\nfunc (m *Cluster) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_Cluster.Merge(m, src)\n}\nfunc (m *Cluster) XXX_Size() int {\n\treturn xxx_messageInfo_Cluster.Size(m)\n}\nfunc (m *Cluster) XXX_DiscardUnknown() {\n\txxx_messageInfo_Cluster.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_Cluster proto.InternalMessageInfo\n\nfunc (m *Cluster) GetNodes() map[string]*Node {\n\tif m != nil {\n\t\treturn m.Nodes\n\t}\n\treturn nil\n}\n\nfunc (m *Cluster) GetLeader() string {\n\tif m != nil {\n\t\treturn m.Leader\n\t}\n\treturn \"\"\n}\n\ntype JoinRequest struct {\n\tId                   string   `protobuf:\"bytes,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tNode                 *Node    `protobuf:\"bytes,2,opt,name=node,proto3\" json:\"node,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *JoinRequest) Reset()         { *m = JoinRequest{} }\nfunc (m *JoinRequest) String() string { return proto.CompactTextString(m) }\nfunc (*JoinRequest) ProtoMessage()    {}\nfunc (*JoinRequest) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{5}\n}\n\nfunc (m *JoinRequest) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_JoinRequest.Unmarshal(m, b)\n}\nfunc (m *JoinRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_JoinRequest.Marshal(b, m, deterministic)\n}\nfunc (m *JoinRequest) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_JoinRequest.Merge(m, src)\n}\nfunc (m *JoinRequest) XXX_Size() int {\n\treturn xxx_messageInfo_JoinRequest.Size(m)\n}\nfunc (m *JoinRequest) XXX_DiscardUnknown() {\n\txxx_messageInfo_JoinRequest.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_JoinRequest proto.InternalMessageInfo\n\nfunc (m *JoinRequest) GetId() string {\n\tif m != nil {\n\t\treturn m.Id\n\t}\n\treturn \"\"\n}\n\nfunc (m *JoinRequest) GetNode() *Node {\n\tif m != nil {\n\t\treturn m.Node\n\t}\n\treturn nil\n}\n\ntype LeaveRequest struct {\n\tId                   string   `protobuf:\"bytes,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *LeaveRequest) Reset()         { *m = LeaveRequest{} }\nfunc (m *LeaveRequest) String() string { return proto.CompactTextString(m) }\nfunc (*LeaveRequest) ProtoMessage()    {}\nfunc (*LeaveRequest) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{6}\n}\n\nfunc (m *LeaveRequest) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_LeaveRequest.Unmarshal(m, b)\n}\nfunc (m *LeaveRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_LeaveRequest.Marshal(b, m, deterministic)\n}\nfunc (m *LeaveRequest) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_LeaveRequest.Merge(m, src)\n}\nfunc (m *LeaveRequest) XXX_Size() int {\n\treturn xxx_messageInfo_LeaveRequest.Size(m)\n}\nfunc (m *LeaveRequest) XXX_DiscardUnknown() {\n\txxx_messageInfo_LeaveRequest.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_LeaveRequest proto.InternalMessageInfo\n\nfunc (m *LeaveRequest) GetId() string {\n\tif m != nil {\n\t\treturn m.Id\n\t}\n\treturn \"\"\n}\n\ntype NodeResponse struct {\n\tNode                 *Node    `protobuf:\"bytes,1,opt,name=node,proto3\" json:\"node,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *NodeResponse) Reset()         { *m = NodeResponse{} }\nfunc (m *NodeResponse) String() string { return proto.CompactTextString(m) }\nfunc (*NodeResponse) ProtoMessage()    {}\nfunc (*NodeResponse) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{7}\n}\n\nfunc (m *NodeResponse) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_NodeResponse.Unmarshal(m, b)\n}\nfunc (m *NodeResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_NodeResponse.Marshal(b, m, deterministic)\n}\nfunc (m *NodeResponse) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_NodeResponse.Merge(m, src)\n}\nfunc (m *NodeResponse) XXX_Size() int {\n\treturn xxx_messageInfo_NodeResponse.Size(m)\n}\nfunc (m *NodeResponse) XXX_DiscardUnknown() {\n\txxx_messageInfo_NodeResponse.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_NodeResponse proto.InternalMessageInfo\n\nfunc (m *NodeResponse) GetNode() *Node {\n\tif m != nil {\n\t\treturn m.Node\n\t}\n\treturn nil\n}\n\ntype ClusterResponse struct {\n\tCluster              *Cluster `protobuf:\"bytes,1,opt,name=cluster,proto3\" json:\"cluster,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *ClusterResponse) Reset()         { *m = ClusterResponse{} }\nfunc (m *ClusterResponse) String() string { return proto.CompactTextString(m) }\nfunc (*ClusterResponse) ProtoMessage()    {}\nfunc (*ClusterResponse) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{8}\n}\n\nfunc (m *ClusterResponse) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_ClusterResponse.Unmarshal(m, b)\n}\nfunc (m *ClusterResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_ClusterResponse.Marshal(b, m, deterministic)\n}\nfunc (m *ClusterResponse) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_ClusterResponse.Merge(m, src)\n}\nfunc (m *ClusterResponse) XXX_Size() int {\n\treturn xxx_messageInfo_ClusterResponse.Size(m)\n}\nfunc (m *ClusterResponse) XXX_DiscardUnknown() {\n\txxx_messageInfo_ClusterResponse.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_ClusterResponse proto.InternalMessageInfo\n\nfunc (m *ClusterResponse) GetCluster() *Cluster {\n\tif m != nil {\n\t\treturn m.Cluster\n\t}\n\treturn nil\n}\n\ntype GetRequest struct {\n\tKey                  string   `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *GetRequest) Reset()         { *m = GetRequest{} }\nfunc (m *GetRequest) String() string { return proto.CompactTextString(m) }\nfunc (*GetRequest) ProtoMessage()    {}\nfunc (*GetRequest) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{9}\n}\n\nfunc (m *GetRequest) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_GetRequest.Unmarshal(m, b)\n}\nfunc (m *GetRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_GetRequest.Marshal(b, m, deterministic)\n}\nfunc (m *GetRequest) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_GetRequest.Merge(m, src)\n}\nfunc (m *GetRequest) XXX_Size() int {\n\treturn xxx_messageInfo_GetRequest.Size(m)\n}\nfunc (m *GetRequest) XXX_DiscardUnknown() {\n\txxx_messageInfo_GetRequest.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_GetRequest proto.InternalMessageInfo\n\nfunc (m *GetRequest) GetKey() string {\n\tif m != nil {\n\t\treturn m.Key\n\t}\n\treturn \"\"\n}\n\ntype GetResponse struct {\n\tValue                []byte   `protobuf:\"bytes,1,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *GetResponse) Reset()         { *m = GetResponse{} }\nfunc (m *GetResponse) String() string { return proto.CompactTextString(m) }\nfunc (*GetResponse) ProtoMessage()    {}\nfunc (*GetResponse) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{10}\n}\n\nfunc (m *GetResponse) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_GetResponse.Unmarshal(m, b)\n}\nfunc (m *GetResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_GetResponse.Marshal(b, m, deterministic)\n}\nfunc (m *GetResponse) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_GetResponse.Merge(m, src)\n}\nfunc (m *GetResponse) XXX_Size() int {\n\treturn xxx_messageInfo_GetResponse.Size(m)\n}\nfunc (m *GetResponse) XXX_DiscardUnknown() {\n\txxx_messageInfo_GetResponse.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_GetResponse proto.InternalMessageInfo\n\nfunc (m *GetResponse) GetValue() []byte {\n\tif m != nil {\n\t\treturn m.Value\n\t}\n\treturn nil\n}\n\ntype ScanRequest struct {\n\tPrefix               string   `protobuf:\"bytes,1,opt,name=prefix,proto3\" json:\"prefix,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *ScanRequest) Reset()         { *m = ScanRequest{} }\nfunc (m *ScanRequest) String() string { return proto.CompactTextString(m) }\nfunc (*ScanRequest) ProtoMessage()    {}\nfunc (*ScanRequest) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{11}\n}\n\nfunc (m *ScanRequest) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_ScanRequest.Unmarshal(m, b)\n}\nfunc (m *ScanRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_ScanRequest.Marshal(b, m, deterministic)\n}\nfunc (m *ScanRequest) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_ScanRequest.Merge(m, src)\n}\nfunc (m *ScanRequest) XXX_Size() int {\n\treturn xxx_messageInfo_ScanRequest.Size(m)\n}\nfunc (m *ScanRequest) XXX_DiscardUnknown() {\n\txxx_messageInfo_ScanRequest.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_ScanRequest proto.InternalMessageInfo\n\nfunc (m *ScanRequest) GetPrefix() string {\n\tif m != nil {\n\t\treturn m.Prefix\n\t}\n\treturn \"\"\n}\n\ntype ScanResponse struct {\n\tValues               [][]byte `protobuf:\"bytes,1,rep,name=values,proto3\" json:\"values,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *ScanResponse) Reset()         { *m = ScanResponse{} }\nfunc (m *ScanResponse) String() string { return proto.CompactTextString(m) }\nfunc (*ScanResponse) ProtoMessage()    {}\nfunc (*ScanResponse) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{12}\n}\n\nfunc (m *ScanResponse) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_ScanResponse.Unmarshal(m, b)\n}\nfunc (m *ScanResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_ScanResponse.Marshal(b, m, deterministic)\n}\nfunc (m *ScanResponse) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_ScanResponse.Merge(m, src)\n}\nfunc (m *ScanResponse) XXX_Size() int {\n\treturn xxx_messageInfo_ScanResponse.Size(m)\n}\nfunc (m *ScanResponse) XXX_DiscardUnknown() {\n\txxx_messageInfo_ScanResponse.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_ScanResponse proto.InternalMessageInfo\n\nfunc (m *ScanResponse) GetValues() [][]byte {\n\tif m != nil {\n\t\treturn m.Values\n\t}\n\treturn nil\n}\n\ntype SetRequest struct {\n\tKey                  string   `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tValue                []byte   `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *SetRequest) Reset()         { *m = SetRequest{} }\nfunc (m *SetRequest) String() string { return proto.CompactTextString(m) }\nfunc (*SetRequest) ProtoMessage()    {}\nfunc (*SetRequest) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{13}\n}\n\nfunc (m *SetRequest) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_SetRequest.Unmarshal(m, b)\n}\nfunc (m *SetRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_SetRequest.Marshal(b, m, deterministic)\n}\nfunc (m *SetRequest) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_SetRequest.Merge(m, src)\n}\nfunc (m *SetRequest) XXX_Size() int {\n\treturn xxx_messageInfo_SetRequest.Size(m)\n}\nfunc (m *SetRequest) XXX_DiscardUnknown() {\n\txxx_messageInfo_SetRequest.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_SetRequest proto.InternalMessageInfo\n\nfunc (m *SetRequest) GetKey() string {\n\tif m != nil {\n\t\treturn m.Key\n\t}\n\treturn \"\"\n}\n\nfunc (m *SetRequest) GetValue() []byte {\n\tif m != nil {\n\t\treturn m.Value\n\t}\n\treturn nil\n}\n\ntype DeleteRequest struct {\n\tKey                  string   `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *DeleteRequest) Reset()         { *m = DeleteRequest{} }\nfunc (m *DeleteRequest) String() string { return proto.CompactTextString(m) }\nfunc (*DeleteRequest) ProtoMessage()    {}\nfunc (*DeleteRequest) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{14}\n}\n\nfunc (m *DeleteRequest) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_DeleteRequest.Unmarshal(m, b)\n}\nfunc (m *DeleteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_DeleteRequest.Marshal(b, m, deterministic)\n}\nfunc (m *DeleteRequest) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_DeleteRequest.Merge(m, src)\n}\nfunc (m *DeleteRequest) XXX_Size() int {\n\treturn xxx_messageInfo_DeleteRequest.Size(m)\n}\nfunc (m *DeleteRequest) XXX_DiscardUnknown() {\n\txxx_messageInfo_DeleteRequest.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_DeleteRequest proto.InternalMessageInfo\n\nfunc (m *DeleteRequest) GetKey() string {\n\tif m != nil {\n\t\treturn m.Key\n\t}\n\treturn \"\"\n}\n\ntype SetMetadataRequest struct {\n\tId                   string    `protobuf:\"bytes,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tMetadata             *Metadata `protobuf:\"bytes,2,opt,name=metadata,proto3\" json:\"metadata,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{}  `json:\"-\"`\n\tXXX_unrecognized     []byte    `json:\"-\"`\n\tXXX_sizecache        int32     `json:\"-\"`\n}\n\nfunc (m *SetMetadataRequest) Reset()         { *m = SetMetadataRequest{} }\nfunc (m *SetMetadataRequest) String() string { return proto.CompactTextString(m) }\nfunc (*SetMetadataRequest) ProtoMessage()    {}\nfunc (*SetMetadataRequest) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{15}\n}\n\nfunc (m *SetMetadataRequest) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_SetMetadataRequest.Unmarshal(m, b)\n}\nfunc (m *SetMetadataRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_SetMetadataRequest.Marshal(b, m, deterministic)\n}\nfunc (m *SetMetadataRequest) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_SetMetadataRequest.Merge(m, src)\n}\nfunc (m *SetMetadataRequest) XXX_Size() int {\n\treturn xxx_messageInfo_SetMetadataRequest.Size(m)\n}\nfunc (m *SetMetadataRequest) XXX_DiscardUnknown() {\n\txxx_messageInfo_SetMetadataRequest.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_SetMetadataRequest proto.InternalMessageInfo\n\nfunc (m *SetMetadataRequest) GetId() string {\n\tif m != nil {\n\t\treturn m.Id\n\t}\n\treturn \"\"\n}\n\nfunc (m *SetMetadataRequest) GetMetadata() *Metadata {\n\tif m != nil {\n\t\treturn m.Metadata\n\t}\n\treturn nil\n}\n\ntype DeleteMetadataRequest struct {\n\tId                   string   `protobuf:\"bytes,1,opt,name=id,proto3\" json:\"id,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *DeleteMetadataRequest) Reset()         { *m = DeleteMetadataRequest{} }\nfunc (m *DeleteMetadataRequest) String() string { return proto.CompactTextString(m) }\nfunc (*DeleteMetadataRequest) ProtoMessage()    {}\nfunc (*DeleteMetadataRequest) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{16}\n}\n\nfunc (m *DeleteMetadataRequest) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_DeleteMetadataRequest.Unmarshal(m, b)\n}\nfunc (m *DeleteMetadataRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_DeleteMetadataRequest.Marshal(b, m, deterministic)\n}\nfunc (m *DeleteMetadataRequest) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_DeleteMetadataRequest.Merge(m, src)\n}\nfunc (m *DeleteMetadataRequest) XXX_Size() int {\n\treturn xxx_messageInfo_DeleteMetadataRequest.Size(m)\n}\nfunc (m *DeleteMetadataRequest) XXX_DiscardUnknown() {\n\txxx_messageInfo_DeleteMetadataRequest.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_DeleteMetadataRequest proto.InternalMessageInfo\n\nfunc (m *DeleteMetadataRequest) GetId() string {\n\tif m != nil {\n\t\treturn m.Id\n\t}\n\treturn \"\"\n}\n\ntype Event struct {\n\tType                 Event_Type `protobuf:\"varint,1,opt,name=type,proto3,enum=kvs.Event_Type\" json:\"type,omitempty\"`\n\tData                 *any.Any   `protobuf:\"bytes,2,opt,name=data,proto3\" json:\"data,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{}   `json:\"-\"`\n\tXXX_unrecognized     []byte     `json:\"-\"`\n\tXXX_sizecache        int32      `json:\"-\"`\n}\n\nfunc (m *Event) Reset()         { *m = Event{} }\nfunc (m *Event) String() string { return proto.CompactTextString(m) }\nfunc (*Event) ProtoMessage()    {}\nfunc (*Event) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{17}\n}\n\nfunc (m *Event) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_Event.Unmarshal(m, b)\n}\nfunc (m *Event) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_Event.Marshal(b, m, deterministic)\n}\nfunc (m *Event) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_Event.Merge(m, src)\n}\nfunc (m *Event) XXX_Size() int {\n\treturn xxx_messageInfo_Event.Size(m)\n}\nfunc (m *Event) XXX_DiscardUnknown() {\n\txxx_messageInfo_Event.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_Event proto.InternalMessageInfo\n\nfunc (m *Event) GetType() Event_Type {\n\tif m != nil {\n\t\treturn m.Type\n\t}\n\treturn Event_Unknown\n}\n\nfunc (m *Event) GetData() *any.Any {\n\tif m != nil {\n\t\treturn m.Data\n\t}\n\treturn nil\n}\n\ntype WatchResponse struct {\n\tEvent                *Event   `protobuf:\"bytes,1,opt,name=event,proto3\" json:\"event,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *WatchResponse) Reset()         { *m = WatchResponse{} }\nfunc (m *WatchResponse) String() string { return proto.CompactTextString(m) }\nfunc (*WatchResponse) ProtoMessage()    {}\nfunc (*WatchResponse) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{18}\n}\n\nfunc (m *WatchResponse) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_WatchResponse.Unmarshal(m, b)\n}\nfunc (m *WatchResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_WatchResponse.Marshal(b, m, deterministic)\n}\nfunc (m *WatchResponse) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_WatchResponse.Merge(m, src)\n}\nfunc (m *WatchResponse) XXX_Size() int {\n\treturn xxx_messageInfo_WatchResponse.Size(m)\n}\nfunc (m *WatchResponse) XXX_DiscardUnknown() {\n\txxx_messageInfo_WatchResponse.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_WatchResponse proto.InternalMessageInfo\n\nfunc (m *WatchResponse) GetEvent() *Event {\n\tif m != nil {\n\t\treturn m.Event\n\t}\n\treturn nil\n}\n\ntype MetricsResponse struct {\n\tMetrics              []byte   `protobuf:\"bytes,1,opt,name=metrics,proto3\" json:\"metrics,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *MetricsResponse) Reset()         { *m = MetricsResponse{} }\nfunc (m *MetricsResponse) String() string { return proto.CompactTextString(m) }\nfunc (*MetricsResponse) ProtoMessage()    {}\nfunc (*MetricsResponse) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{19}\n}\n\nfunc (m *MetricsResponse) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_MetricsResponse.Unmarshal(m, b)\n}\nfunc (m *MetricsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_MetricsResponse.Marshal(b, m, deterministic)\n}\nfunc (m *MetricsResponse) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_MetricsResponse.Merge(m, src)\n}\nfunc (m *MetricsResponse) XXX_Size() int {\n\treturn xxx_messageInfo_MetricsResponse.Size(m)\n}\nfunc (m *MetricsResponse) XXX_DiscardUnknown() {\n\txxx_messageInfo_MetricsResponse.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_MetricsResponse proto.InternalMessageInfo\n\nfunc (m *MetricsResponse) GetMetrics() []byte {\n\tif m != nil {\n\t\treturn m.Metrics\n\t}\n\treturn nil\n}\n\ntype KeyValuePair struct {\n\tKey                  string   `protobuf:\"bytes,1,opt,name=key,proto3\" json:\"key,omitempty\"`\n\tValue                []byte   `protobuf:\"bytes,2,opt,name=value,proto3\" json:\"value,omitempty\"`\n\tXXX_NoUnkeyedLiteral struct{} `json:\"-\"`\n\tXXX_unrecognized     []byte   `json:\"-\"`\n\tXXX_sizecache        int32    `json:\"-\"`\n}\n\nfunc (m *KeyValuePair) Reset()         { *m = KeyValuePair{} }\nfunc (m *KeyValuePair) String() string { return proto.CompactTextString(m) }\nfunc (*KeyValuePair) ProtoMessage()    {}\nfunc (*KeyValuePair) Descriptor() ([]byte, []int) {\n\treturn fileDescriptor_431078ad7b21f851, []int{20}\n}\n\nfunc (m *KeyValuePair) XXX_Unmarshal(b []byte) error {\n\treturn xxx_messageInfo_KeyValuePair.Unmarshal(m, b)\n}\nfunc (m *KeyValuePair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {\n\treturn xxx_messageInfo_KeyValuePair.Marshal(b, m, deterministic)\n}\nfunc (m *KeyValuePair) XXX_Merge(src proto.Message) {\n\txxx_messageInfo_KeyValuePair.Merge(m, src)\n}\nfunc (m *KeyValuePair) XXX_Size() int {\n\treturn xxx_messageInfo_KeyValuePair.Size(m)\n}\nfunc (m *KeyValuePair) XXX_DiscardUnknown() {\n\txxx_messageInfo_KeyValuePair.DiscardUnknown(m)\n}\n\nvar xxx_messageInfo_KeyValuePair proto.InternalMessageInfo\n\nfunc (m *KeyValuePair) GetKey() string {\n\tif m != nil {\n\t\treturn m.Key\n\t}\n\treturn \"\"\n}\n\nfunc (m *KeyValuePair) GetValue() []byte {\n\tif m != nil {\n\t\treturn m.Value\n\t}\n\treturn nil\n}\n\nfunc init() {\n\tproto.RegisterEnum(\"kvs.Event_Type\", Event_Type_name, Event_Type_value)\n\tproto.RegisterType((*LivenessCheckResponse)(nil), \"kvs.LivenessCheckResponse\")\n\tproto.RegisterType((*ReadinessCheckResponse)(nil), \"kvs.ReadinessCheckResponse\")\n\tproto.RegisterType((*Metadata)(nil), \"kvs.Metadata\")\n\tproto.RegisterType((*Node)(nil), \"kvs.Node\")\n\tproto.RegisterType((*Cluster)(nil), \"kvs.Cluster\")\n\tproto.RegisterMapType((map[string]*Node)(nil), \"kvs.Cluster.NodesEntry\")\n\tproto.RegisterType((*JoinRequest)(nil), \"kvs.JoinRequest\")\n\tproto.RegisterType((*LeaveRequest)(nil), \"kvs.LeaveRequest\")\n\tproto.RegisterType((*NodeResponse)(nil), \"kvs.NodeResponse\")\n\tproto.RegisterType((*ClusterResponse)(nil), \"kvs.ClusterResponse\")\n\tproto.RegisterType((*GetRequest)(nil), \"kvs.GetRequest\")\n\tproto.RegisterType((*GetResponse)(nil), \"kvs.GetResponse\")\n\tproto.RegisterType((*ScanRequest)(nil), \"kvs.ScanRequest\")\n\tproto.RegisterType((*ScanResponse)(nil), \"kvs.ScanResponse\")\n\tproto.RegisterType((*SetRequest)(nil), \"kvs.SetRequest\")\n\tproto.RegisterType((*DeleteRequest)(nil), \"kvs.DeleteRequest\")\n\tproto.RegisterType((*SetMetadataRequest)(nil), \"kvs.SetMetadataRequest\")\n\tproto.RegisterType((*DeleteMetadataRequest)(nil), \"kvs.DeleteMetadataRequest\")\n\tproto.RegisterType((*Event)(nil), \"kvs.Event\")\n\tproto.RegisterType((*WatchResponse)(nil), \"kvs.WatchResponse\")\n\tproto.RegisterType((*MetricsResponse)(nil), \"kvs.MetricsResponse\")\n\tproto.RegisterType((*KeyValuePair)(nil), \"kvs.KeyValuePair\")\n}\n\nfunc init() {\n\tproto.RegisterFile(\"protobuf/kvs.proto\", fileDescriptor_431078ad7b21f851)\n}\n\nvar fileDescriptor_431078ad7b21f851 = []byte{\n\t// 1016 bytes of a gzipped FileDescriptorProto\n\t0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0x56, 0xdd, 0x6e, 0xdb, 0x46,\n\t0x13, 0x8d, 0xfe, 0x6c, 0x79, 0x24, 0xdb, 0xcc, 0x58, 0xd6, 0xe7, 0xd0, 0xf9, 0x9c, 0x78, 0x83,\n\t0xa6, 0xae, 0x5b, 0x8b, 0x8d, 0x5b, 0xf4, 0xc7, 0x68, 0x2e, 0x52, 0xd7, 0x08, 0xda, 0x38, 0x8d,\n\t0x41, 0xb5, 0x29, 0xd0, 0x1b, 0x63, 0x4d, 0x8e, 0x65, 0x56, 0x32, 0xc9, 0x92, 0x2b, 0xa5, 0x42,\n\t0x90, 0x9b, 0x02, 0x7d, 0x82, 0xa2, 0x4f, 0xd6, 0x57, 0xe8, 0x83, 0x14, 0xfb, 0x43, 0x51, 0xb2,\n\t0xc4, 0x26, 0x57, 0xe2, 0xee, 0x9c, 0x3d, 0x73, 0x76, 0x66, 0xf6, 0x40, 0x80, 0x71, 0x12, 0x89,\n\t0xe8, 0x62, 0x78, 0xe9, 0xf4, 0x47, 0x69, 0x47, 0x2d, 0xb0, 0xd2, 0x1f, 0xa5, 0xf6, 0x9d, 0x5e,\n\t0x14, 0xf5, 0x06, 0xe4, 0x4c, 0xe2, 0x3c, 0x1c, 0xeb, 0xb8, 0xbd, 0x7d, 0x33, 0x44, 0xd7, 0xb1,\n\t0xc8, 0x82, 0x77, 0x4d, 0x90, 0xc7, 0x81, 0xc3, 0xc3, 0x30, 0x12, 0x5c, 0x04, 0x51, 0x68, 0xa8,\n\t0xed, 0x8f, 0xd4, 0x8f, 0x77, 0xd0, 0xa3, 0xf0, 0x20, 0x7d, 0xc5, 0x7b, 0x3d, 0x4a, 0x9c, 0x28,\n\t0x56, 0x88, 0x79, 0x34, 0x3b, 0x80, 0xcd, 0xd3, 0x60, 0x44, 0x21, 0xa5, 0xe9, 0xf1, 0x15, 0x79,\n\t0x7d, 0x97, 0xd2, 0x38, 0x0a, 0x53, 0xc2, 0x16, 0xd4, 0xf8, 0x20, 0x18, 0xd1, 0x56, 0xe9, 0x7e,\n\t0x69, 0xaf, 0xee, 0xea, 0x05, 0xeb, 0x40, 0xdb, 0x25, 0xee, 0x07, 0x0b, 0xf1, 0x09, 0x71, 0x7f,\n\t0x9c, 0xe1, 0xd5, 0x82, 0x9d, 0x41, 0xfd, 0x39, 0x09, 0xee, 0x73, 0xc1, 0x71, 0x17, 0x9a, 0xbd,\n\t0x24, 0xf6, 0xce, 0xb9, 0xef, 0x27, 0x94, 0xa6, 0x0a, 0xb8, 0xe2, 0x36, 0xe4, 0xde, 0x13, 0xbd,\n\t0x25, 0x21, 0x57, 0x42, 0xc4, 0x13, 0x48, 0x59, 0x43, 0xe4, 0x9e, 0x81, 0xb0, 0x5f, 0xa0, 0xfa,\n\t0x7d, 0xe4, 0x93, 0x84, 0x26, 0xfc, 0x52, 0xdc, 0x64, 0x93, 0x7b, 0x19, 0xdb, 0x07, 0x50, 0xbf,\n\t0x36, 0xc9, 0x15, 0x53, 0xe3, 0x70, 0xb5, 0x23, 0x5b, 0x90, 0x29, 0x72, 0x27, 0x61, 0xa9, 0x3e,\n\t0x15, 0x5c, 0xd0, 0x56, 0x45, 0xd1, 0xe8, 0x05, 0xfb, 0xab, 0x04, 0xcb, 0xc7, 0x83, 0x61, 0x2a,\n\t0x28, 0xc1, 0x03, 0xa8, 0x85, 0x91, 0x4f, 0x32, 0x51, 0x65, 0xaf, 0x71, 0xf8, 0x3f, 0xc5, 0x64,\n\t0x82, 0x1d, 0xa9, 0x28, 0x3d, 0x09, 0x45, 0x32, 0x76, 0x35, 0x0a, 0xdb, 0xb0, 0x34, 0x20, 0xee,\n\t0x53, 0x62, 0xee, 0x60, 0x56, 0xf6, 0x31, 0x40, 0x0e, 0x46, 0x0b, 0x2a, 0x7d, 0x1a, 0x1b, 0xed,\n\t0xf2, 0x13, 0xef, 0x41, 0x6d, 0xc4, 0x07, 0x43, 0x32, 0x82, 0x57, 0x54, 0x1a, 0x79, 0xc2, 0xd5,\n\t0xfb, 0x47, 0xe5, 0x2f, 0x4a, 0xec, 0x2b, 0x68, 0x7c, 0x17, 0x05, 0xa1, 0x4b, 0xbf, 0x0e, 0x29,\n\t0x15, 0xb8, 0x06, 0xe5, 0xc0, 0x37, 0x24, 0xe5, 0xc0, 0xc7, 0xff, 0x43, 0x55, 0x8a, 0x98, 0xa7,\n\t0x50, 0xdb, 0x6c, 0x07, 0x9a, 0xa7, 0xc4, 0x47, 0x54, 0x70, 0x9c, 0x1d, 0x40, 0x53, 0xa1, 0xb3,\n\t0xce, 0x66, 0x74, 0xa5, 0xc5, 0x74, 0x5f, 0xc2, 0xba, 0x29, 0xc3, 0xe4, 0xc4, 0x43, 0x58, 0xf6,\n\t0xf4, 0x96, 0x39, 0xd4, 0x9c, 0xae, 0x96, 0x9b, 0x05, 0xd9, 0x0e, 0xc0, 0x53, 0x12, 0x99, 0x8e,\n\t0xb9, 0x62, 0xb0, 0x07, 0xd0, 0x50, 0xf1, 0x7c, 0xc4, 0x74, 0x6d, 0x24, 0xa4, 0x69, 0x0a, 0xc2,\n\t0xde, 0x83, 0x46, 0xd7, 0xe3, 0x93, 0x62, 0xb4, 0x61, 0x29, 0x4e, 0xe8, 0x32, 0xf8, 0xcd, 0x10,\n\t0x99, 0x15, 0x7b, 0x08, 0x4d, 0x0d, 0x33, 0x64, 0x6d, 0x58, 0x52, 0xe7, 0x75, 0x43, 0x9b, 0xae,\n\t0x59, 0xb1, 0x4f, 0x01, 0xba, 0xff, 0xa1, 0x29, 0x17, 0x51, 0x9e, 0x16, 0xb1, 0x0b, 0xab, 0xdf,\n\t0xd0, 0x80, 0x04, 0x15, 0x5f, 0xe6, 0x05, 0x60, 0x97, 0xc4, 0x64, 0xf6, 0x0a, 0x7a, 0xf7, 0xee,\n\t0x33, 0xcb, 0xde, 0x87, 0x4d, 0x9d, 0xf3, 0x2d, 0x9c, 0x72, 0x8c, 0x6b, 0x27, 0x23, 0x0a, 0x05,\n\t0x3e, 0x80, 0xaa, 0x18, 0xc7, 0xba, 0x80, 0x6b, 0x87, 0xeb, 0x8a, 0x59, 0x45, 0x3a, 0x3f, 0x8c,\n\t0x63, 0x72, 0x55, 0x10, 0xf7, 0xa0, 0x3a, 0x95, 0xbe, 0xd5, 0xd1, 0x6e, 0xd3, 0xc9, 0xac, 0xa8,\n\t0xf3, 0x24, 0x1c, 0xbb, 0x0a, 0xc1, 0x1e, 0x43, 0x55, 0x9e, 0xc3, 0x06, 0x2c, 0xff, 0x18, 0xf6,\n\t0xc3, 0xe8, 0x55, 0x68, 0xdd, 0xc2, 0x3a, 0x54, 0xe5, 0x70, 0x5a, 0x25, 0x5c, 0x81, 0x9a, 0x1a,\n\t0x34, 0xab, 0x8c, 0xcb, 0x50, 0xe9, 0x92, 0xb0, 0x2a, 0x08, 0xb0, 0xa4, 0x45, 0x5b, 0x55, 0xf6,\n\t0x08, 0x56, 0x7f, 0xe2, 0xc2, 0xbb, 0x9a, 0xf4, 0xe4, 0x3e, 0xd4, 0x48, 0xaa, 0x31, 0x53, 0x03,\n\t0xb9, 0x3e, 0x57, 0x07, 0xd8, 0x87, 0xb0, 0xfe, 0x9c, 0x44, 0x12, 0x78, 0xe9, 0xe4, 0xd0, 0x16,\n\t0x2c, 0x5f, 0xeb, 0x2d, 0x33, 0x17, 0xd9, 0x92, 0x7d, 0x06, 0xcd, 0x67, 0x34, 0x7e, 0x29, 0x1b,\n\t0x74, 0xc6, 0x83, 0xe4, 0x5d, 0x9b, 0x79, 0xf8, 0x47, 0x1d, 0x2a, 0xcf, 0x5e, 0x76, 0xf1, 0x1c,\n\t0x56, 0x67, 0xbc, 0x11, 0xdb, 0x73, 0xb5, 0x38, 0x91, 0xb6, 0x6c, 0xdb, 0x4a, 0xe8, 0x42, 0x1f,\n\t0x65, 0xf6, 0xef, 0x7f, 0xff, 0xf3, 0x67, 0xb9, 0x85, 0xe8, 0x8c, 0x1e, 0x39, 0x03, 0x03, 0x39,\n\t0xf7, 0x14, 0xdf, 0x05, 0xac, 0xcd, 0xba, 0x69, 0x61, 0x86, 0x6d, 0x95, 0x61, 0xb1, 0xf5, 0xb2,\n\t0x6d, 0x95, 0x62, 0x13, 0x37, 0x64, 0x8a, 0x24, 0xc3, 0x98, 0x1c, 0xc7, 0xc6, 0x2f, 0x8b, 0x98,\n\t0x6f, 0xe7, 0xef, 0x39, 0xe3, 0xb3, 0x14, 0x1f, 0x60, 0x5d, 0xf2, 0xc9, 0x37, 0x8e, 0x67, 0xba,\n\t0xa7, 0x68, 0x29, 0xf0, 0x94, 0xf7, 0xd8, 0x05, 0xb4, 0x6c, 0x47, 0x71, 0x6c, 0xd9, 0x96, 0xe4,\n\t0x30, 0xef, 0xdd, 0x79, 0x1d, 0xf8, 0x6f, 0x8e, 0x94, 0x6b, 0xe0, 0x69, 0xee, 0xac, 0x45, 0xca,\n\t0x5a, 0x33, 0xa6, 0x91, 0x89, 0xdb, 0x50, 0xc4, 0xab, 0xd8, 0x98, 0x22, 0xc6, 0x53, 0x33, 0x69,\n\t0xa8, 0x6f, 0x33, 0x6d, 0x6f, 0x85, 0x0a, 0xb7, 0x14, 0x11, 0xee, 0xcf, 0x29, 0xc4, 0x33, 0xa8,\n\t0x77, 0x43, 0x1e, 0xa7, 0x57, 0x91, 0x28, 0x14, 0x57, 0xc4, 0xda, 0x52, 0xac, 0x6b, 0xd8, 0x94,\n\t0xac, 0x69, 0xc6, 0x72, 0x0c, 0x95, 0xa7, 0x24, 0x50, 0x3f, 0xb8, 0xdc, 0xf2, 0x6c, 0x2b, 0xdf,\n\t0x30, 0xd7, 0xbb, 0xa3, 0xce, 0x6f, 0xe0, 0x6d, 0x79, 0x5e, 0x3e, 0x32, 0xe7, 0x75, 0x9f, 0xc6,\n\t0x8f, 0xf7, 0xf7, 0xdf, 0xe0, 0xb7, 0x50, 0x95, 0x0e, 0x66, 0x9a, 0x30, 0xe5, 0x79, 0xa6, 0x87,\n\t0xd3, 0xf6, 0xc6, 0xee, 0x2a, 0x9e, 0x36, 0xb6, 0x72, 0x1e, 0x6d, 0x84, 0x8a, 0xea, 0x54, 0x3d,\n\t0x47, 0xa3, 0x27, 0xb7, 0xbb, 0xc2, 0x5b, 0x19, 0x36, 0x7b, 0x5e, 0xd5, 0x51, 0x69, 0x1f, 0x5f,\n\t0x64, 0x6f, 0x1a, 0x51, 0x11, 0xce, 0x38, 0x61, 0x21, 0xa7, 0xb9, 0xe9, 0xfe, 0x82, 0x9b, 0x7e,\n\t0x0e, 0x35, 0x65, 0x0c, 0x85, 0xd5, 0xd7, 0x79, 0x66, 0xcc, 0x83, 0xdd, 0xfa, 0xb8, 0x24, 0xa7,\n\t0xca, 0xd8, 0xc3, 0x5b, 0xa6, 0xea, 0x86, 0x89, 0xcc, 0x4e, 0x95, 0xf1, 0x8f, 0xaf, 0x77, 0x7f,\n\t0xbe, 0xd7, 0x0b, 0xc4, 0xd5, 0xf0, 0xa2, 0xe3, 0x45, 0xd7, 0xce, 0x75, 0x94, 0x0e, 0xfb, 0xdc,\n\t0xf1, 0x48, 0xe4, 0x7f, 0xcb, 0x2e, 0x96, 0xd4, 0xd7, 0x27, 0xff, 0x06, 0x00, 0x00, 0xff, 0xff,\n\t0x2e, 0xf6, 0xd7, 0x64, 0xe4, 0x09, 0x00, 0x00,\n}\n\n// Reference imports to suppress errors if they are not otherwise used.\nvar _ context.Context\nvar _ grpc.ClientConnInterface\n\n// This is a compile-time assertion to ensure that this generated file\n// is compatible with the grpc package it is being compiled against.\nconst _ = grpc.SupportPackageIsVersion6\n\n// KVSClient is the client API for KVS service.\n//\n// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.\ntype KVSClient interface {\n\tLivenessCheck(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*LivenessCheckResponse, error)\n\tReadinessCheck(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*ReadinessCheckResponse, error)\n\tNode(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*NodeResponse, error)\n\tJoin(ctx context.Context, in *JoinRequest, opts ...grpc.CallOption) (*empty.Empty, error)\n\tCluster(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*ClusterResponse, error)\n\tLeave(ctx context.Context, in *LeaveRequest, opts ...grpc.CallOption) (*empty.Empty, error)\n\tSnapshot(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error)\n\tGet(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error)\n\tScan(ctx context.Context, in *ScanRequest, opts ...grpc.CallOption) (*ScanResponse, error)\n\tSet(ctx context.Context, in *SetRequest, opts ...grpc.CallOption) (*empty.Empty, error)\n\tDelete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*empty.Empty, error)\n\tWatch(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (KVS_WatchClient, error)\n\tMetrics(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*MetricsResponse, error)\n}\n\ntype kVSClient struct {\n\tcc grpc.ClientConnInterface\n}\n\nfunc NewKVSClient(cc grpc.ClientConnInterface) KVSClient {\n\treturn &kVSClient{cc}\n}\n\nfunc (c *kVSClient) LivenessCheck(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*LivenessCheckResponse, error) {\n\tout := new(LivenessCheckResponse)\n\terr := c.cc.Invoke(ctx, \"/kvs.KVS/LivenessCheck\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *kVSClient) ReadinessCheck(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*ReadinessCheckResponse, error) {\n\tout := new(ReadinessCheckResponse)\n\terr := c.cc.Invoke(ctx, \"/kvs.KVS/ReadinessCheck\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *kVSClient) Node(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*NodeResponse, error) {\n\tout := new(NodeResponse)\n\terr := c.cc.Invoke(ctx, \"/kvs.KVS/Node\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *kVSClient) Join(ctx context.Context, in *JoinRequest, opts ...grpc.CallOption) (*empty.Empty, error) {\n\tout := new(empty.Empty)\n\terr := c.cc.Invoke(ctx, \"/kvs.KVS/Join\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *kVSClient) Cluster(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*ClusterResponse, error) {\n\tout := new(ClusterResponse)\n\terr := c.cc.Invoke(ctx, \"/kvs.KVS/Cluster\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *kVSClient) Leave(ctx context.Context, in *LeaveRequest, opts ...grpc.CallOption) (*empty.Empty, error) {\n\tout := new(empty.Empty)\n\terr := c.cc.Invoke(ctx, \"/kvs.KVS/Leave\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *kVSClient) Snapshot(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) {\n\tout := new(empty.Empty)\n\terr := c.cc.Invoke(ctx, \"/kvs.KVS/Snapshot\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *kVSClient) Get(ctx context.Context, in *GetRequest, opts ...grpc.CallOption) (*GetResponse, error) {\n\tout := new(GetResponse)\n\terr := c.cc.Invoke(ctx, \"/kvs.KVS/Get\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *kVSClient) Scan(ctx context.Context, in *ScanRequest, opts ...grpc.CallOption) (*ScanResponse, error) {\n\tout := new(ScanResponse)\n\terr := c.cc.Invoke(ctx, \"/kvs.KVS/Scan\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *kVSClient) Set(ctx context.Context, in *SetRequest, opts ...grpc.CallOption) (*empty.Empty, error) {\n\tout := new(empty.Empty)\n\terr := c.cc.Invoke(ctx, \"/kvs.KVS/Set\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *kVSClient) Delete(ctx context.Context, in *DeleteRequest, opts ...grpc.CallOption) (*empty.Empty, error) {\n\tout := new(empty.Empty)\n\terr := c.cc.Invoke(ctx, \"/kvs.KVS/Delete\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\nfunc (c *kVSClient) Watch(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (KVS_WatchClient, error) {\n\tstream, err := c.cc.NewStream(ctx, &_KVS_serviceDesc.Streams[0], \"/kvs.KVS/Watch\", opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tx := &kVSWatchClient{stream}\n\tif err := x.ClientStream.SendMsg(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif err := x.ClientStream.CloseSend(); err != nil {\n\t\treturn nil, err\n\t}\n\treturn x, nil\n}\n\ntype KVS_WatchClient interface {\n\tRecv() (*WatchResponse, error)\n\tgrpc.ClientStream\n}\n\ntype kVSWatchClient struct {\n\tgrpc.ClientStream\n}\n\nfunc (x *kVSWatchClient) Recv() (*WatchResponse, error) {\n\tm := new(WatchResponse)\n\tif err := x.ClientStream.RecvMsg(m); err != nil {\n\t\treturn nil, err\n\t}\n\treturn m, nil\n}\n\nfunc (c *kVSClient) Metrics(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*MetricsResponse, error) {\n\tout := new(MetricsResponse)\n\terr := c.cc.Invoke(ctx, \"/kvs.KVS/Metrics\", in, out, opts...)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn out, nil\n}\n\n// KVSServer is the server API for KVS service.\ntype KVSServer interface {\n\tLivenessCheck(context.Context, *empty.Empty) (*LivenessCheckResponse, error)\n\tReadinessCheck(context.Context, *empty.Empty) (*ReadinessCheckResponse, error)\n\tNode(context.Context, *empty.Empty) (*NodeResponse, error)\n\tJoin(context.Context, *JoinRequest) (*empty.Empty, error)\n\tCluster(context.Context, *empty.Empty) (*ClusterResponse, error)\n\tLeave(context.Context, *LeaveRequest) (*empty.Empty, error)\n\tSnapshot(context.Context, *empty.Empty) (*empty.Empty, error)\n\tGet(context.Context, *GetRequest) (*GetResponse, error)\n\tScan(context.Context, *ScanRequest) (*ScanResponse, error)\n\tSet(context.Context, *SetRequest) (*empty.Empty, error)\n\tDelete(context.Context, *DeleteRequest) (*empty.Empty, error)\n\tWatch(*empty.Empty, KVS_WatchServer) error\n\tMetrics(context.Context, *empty.Empty) (*MetricsResponse, error)\n}\n\n// UnimplementedKVSServer can be embedded to have forward compatible implementations.\ntype UnimplementedKVSServer struct {\n}\n\nfunc (*UnimplementedKVSServer) LivenessCheck(ctx context.Context, req *empty.Empty) (*LivenessCheckResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method LivenessCheck not implemented\")\n}\nfunc (*UnimplementedKVSServer) ReadinessCheck(ctx context.Context, req *empty.Empty) (*ReadinessCheckResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method ReadinessCheck not implemented\")\n}\nfunc (*UnimplementedKVSServer) Node(ctx context.Context, req *empty.Empty) (*NodeResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Node not implemented\")\n}\nfunc (*UnimplementedKVSServer) Join(ctx context.Context, req *JoinRequest) (*empty.Empty, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Join not implemented\")\n}\nfunc (*UnimplementedKVSServer) Cluster(ctx context.Context, req *empty.Empty) (*ClusterResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Cluster not implemented\")\n}\nfunc (*UnimplementedKVSServer) Leave(ctx context.Context, req *LeaveRequest) (*empty.Empty, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Leave not implemented\")\n}\nfunc (*UnimplementedKVSServer) Snapshot(ctx context.Context, req *empty.Empty) (*empty.Empty, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Snapshot not implemented\")\n}\nfunc (*UnimplementedKVSServer) Get(ctx context.Context, req *GetRequest) (*GetResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Get not implemented\")\n}\nfunc (*UnimplementedKVSServer) Scan(ctx context.Context, req *ScanRequest) (*ScanResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Scan not implemented\")\n}\nfunc (*UnimplementedKVSServer) Set(ctx context.Context, req *SetRequest) (*empty.Empty, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Set not implemented\")\n}\nfunc (*UnimplementedKVSServer) Delete(ctx context.Context, req *DeleteRequest) (*empty.Empty, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Delete not implemented\")\n}\nfunc (*UnimplementedKVSServer) Watch(req *empty.Empty, srv KVS_WatchServer) error {\n\treturn status.Errorf(codes.Unimplemented, \"method Watch not implemented\")\n}\nfunc (*UnimplementedKVSServer) Metrics(ctx context.Context, req *empty.Empty) (*MetricsResponse, error) {\n\treturn nil, status.Errorf(codes.Unimplemented, \"method Metrics not implemented\")\n}\n\nfunc RegisterKVSServer(s *grpc.Server, srv KVSServer) {\n\ts.RegisterService(&_KVS_serviceDesc, srv)\n}\n\nfunc _KVS_LivenessCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(empty.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(KVSServer).LivenessCheck(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/kvs.KVS/LivenessCheck\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(KVSServer).LivenessCheck(ctx, req.(*empty.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _KVS_ReadinessCheck_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(empty.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(KVSServer).ReadinessCheck(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/kvs.KVS/ReadinessCheck\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(KVSServer).ReadinessCheck(ctx, req.(*empty.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _KVS_Node_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(empty.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(KVSServer).Node(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/kvs.KVS/Node\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(KVSServer).Node(ctx, req.(*empty.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _KVS_Join_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(JoinRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(KVSServer).Join(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/kvs.KVS/Join\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(KVSServer).Join(ctx, req.(*JoinRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _KVS_Cluster_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(empty.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(KVSServer).Cluster(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/kvs.KVS/Cluster\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(KVSServer).Cluster(ctx, req.(*empty.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _KVS_Leave_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(LeaveRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(KVSServer).Leave(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/kvs.KVS/Leave\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(KVSServer).Leave(ctx, req.(*LeaveRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _KVS_Snapshot_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(empty.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(KVSServer).Snapshot(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/kvs.KVS/Snapshot\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(KVSServer).Snapshot(ctx, req.(*empty.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _KVS_Get_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(GetRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(KVSServer).Get(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/kvs.KVS/Get\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(KVSServer).Get(ctx, req.(*GetRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _KVS_Scan_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(ScanRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(KVSServer).Scan(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/kvs.KVS/Scan\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(KVSServer).Scan(ctx, req.(*ScanRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _KVS_Set_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(SetRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(KVSServer).Set(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/kvs.KVS/Set\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(KVSServer).Set(ctx, req.(*SetRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _KVS_Delete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(DeleteRequest)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(KVSServer).Delete(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/kvs.KVS/Delete\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(KVSServer).Delete(ctx, req.(*DeleteRequest))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nfunc _KVS_Watch_Handler(srv interface{}, stream grpc.ServerStream) error {\n\tm := new(empty.Empty)\n\tif err := stream.RecvMsg(m); err != nil {\n\t\treturn err\n\t}\n\treturn srv.(KVSServer).Watch(m, &kVSWatchServer{stream})\n}\n\ntype KVS_WatchServer interface {\n\tSend(*WatchResponse) error\n\tgrpc.ServerStream\n}\n\ntype kVSWatchServer struct {\n\tgrpc.ServerStream\n}\n\nfunc (x *kVSWatchServer) Send(m *WatchResponse) error {\n\treturn x.ServerStream.SendMsg(m)\n}\n\nfunc _KVS_Metrics_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {\n\tin := new(empty.Empty)\n\tif err := dec(in); err != nil {\n\t\treturn nil, err\n\t}\n\tif interceptor == nil {\n\t\treturn srv.(KVSServer).Metrics(ctx, in)\n\t}\n\tinfo := &grpc.UnaryServerInfo{\n\t\tServer:     srv,\n\t\tFullMethod: \"/kvs.KVS/Metrics\",\n\t}\n\thandler := func(ctx context.Context, req interface{}) (interface{}, error) {\n\t\treturn srv.(KVSServer).Metrics(ctx, req.(*empty.Empty))\n\t}\n\treturn interceptor(ctx, in, info, handler)\n}\n\nvar _KVS_serviceDesc = grpc.ServiceDesc{\n\tServiceName: \"kvs.KVS\",\n\tHandlerType: (*KVSServer)(nil),\n\tMethods: []grpc.MethodDesc{\n\t\t{\n\t\t\tMethodName: \"LivenessCheck\",\n\t\t\tHandler:    _KVS_LivenessCheck_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"ReadinessCheck\",\n\t\t\tHandler:    _KVS_ReadinessCheck_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Node\",\n\t\t\tHandler:    _KVS_Node_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Join\",\n\t\t\tHandler:    _KVS_Join_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Cluster\",\n\t\t\tHandler:    _KVS_Cluster_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Leave\",\n\t\t\tHandler:    _KVS_Leave_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Snapshot\",\n\t\t\tHandler:    _KVS_Snapshot_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Get\",\n\t\t\tHandler:    _KVS_Get_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Scan\",\n\t\t\tHandler:    _KVS_Scan_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Set\",\n\t\t\tHandler:    _KVS_Set_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Delete\",\n\t\t\tHandler:    _KVS_Delete_Handler,\n\t\t},\n\t\t{\n\t\t\tMethodName: \"Metrics\",\n\t\t\tHandler:    _KVS_Metrics_Handler,\n\t\t},\n\t},\n\tStreams: []grpc.StreamDesc{\n\t\t{\n\t\t\tStreamName:    \"Watch\",\n\t\t\tHandler:       _KVS_Watch_Handler,\n\t\t\tServerStreams: true,\n\t\t},\n\t},\n\tMetadata: \"protobuf/kvs.proto\",\n}\n"
  },
  {
    "path": "protobuf/kvs.pb.gw.go",
    "content": "// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.\n// source: protobuf/kvs.proto\n\n/*\nPackage protobuf is a reverse proxy.\n\nIt translates gRPC into RESTful JSON APIs.\n*/\npackage protobuf\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"net/http\"\n\n\t\"github.com/golang/protobuf/descriptor\"\n\t\"github.com/golang/protobuf/proto\"\n\t\"github.com/golang/protobuf/ptypes/empty\"\n\t\"github.com/grpc-ecosystem/grpc-gateway/runtime\"\n\t\"github.com/grpc-ecosystem/grpc-gateway/utilities\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/grpclog\"\n\t\"google.golang.org/grpc/status\"\n)\n\n// Suppress \"imported and not used\" errors\nvar _ codes.Code\nvar _ io.Reader\nvar _ status.Status\nvar _ = runtime.String\nvar _ = utilities.NewDoubleArray\nvar _ = descriptor.ForMessage\n\nfunc request_KVS_LivenessCheck_0(ctx context.Context, marshaler runtime.Marshaler, client KVSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := client.LivenessCheck(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_KVS_LivenessCheck_0(ctx context.Context, marshaler runtime.Marshaler, server KVSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := server.LivenessCheck(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_KVS_ReadinessCheck_0(ctx context.Context, marshaler runtime.Marshaler, client KVSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := client.ReadinessCheck(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_KVS_ReadinessCheck_0(ctx context.Context, marshaler runtime.Marshaler, server KVSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := server.ReadinessCheck(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_KVS_Node_0(ctx context.Context, marshaler runtime.Marshaler, client KVSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := client.Node(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_KVS_Node_0(ctx context.Context, marshaler runtime.Marshaler, server KVSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := server.Node(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_KVS_Join_0(ctx context.Context, marshaler runtime.Marshaler, client KVSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq JoinRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Node); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"id\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"id\")\n\t}\n\n\tprotoReq.Id, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"id\", err)\n\t}\n\n\tmsg, err := client.Join(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_KVS_Join_0(ctx context.Context, marshaler runtime.Marshaler, server KVSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq JoinRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq.Node); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"id\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"id\")\n\t}\n\n\tprotoReq.Id, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"id\", err)\n\t}\n\n\tmsg, err := server.Join(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_KVS_Cluster_0(ctx context.Context, marshaler runtime.Marshaler, client KVSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := client.Cluster(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_KVS_Cluster_0(ctx context.Context, marshaler runtime.Marshaler, server KVSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := server.Cluster(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_KVS_Leave_0(ctx context.Context, marshaler runtime.Marshaler, client KVSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq LeaveRequest\n\tvar metadata runtime.ServerMetadata\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"id\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"id\")\n\t}\n\n\tprotoReq.Id, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"id\", err)\n\t}\n\n\tmsg, err := client.Leave(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_KVS_Leave_0(ctx context.Context, marshaler runtime.Marshaler, server KVSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq LeaveRequest\n\tvar metadata runtime.ServerMetadata\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"id\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"id\")\n\t}\n\n\tprotoReq.Id, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"id\", err)\n\t}\n\n\tmsg, err := server.Leave(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_KVS_Snapshot_0(ctx context.Context, marshaler runtime.Marshaler, client KVSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := client.Snapshot(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_KVS_Snapshot_0(ctx context.Context, marshaler runtime.Marshaler, server KVSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := server.Snapshot(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_KVS_Get_0(ctx context.Context, marshaler runtime.Marshaler, client KVSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetRequest\n\tvar metadata runtime.ServerMetadata\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"key\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"key\")\n\t}\n\n\tprotoReq.Key, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"key\", err)\n\t}\n\n\tmsg, err := client.Get(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_KVS_Get_0(ctx context.Context, marshaler runtime.Marshaler, server KVSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq GetRequest\n\tvar metadata runtime.ServerMetadata\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"key\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"key\")\n\t}\n\n\tprotoReq.Key, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"key\", err)\n\t}\n\n\tmsg, err := server.Get(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_KVS_Scan_0(ctx context.Context, marshaler runtime.Marshaler, client KVSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ScanRequest\n\tvar metadata runtime.ServerMetadata\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"prefix\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"prefix\")\n\t}\n\n\tprotoReq.Prefix, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"prefix\", err)\n\t}\n\n\tmsg, err := client.Scan(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_KVS_Scan_0(ctx context.Context, marshaler runtime.Marshaler, server KVSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq ScanRequest\n\tvar metadata runtime.ServerMetadata\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"prefix\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"prefix\")\n\t}\n\n\tprotoReq.Prefix, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"prefix\", err)\n\t}\n\n\tmsg, err := server.Scan(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_KVS_Set_0(ctx context.Context, marshaler runtime.Marshaler, client KVSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq SetRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"key\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"key\")\n\t}\n\n\tprotoReq.Key, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"key\", err)\n\t}\n\n\tmsg, err := client.Set(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_KVS_Set_0(ctx context.Context, marshaler runtime.Marshaler, server KVSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq SetRequest\n\tvar metadata runtime.ServerMetadata\n\n\tnewReader, berr := utilities.IOReaderFactory(req.Body)\n\tif berr != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", berr)\n\t}\n\tif err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"%v\", err)\n\t}\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"key\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"key\")\n\t}\n\n\tprotoReq.Key, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"key\", err)\n\t}\n\n\tmsg, err := server.Set(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_KVS_Delete_0(ctx context.Context, marshaler runtime.Marshaler, client KVSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq DeleteRequest\n\tvar metadata runtime.ServerMetadata\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"key\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"key\")\n\t}\n\n\tprotoReq.Key, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"key\", err)\n\t}\n\n\tmsg, err := client.Delete(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_KVS_Delete_0(ctx context.Context, marshaler runtime.Marshaler, server KVSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq DeleteRequest\n\tvar metadata runtime.ServerMetadata\n\n\tvar (\n\t\tval string\n\t\tok  bool\n\t\terr error\n\t\t_   = err\n\t)\n\n\tval, ok = pathParams[\"key\"]\n\tif !ok {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"missing parameter %s\", \"key\")\n\t}\n\n\tprotoReq.Key, err = runtime.String(val)\n\n\tif err != nil {\n\t\treturn nil, metadata, status.Errorf(codes.InvalidArgument, \"type mismatch, parameter: %s, error: %v\", \"key\", err)\n\t}\n\n\tmsg, err := server.Delete(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\nfunc request_KVS_Metrics_0(ctx context.Context, marshaler runtime.Marshaler, client KVSClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := client.Metrics(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))\n\treturn msg, metadata, err\n\n}\n\nfunc local_request_KVS_Metrics_0(ctx context.Context, marshaler runtime.Marshaler, server KVSServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {\n\tvar protoReq empty.Empty\n\tvar metadata runtime.ServerMetadata\n\n\tmsg, err := server.Metrics(ctx, &protoReq)\n\treturn msg, metadata, err\n\n}\n\n// RegisterKVSHandlerServer registers the http handlers for service KVS to \"mux\".\n// UnaryRPC     :call KVSServer directly.\n// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.\nfunc RegisterKVSHandlerServer(ctx context.Context, mux *runtime.ServeMux, server KVSServer) error {\n\n\tmux.Handle(\"GET\", pattern_KVS_LivenessCheck_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_KVS_LivenessCheck_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_LivenessCheck_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_ReadinessCheck_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_KVS_ReadinessCheck_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_ReadinessCheck_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_Node_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_KVS_Node_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Node_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"PUT\", pattern_KVS_Join_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_KVS_Join_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Join_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_Cluster_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_KVS_Cluster_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Cluster_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"DELETE\", pattern_KVS_Leave_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_KVS_Leave_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Leave_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_Snapshot_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_KVS_Snapshot_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Snapshot_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_Get_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_KVS_Get_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Get_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_Scan_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_KVS_Scan_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Scan_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"PUT\", pattern_KVS_Set_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_KVS_Set_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Set_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"DELETE\", pattern_KVS_Delete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_KVS_Delete_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Delete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_Metrics_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := local_request_KVS_Metrics_0(rctx, inboundMarshaler, server, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Metrics_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\treturn nil\n}\n\n// RegisterKVSHandlerFromEndpoint is same as RegisterKVSHandler but\n// automatically dials to \"endpoint\" and closes the connection when \"ctx\" gets done.\nfunc RegisterKVSHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {\n\tconn, err := grpc.Dial(endpoint, opts...)\n\tif err != nil {\n\t\treturn err\n\t}\n\tdefer func() {\n\t\tif err != nil {\n\t\t\tif cerr := conn.Close(); cerr != nil {\n\t\t\t\tgrpclog.Infof(\"Failed to close conn to %s: %v\", endpoint, cerr)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tgo func() {\n\t\t\t<-ctx.Done()\n\t\t\tif cerr := conn.Close(); cerr != nil {\n\t\t\t\tgrpclog.Infof(\"Failed to close conn to %s: %v\", endpoint, cerr)\n\t\t\t}\n\t\t}()\n\t}()\n\n\treturn RegisterKVSHandler(ctx, mux, conn)\n}\n\n// RegisterKVSHandler registers the http handlers for service KVS to \"mux\".\n// The handlers forward requests to the grpc endpoint over \"conn\".\nfunc RegisterKVSHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {\n\treturn RegisterKVSHandlerClient(ctx, mux, NewKVSClient(conn))\n}\n\n// RegisterKVSHandlerClient registers the http handlers for service KVS\n// to \"mux\". The handlers forward requests to the grpc endpoint over the given implementation of \"KVSClient\".\n// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in \"KVSClient\"\n// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in\n// \"KVSClient\" to call the correct interceptors.\nfunc RegisterKVSHandlerClient(ctx context.Context, mux *runtime.ServeMux, client KVSClient) error {\n\n\tmux.Handle(\"GET\", pattern_KVS_LivenessCheck_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_KVS_LivenessCheck_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_LivenessCheck_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_ReadinessCheck_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_KVS_ReadinessCheck_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_ReadinessCheck_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_Node_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_KVS_Node_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Node_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"PUT\", pattern_KVS_Join_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_KVS_Join_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Join_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_Cluster_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_KVS_Cluster_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Cluster_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"DELETE\", pattern_KVS_Leave_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_KVS_Leave_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Leave_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_Snapshot_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_KVS_Snapshot_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Snapshot_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_Get_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_KVS_Get_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Get_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_Scan_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_KVS_Scan_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Scan_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"PUT\", pattern_KVS_Set_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_KVS_Set_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Set_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"DELETE\", pattern_KVS_Delete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_KVS_Delete_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Delete_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\tmux.Handle(\"GET\", pattern_KVS_Metrics_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {\n\t\tctx, cancel := context.WithCancel(req.Context())\n\t\tdefer cancel()\n\t\tinboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)\n\t\trctx, err := runtime.AnnotateContext(ctx, mux, req)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\t\tresp, md, err := request_KVS_Metrics_0(rctx, inboundMarshaler, client, req, pathParams)\n\t\tctx = runtime.NewServerMetadataContext(ctx, md)\n\t\tif err != nil {\n\t\t\truntime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)\n\t\t\treturn\n\t\t}\n\n\t\tforward_KVS_Metrics_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)\n\n\t})\n\n\treturn nil\n}\n\nvar (\n\tpattern_KVS_LivenessCheck_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"liveness_check\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_KVS_ReadinessCheck_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"readiness_check\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_KVS_Node_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"node\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_KVS_Join_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{\"v1\", \"cluster\", \"id\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_KVS_Cluster_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"cluster\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_KVS_Leave_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{\"v1\", \"cluster\", \"id\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_KVS_Snapshot_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"snapshot\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_KVS_Get_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 3, 0, 4, 1, 5, 2}, []string{\"v1\", \"data\", \"key\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_KVS_Scan_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 3, 0, 4, 1, 5, 2}, []string{\"v1\", \"data\", \"prefix\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_KVS_Set_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 3, 0, 4, 1, 5, 2}, []string{\"v1\", \"data\", \"key\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_KVS_Delete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 3, 0, 4, 1, 5, 2}, []string{\"v1\", \"data\", \"key\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n\n\tpattern_KVS_Metrics_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{\"v1\", \"metrics\"}, \"\", runtime.AssumeColonVerbOpt(true)))\n)\n\nvar (\n\tforward_KVS_LivenessCheck_0 = runtime.ForwardResponseMessage\n\n\tforward_KVS_ReadinessCheck_0 = runtime.ForwardResponseMessage\n\n\tforward_KVS_Node_0 = runtime.ForwardResponseMessage\n\n\tforward_KVS_Join_0 = runtime.ForwardResponseMessage\n\n\tforward_KVS_Cluster_0 = runtime.ForwardResponseMessage\n\n\tforward_KVS_Leave_0 = runtime.ForwardResponseMessage\n\n\tforward_KVS_Snapshot_0 = runtime.ForwardResponseMessage\n\n\tforward_KVS_Get_0 = runtime.ForwardResponseMessage\n\n\tforward_KVS_Scan_0 = runtime.ForwardResponseMessage\n\n\tforward_KVS_Set_0 = runtime.ForwardResponseMessage\n\n\tforward_KVS_Delete_0 = runtime.ForwardResponseMessage\n\n\tforward_KVS_Metrics_0 = runtime.ForwardResponseMessage\n)\n"
  },
  {
    "path": "protobuf/kvs.proto",
    "content": "syntax = \"proto3\";\n\nimport \"google/protobuf/any.proto\";\nimport \"google/protobuf/empty.proto\";\nimport \"google/api/annotations.proto\";\nimport \"protoc-gen-swagger/options/annotations.proto\";\n\npackage kvs;\n\noption go_package = \"github.com/mosuka/cete/protobuf\";\n\nservice KVS {\n    rpc LivenessCheck (google.protobuf.Empty) returns (LivenessCheckResponse) {\n        option (google.api.http) = {\n            get: \"/v1/liveness_check\"\n        };\n    }\n\n    rpc ReadinessCheck (google.protobuf.Empty) returns (ReadinessCheckResponse) {\n        option (google.api.http) = {\n            get: \"/v1/readiness_check\"\n        };\n    }\n\n    rpc Node (google.protobuf.Empty) returns (NodeResponse) {\n        option (google.api.http) = {\n            get: \"/v1/node\"\n        };\n    }\n    rpc Join (JoinRequest) returns (google.protobuf.Empty) {\n        option (google.api.http) = {\n            put: \"/v1/cluster/{id}\"\n            body: \"node\"\n        };\n    }\n    rpc Cluster (google.protobuf.Empty) returns (ClusterResponse) {\n        option (google.api.http) = {\n            get: \"/v1/cluster\"\n        };\n    }\n    rpc Leave (LeaveRequest) returns (google.protobuf.Empty) {\n        option (google.api.http) = {\n            delete: \"/v1/cluster/{id}\"\n        };\n    }\n\n    rpc Snapshot (google.protobuf.Empty) returns (google.protobuf.Empty) {\n        option (google.api.http) = {\n            get: \"/v1/snapshot\"\n        };\n    }\n\n    rpc Get (GetRequest) returns (GetResponse) {\n        option (google.api.http) = {\n            get: \"/v1/data/{key=**}\"\n        };\n    }\n\n    rpc Scan (ScanRequest) returns (ScanResponse) {\n        option (google.api.http) = {\n            get: \"/v1/data/{prefix=**}\"\n        };\n    }\n\n    rpc Set (SetRequest) returns (google.protobuf.Empty) {\n        option (google.api.http) = {\n            put: \"/v1/data/{key=**}\"\n            body: \"*\"\n        };\n    }\n\n    rpc Delete (DeleteRequest) returns (google.protobuf.Empty) {\n        option (google.api.http) = {\n            delete: \"/v1/data/{key=**}\"\n        };\n    }\n\n    rpc Watch (google.protobuf.Empty) returns (stream WatchResponse) {}\n\n    rpc Metrics (google.protobuf.Empty) returns (MetricsResponse) {\n        option (google.api.http) = {\n            get: \"/v1/metrics\"\n        };\n    }\n}\n\nmessage LivenessCheckResponse {\n    bool alive = 1;\n}\n\nmessage ReadinessCheckResponse {\n    bool ready = 1;\n}\n\nmessage Metadata {\n    string grpc_address = 1;\n    string http_address = 2;\n}\n\nmessage Node {\n    string raft_address = 1;\n    Metadata metadata = 2;\n    string state = 3;\n}\n\nmessage Cluster {\n    map<string, Node> nodes = 1;\n    string leader = 2;\n}\n\nmessage JoinRequest {\n    string id = 1;\n    Node node = 2;\n}\n\nmessage LeaveRequest {\n    string id = 1;\n}\n\nmessage NodeResponse {\n    Node node = 1;\n}\n\nmessage ClusterResponse {\n    Cluster cluster = 1;\n}\n\nmessage GetRequest {\n    string key = 1;\n}\n\nmessage GetResponse {\n    bytes value = 1;\n}\n\nmessage ScanRequest {\n    string prefix = 1;\n}\n\nmessage ScanResponse {\n    repeated bytes values = 1;\n}\n\nmessage SetRequest {\n    string key = 1;\n    bytes value = 2;\n}\n\nmessage DeleteRequest {\n    string key = 1;\n}\n\nmessage SetMetadataRequest {\n    string id = 1;\n    Metadata metadata = 2;\n}\n\nmessage DeleteMetadataRequest {\n    string id = 1;\n}\n\nmessage Event {\n    enum Type {\n        Unknown = 0;\n        Join = 1;\n        Leave = 2;\n        Set = 3;\n        Delete = 4;\n    }\n    Type type = 1;\n    google.protobuf.Any data = 2;\n}\n\nmessage WatchResponse {\n    Event event = 1;\n}\n\nmessage MetricsResponse {\n    bytes metrics = 1;\n}\n\nmessage KeyValuePair {\n    string key = 1;\n    bytes value = 2;\n}\n"
  },
  {
    "path": "registry/type.go",
    "content": "package registry\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n)\n\ntype TypeRegistry map[string]reflect.Type\n\nvar Types = make(TypeRegistry, 0)\n\nfunc RegisterType(name string, typ reflect.Type) {\n\tif _, exists := Types[name]; exists {\n\t\tpanic(errors.New(fmt.Sprintf(\"attempted to register duplicate index: %s\", name)))\n\t}\n\tTypes[name] = typ\n}\n\nfunc TypeByName(name string) reflect.Type {\n\treturn Types[name]\n}\n\nfunc TypeNameByInstance(instance interface{}) string {\n\tswitch ins := instance.(type) {\n\tcase map[string]interface{}:\n\t\treturn reflect.TypeOf(ins).String()\n\tdefault:\n\t\treturn reflect.TypeOf(ins).Elem().String()\n\t}\n}\n\nfunc TypeInstanceByName(name string) interface{} {\n\treturn reflect.New(TypeByName(name)).Interface()\n}\n"
  },
  {
    "path": "server/grpc_gateway.go",
    "content": "package server\n\nimport (\n\t\"context\"\n\t\"math\"\n\t\"net\"\n\t\"net/http\"\n\t\"time\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"github.com/grpc-ecosystem/grpc-gateway/runtime\"\n\t\"github.com/mosuka/cete/marshaler\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"go.uber.org/zap\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/keepalive\"\n)\n\nfunc responseFilter(ctx context.Context, w http.ResponseWriter, resp proto.Message) error {\n\tswitch resp.(type) {\n\tcase *protobuf.GetResponse:\n\t\tif r, ok := resp.(*protobuf.GetResponse); ok {\n\t\t\tw.Header().Set(\"Content-Type\", http.DetectContentType(r.Value))\n\t\t}\n\tcase *protobuf.MetricsResponse:\n\t\tw.Header().Set(\"Content-Type\", \"text/plain; version=0.0.4; charset=utf-8\")\n\tdefault:\n\t\tw.Header().Set(\"Content-Type\", marshaler.DefaultContentType)\n\t}\n\n\treturn nil\n}\n\ntype GRPCGateway struct {\n\thttpAddress string\n\tgrpcAddress string\n\n\tcancel   context.CancelFunc\n\tlistener net.Listener\n\tmux      *runtime.ServeMux\n\n\tcertificateFile string\n\tkeyFile         string\n\n\tlogger *zap.Logger\n}\n\nfunc NewGRPCGateway(httpAddress string, grpcAddress string, certificateFile string, keyFile string, commonName string, logger *zap.Logger) (*GRPCGateway, error) {\n\tdialOpts := []grpc.DialOption{\n\t\tgrpc.WithDefaultCallOptions(\n\t\t\tgrpc.MaxCallSendMsgSize(math.MaxInt64),\n\t\t\tgrpc.MaxCallRecvMsgSize(math.MaxInt64),\n\t\t),\n\t\tgrpc.WithKeepaliveParams(\n\t\t\tkeepalive.ClientParameters{\n\t\t\t\tTime:                1 * time.Second,\n\t\t\t\tTimeout:             5 * time.Second,\n\t\t\t\tPermitWithoutStream: true,\n\t\t\t},\n\t\t),\n\t}\n\n\tbaseCtx := context.TODO()\n\tctx, cancel := context.WithCancel(baseCtx)\n\n\tmux := runtime.NewServeMux(\n\t\truntime.WithMarshalerOption(runtime.MIMEWildcard, new(marshaler.CeteMarshaler)),\n\t\truntime.WithForwardResponseOption(responseFilter),\n\t)\n\n\tif certificateFile == \"\" {\n\t\tdialOpts = append(dialOpts, grpc.WithInsecure())\n\t} else {\n\t\tcreds, err := credentials.NewClientTLSFromFile(certificateFile, commonName)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdialOpts = append(dialOpts, grpc.WithTransportCredentials(creds))\n\t}\n\n\terr := protobuf.RegisterKVSHandlerFromEndpoint(ctx, mux, grpcAddress, dialOpts)\n\tif err != nil {\n\t\tlogger.Error(\"failed to register KVS handler from endpoint\", zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\tlistener, err := net.Listen(\"tcp\", httpAddress)\n\tif err != nil {\n\t\tlogger.Error(\"failed to create key value store service\", zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\treturn &GRPCGateway{\n\t\thttpAddress:     httpAddress,\n\t\tgrpcAddress:     grpcAddress,\n\t\tlistener:        listener,\n\t\tmux:             mux,\n\t\tcancel:          cancel,\n\t\tcertificateFile: certificateFile,\n\t\tkeyFile:         keyFile,\n\t\tlogger:          logger,\n\t}, nil\n}\n\nfunc (s *GRPCGateway) Start() error {\n\tif s.certificateFile == \"\" && s.keyFile == \"\" {\n\t\tgo func() {\n\t\t\t_ = http.Serve(s.listener, s.mux)\n\t\t}()\n\t} else {\n\t\tgo func() {\n\t\t\t_ = http.ServeTLS(s.listener, s.mux, s.certificateFile, s.keyFile)\n\t\t}()\n\t}\n\n\ts.logger.Info(\"gRPC gateway started\", zap.String(\"http_address\", s.httpAddress))\n\treturn nil\n}\n\nfunc (s *GRPCGateway) Stop() error {\n\tdefer s.cancel()\n\n\terr := s.listener.Close()\n\tif err != nil {\n\t\ts.logger.Error(\"failed to close listener\", zap.String(\"http_address\", s.listener.Addr().String()), zap.Error(err))\n\t}\n\n\ts.logger.Info(\"gRPC gateway stopped\", zap.String(\"http_address\", s.httpAddress))\n\treturn nil\n}\n"
  },
  {
    "path": "server/grpc_server.go",
    "content": "package server\n\nimport (\n\t\"math\"\n\t\"net\"\n\t\"time\"\n\n\tgrpcmiddleware \"github.com/grpc-ecosystem/go-grpc-middleware\"\n\tgrpczap \"github.com/grpc-ecosystem/go-grpc-middleware/logging/zap\"\n\tgrpc_prometheus \"github.com/grpc-ecosystem/go-grpc-prometheus\"\n\t\"github.com/mosuka/cete/metric\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"go.uber.org/zap\"\n\t\"google.golang.org/grpc\"\n\t\"google.golang.org/grpc/credentials\"\n\t\"google.golang.org/grpc/keepalive\"\n)\n\ntype GRPCServer struct {\n\tgrpcAddress string\n\tservice     *GRPCService\n\tserver      *grpc.Server\n\tlistener    net.Listener\n\n\tcertFile     string\n\tkeyFile      string\n\tcertHostname string\n\n\tlogger *zap.Logger\n}\n\nfunc NewGRPCServer(grpcAddress string, raftServer *RaftServer, certificateFile string, keyFile string, commonName string, logger *zap.Logger) (*GRPCServer, error) {\n\tgrpcLogger := logger.Named(\"grpc\")\n\n\topts := []grpc.ServerOption{\n\t\tgrpc.MaxRecvMsgSize(math.MaxInt64),\n\t\tgrpc.MaxSendMsgSize(math.MaxInt64),\n\t\tgrpc.StreamInterceptor(\n\t\t\tgrpcmiddleware.ChainStreamServer(\n\t\t\t\tmetric.GrpcMetrics.StreamServerInterceptor(),\n\t\t\t\tgrpczap.StreamServerInterceptor(grpcLogger),\n\t\t\t),\n\t\t),\n\t\tgrpc.UnaryInterceptor(\n\t\t\tgrpcmiddleware.ChainUnaryServer(\n\t\t\t\tmetric.GrpcMetrics.UnaryServerInterceptor(),\n\t\t\t\tgrpczap.UnaryServerInterceptor(grpcLogger),\n\t\t\t),\n\t\t),\n\t\tgrpc.KeepaliveParams(\n\t\t\tkeepalive.ServerParameters{\n\t\t\t\t//MaxConnectionIdle:     0,\n\t\t\t\t//MaxConnectionAge:      0,\n\t\t\t\t//MaxConnectionAgeGrace: 0,\n\t\t\t\tTime:    5 * time.Second,\n\t\t\t\tTimeout: 5 * time.Second,\n\t\t\t},\n\t\t),\n\t}\n\n\tif certificateFile == \"\" && keyFile == \"\" {\n\t\tlogger.Info(\"disabling TLS\")\n\t} else {\n\t\tlogger.Info(\"enabling TLS\")\n\t\tcreds, err := credentials.NewServerTLSFromFile(certificateFile, keyFile)\n\t\tif err != nil {\n\t\t\tlogger.Error(\"failed to create credentials\", zap.Error(err))\n\t\t}\n\t\topts = append(opts, grpc.Creds(creds))\n\t}\n\n\tserver := grpc.NewServer(\n\t\topts...,\n\t)\n\n\tservice, err := NewGRPCService(raftServer, certificateFile, commonName, logger)\n\tif err != nil {\n\t\tlogger.Error(\"failed to create key value store service\", zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\tprotobuf.RegisterKVSServer(server, service)\n\n\t// Initialize all metrics.\n\tmetric.GrpcMetrics.InitializeMetrics(server)\n\tgrpc_prometheus.Register(server)\n\n\tlistener, err := net.Listen(\"tcp\", grpcAddress)\n\tif err != nil {\n\t\tlogger.Error(\"failed to create listener\", zap.String(\"grpc_address\", grpcAddress), zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\treturn &GRPCServer{\n\t\tgrpcAddress:  grpcAddress,\n\t\tservice:      service,\n\t\tserver:       server,\n\t\tlistener:     listener,\n\t\tcertFile:     certificateFile,\n\t\tkeyFile:      keyFile,\n\t\tcertHostname: commonName,\n\t\tlogger:       logger,\n\t}, nil\n}\n\nfunc (s *GRPCServer) Start() error {\n\tif err := s.service.Start(); err != nil {\n\t\ts.logger.Error(\"failed to start service\", zap.Error(err))\n\t}\n\n\tgo func() {\n\t\t_ = s.server.Serve(s.listener)\n\t}()\n\n\ts.logger.Info(\"gRPC server started\", zap.String(\"grpc_address\", s.grpcAddress))\n\treturn nil\n}\n\nfunc (s *GRPCServer) Stop() error {\n\tif err := s.service.Stop(); err != nil {\n\t\ts.logger.Error(\"failed to stop service\", zap.Error(err))\n\t}\n\n\t//s.server.GracefulStop()\n\ts.server.Stop()\n\n\ts.logger.Info(\"gRPC server stopped\", zap.String(\"grpc_address\", s.grpcAddress))\n\treturn nil\n}\n"
  },
  {
    "path": "server/grpc_service.go",
    "content": "package server\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/golang/protobuf/ptypes/empty\"\n\t\"github.com/hashicorp/raft\"\n\t\"github.com/mosuka/cete/client\"\n\t\"github.com/mosuka/cete/errors\"\n\t\"github.com/mosuka/cete/metric\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"github.com/prometheus/common/expfmt\"\n\t\"go.uber.org/zap\"\n\t\"google.golang.org/grpc/codes\"\n\t\"google.golang.org/grpc/status\"\n)\n\ntype GRPCService struct {\n\traftServer      *RaftServer\n\tcertificateFile string\n\tcommonName      string\n\tlogger          *zap.Logger\n\n\twatchMutex sync.RWMutex\n\twatchChans map[chan protobuf.WatchResponse]struct{}\n\n\tpeerClients map[string]*client.GRPCClient\n\n\twatchClusterStopCh chan struct{}\n\twatchClusterDoneCh chan struct{}\n}\n\nfunc NewGRPCService(raftServer *RaftServer, certificateFile string, commonName string, logger *zap.Logger) (*GRPCService, error) {\n\treturn &GRPCService{\n\t\traftServer:      raftServer,\n\t\tcertificateFile: certificateFile,\n\t\tcommonName:      commonName,\n\t\tlogger:          logger,\n\n\t\twatchChans: make(map[chan protobuf.WatchResponse]struct{}),\n\n\t\tpeerClients: make(map[string]*client.GRPCClient, 0),\n\n\t\twatchClusterStopCh: make(chan struct{}),\n\t\twatchClusterDoneCh: make(chan struct{}),\n\t}, nil\n}\n\nfunc (s *GRPCService) Start() error {\n\tgo func() {\n\t\ts.startWatchCluster(500 * time.Millisecond)\n\t}()\n\n\ts.logger.Info(\"gRPC service started\")\n\treturn nil\n}\n\nfunc (s *GRPCService) Stop() error {\n\ts.stopWatchCluster()\n\n\ts.logger.Info(\"gRPC service stopped\")\n\treturn nil\n}\n\nfunc (s *GRPCService) startWatchCluster(checkInterval time.Duration) {\n\ts.logger.Info(\"start to update cluster info\")\n\n\tdefer func() {\n\t\tclose(s.watchClusterDoneCh)\n\t}()\n\n\tticker := time.NewTicker(checkInterval)\n\tdefer ticker.Stop()\n\n\ttimeout := 60 * time.Second\n\tif err := s.raftServer.WaitForDetectLeader(timeout); err != nil {\n\t\tif err == errors.ErrTimeout {\n\t\t\ts.logger.Error(\"leader detection timed out\", zap.Duration(\"timeout\", timeout), zap.Error(err))\n\t\t} else {\n\t\t\ts.logger.Error(\"failed to detect leader\", zap.Error(err))\n\t\t}\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-s.watchClusterStopCh:\n\t\t\ts.logger.Info(\"received a request to stop updating a cluster\")\n\t\t\treturn\n\t\tcase event := <-s.raftServer.applyCh:\n\t\t\twatchResp := &protobuf.WatchResponse{\n\t\t\t\tEvent: event,\n\t\t\t}\n\t\t\tfor c := range s.watchChans {\n\t\t\t\tc <- *watchResp\n\t\t\t}\n\t\tcase <-ticker.C:\n\t\t\ts.watchMutex.Lock()\n\n\t\t\t// open clients for peer nodes\n\t\t\tnodes, err := s.raftServer.Nodes()\n\t\t\tif err != nil {\n\t\t\t\ts.logger.Warn(\"failed to get cluster info\", zap.String(\"err\", err.Error()))\n\t\t\t}\n\t\t\tfor id, node := range nodes {\n\t\t\t\tif id == s.raftServer.id {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif node.Metadata == nil || node.Metadata.GrpcAddress == \"\" {\n\t\t\t\t\ts.logger.Debug(\"gRPC address missing\", zap.String(\"id\", id))\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tif c, ok := s.peerClients[id]; ok {\n\t\t\t\t\tif c.Target() != node.Metadata.GrpcAddress {\n\t\t\t\t\t\ts.logger.Debug(\"close client\", zap.String(\"id\", id), zap.String(\"grpc_address\", c.Target()))\n\t\t\t\t\t\tdelete(s.peerClients, id)\n\t\t\t\t\t\tif err := c.Close(); err != nil {\n\t\t\t\t\t\t\ts.logger.Warn(\"failed to close client\", zap.String(\"id\", id), zap.String(\"grpc_address\", c.Target()), zap.Error(err))\n\t\t\t\t\t\t}\n\t\t\t\t\t\ts.logger.Debug(\"create client\", zap.String(\"id\", id), zap.String(\"grpc_address\", node.Metadata.GrpcAddress))\n\t\t\t\t\t\tif newClient, err := client.NewGRPCClientWithContextTLS(node.Metadata.GrpcAddress, context.TODO(), s.certificateFile, s.commonName); err == nil {\n\t\t\t\t\t\t\ts.peerClients[id] = newClient\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\ts.logger.Warn(\"failed to create client\", zap.String(\"id\", id), zap.String(\"grpc_address\", c.Target()), zap.Error(err))\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ts.logger.Debug(\"create client\", zap.String(\"id\", id), zap.String(\"grpc_address\", node.Metadata.GrpcAddress))\n\t\t\t\t\tif newClient, err := client.NewGRPCClientWithContextTLS(node.Metadata.GrpcAddress, context.TODO(), s.certificateFile, s.commonName); err == nil {\n\t\t\t\t\t\ts.peerClients[id] = newClient\n\t\t\t\t\t} else {\n\t\t\t\t\t\ts.logger.Warn(\"failed to create client\", zap.String(\"id\", id), zap.String(\"grpc_address\", c.Target()), zap.Error(err))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// close clients for non-existent peer nodes\n\t\t\tfor id, c := range s.peerClients {\n\t\t\t\tif _, exist := nodes[id]; !exist {\n\t\t\t\t\ts.logger.Debug(\"close client\", zap.String(\"id\", id), zap.String(\"grpc_address\", c.Target()))\n\t\t\t\t\tdelete(s.peerClients, id)\n\t\t\t\t\tif err := c.Close(); err != nil {\n\t\t\t\t\t\ts.logger.Warn(\"failed to close old client\", zap.String(\"id\", id), zap.String(\"grpc_address\", c.Target()), zap.Error(err))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ts.watchMutex.Unlock()\n\t\t}\n\t}\n}\n\nfunc (s *GRPCService) stopWatchCluster() {\n\tif s.watchClusterStopCh != nil {\n\t\ts.logger.Info(\"send a request to stop updating a cluster\")\n\t\tclose(s.watchClusterStopCh)\n\t}\n\n\ts.logger.Info(\"wait for the cluster watching to stop\")\n\t<-s.watchClusterDoneCh\n\ts.logger.Info(\"the cluster watching has been stopped\")\n\n\ts.logger.Info(\"close all peer clients\")\n\tfor id, c := range s.peerClients {\n\t\ts.logger.Debug(\"close client\", zap.String(\"id\", id), zap.String(\"grpc_address\", c.Target()))\n\t\tdelete(s.peerClients, id)\n\t\tif err := c.Close(); err != nil {\n\t\t\ts.logger.Warn(\"failed to close client\", zap.String(\"id\", id), zap.String(\"grpc_address\", c.Target()), zap.Error(err))\n\t\t}\n\t}\n}\n\nfunc (s *GRPCService) LivenessCheck(ctx context.Context, req *empty.Empty) (*protobuf.LivenessCheckResponse, error) {\n\tresp := &protobuf.LivenessCheckResponse{}\n\n\tresp.Alive = true\n\n\treturn resp, nil\n}\n\nfunc (s *GRPCService) ReadinessCheck(ctx context.Context, req *empty.Empty) (*protobuf.ReadinessCheckResponse, error) {\n\tresp := &protobuf.ReadinessCheckResponse{}\n\n\ttimeout := 10 * time.Second\n\tif err := s.raftServer.WaitForDetectLeader(timeout); err != nil {\n\t\ts.logger.Error(\"missing leader node\", zap.Error(err))\n\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t}\n\n\tif s.raftServer.State() == raft.Candidate || s.raftServer.State() == raft.Shutdown {\n\t\terr := errors.ErrNodeNotReady\n\t\ts.logger.Error(err.Error(), zap.Error(err))\n\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t}\n\n\tresp.Ready = true\n\n\treturn resp, nil\n}\n\nfunc (s *GRPCService) Join(ctx context.Context, req *protobuf.JoinRequest) (*empty.Empty, error) {\n\tresp := &empty.Empty{}\n\n\tif s.raftServer.raft.State() != raft.Leader {\n\t\tclusterResp, err := s.Cluster(ctx, &empty.Empty{})\n\t\tif err != nil {\n\t\t\ts.logger.Error(\"failed to get cluster info\", zap.Error(err))\n\t\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t\t}\n\n\t\tc := s.peerClients[clusterResp.Cluster.Leader]\n\t\terr = c.Join(req)\n\t\tif err != nil {\n\t\t\ts.logger.Error(\"failed to forward request\", zap.String(\"grpc_address\", c.Target()), zap.Error(err))\n\t\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t\t}\n\n\t\treturn resp, nil\n\t}\n\n\terr := s.raftServer.Join(req.Id, req.Node)\n\tif err != nil {\n\t\tswitch err {\n\t\tcase errors.ErrNodeAlreadyExists:\n\t\t\ts.logger.Debug(\"node already exists\", zap.Any(\"req\", req), zap.Error(err))\n\t\tdefault:\n\t\t\ts.logger.Error(\"failed to join node to the cluster\", zap.String(\"id\", req.Id), zap.Error(err))\n\t\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t\t}\n\t}\n\n\treturn resp, nil\n}\n\nfunc (s *GRPCService) Leave(ctx context.Context, req *protobuf.LeaveRequest) (*empty.Empty, error) {\n\tresp := &empty.Empty{}\n\n\tif s.raftServer.raft.State() != raft.Leader {\n\t\tclusterResp, err := s.Cluster(ctx, &empty.Empty{})\n\t\tif err != nil {\n\t\t\ts.logger.Error(\"failed to get cluster info\", zap.Error(err))\n\t\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t\t}\n\n\t\tc := s.peerClients[clusterResp.Cluster.Leader]\n\t\terr = c.Leave(req)\n\t\tif err != nil {\n\t\t\ts.logger.Error(\"failed to forward request\", zap.String(\"grpc_address\", c.Target()), zap.Error(err))\n\t\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t\t}\n\n\t\treturn resp, nil\n\t}\n\n\terr := s.raftServer.Leave(req.Id)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to leave node from the cluster\", zap.Any(\"req\", req), zap.Error(err))\n\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t}\n\n\treturn resp, nil\n}\n\nfunc (s *GRPCService) Node(ctx context.Context, req *empty.Empty) (*protobuf.NodeResponse, error) {\n\tresp := &protobuf.NodeResponse{}\n\n\tnode, err := s.raftServer.Node()\n\tif err != nil {\n\t\ts.logger.Error(\"failed to get node info\", zap.String(\"err\", err.Error()))\n\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t}\n\n\tresp.Node = node\n\n\treturn resp, nil\n}\n\nfunc (s *GRPCService) Cluster(ctx context.Context, req *empty.Empty) (*protobuf.ClusterResponse, error) {\n\tresp := &protobuf.ClusterResponse{}\n\n\tcluster := &protobuf.Cluster{}\n\n\tnodes, err := s.raftServer.Nodes()\n\tif err != nil {\n\t\ts.logger.Error(\"failed to get cluster info\", zap.String(\"err\", err.Error()))\n\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t}\n\n\tfor id, node := range nodes {\n\t\tif id == s.raftServer.id {\n\t\t\tnode.State = s.raftServer.StateStr()\n\t\t} else {\n\t\t\tc := s.peerClients[id]\n\t\t\tnodeResp, err := c.Node()\n\t\t\tif err != nil {\n\t\t\t\tnode.State = raft.Shutdown.String()\n\t\t\t\ts.logger.Error(\"failed to get node info\", zap.String(\"grpc_address\", node.Metadata.GrpcAddress), zap.String(\"err\", err.Error()))\n\t\t\t} else {\n\t\t\t\tnode.State = nodeResp.Node.State\n\t\t\t}\n\t\t}\n\t}\n\tcluster.Nodes = nodes\n\n\tserverID, err := s.raftServer.LeaderID(60 * time.Second)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to get cluster info\", zap.String(\"err\", err.Error()))\n\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t}\n\tcluster.Leader = string(serverID)\n\n\tresp.Cluster = cluster\n\n\treturn resp, nil\n}\n\nfunc (s *GRPCService) Snapshot(ctx context.Context, req *empty.Empty) (*empty.Empty, error) {\n\tresp := &empty.Empty{}\n\n\terr := s.raftServer.Snapshot()\n\tif err != nil {\n\t\ts.logger.Error(\"failed to snapshot data\", zap.String(\"err\", err.Error()))\n\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t}\n\n\treturn resp, nil\n}\n\nfunc (s *GRPCService) Get(ctx context.Context, req *protobuf.GetRequest) (*protobuf.GetResponse, error) {\n\tresp := &protobuf.GetResponse{}\n\n\tvar err error\n\n\tresp, err = s.raftServer.Get(req)\n\tif err != nil {\n\t\tswitch err {\n\t\tcase errors.ErrNotFound:\n\t\t\ts.logger.Debug(\"key not found\", zap.String(\"key\", req.Key), zap.String(\"err\", err.Error()))\n\t\t\treturn resp, status.Error(codes.NotFound, err.Error())\n\t\tdefault:\n\t\t\ts.logger.Debug(\"failed to get data\", zap.String(\"key\", req.Key), zap.String(\"err\", err.Error()))\n\t\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t\t}\n\t}\n\n\treturn resp, nil\n}\n\nfunc (s *GRPCService) Scan(ctx context.Context, req *protobuf.ScanRequest) (*protobuf.ScanResponse, error) {\n\tresp := &protobuf.ScanResponse{}\n\n\tvar err error\n\n\tresp, err = s.raftServer.Scan(req)\n\tif err != nil {\n\t\tswitch err {\n\t\tdefault:\n\t\t\ts.logger.Debug(\"failed to scan data\", zap.String(\"prefix\", req.Prefix), zap.String(\"err\", err.Error()))\n\t\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t\t}\n\t}\n\n\treturn resp, nil\n}\n\nfunc (s *GRPCService) Set(ctx context.Context, req *protobuf.SetRequest) (*empty.Empty, error) {\n\tresp := &empty.Empty{}\n\n\tif s.raftServer.raft.State() != raft.Leader {\n\t\tclusterResp, err := s.Cluster(ctx, &empty.Empty{})\n\t\tif err != nil {\n\t\t\ts.logger.Error(\"failed to get cluster info\", zap.Error(err))\n\t\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t\t}\n\n\t\tc := s.peerClients[clusterResp.Cluster.Leader]\n\t\terr = c.Set(req)\n\t\tif err != nil {\n\t\t\ts.logger.Error(\"failed to forward request\", zap.String(\"grpc_address\", c.Target()), zap.Error(err))\n\t\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t\t}\n\n\t\treturn resp, nil\n\t}\n\n\terr := s.raftServer.Set(req)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to put data\", zap.Any(\"req\", req), zap.Error(err))\n\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t}\n\n\treturn resp, nil\n}\n\nfunc (s *GRPCService) Delete(ctx context.Context, req *protobuf.DeleteRequest) (*empty.Empty, error) {\n\tresp := &empty.Empty{}\n\n\tif s.raftServer.raft.State() != raft.Leader {\n\t\tclusterResp, err := s.Cluster(ctx, &empty.Empty{})\n\t\tif err != nil {\n\t\t\ts.logger.Error(\"failed to get cluster info\", zap.Error(err))\n\t\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t\t}\n\n\t\tc := s.peerClients[clusterResp.Cluster.Leader]\n\t\terr = c.Delete(req)\n\t\tif err != nil {\n\t\t\ts.logger.Error(\"failed to forward request\", zap.String(\"grpc_address\", c.Target()), zap.Error(err))\n\t\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t\t}\n\n\t\treturn resp, nil\n\t}\n\n\terr := s.raftServer.Delete(req)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to delete data\", zap.String(\"key\", req.Key), zap.Error(err))\n\t\treturn resp, status.Error(codes.Internal, err.Error())\n\t}\n\n\treturn resp, nil\n}\n\nfunc (s *GRPCService) Watch(req *empty.Empty, server protobuf.KVS_WatchServer) error {\n\tchans := make(chan protobuf.WatchResponse)\n\n\ts.watchMutex.Lock()\n\ts.watchChans[chans] = struct{}{}\n\ts.watchMutex.Unlock()\n\n\tdefer func() {\n\t\ts.watchMutex.Lock()\n\t\tdelete(s.watchChans, chans)\n\t\ts.watchMutex.Unlock()\n\t\tclose(chans)\n\t}()\n\n\tfor resp := range chans {\n\t\tif err := server.Send(&resp); err != nil {\n\t\t\ts.logger.Error(\"failed to send watch data\", zap.String(\"event\", resp.Event.String()), zap.Error(err))\n\t\t\treturn status.Error(codes.Internal, err.Error())\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (s *GRPCService) Metrics(ctx context.Context, req *empty.Empty) (*protobuf.MetricsResponse, error) {\n\tresp := &protobuf.MetricsResponse{}\n\n\tvar err error\n\n\tgather, err := metric.Registry.Gather()\n\tif err != nil {\n\t\ts.logger.Error(\"failed to get gather\", zap.Error(err))\n\t}\n\tout := &bytes.Buffer{}\n\tfor _, mf := range gather {\n\t\tif _, err := expfmt.MetricFamilyToText(out, mf); err != nil {\n\t\t\ts.logger.Error(\"failed to parse metric family\", zap.Error(err))\n\t\t}\n\t}\n\n\tresp.Metrics = out.Bytes()\n\n\treturn resp, nil\n}\n"
  },
  {
    "path": "server/raft_fsm.go",
    "content": "package server\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"sync\"\n\t\"time\"\n\n\t\"github.com/golang/protobuf/proto\"\n\t\"github.com/hashicorp/raft\"\n\t\"github.com/mosuka/cete/marshaler\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"github.com/mosuka/cete/storage\"\n\t\"go.uber.org/zap\"\n)\n\ntype RaftFSM struct {\n\tlogger *zap.Logger\n\n\tkvs        *storage.KVS\n\tmetadata   map[string]*protobuf.Metadata\n\tnodesMutex sync.RWMutex\n\n\tapplyCh chan *protobuf.Event\n}\n\nfunc NewRaftFSM(path string, logger *zap.Logger) (*RaftFSM, error) {\n\terr := os.MkdirAll(path, 0755)\n\tif err != nil && !os.IsExist(err) {\n\t\tlogger.Error(\"failed to make directories\", zap.String(\"path\", path), zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\tkvs, err := storage.NewKVS(path, path, logger)\n\tif err != nil {\n\t\tlogger.Error(\"failed to create key value store\", zap.String(\"path\", path), zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\t// TODO: Context should be passed down to allow for cascade cancellation.\n\t// TODO: GC should have its own flags for both the interval (--gc-interval=5m) and ratio (--gc-discard-ratio=0.5).\n\tkvs.RunGC(context.Background(), 5*time.Minute, 0.5)\n\n\treturn &RaftFSM{\n\t\tlogger:   logger,\n\t\tkvs:      kvs,\n\t\tmetadata: make(map[string]*protobuf.Metadata, 0),\n\t\tapplyCh:  make(chan *protobuf.Event, 1024),\n\t}, nil\n}\n\nfunc (f *RaftFSM) Close() error {\n\tf.applyCh <- nil\n\tf.logger.Info(\"apply channel has closed\")\n\n\terr := f.kvs.Close()\n\tif err != nil {\n\t\tf.logger.Error(\"failed to close key value store\", zap.Error(err))\n\t\treturn err\n\t}\n\tf.logger.Info(\"KVS has closed\")\n\n\treturn nil\n}\n\nfunc (f *RaftFSM) Get(key string) ([]byte, error) {\n\tvalue, err := f.kvs.Get(key)\n\tif err != nil {\n\t\tf.logger.Error(\"failed to get value\", zap.String(\"key\", key), zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\treturn value, nil\n}\n\nfunc (f *RaftFSM) Scan(prefix string) ([][]byte, error) {\n\tvalues, err := f.kvs.Scan(prefix)\n\tif err != nil {\n\t\tf.logger.Error(\"failed to scan values\", zap.String(\"prefix\", prefix), zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\treturn values, nil\n}\n\nfunc (f *RaftFSM) applySet(key string, value []byte) interface{} {\n\terr := f.kvs.Set(key, value)\n\tif err != nil {\n\t\tf.logger.Error(\"failed to set value\", zap.String(\"key\", key), zap.Error(err))\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (f *RaftFSM) applyDelete(key string) interface{} {\n\terr := f.kvs.Delete(key)\n\tif err != nil {\n\t\tf.logger.Error(\"failed to delete value\", zap.String(\"key\", key), zap.Error(err))\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (f *RaftFSM) getMetadata(id string) *protobuf.Metadata {\n\tif metadata, exists := f.metadata[id]; exists {\n\t\treturn metadata\n\t} else {\n\t\tf.logger.Warn(\"metadata not found\", zap.String(\"id\", id))\n\t\treturn nil\n\t}\n}\n\nfunc (f *RaftFSM) setMetadata(id string, metadata *protobuf.Metadata) {\n\tf.nodesMutex.Lock()\n\tf.metadata[id] = metadata\n\tf.nodesMutex.Unlock()\n}\n\nfunc (f *RaftFSM) deleteMetadata(id string) {\n\tf.nodesMutex.Lock()\n\tif _, exists := f.metadata[id]; exists {\n\t\tdelete(f.metadata, id)\n\t} else {\n\t\tf.logger.Warn(\"metadata not found\", zap.String(\"id\", id))\n\t}\n\tf.nodesMutex.Unlock()\n}\n\nfunc (f *RaftFSM) applySetMetadata(id string, metadata *protobuf.Metadata) interface{} {\n\tf.logger.Debug(\"set metadata\", zap.String(\"id\", id), zap.Any(\"metadata\", metadata))\n\tf.setMetadata(id, metadata)\n\n\treturn nil\n}\n\nfunc (f *RaftFSM) applyDeleteMetadata(nodeId string) interface{} {\n\tf.deleteMetadata(nodeId)\n\n\treturn nil\n}\n\nfunc (f *RaftFSM) Apply(l *raft.Log) interface{} {\n\tvar event protobuf.Event\n\terr := proto.Unmarshal(l.Data, &event)\n\tif err != nil {\n\t\tf.logger.Error(\"failed to unmarshal message bytes to KVS command\", zap.Error(err))\n\t\treturn err\n\t}\n\n\tswitch event.Type {\n\tcase protobuf.Event_Join:\n\t\tdata, err := marshaler.MarshalAny(event.Data)\n\t\tif err != nil {\n\t\t\tf.logger.Error(\"failed to marshal to request from KVS command request\", zap.String(\"type\", event.Type.String()), zap.Error(err))\n\t\t\treturn err\n\t\t}\n\t\tif data == nil {\n\t\t\terr = errors.New(\"nil\")\n\t\t\tf.logger.Error(\"request is nil\", zap.String(\"type\", event.Type.String()), zap.Error(err))\n\t\t\treturn err\n\t\t}\n\t\treq := data.(*protobuf.SetMetadataRequest)\n\n\t\tret := f.applySetMetadata(req.Id, req.Metadata)\n\t\tif ret == nil {\n\t\t\tf.applyCh <- &event\n\t\t}\n\n\t\treturn ret\n\tcase protobuf.Event_Leave:\n\t\tdata, err := marshaler.MarshalAny(event.Data)\n\t\tif err != nil {\n\t\t\tf.logger.Error(\"failed to marshal to request from KVS command request\", zap.String(\"type\", event.Type.String()), zap.Error(err))\n\t\t\treturn err\n\t\t}\n\t\tif data == nil {\n\t\t\terr = errors.New(\"nil\")\n\t\t\tf.logger.Error(\"request is nil\", zap.String(\"type\", event.Type.String()), zap.Error(err))\n\t\t\treturn err\n\t\t}\n\t\treq := *data.(*protobuf.DeleteMetadataRequest)\n\n\t\tret := f.applyDeleteMetadata(req.Id)\n\t\tif ret == nil {\n\t\t\tf.applyCh <- &event\n\t\t}\n\n\t\treturn ret\n\tcase protobuf.Event_Set:\n\t\tdata, err := marshaler.MarshalAny(event.Data)\n\t\tif err != nil {\n\t\t\tf.logger.Error(\"failed to marshal to request from KVS command request\", zap.String(\"type\", event.Type.String()), zap.Error(err))\n\t\t\treturn err\n\t\t}\n\t\tif data == nil {\n\t\t\terr = errors.New(\"nil\")\n\t\t\tf.logger.Error(\"request is nil\", zap.String(\"type\", event.Type.String()), zap.Error(err))\n\t\t\treturn err\n\t\t}\n\t\treq := *data.(*protobuf.SetRequest)\n\n\t\tret := f.applySet(req.Key, req.Value)\n\t\tif ret == nil {\n\t\t\tf.applyCh <- &event\n\t\t}\n\n\t\treturn ret\n\tcase protobuf.Event_Delete:\n\t\tdata, err := marshaler.MarshalAny(event.Data)\n\t\tif err != nil {\n\t\t\tf.logger.Error(\"failed to marshal to request from KVS command request\", zap.String(\"type\", event.Type.String()), zap.Error(err))\n\t\t\treturn err\n\t\t}\n\t\tif data == nil {\n\t\t\terr = errors.New(\"nil\")\n\t\t\tf.logger.Error(\"request is nil\", zap.String(\"type\", event.Type.String()), zap.Error(err))\n\t\t\treturn err\n\t\t}\n\t\treq := *data.(*protobuf.DeleteRequest)\n\n\t\tret := f.applyDelete(req.Key)\n\t\tif ret == nil {\n\t\t\tf.applyCh <- &event\n\t\t}\n\n\t\treturn ret\n\tdefault:\n\t\terr = errors.New(\"command type not support\")\n\t\tf.logger.Error(\"unsupported command\", zap.String(\"type\", event.Type.String()), zap.Error(err))\n\t\treturn err\n\t}\n}\n\nfunc (f *RaftFSM) Stats() map[string]string {\n\treturn f.kvs.Stats()\n}\n\nfunc (f *RaftFSM) Snapshot() (raft.FSMSnapshot, error) {\n\treturn &KVSFSMSnapshot{\n\t\tkvs:    f.kvs,\n\t\tlogger: f.logger,\n\t}, nil\n}\n\nfunc (f *RaftFSM) Restore(rc io.ReadCloser) error {\n\tstart := time.Now()\n\n\tf.logger.Info(\"start to restore items\")\n\n\tdefer func() {\n\t\terr := rc.Close()\n\t\tif err != nil {\n\t\t\tf.logger.Error(\"failed to close reader\", zap.Error(err))\n\t\t}\n\t}()\n\n\tdata, err := ioutil.ReadAll(rc)\n\tif err != nil {\n\t\tf.logger.Error(\"failed to open reader\", zap.Error(err))\n\t\treturn err\n\t}\n\n\tkeyCount := uint64(0)\n\n\tbuff := proto.NewBuffer(data)\n\tfor {\n\t\tkvp := &protobuf.KeyValuePair{}\n\t\terr = buff.DecodeMessage(kvp)\n\t\tif err == io.ErrUnexpectedEOF {\n\t\t\tf.logger.Debug(\"reached the EOF\", zap.Error(err))\n\t\t\tbreak\n\t\t}\n\t\tif err != nil {\n\t\t\tf.logger.Error(\"failed to read key value pair\", zap.Error(err))\n\t\t\treturn err\n\t\t}\n\n\t\t// apply item to store\n\t\terr = f.kvs.Set(kvp.Key, kvp.Value)\n\t\tif err != nil {\n\t\t\tf.logger.Error(\"failed to set key value pair to key value store\", zap.Error(err))\n\t\t\treturn err\n\t\t}\n\n\t\tf.logger.Debug(\"restore\", zap.String(\"key\", kvp.Key))\n\t\tkeyCount = keyCount + 1\n\t}\n\n\tf.logger.Info(\"finished to restore items\", zap.Uint64(\"count\", keyCount), zap.Float64(\"time\", float64(time.Since(start))/float64(time.Second)))\n\n\treturn nil\n}\n\n// ---------------------\n\ntype KVSFSMSnapshot struct {\n\tkvs    *storage.KVS\n\tlogger *zap.Logger\n}\n\nfunc (f *KVSFSMSnapshot) Persist(sink raft.SnapshotSink) error {\n\tstart := time.Now()\n\n\tf.logger.Info(\"start to persist items\")\n\n\tdefer func() {\n\t\terr := sink.Close()\n\t\tif err != nil {\n\t\t\tf.logger.Error(\"failed to close sink\", zap.Error(err))\n\t\t}\n\t}()\n\n\tch := f.kvs.SnapshotItems()\n\n\tkvpCount := uint64(0)\n\n\tfor {\n\t\tkvp := <-ch\n\t\tif kvp == nil {\n\t\t\tf.logger.Debug(\"channel closed\")\n\t\t\tbreak\n\t\t}\n\n\t\tkvpCount = kvpCount + 1\n\n\t\tbuff := proto.NewBuffer([]byte{})\n\t\terr := buff.EncodeMessage(kvp)\n\t\tif err != nil {\n\t\t\tf.logger.Error(\"failed to encode key value pair\", zap.Error(err))\n\t\t\treturn err\n\t\t}\n\n\t\t_, err = sink.Write(buff.Bytes())\n\t\tif err != nil {\n\t\t\tf.logger.Error(\"failed to write key value pair\", zap.Error(err))\n\t\t\treturn err\n\t\t}\n\t}\n\n\tf.logger.Info(\"finished to persist items\", zap.Uint64(\"count\", kvpCount), zap.Float64(\"time\", float64(time.Since(start))/float64(time.Second)))\n\n\treturn nil\n}\n\nfunc (f *KVSFSMSnapshot) Release() {\n\tf.logger.Info(\"release\")\n}\n"
  },
  {
    "path": "server/raft_server.go",
    "content": "package server\n\nimport (\n\t\"encoding/json\"\n\t\"io/ioutil\"\n\t\"net\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strconv\"\n\t\"time\"\n\n\traftbadgerdb \"github.com/BBVA/raft-badger\"\n\t\"github.com/dgraph-io/badger/v2\"\n\t\"github.com/golang/protobuf/proto\"\n\t\"github.com/golang/protobuf/ptypes/any\"\n\t\"github.com/hashicorp/raft\"\n\t\"github.com/mosuka/cete/errors\"\n\t\"github.com/mosuka/cete/marshaler\"\n\t\"github.com/mosuka/cete/metric\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"go.uber.org/zap\"\n)\n\ntype RaftServer struct {\n\tid            string\n\traftAddress   string\n\tdataDirectory string\n\tbootstrap     bool\n\tlogger        *zap.Logger\n\n\tfsm *RaftFSM\n\n\ttransport *raft.NetworkTransport\n\traft      *raft.Raft\n\n\twatchClusterStopCh chan struct{}\n\twatchClusterDoneCh chan struct{}\n\n\tapplyCh chan *protobuf.Event\n}\n\nfunc NewRaftServer(id string, raftAddress string, dataDirectory string, bootstrap bool, logger *zap.Logger) (*RaftServer, error) {\n\tfsmPath := filepath.Join(dataDirectory, \"kvs\")\n\tfsm, err := NewRaftFSM(fsmPath, logger)\n\tif err != nil {\n\t\tlogger.Error(\"failed to create FSM\", zap.String(\"path\", fsmPath), zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\treturn &RaftServer{\n\t\tid:            id,\n\t\traftAddress:   raftAddress,\n\t\tdataDirectory: dataDirectory,\n\t\tbootstrap:     bootstrap,\n\t\tfsm:           fsm,\n\t\tlogger:        logger,\n\n\t\twatchClusterStopCh: make(chan struct{}),\n\t\twatchClusterDoneCh: make(chan struct{}),\n\n\t\tapplyCh: make(chan *protobuf.Event, 1024),\n\t}, nil\n}\n\nfunc (s *RaftServer) Start() error {\n\tconfig := raft.DefaultConfig()\n\tconfig.LocalID = raft.ServerID(s.id)\n\tconfig.SnapshotThreshold = 1024\n\tconfig.LogOutput = ioutil.Discard\n\n\taddr, err := net.ResolveTCPAddr(\"tcp\", s.raftAddress)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to resolve TCP address\", zap.String(\"raft_address\", s.raftAddress), zap.Error(err))\n\t\treturn err\n\t}\n\n\ts.transport, err = raft.NewTCPTransport(s.raftAddress, addr, 3, 10*time.Second, ioutil.Discard)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to create TCP transport\", zap.String(\"raft_address\", s.raftAddress), zap.Error(err))\n\t\treturn err\n\t}\n\n\t// create snapshot store\n\tsnapshotStore, err := raft.NewFileSnapshotStore(s.dataDirectory, 2, ioutil.Discard)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to create file snapshot store\", zap.String(\"path\", s.dataDirectory), zap.Error(err))\n\t\treturn err\n\t}\n\n\tlogStorePath := filepath.Join(s.dataDirectory, \"raft\", \"log\")\n\terr = os.MkdirAll(logStorePath, 0755)\n\tif err != nil {\n\t\ts.logger.Fatal(err.Error())\n\t\treturn err\n\t}\n\tlogStoreBadgerOpts := badger.DefaultOptions(logStorePath)\n\tlogStoreBadgerOpts.ValueDir = logStorePath\n\tlogStoreBadgerOpts.SyncWrites = false\n\tlogStoreBadgerOpts.Logger = nil\n\tlogStoreOpts := raftbadgerdb.Options{\n\t\tPath:          logStorePath,\n\t\tBadgerOptions: &logStoreBadgerOpts,\n\t}\n\traftLogStore, err := raftbadgerdb.New(logStoreOpts)\n\tif err != nil {\n\t\ts.logger.Fatal(err.Error())\n\t\treturn err\n\t}\n\n\tstableStorePath := filepath.Join(s.dataDirectory, \"raft\", \"stable\")\n\terr = os.MkdirAll(stableStorePath, 0755)\n\tif err != nil {\n\t\ts.logger.Fatal(err.Error())\n\t\treturn err\n\t}\n\tstableStoreBadgerOpts := badger.DefaultOptions(stableStorePath)\n\tstableStoreBadgerOpts.ValueDir = stableStorePath\n\tstableStoreBadgerOpts.SyncWrites = false\n\tstableStoreBadgerOpts.Logger = nil\n\tstableStoreOpts := raftbadgerdb.Options{\n\t\tPath:          stableStorePath,\n\t\tBadgerOptions: &stableStoreBadgerOpts,\n\t}\n\traftStableStore, err := raftbadgerdb.New(stableStoreOpts)\n\tif err != nil {\n\t\ts.logger.Fatal(err.Error())\n\t\treturn err\n\t}\n\n\t// create raft\n\ts.raft, err = raft.NewRaft(config, s.fsm, raftLogStore, raftStableStore, snapshotStore, s.transport)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to create raft\", zap.Any(\"config\", config), zap.Error(err))\n\t\treturn err\n\t}\n\n\tif s.bootstrap {\n\t\tconfiguration := raft.Configuration{\n\t\t\tServers: []raft.Server{\n\t\t\t\t{\n\t\t\t\t\tID:      config.LocalID,\n\t\t\t\t\tAddress: s.transport.LocalAddr(),\n\t\t\t\t},\n\t\t\t},\n\t\t}\n\t\ts.raft.BootstrapCluster(configuration)\n\t}\n\n\tgo func() {\n\t\ts.startWatchCluster(500 * time.Millisecond)\n\t}()\n\n\ts.logger.Info(\"Raft server started\", zap.String(\"raft_address\", s.raftAddress))\n\treturn nil\n}\n\nfunc (s *RaftServer) Stop() error {\n\ts.applyCh <- nil\n\ts.logger.Info(\"apply channel has closed\")\n\n\ts.stopWatchCluster()\n\n\tif err := s.fsm.Close(); err != nil {\n\t\ts.logger.Error(\"failed to close FSM\", zap.Error(err))\n\t}\n\ts.logger.Info(\"Raft FSM Closed\")\n\n\tif future := s.raft.Shutdown(); future.Error() != nil {\n\t\ts.logger.Info(\"failed to shutdown Raft\", zap.Error(future.Error()))\n\t}\n\ts.logger.Info(\"Raft has shutdown\", zap.String(\"raft_address\", s.raftAddress))\n\n\treturn nil\n}\n\nfunc (s *RaftServer) startWatchCluster(checkInterval time.Duration) {\n\ts.logger.Info(\"start to update cluster info\")\n\n\tdefer func() {\n\t\tclose(s.watchClusterDoneCh)\n\t}()\n\n\tticker := time.NewTicker(checkInterval)\n\tdefer ticker.Stop()\n\n\ttimeout := 60 * time.Second\n\tif err := s.WaitForDetectLeader(timeout); err != nil {\n\t\tif err == errors.ErrTimeout {\n\t\t\ts.logger.Error(\"leader detection timed out\", zap.Duration(\"timeout\", timeout), zap.Error(err))\n\t\t} else {\n\t\t\ts.logger.Error(\"failed to detect leader\", zap.Error(err))\n\t\t}\n\t}\n\n\tfor {\n\t\tselect {\n\t\tcase <-s.watchClusterStopCh:\n\t\t\ts.logger.Info(\"received a request to stop updating a cluster\")\n\t\t\treturn\n\t\tcase <-s.raft.LeaderCh():\n\t\t\ts.logger.Info(\"became a leader\", zap.String(\"leaderAddr\", string(s.raft.Leader())))\n\t\tcase event := <-s.fsm.applyCh:\n\t\t\ts.applyCh <- event\n\t\tcase <-ticker.C:\n\t\t\traftStats := s.raft.Stats()\n\n\t\t\tswitch raftStats[\"state\"] {\n\t\t\tcase \"Follower\":\n\t\t\t\tmetric.RaftStateMetric.WithLabelValues(s.id).Set(float64(raft.Follower))\n\t\t\tcase \"Candidate\":\n\t\t\t\tmetric.RaftStateMetric.WithLabelValues(s.id).Set(float64(raft.Candidate))\n\t\t\tcase \"Leader\":\n\t\t\t\tmetric.RaftStateMetric.WithLabelValues(s.id).Set(float64(raft.Leader))\n\t\t\tcase \"Shutdown\":\n\t\t\t\tmetric.RaftStateMetric.WithLabelValues(s.id).Set(float64(raft.Shutdown))\n\t\t\t}\n\n\t\t\tif term, err := strconv.ParseFloat(raftStats[\"term\"], 64); err == nil {\n\t\t\t\tmetric.RaftTermMetric.WithLabelValues(s.id).Set(term)\n\t\t\t}\n\n\t\t\tif lastLogIndex, err := strconv.ParseFloat(raftStats[\"last_log_index\"], 64); err == nil {\n\t\t\t\tmetric.RaftLastLogIndexMetric.WithLabelValues(s.id).Set(lastLogIndex)\n\t\t\t}\n\n\t\t\tif lastLogTerm, err := strconv.ParseFloat(raftStats[\"last_log_term\"], 64); err == nil {\n\t\t\t\tmetric.RaftLastLogTermMetric.WithLabelValues(s.id).Set(lastLogTerm)\n\t\t\t}\n\n\t\t\tif commitIndex, err := strconv.ParseFloat(raftStats[\"commit_index\"], 64); err == nil {\n\t\t\t\tmetric.RaftCommitIndexMetric.WithLabelValues(s.id).Set(commitIndex)\n\t\t\t}\n\n\t\t\tif appliedIndex, err := strconv.ParseFloat(raftStats[\"applied_index\"], 64); err == nil {\n\t\t\t\tmetric.RaftAppliedIndexMetric.WithLabelValues(s.id).Set(appliedIndex)\n\t\t\t}\n\n\t\t\tif fsmPending, err := strconv.ParseFloat(raftStats[\"fsm_pending\"], 64); err == nil {\n\t\t\t\tmetric.RaftFsmPendingMetric.WithLabelValues(s.id).Set(fsmPending)\n\t\t\t}\n\n\t\t\tif lastSnapshotIndex, err := strconv.ParseFloat(raftStats[\"last_snapshot_index\"], 64); err == nil {\n\t\t\t\tmetric.RaftLastSnapshotIndexMetric.WithLabelValues(s.id).Set(lastSnapshotIndex)\n\t\t\t}\n\n\t\t\tif lastSnapshotTerm, err := strconv.ParseFloat(raftStats[\"last_snapshot_term\"], 64); err == nil {\n\t\t\t\tmetric.RaftLastSnapshotTermMetric.WithLabelValues(s.id).Set(lastSnapshotTerm)\n\t\t\t}\n\n\t\t\tif latestConfigurationIndex, err := strconv.ParseFloat(raftStats[\"latest_configuration_index\"], 64); err == nil {\n\t\t\t\tmetric.RaftLatestConfigurationIndexMetric.WithLabelValues(s.id).Set(latestConfigurationIndex)\n\t\t\t}\n\n\t\t\tif numPeers, err := strconv.ParseFloat(raftStats[\"num_peers\"], 64); err == nil {\n\t\t\t\tmetric.RaftNumPeersMetric.WithLabelValues(s.id).Set(numPeers)\n\t\t\t}\n\n\t\t\tif lastContact, err := strconv.ParseFloat(raftStats[\"last_contact\"], 64); err == nil {\n\t\t\t\tmetric.RaftLastContactMetric.WithLabelValues(s.id).Set(lastContact)\n\t\t\t}\n\n\t\t\tif nodes, err := s.Nodes(); err == nil {\n\t\t\t\tmetric.RaftNumNodesMetric.WithLabelValues(s.id).Set(float64(len(nodes)))\n\t\t\t}\n\n\t\t\tkvsStats := s.fsm.Stats()\n\n\t\t\tif numReads, err := strconv.ParseFloat(kvsStats[\"num_reads\"], 64); err == nil {\n\t\t\t\tmetric.KvsNumReadsMetric.WithLabelValues(s.id).Set(numReads)\n\t\t\t}\n\n\t\t\tif numWrites, err := strconv.ParseFloat(kvsStats[\"num_writes\"], 64); err == nil {\n\t\t\t\tmetric.KvsNumWritesMetric.WithLabelValues(s.id).Set(numWrites)\n\t\t\t}\n\n\t\t\tif numBytesRead, err := strconv.ParseFloat(kvsStats[\"num_bytes_read\"], 64); err == nil {\n\t\t\t\tmetric.KvsNumBytesReadMetric.WithLabelValues(s.id).Set(numBytesRead)\n\t\t\t}\n\n\t\t\tif numBytesWritten, err := strconv.ParseFloat(kvsStats[\"num_bytes_written\"], 64); err == nil {\n\t\t\t\tmetric.KvsNumBytesWrittenMetric.WithLabelValues(s.id).Set(numBytesWritten)\n\t\t\t}\n\n\t\t\tvar numLsmGets map[string]interface{}\n\t\t\tif err := json.Unmarshal([]byte(kvsStats[\"num_lsm_gets\"]), &numLsmGets); err == nil {\n\t\t\t\tfor key, value := range numLsmGets {\n\t\t\t\t\ts.logger.Info(\"\", zap.String(\"key\", key), zap.Any(\"value\", value))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar numLsmBloomHits map[string]interface{}\n\t\t\tif err := json.Unmarshal([]byte(kvsStats[\"num_lsm_bloom_Hits\"]), &numLsmBloomHits); err == nil {\n\t\t\t\tfor key, value := range numLsmBloomHits {\n\t\t\t\t\ts.logger.Info(\"\", zap.String(\"key\", key), zap.Any(\"value\", value))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif numGets, err := strconv.ParseFloat(kvsStats[\"num_gets\"], 64); err == nil {\n\t\t\t\tmetric.KvsNumGetsMetric.WithLabelValues(s.id).Set(numGets)\n\t\t\t}\n\n\t\t\tif numPuts, err := strconv.ParseFloat(kvsStats[\"num_puts\"], 64); err == nil {\n\t\t\t\tmetric.KvsNumPutsMetric.WithLabelValues(s.id).Set(numPuts)\n\t\t\t}\n\n\t\t\tif numBlockedPuts, err := strconv.ParseFloat(kvsStats[\"num_blocked_puts\"], 64); err == nil {\n\t\t\t\tmetric.KvsNumBlockedPutsMetric.WithLabelValues(s.id).Set(numBlockedPuts)\n\t\t\t}\n\n\t\t\tif numMemtablesGets, err := strconv.ParseFloat(kvsStats[\"num_memtables_gets\"], 64); err == nil {\n\t\t\t\tmetric.KvsNumMemtablesGetsMetric.WithLabelValues(s.id).Set(numMemtablesGets)\n\t\t\t}\n\n\t\t\tvar lsmSize map[string]interface{}\n\t\t\tif err := json.Unmarshal([]byte(kvsStats[\"lsm_size\"]), &lsmSize); err == nil {\n\t\t\t\tfor key, value := range lsmSize {\n\t\t\t\t\tmetric.KvsLSMSizeMetric.WithLabelValues(s.id, key).Set(value.(float64))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar vlogSize map[string]interface{}\n\t\t\tif err := json.Unmarshal([]byte(kvsStats[\"vlog_size\"]), &vlogSize); err == nil {\n\t\t\t\tfor key, value := range vlogSize {\n\t\t\t\t\tmetric.KvsVlogSizeMetric.WithLabelValues(s.id, key).Set(value.(float64))\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tvar pendingWrites map[string]interface{}\n\t\t\tif err := json.Unmarshal([]byte(kvsStats[\"pending_writes\"]), &pendingWrites); err == nil {\n\t\t\t\tfor key, value := range pendingWrites {\n\t\t\t\t\tmetric.KvsPendingWritesMetric.WithLabelValues(s.id, key).Set(value.(float64))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunc (s *RaftServer) stopWatchCluster() {\n\tif s.watchClusterStopCh != nil {\n\t\ts.logger.Info(\"send a request to stop updating a cluster\")\n\t\tclose(s.watchClusterStopCh)\n\t}\n\n\ts.logger.Info(\"wait for the cluster update to stop\")\n\t<-s.watchClusterDoneCh\n\ts.logger.Info(\"the cluster update has been stopped\")\n}\n\nfunc (s *RaftServer) LeaderAddress(timeout time.Duration) (raft.ServerAddress, error) {\n\tticker := time.NewTicker(100 * time.Millisecond)\n\tdefer ticker.Stop()\n\ttimer := time.NewTimer(timeout)\n\tdefer timer.Stop()\n\n\tfor {\n\t\tselect {\n\t\tcase <-ticker.C:\n\t\t\tleaderAddr := s.raft.Leader()\n\t\t\tif leaderAddr != \"\" {\n\t\t\t\ts.logger.Debug(\"detected a leader address\", zap.String(\"raft_address\", string(leaderAddr)))\n\t\t\t\treturn leaderAddr, nil\n\t\t\t}\n\t\tcase <-timer.C:\n\t\t\terr := errors.ErrTimeout\n\t\t\ts.logger.Error(\"failed to detect leader address\", zap.Error(err))\n\t\t\treturn \"\", err\n\t\t}\n\t}\n}\n\nfunc (s *RaftServer) LeaderID(timeout time.Duration) (raft.ServerID, error) {\n\tleaderAddr, err := s.LeaderAddress(timeout)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to get leader address\", zap.Error(err))\n\t\treturn \"\", err\n\t}\n\n\tcf := s.raft.GetConfiguration()\n\tif err := cf.Error(); err != nil {\n\t\ts.logger.Error(\"failed to get Raft configuration\", zap.Error(err))\n\t\treturn \"\", err\n\t}\n\n\tfor _, server := range cf.Configuration().Servers {\n\t\tif server.Address == leaderAddr {\n\t\t\ts.logger.Info(\"detected a leader ID\", zap.String(\"id\", string(server.ID)))\n\t\t\treturn server.ID, nil\n\t\t}\n\t}\n\n\terr = errors.ErrNotFoundLeader\n\ts.logger.Error(\"failed to detect leader ID\", zap.Error(err))\n\treturn \"\", err\n}\n\nfunc (s *RaftServer) WaitForDetectLeader(timeout time.Duration) error {\n\tif _, err := s.LeaderAddress(timeout); err != nil {\n\t\ts.logger.Error(\"failed to wait for detect leader\", zap.Error(err))\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *RaftServer) State() raft.RaftState {\n\treturn s.raft.State()\n}\n\nfunc (s *RaftServer) StateStr() string {\n\treturn s.State().String()\n}\n\nfunc (s *RaftServer) Exist(id string) (bool, error) {\n\texist := false\n\n\tcf := s.raft.GetConfiguration()\n\terr := cf.Error()\n\tif err != nil {\n\t\ts.logger.Error(\"failed to get Raft configuration\", zap.Error(err))\n\t\treturn false, err\n\t}\n\n\tfor _, server := range cf.Configuration().Servers {\n\t\tif server.ID == raft.ServerID(id) {\n\t\t\ts.logger.Debug(\"node already joined the cluster\", zap.String(\"id\", id))\n\t\t\texist = true\n\t\t\tbreak\n\t\t}\n\t}\n\n\treturn exist, nil\n}\n\nfunc (s *RaftServer) join(id string, metadata *protobuf.Metadata) error {\n\tdata := &protobuf.SetMetadataRequest{\n\t\tId:       id,\n\t\tMetadata: metadata,\n\t}\n\n\tdataAny := &any.Any{}\n\terr := marshaler.UnmarshalAny(data, dataAny)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to unmarshal request to the command data\", zap.String(\"id\", id), zap.Any(\"metadata\", metadata), zap.Error(err))\n\t\treturn err\n\t}\n\n\tc := &protobuf.Event{\n\t\tType: protobuf.Event_Join,\n\t\tData: dataAny,\n\t}\n\n\tmsg, err := proto.Marshal(c)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to marshal the command into the bytes as message\", zap.String(\"id\", id), zap.Any(\"metadata\", metadata), zap.Error(err))\n\t\treturn err\n\t}\n\n\tf := s.raft.Apply(msg, 10*time.Second)\n\tif err = f.Error(); err != nil {\n\t\ts.logger.Error(\"failed to apply message\", zap.String(\"id\", id), zap.Any(\"metadata\", metadata), zap.Error(err))\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *RaftServer) Join(id string, node *protobuf.Node) error {\n\tnodeExists, err := s.Exist(id)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif nodeExists {\n\t\ts.logger.Debug(\"node already exists\", zap.String(\"id\", id), zap.String(\"raft_address\", node.RaftAddress))\n\t} else {\n\t\tif future := s.raft.AddVoter(raft.ServerID(id), raft.ServerAddress(node.RaftAddress), 0, 0); future.Error() != nil {\n\t\t\ts.logger.Error(\"failed to add voter\", zap.String(\"id\", id), zap.String(\"raft_address\", node.RaftAddress), zap.Error(future.Error()))\n\t\t\treturn future.Error()\n\t\t}\n\t\ts.logger.Info(\"node has successfully joined\", zap.String(\"id\", id), zap.String(\"raft_address\", node.RaftAddress))\n\t}\n\n\tif err := s.join(id, node.Metadata); err != nil {\n\t\ts.logger.Error(\"failed to set node metadata\", zap.String(\"id\", id), zap.Any(\"metadata\", node.Metadata), zap.Error(err))\n\t\treturn err\n\t}\n\ts.logger.Info(\"node metadata has successfully set\", zap.String(\"id\", id), zap.Any(\"metadata\", node.Metadata))\n\n\tif nodeExists {\n\t\treturn errors.ErrNodeAlreadyExists\n\t} else {\n\t\treturn nil\n\t}\n}\n\nfunc (s *RaftServer) leave(id string) error {\n\tdata := &protobuf.DeleteMetadataRequest{\n\t\tId: id,\n\t}\n\n\tdataAny := &any.Any{}\n\terr := marshaler.UnmarshalAny(data, dataAny)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to unmarshal request to the command data\", zap.String(\"id\", id), zap.Error(err))\n\t\treturn err\n\t}\n\n\tc := &protobuf.Event{\n\t\tType: protobuf.Event_Leave,\n\t\tData: dataAny,\n\t}\n\n\tmsg, err := proto.Marshal(c)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to marshal the command into the bytes as the message\", zap.String(\"id\", id), zap.Error(err))\n\t\treturn err\n\t}\n\n\tf := s.raft.Apply(msg, 10*time.Second)\n\tif err = f.Error(); err != nil {\n\t\ts.logger.Error(\"failed to apply the message\", zap.String(\"id\", id), zap.Error(err))\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *RaftServer) Leave(id string) error {\n\tnodeExists, err := s.Exist(id)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif nodeExists {\n\t\tif future := s.raft.RemoveServer(raft.ServerID(id), 0, 0); future.Error() != nil {\n\t\t\ts.logger.Error(\"failed to remove server\", zap.String(\"id\", id), zap.Error(future.Error()))\n\t\t\treturn future.Error()\n\t\t}\n\t\ts.logger.Info(\"node has successfully left\", zap.String(\"id\", id))\n\t} else {\n\t\ts.logger.Debug(\"node does not exists\", zap.String(\"id\", id))\n\t}\n\n\tif err = s.leave(id); err != nil {\n\t\ts.logger.Error(\"failed to join node\", zap.String(\"id\", id), zap.Error(err))\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (s *RaftServer) Node() (*protobuf.Node, error) {\n\tnodes, err := s.Nodes()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tnode, ok := nodes[s.id]\n\tif !ok {\n\t\treturn nil, errors.ErrNotFound\n\t}\n\n\tnode.State = s.StateStr()\n\n\treturn node, nil\n}\n\nfunc (s *RaftServer) Nodes() (map[string]*protobuf.Node, error) {\n\tcf := s.raft.GetConfiguration()\n\tif err := cf.Error(); err != nil {\n\t\ts.logger.Error(\"failed to get Raft configuration\", zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\tnodes := make(map[string]*protobuf.Node, 0)\n\tfor _, server := range cf.Configuration().Servers {\n\t\tnodes[string(server.ID)] = &protobuf.Node{\n\t\t\tRaftAddress: string(server.Address),\n\t\t\tMetadata:    s.fsm.getMetadata(string(server.ID)),\n\t\t}\n\t}\n\n\treturn nodes, nil\n}\n\nfunc (s *RaftServer) Snapshot() error {\n\tif future := s.raft.Snapshot(); future.Error() != nil {\n\t\ts.logger.Error(\"failed to snapshot\", zap.Error(future.Error()))\n\t\treturn future.Error()\n\t}\n\n\treturn nil\n}\n\nfunc (s *RaftServer) Get(req *protobuf.GetRequest) (*protobuf.GetResponse, error) {\n\tvalue, err := s.fsm.Get(req.Key)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to get\", zap.Any(\"key\", req.Key), zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\tresp := &protobuf.GetResponse{\n\t\tValue: value,\n\t}\n\n\treturn resp, nil\n}\n\nfunc (s *RaftServer) Scan(req *protobuf.ScanRequest) (*protobuf.ScanResponse, error) {\n\tvalues, err := s.fsm.Scan(req.Prefix)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to scan\", zap.Any(\"prefix\", req.Prefix), zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\tresp := &protobuf.ScanResponse{\n\t\tValues: values,\n\t}\n\n\treturn resp, nil\n}\n\nfunc (s *RaftServer) Set(req *protobuf.SetRequest) error {\n\tkvpAny := &any.Any{}\n\tif err := marshaler.UnmarshalAny(req, kvpAny); err != nil {\n\t\ts.logger.Error(\"failed to unmarshal request to the command data\", zap.String(\"key\", req.Key), zap.Error(err))\n\t\treturn err\n\t}\n\n\tc := &protobuf.Event{\n\t\tType: protobuf.Event_Set,\n\t\tData: kvpAny,\n\t}\n\n\tmsg, err := proto.Marshal(c)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to marshal the command into the bytes as the message\", zap.String(\"key\", req.Key), zap.Error(err))\n\t\treturn err\n\t}\n\n\tif future := s.raft.Apply(msg, 10*time.Second); future.Error() != nil {\n\t\ts.logger.Error(\"failed to apply the message\", zap.Error(future.Error()))\n\t\treturn future.Error()\n\t}\n\n\treturn nil\n}\n\nfunc (s *RaftServer) Delete(req *protobuf.DeleteRequest) error {\n\tkvpAny := &any.Any{}\n\tif err := marshaler.UnmarshalAny(req, kvpAny); err != nil {\n\t\ts.logger.Error(\"failed to unmarshal request to the command data\", zap.String(\"key\", req.Key), zap.Error(err))\n\t\treturn err\n\t}\n\n\tc := &protobuf.Event{\n\t\tType: protobuf.Event_Delete,\n\t\tData: kvpAny,\n\t}\n\n\tmsg, err := proto.Marshal(c)\n\tif err != nil {\n\t\ts.logger.Error(\"failed to marshal the command into the bytes as the message\", zap.String(\"key\", req.Key), zap.Error(err))\n\t\treturn err\n\t}\n\n\tif future := s.raft.Apply(msg, 10*time.Second); future.Error() != nil {\n\t\ts.logger.Error(\"failed to unmarshal request to the command data\", zap.String(\"key\", req.Key), zap.Error(future.Error()))\n\t\treturn future.Error()\n\t}\n\n\treturn nil\n}\n"
  },
  {
    "path": "storage/kvs.go",
    "content": "package storage\n\nimport (\n\t\"context\"\n\t\"time\"\n\n\t\"github.com/dgraph-io/badger/v2\"\n\t\"github.com/dgraph-io/badger/v2/y\"\n\t\"github.com/mosuka/cete/errors\"\n\t\"github.com/mosuka/cete/protobuf\"\n\t\"go.uber.org/zap\"\n)\n\ntype KVS struct {\n\tdir      string\n\tvalueDir string\n\tdb       *badger.DB\n\tlogger   *zap.Logger\n}\n\nfunc NewKVS(dir string, valueDir string, logger *zap.Logger) (*KVS, error) {\n\topts := badger.DefaultOptions(dir)\n\topts.ValueDir = valueDir\n\topts.SyncWrites = false\n\topts.Logger = nil\n\n\tdb, err := badger.Open(opts)\n\tif err != nil {\n\t\tlogger.Error(\"failed to open database\", zap.Any(\"opts\", opts), zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\treturn &KVS{\n\t\tdir:      dir,\n\t\tvalueDir: valueDir,\n\t\tdb:       db,\n\t\tlogger:   logger,\n\t}, nil\n}\n\nfunc (k *KVS) Close() error {\n\tif err := k.db.Close(); err != nil {\n\t\tk.logger.Error(\"failed to close database\", zap.Error(err))\n\t\treturn err\n\t}\n\n\treturn nil\n}\n\nfunc (k *KVS) RunGC(ctx context.Context, interval time.Duration, discardRatio float64) {\n\tgo func() {\n\t\tticker := time.NewTicker(interval)\n\t\tdefer ticker.Stop()\n\n\t\tfor {\n\t\t\tselect {\n\t\t\tcase <-ticker.C:\n\t\t\t\tstart := time.Now()\n\n\t\t\t\tfor {\n\t\t\t\t\terr := k.db.RunValueLogGC(discardRatio)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tif err == badger.ErrNoRewrite {\n\t\t\t\t\t\t\tbreak\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tk.logger.Error(\"garbage collection failed\", zap.Error(err))\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tk.logger.Info(\"garbage collection finished\", zap.Float64(\"time\", float64(time.Since(start))/float64(time.Second)))\n\t\t\tcase <-ctx.Done():\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}()\n}\n\nfunc (k *KVS) Get(key string) ([]byte, error) {\n\tstart := time.Now()\n\n\tvar value []byte\n\tif err := k.db.View(func(txn *badger.Txn) error {\n\t\titem, err := txn.Get([]byte(key))\n\t\tif err != nil {\n\t\t\tk.logger.Error(\"failed to get item\", zap.String(\"key\", key), zap.Error(err))\n\t\t\treturn err\n\t\t}\n\n\t\terr = item.Value(func(val []byte) error {\n\t\t\tvalue = append([]byte{}, val...)\n\t\t\treturn nil\n\t\t})\n\t\tif err != nil {\n\t\t\tk.logger.Error(\"failed to get item value\", zap.String(\"key\", key), zap.Error(err))\n\t\t\treturn err\n\t\t}\n\n\t\treturn nil\n\t}); err == badger.ErrKeyNotFound {\n\t\tk.logger.Debug(\"not found\", zap.String(\"key\", key), zap.Error(err))\n\t\treturn nil, errors.ErrNotFound\n\t} else if err != nil {\n\t\tk.logger.Error(\"failed to get value\", zap.String(\"key\", key), zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\tk.logger.Debug(\"get\", zap.String(\"key\", key), zap.Float64(\"time\", float64(time.Since(start))/float64(time.Second)))\n\treturn value, nil\n}\n\nfunc (k *KVS) Scan(prefix string) ([][]byte, error) {\n\tstart := time.Now()\n\n\tvar value [][]byte\n\tif err := k.db.View(func(txn *badger.Txn) error {\n\t\tit := txn.NewIterator(badger.DefaultIteratorOptions)\n\t\tdefer it.Close()\n\t\tprefixBytes := []byte(prefix)\n\t\tfor it.Seek(prefixBytes); it.ValidForPrefix(prefixBytes); it.Next() {\n\t\t\titem := it.Item()\n\t\t\terr := item.Value(func(val []byte) error {\n\t\t\t\tvalue = append(value, append([]byte{}, val...))\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}); err != nil {\n\t\tk.logger.Error(\"failed to scan value\", zap.String(\"prefix\", prefix), zap.Error(err))\n\t\treturn nil, err\n\t}\n\n\tk.logger.Debug(\"scan\", zap.String(\"prefix\", prefix), zap.Float64(\"time\", float64(time.Since(start))/float64(time.Second)))\n\treturn value, nil\n}\n\nfunc (k *KVS) Set(key string, value []byte) error {\n\tstart := time.Now()\n\n\tif err := k.db.Update(func(txn *badger.Txn) error {\n\t\terr := txn.Set([]byte(key), value)\n\t\tif err != nil {\n\t\t\tk.logger.Error(\"failed to set item\", zap.String(\"key\", key), zap.Error(err))\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}); err != nil {\n\t\tk.logger.Error(\"failed to set value\", zap.String(\"key\", key), zap.Error(err))\n\t\treturn err\n\t}\n\n\tk.logger.Debug(\"set\", zap.String(\"key\", key), zap.Float64(\"time\", float64(time.Since(start))/float64(time.Second)))\n\treturn nil\n}\n\nfunc (k *KVS) Delete(key string) error {\n\tstart := time.Now()\n\n\tif err := k.db.Update(func(txn *badger.Txn) error {\n\t\terr := txn.Delete([]byte(key))\n\t\tif err != nil {\n\t\t\tk.logger.Error(\"failed to delete item\", zap.String(\"key\", key), zap.Error(err))\n\t\t\treturn err\n\t\t}\n\t\treturn nil\n\t}); err != nil {\n\t\tk.logger.Error(\"failed to delete value\", zap.String(\"key\", key), zap.Error(err))\n\t\treturn err\n\t}\n\n\tk.logger.Debug(\"delete\", zap.String(\"key\", key), zap.Float64(\"time\", float64(time.Since(start))/float64(time.Second)))\n\treturn nil\n}\n\nfunc (k *KVS) Stats() map[string]string {\n\tstats := map[string]string{}\n\n\tstats[\"num_reads\"] = y.NumReads.String()\n\tstats[\"num_writes\"] = y.NumWrites.String()\n\tstats[\"num_bytes_read\"] = y.NumBytesRead.String()\n\tstats[\"num_bytes_written\"] = y.NumBytesWritten.String()\n\tstats[\"num_lsm_gets\"] = y.NumLSMGets.String()\n\tstats[\"num_lsm_bloom_Hits\"] = y.NumLSMBloomHits.String()\n\tstats[\"num_gets\"] = y.NumGets.String()\n\tstats[\"num_puts\"] = y.NumPuts.String()\n\tstats[\"num_blocked_puts\"] = y.NumBlockedPuts.String()\n\tstats[\"num_memtables_gets\"] = y.NumMemtableGets.String()\n\tstats[\"lsm_size\"] = y.LSMSize.String()\n\tstats[\"vlog_size\"] = y.VlogSize.String()\n\tstats[\"pending_writes\"] = y.PendingWrites.String()\n\n\treturn stats\n}\n\nfunc (k *KVS) SnapshotItems() <-chan *protobuf.KeyValuePair {\n\tch := make(chan *protobuf.KeyValuePair, 1024)\n\n\tgo func() {\n\t\tstart := time.Now()\n\n\t\tk.logger.Info(\"start to snapshot items\")\n\n\t\tkeyCount := uint64(0)\n\n\t\tif err := k.db.View(func(txn *badger.Txn) error {\n\t\t\topts := badger.DefaultIteratorOptions\n\t\t\topts.PrefetchSize = 10\n\t\t\tit := txn.NewIterator(opts)\n\t\t\tdefer it.Close()\n\n\t\t\tfor it.Rewind(); it.Valid(); it.Next() {\n\t\t\t\titem := it.Item()\n\t\t\t\tkey := string(item.Key())\n\n\t\t\t\tvar value []byte\n\t\t\t\tif err := item.Value(func(val []byte) error {\n\t\t\t\t\tvalue = append([]byte{}, val...)\n\t\t\t\t\treturn nil\n\t\t\t\t}); err != nil {\n\t\t\t\t\tk.logger.Error(\"failed to get item value\", zap.String(\"key\", key), zap.Error(err))\n\t\t\t\t\treturn err\n\t\t\t\t}\n\n\t\t\t\tch <- &protobuf.KeyValuePair{\n\t\t\t\t\tKey:   key,\n\t\t\t\t\tValue: append([]byte{}, value...),\n\t\t\t\t}\n\n\t\t\t\tkeyCount = keyCount + 1\n\t\t\t}\n\t\t\tch <- nil\n\t\t\treturn nil\n\t\t}); err != nil {\n\t\t\tk.logger.Error(\"failed to snapshot items\", zap.Error(err))\n\t\t\treturn\n\t\t}\n\n\t\tk.logger.Info(\"finished to snapshot items\", zap.Uint64(\"count\", keyCount), zap.Float64(\"time\", float64(time.Since(start))/float64(time.Second)))\n\t}()\n\n\treturn ch\n}\n"
  },
  {
    "path": "version/version.go",
    "content": "package version\n\nvar (\n\tVersion = \"latest\"\n)\n"
  }
]