diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000..1c2eb19 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,80 @@ +# Update the VARIANT arg in devcontainer.json to pick an Go version +ARG VARIANT=1 +FROM golang:1.14 + +# This Dockerfile adds a non-root user with sudo access. Update the “remoteUser” property in +# devcontainer.json to use it. More info: https://aka.ms/vscode-remote/containers/non-root-user. +ARG USERNAME=vscode +ARG USER_UID=1000 +ARG USER_GID=$USER_UID + +# Options for common setup script - SHA generated on release +ARG INSTALL_ZSH="true" +ARG UPGRADE_PACKAGES="false" +ARG COMMON_SCRIPT_SOURCE="https://raw.githubusercontent.com/microsoft/vscode-dev-containers/master/script-library/common-debian.sh" +ARG COMMON_SCRIPT_SHA="dev-mode" + +# Install needed packages and setup non-root user. Use a separate RUN statement to add your own dependencies. +RUN apt-get update \ + && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends curl ca-certificates 2>&1 \ + && curl -sSL ${COMMON_SCRIPT_SOURCE} -o /tmp/common-setup.sh \ + && ([ "${COMMON_SCRIPT_SHA}" = "dev-mode" ] || (echo "${COMMON_SCRIPT_SHA} /tmp/common-setup.sh" | sha256sum -c -)) \ + && /bin/bash /tmp/common-setup.sh "${INSTALL_ZSH}" "${USERNAME}" "${USER_UID}" "${USER_GID}" "${UPGRADE_PACKAGES}" \ + # Clean up + && apt-get autoremove -y \ + && apt-get clean -y \ + && rm -rf /var/lib/apt/lists/* + +# Use Docker within a Codespace +# https://docs.microsoft.com/en-us/visualstudio/codespaces/reference/configuring#use-docker-within-a-codespace +RUN groupadd -g 800 docker +RUN usermod -a -G docker vscode + +# Install Go tools +ARG GO_TOOLS_WITH_MODULES="\ + golang.org/x/tools/gopls \ + honnef.co/go/tools/... \ + golang.org/x/tools/cmd/gorename \ + golang.org/x/tools/cmd/goimports \ + golang.org/x/tools/cmd/guru \ + golang.org/x/lint/golint \ + github.com/mdempsky/gocode \ + github.com/cweill/gotests/... \ + github.com/haya14busa/goplay/cmd/goplay \ + github.com/sqs/goreturns \ + github.com/josharian/impl \ + github.com/davidrjenni/reftools/cmd/fillstruct \ + github.com/uudashr/gopkgs/v2/cmd/gopkgs \ + github.com/ramya-rao-a/go-outline \ + github.com/acroca/go-symbols \ + github.com/godoctor/godoctor \ + github.com/rogpeppe/godef \ + github.com/zmb3/gogetdoc \ + github.com/fatih/gomodifytags \ + github.com/mgechev/revive \ + github.com/go-delve/delve/cmd/dlv" +RUN mkdir -p /tmp/gotools \ + && cd /tmp/gotools \ + && export GOPATH=/tmp/gotools \ + # Go tools w/module support + && export GO111MODULE=on \ + && (echo "${GO_TOOLS_WITH_MODULES}" | xargs -n 1 go get -x )2>&1 \ + # gocode-gomod + && export GO111MODULE=auto \ + && go get -x -d github.com/stamblerre/gocode 2>&1 \ + && go build -o gocode-gomod github.com/stamblerre/gocode \ + # golangci-lint + && curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b /usr/local/bin 2>&1 \ + # Move Go tools into path and clean up + && mv /tmp/gotools/bin/* /usr/local/bin/ \ + && mv gocode-gomod /usr/local/bin/ \ + && rm -rf /tmp/gotools + +ENV GO111MODULE=auto + +RUN go get github.com/golang/protobuf/protoc-gen-go + +RUN apt-get update \ + && export DEBIAN_FRONTEND=noninteractive \ + && apt-get -y install --no-install-recommends protobuf-compiler docker.io \ No newline at end of file diff --git a/.devcontainer/build.sh b/.devcontainer/build.sh new file mode 100755 index 0000000..4bbed2f --- /dev/null +++ b/.devcontainer/build.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -o nounset +set -o errexit +set -o pipefail + +readonly CMD=${1:-image} +readonly IMAGE=cloudstateio/cloudstate-go-devcontainer:latest +docker build . -t "$IMAGE" +if [ "$CMD" == "push" ]; then + docker push "$IMAGE" +fi diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..4be6781 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,19 @@ +{ + "name": "Go", + "image": "cloudstateio/cloudstate-go-devcontainer", + "runArgs": [ + "--cap-add=SYS_PTRACE", + "--security-opt", + "seccomp=unconfined", + "-v", + "/var/run/docker.sock:/var/run/docker.sock" + ], + "settings": { + "terminal.integrated.shell.linux": "/bin/bash", + "go.gopath": "/go" + }, + "extensions": [ + "golang.go" + ], + "remoteUser": "vscode" +} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 5adf9f5..e764ed5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,26 +2,42 @@ language: go os: - linux go: - - 1.13.x - + - 1.14.x +services: + - docker +env: + global: + # encrypted with: travis encrypt --pro -r cloudstateio/go-support DEPLOY_DOCS_TOKEN= + - secure: "L1uMy3mR5U+0HFmjJwSD6i/av667T187DkzIlRwfTnEGPG6LoZ5EwyGC/IxbKbV2EyUmxt7zDO+OXvsiZx0l0mXZ5ozAKdTB7eb/ujhinwnvB82OtKu8ejvZqI0ooPO+D1RlxqZF5HCX69L0DfTjhytkqLUIlN4CTtSO4ElJ/1Ottg0c3qiNUYvNdFqsKsF7Dq7EJU8G/vZ6o1WCUJzawLshOGDQ9jSL14QnKquFr/cMXHcg3GgiPVl2NFWAld0fOuNpYqUy2X3O7V4/FOJGe+btOao4xQyVsn9V/1VFsqRCyp1uy+kPbQbA0f+fBY3CnDpLKHrhYv8TDdfP9tbUEIhGikc+aqYeGOP6+4vPK/Xi/p2pZEZErPcBfc7CoJECNG4csMjq0GGdhp6UYJO1JPMVrLFZsWLoxPiXTkreQ+Gj4+Jgia20xfcUR/tkZrCQMnkySfFPHK48g2VOadfIZNz6hbdMGrZUarMrWC/hi3DIUdoT0Wn6y5LuP8goAbIBI/+KXvECIdiqTHu7WIwtdesTIZJvHhdp44zec8Teb0Bo6uYoIrKXvfTQbgvTzMzZO8DZ1L21OL7EKD9H6rvFabZXz5I2i9695Q6gkQYmK6Twg6CK1p/aZXmJWN8QXceXPavl3iNvC2fMSFxZvHBuqAjknCQlmTH7/BKyEw5AQ/Q=" + # Docker hub password; encrypted with: travis encrypt --pro -r cloudstateio/go-support DOCKER_PASSWORD={password} + - secure: "OMwsvgBLGl+804bEIo9UigU9EDz3jnKR3oCkowbzfeT+yGb/aGqUFBBBw6fzruaB3h8Uyhe1wQUgAOwEE7xMQmNhKvHEYW0esQZQHmGeUgyCyeelh5U7iamivokXnCx2zhRj+kgd4gQE+RCunhqDcHNXGxDEf1GmQ0U/HAYVNyt6jEOVEEqb0UiG0NkTO6wRcw5fJsNrb1kPRHBM5OkoVlSNwu90kVlDgo/MPbEaNw1qkx52cA1FrTuBap4sHZNXs4BRFAoIivJNrHhrjiz41jdblcmBPLnL6hkGUguJKCBTxyuKInRKI4/grU47yg/0KNqjGOOF1MZcNbp1e09vZ1TDLHxYj4Qy3hclJTrpemcT5xdoud4nsIVyAFstR1xm2J6iKNJ+qz85wWYhxfgk8o3MJFepYqEZsNaDfGd/lWHYRXml5UJwlwA5eG/D6Q6CKn4qF1DUn5+yLgsO73MQ1qAMADgp1dhkhHELcs94w8GOWCvaNy7Zt4fKpEOLc1ThCnKQYjXQ3zOsEcciuoYtK0QxgaqpHgnvNZcZOB3H/iBkdnNW3YaQUl2+4Ooq/JmYissj6GXD1NbP5xNCEThFCGsroHm6OAJRM3BaWmna6DBworwg+lr6PMyn9fVhbOJKaH5wdfwQXOFwQ798rxK6n/oZVIBSztHhY29JNCZMtoo=" jobs: include: - stage: build before_install: - go get -t -v ./... script: - - go test -v -race -coverprofile=coverage.txt -covermode=atomic -bench=. ./... + - go test -v -race -coverprofile=coverage_all.txt -covermode=atomic -coverpkg=github.com/cloudstateio/go-support/cloudstate/... ./... + - cat coverage_all.txt | grep -v ".pb.go" > coverage.txt && rm coverage_all.txt after_success: - if [ "$TRAVIS_OS_NAME" = "linux" ]; then bash <(curl -s https://codecov.io/bash); fi - - - stage: validate docs - script: make -C docs - + - stage: verification + name: tck verification + script: + - cd tck && ./run_tck.sh - stage: deploy docs + name: deploy release docs to cloudstate.io if: tag =~ ^v - script: make -C docs deploy - -env: - global: - # encrypted with: travis encrypt --pro -r cloudstateio/go-support DEPLOY_DOCS_TOKEN= - secure: "L1uMy3mR5U+0HFmjJwSD6i/av667T187DkzIlRwfTnEGPG6LoZ5EwyGC/IxbKbV2EyUmxt7zDO+OXvsiZx0l0mXZ5ozAKdTB7eb/ujhinwnvB82OtKu8ejvZqI0ooPO+D1RlxqZF5HCX69L0DfTjhytkqLUIlN4CTtSO4ElJ/1Ottg0c3qiNUYvNdFqsKsF7Dq7EJU8G/vZ6o1WCUJzawLshOGDQ9jSL14QnKquFr/cMXHcg3GgiPVl2NFWAld0fOuNpYqUy2X3O7V4/FOJGe+btOao4xQyVsn9V/1VFsqRCyp1uy+kPbQbA0f+fBY3CnDpLKHrhYv8TDdfP9tbUEIhGikc+aqYeGOP6+4vPK/Xi/p2pZEZErPcBfc7CoJECNG4csMjq0GGdhp6UYJO1JPMVrLFZsWLoxPiXTkreQ+Gj4+Jgia20xfcUR/tkZrCQMnkySfFPHK48g2VOadfIZNz6hbdMGrZUarMrWC/hi3DIUdoT0Wn6y5LuP8goAbIBI/+KXvECIdiqTHu7WIwtdesTIZJvHhdp44zec8Teb0Bo6uYoIrKXvfTQbgvTzMzZO8DZ1L21OL7EKD9H6rvFabZXz5I2i9695Q6gkQYmK6Twg6CK1p/aZXmJWN8QXceXPavl3iNvC2fMSFxZvHBuqAjknCQlmTH7/BKyEw5AQ/Q=" + language: scala + script: cd docs && sbt deploy + - stage: deploy docs + name: deploy snapshot docs to cloudstate.io + if: branch = master AND type = push + language: scala + script: cd docs && sbt deploy + - stage: deploy devcontainer image + name: deploy devcontainer image to dockerhub + if: branch = master AND type = push + script: + - echo "$DOCKER_PASSWORD" | docker login -u cloudstatebot --password-stdin + - pushd . && cd .devcontainer && ./build.sh push && popd diff --git a/README.md b/README.md index 0f0af2b..bca4727 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ # Cloudstate stateful service support in Go -[![Build Status](https://travis-ci.com/cloudstateio/go-support.svg)](https://travis-ci.com/cloudstateio/go-support) +[![GoDev](https://img.shields.io/static/v1?label=godev&message=reference&color=00add8)](https://pkg.go.dev/mod/github.com/cloudstateio/go-support) +[![Build Status](https://travis-ci.com/cloudstateio/go-support.svg)](https://travis-ci.com/cloudstateio/go-support) +[![Go Report Card](https://goreportcard.com/badge/github.com/cloudstateio/go-support)](https://goreportcard.com/report/github.com/cloudstateio/go-support) [![codecov](https://codecov.io/gh/cloudstateio/go-support/branch/master/graph/badge.svg)](https://codecov.io/gh/cloudstateio/go-support) -[![GoDoc](https://godoc.org/github.com/cloudstateio/go-support/cloudstate?status.svg)](https://godoc.org/github.com/cloudstateio/go-support/cloudstate) This package provides support for writing [Cloudstate](https://github.com/cloudstateio/cloudstate) stateful functions in Go. diff --git a/build/TCK.Dockerfile b/build/TCK.Dockerfile index d31efa8..a17db80 100644 --- a/build/TCK.Dockerfile +++ b/build/TCK.Dockerfile @@ -1,23 +1,22 @@ -FROM golang:1.13.1-alpine3.10 +FROM golang:1.14.4-alpine3.12 as builder RUN apk --no-cache add git +RUN apk --no-cache add ca-certificates WORKDIR /go/src/app COPY . . - +# # -race and therefore CGO needs gcc, we don't want it to have in our build -RUN CGO_ENABLED=0 go build -v -o tck_shoppingcart ./tck/cmd/tck_shoppingcart +RUN CGO_ENABLED=0 go build -v -o tck_eventsourced ./tck/cmd/tck_eventsourced RUN go install -v ./... - +# # multistage – copy over the binary FROM alpine:latest -RUN apk --no-cache add ca-certificates - -WORKDIR /root/ -COPY --from=0 /go/bin/tck_shoppingcart . - +RUN mkdir -p /srv/ +WORKDIR /srv +COPY --from=builder /go/bin/tck_eventsourced . +COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ EXPOSE 8080 ENV HOST 0.0.0.0 ENV PORT 8080 - -CMD ["./tck_shoppingcart"] +CMD ["./tck_eventsourced"] diff --git a/build/build-and-publish-docker-image-tck.sh b/build/build-and-publish-docker-image-tck.sh index 933b86a..5a24da7 100755 --- a/build/build-and-publish-docker-image-tck.sh +++ b/build/build-and-publish-docker-image-tck.sh @@ -4,5 +4,5 @@ set -o nounset set -o errexit set -o pipefail -docker build -t gcr.io/mrcllnz/cloudstate-go-tck:latest -f ./build/TCK.Dockerfile . -docker push gcr.io/mrcllnz/cloudstate-go-tck:latest +DOCKER_BUILDKIT=1 docker build -t cloudstateio/cloudstate-go-tck:latest -f ./build/TCK.Dockerfile . || exit $? +docker push cloudstateio/cloudstate-go-tck:latest diff --git a/build/compile-pb.sh b/build/compile-pb.sh index 93d65d0..fa47573 100755 --- a/build/compile-pb.sh +++ b/build/compile-pb.sh @@ -4,12 +4,70 @@ set -o nounset set -o errexit set -o pipefail -# CloudState protocol -protoc --go_out=plugins=grpc,paths=source_relative:. --proto_path=protobuf/frontend/ protobuf/frontend/cloudstate/entity_key.proto -protoc --go_out=plugins=grpc:. --proto_path=protobuf/protocol/ protobuf/protocol/cloudstate/entity.proto -protoc --go_out=plugins=grpc:. --proto_path=protobuf/protocol/ protobuf/protocol/cloudstate/event_sourced.proto -protoc --go_out=plugins=grpc:. --proto_path=protobuf/protocol/ protobuf/protocol/cloudstate/function.proto - -# TCK shopping cart sample -protoc --go_out=plugins=grpc:. --proto_path=protobuf/protocol/ --proto_path=protobuf/frontend/ --proto_path=protobuf/proxy/ --proto_path=protobuf/example/ protobuf/example/shoppingcart/shoppingcart.proto -protoc --go_out=plugins=grpc,paths=source_relative:tck/shoppingcart/persistence --proto_path=protobuf/protocol/ --proto_path=protobuf/frontend/ --proto_path=protobuf/proxy/ --proto_path=protobuf/example/shoppingcart/persistence/ protobuf/example/shoppingcart/persistence/domain.proto +# Cloudstate +protoc --go_out=plugins=grpc,paths=source_relative:cloudstate/protocol --proto_path=protobuf/protocol/cloudstate entity.proto +protoc --go_out=plugins=grpc,paths=source_relative:. --proto_path=protobuf/frontend/ cloudstate/entity_key.proto +protoc --go_out=plugins=grpc,paths=source_relative:cloudstate/entity --proto_path=protobuf/protocol \ + --proto_path=protobuf/protocol/cloudstate crdt.proto +protoc --go_out=plugins=grpc,paths=source_relative:cloudstate/entity --proto_path=protobuf/protocol/ \ + --proto_path=protobuf/protocol/cloudstate function.proto +protoc --go_out=plugins=grpc,paths=source_relative:cloudstate/entity --proto_path=protobuf/protocol/ \ + --proto_path=protobuf/protocol/cloudstate event_sourced.proto + +# TCK CRDT +protoc --go_out=plugins=grpc,paths=source_relative:./tck/crdt \ + --proto_path=protobuf/protocol \ + --proto_path=protobuf/frontend \ + --proto_path=protobuf/frontend/cloudstate \ + --proto_path=protobuf/proxy \ + --proto_path=protobuf/tck tck_crdt.proto + +# TCK Eventsourced +protoc --go_out=plugins=grpc,paths=source_relative:./tck/eventsourced \ + --proto_path=protobuf/protocol \ + --proto_path=protobuf/frontend \ + --proto_path=protobuf/frontend/cloudstate \ + --proto_path=protobuf/proxy \ + --proto_path=protobuf/tck/cloudstate/tck/model \ + --proto_path=protobuf/tck eventsourced.proto + +# CRDT shopping cart example +protoc --go_out=plugins=grpc,paths=source_relative:./example/crdt_shoppingcart/shoppingcart --proto_path=protobuf/protocol \ + --proto_path=protobuf/frontend \ + --proto_path=protobuf/frontend/cloudstate \ + --proto_path=protobuf/proxy \ + --proto_path=example/crdt_shoppingcart/shoppingcart shoppingcart.proto hotitems.proto + +protoc --go_out=plugins=grpc,paths=source_relative:./example/crdt_shoppingcart/domain --proto_path=protobuf/protocol \ + --proto_path=protobuf/frontend \ + --proto_path=protobuf/frontend/cloudstate \ + --proto_path=protobuf/proxy \ + --proto_path=example/crdt_shoppingcart/domain domain.proto + +# event sourced shopping cart example +protoc --go_out=plugins=grpc,paths=source_relative:./example/shoppingcart/ \ + --proto_path=protobuf/protocol \ + --proto_path=protobuf/frontend \ + --proto_path=protobuf/frontend/cloudstate \ + --proto_path=protobuf/proxy \ + --proto_path=example/shoppingcart shoppingcart.proto +protoc --go_out=plugins=grpc,paths=source_relative:./example/shoppingcart/persistence \ + --proto_path=protobuf/protocol \ + --proto_path=protobuf/frontend \ + --proto_path=protobuf/frontend/cloudstate \ + --proto_path=protobuf/proxy \ + --proto_path=example/shoppingcart/persistence domain.proto + +# chat example +protoc --go_out=plugins=grpc,paths=source_relative:./example/chat/presence/ \ + --proto_path=protobuf/protocol \ + --proto_path=protobuf/frontend \ + --proto_path=protobuf/frontend/cloudstate \ + --proto_path=protobuf/proxy \ + --proto_path=example/chat/presence/ example/chat/presence/presence.proto +protoc --go_out=plugins=grpc,paths=source_relative:./example/chat/friends/ \ + --proto_path=protobuf/protocol \ + --proto_path=protobuf/frontend \ + --proto_path=protobuf/frontend/cloudstate \ + --proto_path=protobuf/proxy \ + --proto_path=example/chat/friends/ example/chat/friends/friends.proto diff --git a/build/fetch-cloudstate-pb.sh b/build/fetch-cloudstate-pb.sh deleted file mode 100755 index 3e8714d..0000000 --- a/build/fetch-cloudstate-pb.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/usr/bin/env bash - -set -o nounset -set -o errexit -set -o pipefail - -function fetch() { - local path=$1 - local tag=$2 - mkdir -p "protobuf/$(dirname $path)" - curl -o "protobuf/${path}" "https://raw.githubusercontent.com/cloudstateio/cloudstate/${tag}/protocols/${path}" -} - -tag=$1 - -# CloudState protocol -fetch "protocol/cloudstate/entity.proto" "${tag}" -fetch "protocol/cloudstate/event_sourced.proto" "${tag}" -fetch "protocol/cloudstate/function.proto" "${tag}" -fetch "protocol/cloudstate/crdt.proto" "${tag}" - -# TCK shopping cart example -fetch "example/shoppingcart/shoppingcart.proto" "${tag}" -fetch "example/shoppingcart/persistence/domain.proto" "${tag}" - -# CloudState frontend -fetch "frontend/cloudstate/entity_key.proto" "${tag}" - -# dependencies -fetch "proxy/grpc/reflection/v1alpha/reflection.proto" "${tag}" -fetch "frontend/google/api/annotations.proto" "${tag}" -fetch "frontend/google/api/http.proto" "${tag}" diff --git a/cloudstate/cloudstate.go b/cloudstate/cloudstate.go index e2676d0..3679e0a 100644 --- a/cloudstate/cloudstate.go +++ b/cloudstate/cloudstate.go @@ -16,230 +16,92 @@ package cloudstate import ( - "context" "errors" "fmt" "log" "net" "os" - "runtime" + "github.com/cloudstateio/go-support/cloudstate/crdt" + "github.com/cloudstateio/go-support/cloudstate/discovery" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/cloudstate/eventsourced" "github.com/cloudstateio/go-support/cloudstate/protocol" - "github.com/golang/protobuf/descriptor" - "github.com/golang/protobuf/proto" - filedescr "github.com/golang/protobuf/protoc-gen-go/descriptor" - "github.com/golang/protobuf/ptypes/empty" "google.golang.org/grpc" ) -const ( - SupportLibraryVersion = "0.1.1" - SupportLibraryName = "cloudstate-go-support" -) - -// CloudState is an instance of a CloudState User Function +// CloudState is an instance of a Cloudstate User Function. type CloudState struct { - server *grpc.Server - entityDiscoveryServer *EntityDiscoveryServer - eventSourcedServer *EventSourcedServer + grpcServer *grpc.Server + entityDiscoveryServer *discovery.EntityDiscoveryServer + eventSourcedServer *eventsourced.Server + crdtServer *crdt.Server } // New returns a new CloudState instance. -func New(config Config) (*CloudState, error) { - eds, err := newEntityDiscoveryServer(config) - if err != nil { - return nil, err - } +func New(c protocol.Config) (*CloudState, error) { cs := &CloudState{ - server: grpc.NewServer(), - entityDiscoveryServer: eds, - eventSourcedServer: newEventSourcedServer(), - } - protocol.RegisterEntityDiscoveryServer(cs.server, cs.entityDiscoveryServer) - protocol.RegisterEventSourcedServer(cs.server, cs.eventSourcedServer) + grpcServer: grpc.NewServer(), + entityDiscoveryServer: discovery.NewServer(c), + eventSourcedServer: eventsourced.NewServer(), + crdtServer: crdt.NewServer(), + } + protocol.RegisterEntityDiscoveryServer(cs.grpcServer, cs.entityDiscoveryServer) + entity.RegisterEventSourcedServer(cs.grpcServer, cs.eventSourcedServer) + entity.RegisterCrdtServer(cs.grpcServer, cs.crdtServer) return cs, nil } -// Config go get a CloudState instance configured. -type Config struct { - ServiceName string - ServiceVersion string -} - -// DescriptorConfig configures service and dependent descriptors. -type DescriptorConfig struct { - Service string - Domain []string - DomainMessages []descriptor.Message -} - -func (dc DescriptorConfig) AddDomainMessage(m descriptor.Message) DescriptorConfig { - dc.DomainMessages = append(dc.DomainMessages, m) - return dc -} - -func (dc DescriptorConfig) AddDomainDescriptor(filename string) DescriptorConfig { - dc.Domain = append(dc.Domain, filename) - return dc +// RegisterEventSourced registers an event sourced entity. +func (cs *CloudState) RegisterEventSourced(entity *eventsourced.Entity, config protocol.DescriptorConfig) error { + if err := cs.eventSourcedServer.Register(entity); err != nil { + return err + } + if err := cs.entityDiscoveryServer.RegisterEventSourcedEntity(entity, config); err != nil { + return err + } + return nil } -// RegisterEventSourcedEntity registers an event sourced entity for CloudState. -func (cs *CloudState) RegisterEventSourcedEntity(ese *EventSourcedEntity, config DescriptorConfig) (err error) { - ese.registerOnce.Do(func() { - if err = ese.init(); err != nil { - return - } - if err = cs.eventSourcedServer.registerEntity(ese); err != nil { - return - } - if err = cs.entityDiscoveryServer.registerEntity(ese, config); err != nil { - return - } - }) - return +// RegisterCRDT registers a CRDT entity. +func (cs *CloudState) RegisterCRDT(entity *crdt.Entity, config protocol.DescriptorConfig) error { + if err := cs.crdtServer.Register(entity); err != nil { + return err + } + if err := cs.entityDiscoveryServer.RegisterCRDTEntity(entity, config); err != nil { + return err + } + return nil } -// Run runs the CloudState instance. +// Run runs the CloudState instance on the interface and port defined by +// the HOST and PORT environment variable. func (cs *CloudState) Run() error { host, ok := os.LookupEnv("HOST") if !ok { - return fmt.Errorf("unable to get environment variable \"HOST\"") + return errors.New("unable to get environment variable \"HOST\"") } port, ok := os.LookupEnv("PORT") if !ok { - return fmt.Errorf("unable to get environment variable \"PORT\"") + return errors.New("unable to get environment variable \"PORT\"") } lis, err := net.Listen("tcp", fmt.Sprintf("%s:%s", host, port)) if err != nil { - return fmt.Errorf("failed to listen: %v", err) + return fmt.Errorf("failed to listen: %w", err) } - if e := cs.server.Serve(lis); e != nil { - return fmt.Errorf("failed to grpcServer.Serve for: %v", lis) + if err := cs.RunWithListener(lis); err != nil { + return fmt.Errorf("failed to RunWithListener for: %v with: %w", lis, err) } return nil } -// EntityDiscoveryServer implements the Cloudstate discovery protocol. -type EntityDiscoveryServer struct { - fileDescriptorSet *filedescr.FileDescriptorSet - entitySpec *protocol.EntitySpec - message *descriptor.Message +// Run runs the CloudState instance with a listener provided. +func (cs *CloudState) RunWithListener(lis net.Listener) error { + return cs.grpcServer.Serve(lis) } -// newEntityDiscoveryServer returns a new and initialized EntityDiscoveryServer. -func newEntityDiscoveryServer(config Config) (*EntityDiscoveryServer, error) { - svr := &EntityDiscoveryServer{} - svr.entitySpec = &protocol.EntitySpec{ - Entities: make([]*protocol.Entity, 0), - ServiceInfo: &protocol.ServiceInfo{ - ServiceName: config.ServiceName, - ServiceVersion: config.ServiceVersion, - ServiceRuntime: fmt.Sprintf("%s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH), - SupportLibraryName: SupportLibraryName, - SupportLibraryVersion: SupportLibraryVersion, - }, - } - svr.fileDescriptorSet = &filedescr.FileDescriptorSet{ - File: make([]*filedescr.FileDescriptorProto, 0), - } - return svr, nil -} - -// Discover returns an entity spec for registered entities. -func (r *EntityDiscoveryServer) Discover(_ context.Context, pi *protocol.ProxyInfo) (*protocol.EntitySpec, error) { - log.Printf("Received discovery call from sidecar [%s w%s] supporting Cloudstate %v.%v\n", - pi.ProxyName, - pi.ProxyVersion, - pi.ProtocolMajorVersion, - pi.ProtocolMinorVersion, - ) - log.Printf("Responding with: %v\n", r.entitySpec.GetServiceInfo()) - return r.entitySpec, nil -} - -// ReportError logs any user function error reported by the Cloudstate proxy. -func (r *EntityDiscoveryServer) ReportError(_ context.Context, fe *protocol.UserFunctionError) (*empty.Empty, error) { - log.Printf("ReportError: %v\n", fe) - return &empty.Empty{}, nil -} - -func (r *EntityDiscoveryServer) updateSpec() (err error) { - protoBytes, err := proto.Marshal(r.fileDescriptorSet) - if err != nil { - return errors.New("unable to Marshal FileDescriptorSet") - } - r.entitySpec.Proto = protoBytes - return nil -} - -func (r *EntityDiscoveryServer) resolveFileDescriptors(dc DescriptorConfig) error { - // service - if dc.Service != "" { - if err := r.registerFileDescriptorProto(dc.Service); err != nil { - return err - } - } - // and dependent domain descriptors - for _, dp := range dc.Domain { - if err := r.registerFileDescriptorProto(dp); err != nil { - return err - } - } - for _, dm := range dc.DomainMessages { - if err := r.registerFileDescriptor(dm); err != nil { - return err - } - } - return nil -} - -func (r *EntityDiscoveryServer) registerEntity(e *EventSourcedEntity, config DescriptorConfig) error { - if err := r.resolveFileDescriptors(config); err != nil { - return fmt.Errorf("failed to resolveFileDescriptor for DescriptorConfig: %+v: %w", config, err) - } - r.entitySpec.Entities = append(r.entitySpec.Entities, &protocol.Entity{ - EntityType: EventSourced, - ServiceName: e.ServiceName, - PersistenceId: e.PersistenceID, - }) - return r.updateSpec() -} - -func (r *EntityDiscoveryServer) hasRegistered(filename string) bool { - for _, f := range r.fileDescriptorSet.File { - if f.GetName() == filename { - return true - } - } - return false -} - -func (r *EntityDiscoveryServer) registerFileDescriptorProto(filename string) error { - if r.hasRegistered(filename) { - return nil - } - descriptorProto, err := unpackFile(proto.FileDescriptor(filename)) - if err != nil { - return fmt.Errorf("failed to registerFileDescriptorProto for filename: %s: %w", filename, err) - } - r.fileDescriptorSet.File = append(r.fileDescriptorSet.File, descriptorProto) - for _, fn := range descriptorProto.Dependency { - err := r.registerFileDescriptorProto(fn) - if err != nil { - return err - } - } - return r.updateSpec() -} - -func (r *EntityDiscoveryServer) registerFileDescriptor(msg descriptor.Message) error { - fd, _ := descriptor.ForMessage(msg) // this can panic - if r := recover(); r != nil { - return fmt.Errorf("descriptor.ForMessage panicked (%v) for: %+v", r, msg) - } - if r.hasRegistered(fd.GetName()) { - return nil - } - r.fileDescriptorSet.File = append(r.fileDescriptorSet.File, fd) - return nil +// Stop gracefully stops the Cloudstate instance. +func (cs *CloudState) Stop() { + cs.grpcServer.GracefulStop() + log.Println("CloudState stopped") } diff --git a/cloudstate/cloudstate_test.go b/cloudstate/cloudstate_test.go index ee1fdc8..26775e4 100644 --- a/cloudstate/cloudstate_test.go +++ b/cloudstate/cloudstate_test.go @@ -24,20 +24,21 @@ import ( "strings" "testing" + "github.com/cloudstateio/go-support/cloudstate/discovery" "github.com/cloudstateio/go-support/cloudstate/protocol" _ "google.golang.org/genproto/googleapis/api/annotations" ) func TestNewCloudState(t *testing.T) { - cloudState, _ := New(Config{}) - si := cloudState.server.GetServiceInfo() + cloudState, _ := New(protocol.Config{}) + si := cloudState.grpcServer.GetServiceInfo() if si == nil { t.Fail() } } func TestEntityDiscoveryResponderDiscover(t *testing.T) { - server, _ := newEntityDiscoveryServer(Config{ + server := discovery.NewServer(protocol.Config{ ServiceName: "service.one", ServiceVersion: "0.0.1", }) @@ -79,7 +80,7 @@ func captureOutput(f func()) string { } func TestEntityDiscoveryResponderReportError(t *testing.T) { - server, _ := newEntityDiscoveryServer(Config{ + server := discovery.NewServer(protocol.Config{ ServiceName: "service.one", ServiceVersion: "0.0.1", }) diff --git a/cloudstate/crdt/cmdcontext.go b/cloudstate/crdt/cmdcontext.go new file mode 100644 index 0000000..67e44bc --- /dev/null +++ b/cloudstate/crdt/cmdcontext.go @@ -0,0 +1,214 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "errors" + "fmt" + "reflect" + "strings" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" +) + +var ErrCtxFailCalled = errors.New("context failed") +var ErrStateChanged = errors.New("CRDT change not allowed") + +type ChangeFunc func(c *CommandContext) (*any.Any, error) +type CancelFunc func(c *CommandContext) error + +// A CommandContext carries change and cancel function handlers and other +// values to handle a command over different phases of a commands lifecycle. +type CommandContext struct { + *Context + CommandID CommandID + change ChangeFunc + cancel CancelFunc + cmd *protocol.Command + forward *protocol.Forward + sideEffects []*protocol.SideEffect + // ended means, we will send a streamed message where we mark the message + // as the last one in the stream and therefore, the streamed command has ended. + ended bool +} + +// Command returns the protobuf message the context is handling as a command. +func (c *CommandContext) Command() *protocol.Command { + return c.cmd +} + +// Streamed returns whether the command handled by the context is streamed. +func (c *CommandContext) Streamed() bool { + if c.cmd == nil { + return false + } + return c.cmd.Streamed +} + +// ChangeFunc sets the function to be called whenever the CRDT is changed. +// For non-streamed contexts this is a `no operation`. +func (c *CommandContext) ChangeFunc(f ChangeFunc) { + if !c.Streamed() { + return + } + c.change = f +} + +// CancelFunc registers an on cancel handler for this command. +// The registered function will be invoked if the client initiates a stream cancel. +// It will not be invoked if the entity cancels the stream itself. +// The CancelFunc may update the CRDT, and may emit side effects. +func (c *CommandContext) CancelFunc(f CancelFunc) { + if !c.Streamed() { + return + } + c.cancel = f +} + +// EndStream marks a command stream to be ended. +func (c *CommandContext) EndStream() { + if !c.Streamed() { + return + } + c.ended = true +} + +// Forward forwards this command to another service. +// The protocol.Forward provided has to ensure it references a valid service and command. +func (c *CommandContext) Forward(forward *protocol.Forward) { + if c.forward != nil { + c.fail(errors.New("this context has already forwarded")) + } + c.forward = forward +} + +// SideEffect adds a side effect to being emitted after the current command successfully has completed. +func (c *CommandContext) SideEffect(effect *protocol.SideEffect) { + c.sideEffects = append(c.sideEffects, effect) +} + +func (c *CommandContext) runCommand(cmd *protocol.Command) (*any.Any, error) { + // unmarshal the commands message + msgName := strings.TrimPrefix(cmd.GetPayload().GetTypeUrl(), "type.googleapis.com/") + messageType := proto.MessageType(msgName) + message, ok := reflect.New(messageType.Elem()).Interface().(proto.Message) + if !ok { + return nil, fmt.Errorf("messageType is no proto.Message: %v", messageType) + } + if err := proto.Unmarshal(cmd.Payload.Value, message); err != nil { + return nil, err + } + return c.Instance.HandleCommand(c, cmd.Name, message) +} + +func (c *CommandContext) clientActionFor(reply *any.Any) (*protocol.ClientAction, error) { + if c.failed != nil { + return &protocol.ClientAction{ + Action: &protocol.ClientAction_Failure{ + Failure: &protocol.Failure{ + CommandId: c.CommandID.Value(), + Description: c.failed.Error(), + }, + }, + }, nil + } + if reply != nil { + if c.forward != nil { + return nil, errors.New("this context has already been forwarded") + } + return &protocol.ClientAction{ + Action: &protocol.ClientAction_Reply{ + Reply: &protocol.Reply{ + Payload: reply, + }, + }, + }, nil + } + if c.forward != nil { + return &protocol.ClientAction{ + Action: &protocol.ClientAction_Forward{ + Forward: c.forward, + }, + }, nil + } + return nil, nil +} + +func (c *CommandContext) stateAction() *entity.CrdtStateAction { + if c.created && c.crdt.HasDelta() { + c.created = false + if c.deleted { + c.crdt = nil + return nil + } + c.crdt.resetDelta() + return &entity.CrdtStateAction{ + Action: &entity.CrdtStateAction_Create{Create: c.crdt.State()}, + } + } + if c.created && c.deleted { + c.created = false + c.crdt = nil + return nil + } + if c.deleted { + c.crdt = nil + return &entity.CrdtStateAction{ + Action: &entity.CrdtStateAction_Delete{Delete: &entity.CrdtDelete{}}, + } + } + if c.crdt.HasDelta() { + delta := c.crdt.Delta() + c.crdt.resetDelta() + return &entity.CrdtStateAction{ + Action: &entity.CrdtStateAction_Update{Update: delta}, + } + } + return nil +} + +func (c *CommandContext) clearSideEffect() { + c.sideEffects = make([]*protocol.SideEffect, 0) +} + +func (c *CommandContext) changed() (reply *any.Any, err error) { + reply, err = c.change(c) + if c.crdt.HasDelta() { + // the user is not allowed to change the CRDT. + err = ErrStateChanged + } + return +} + +func (c *CommandContext) cancelled() error { + return c.cancel(c) +} + +func (c *Context) commandContextFor(cmd *protocol.Command) *CommandContext { + return &CommandContext{ + Context: c, + cmd: cmd, + CommandID: CommandID(cmd.Id), + sideEffects: make([]*protocol.SideEffect, 0), + } +} + +func (c *CommandContext) trackChanges() { + c.streamedCtx[c.CommandID] = c +} diff --git a/cloudstate/crdt/context.go b/cloudstate/crdt/context.go new file mode 100644 index 0000000..2bc9a6a --- /dev/null +++ b/cloudstate/crdt/context.go @@ -0,0 +1,89 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "context" + "errors" +) + +// Context holds the context of a running entity. +type Context struct { + // EntityID is the ID of the entity. + EntityID EntityID + // Entity describes the instance that is used as an entity. + Entity *Entity + // Instance is the instance of the entity this context is for. + Instance EntityHandler + // the root CRDT managed by this user function. + crdt CRDT + // ctx is the context.Context from the stream this context is assigned to. + ctx context.Context + // streamedCtx are command contexts of streamed commands. + streamedCtx map[CommandID]*CommandContext + // created defines if the CRDT was created by the user function. + created bool + deleted bool + // failed holds an internal error occurred during message processing where no error path was possible. + // user function Emit calls are an example. + failed error +} + +// StreamCtx returns the context.Context from the transport stream this context is assigned to. +func (c *Context) StreamCtx() context.Context { + return c.ctx +} + +// TODO: do we really need that? +func (c *Context) CRDT() CRDT { + return c.crdt +} + +// Delete marks the CRDT to be deleted initiated by the user function. +func (c *Context) Delete() { + c.deleted = true +} + +// fail fails the command context with the given message. +func (c *Context) fail(err error) { + if c.failed != nil { + return + } + c.failed = err +} + +// initDefault initializes the CRDT with a default value if it's not already set. +func (c *Context) initDefault() error { + // with a handled state, the CRDT might already be set. + if c.crdt != nil { + // TODO: the type of c.Instance.Default(c) and c.crdt have to match. should we check that? + return c.Instance.Set(c, c.crdt) + } + // with no state given, the entity instance can provide one. + var err error + if c.crdt, err = c.Instance.Default(c); err != nil { + return err + } + if c.crdt == nil { + return errors.New("no default CRDT set by the entities default method") + } + // the entity gets the CRDT to be set. + if err := c.Instance.Set(c, c.crdt); err != nil { + return err + } + c.created = true + return nil +} diff --git a/cloudstate/types.go b/cloudstate/crdt/doc.go similarity index 87% rename from cloudstate/types.go rename to cloudstate/crdt/doc.go index 1e53adc..3ad4553 100644 --- a/cloudstate/types.go +++ b/cloudstate/crdt/doc.go @@ -13,8 +13,5 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cloudstate - -const ( - EventSourced = "cloudstate.eventsourced.EventSourced" -) +// Package crdt implements the Cloudstate CRDT state model support. +package crdt diff --git a/cloudstate/crdt/entity.go b/cloudstate/crdt/entity.go new file mode 100644 index 0000000..5c862c7 --- /dev/null +++ b/cloudstate/crdt/entity.go @@ -0,0 +1,42 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" +) + +// Entity captures an Entity with its ServiceName. It is used to be registered +// as an CRDT entity on a Cloudstate instance. +type Entity struct { + // ServiceName is the fully qualified name of the service that implements + // this entities interface. Setting it is mandatory. + ServiceName ServiceName + // EntityFunc creates a new entity. + EntityFunc func(id EntityID) EntityHandler +} + +// EntityHandler has to be implemented by any type that wants to get +// registered as a crdt.Entity +// tag::entity-handler[] +type EntityHandler interface { + HandleCommand(ctx *CommandContext, name string, msg proto.Message) (*any.Any, error) + Default(ctx *Context) (CRDT, error) + Set(ctx *Context, state CRDT) error +} + +// end::entity-handler[] diff --git a/cloudstate/crdt/flag.go b/cloudstate/crdt/flag.go new file mode 100644 index 0000000..4e81d46 --- /dev/null +++ b/cloudstate/crdt/flag.go @@ -0,0 +1,93 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/entity" +) + +// A Flag is a boolean value that starts as false, and can be set to true. +// Once set to true, it cannot be set back to false. A flag is a very simple CRDT, +// the merge function is simply a boolean or over the two flag values being merged. +type Flag struct { + value bool + delta bool +} + +var _ CRDT = (*Flag)(nil) + +func NewFlag() *Flag { + return &Flag{} +} + +func (f Flag) Value() bool { + return f.value +} + +// Enables enables this flag. Once enabled, it can't be disabled. +func (f *Flag) Enable() { + if !f.value { + f.value, f.delta = true, true + } +} + +func (f Flag) Delta() *entity.CrdtDelta { + return &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Flag{ + Flag: &entity.FlagDelta{ + Value: f.delta, + }, + }, + } +} + +func (f *Flag) HasDelta() bool { + return f.delta +} + +func (f *Flag) resetDelta() { + f.delta = false +} + +func (f *Flag) applyDelta(delta *entity.CrdtDelta) error { + d := delta.GetFlag() + if d == nil { + return fmt.Errorf("unable to apply delta %+v to Flag", delta) + } + f.value = f.value || d.Value + return nil +} + +func (f Flag) State() *entity.CrdtState { + return &entity.CrdtState{ + State: &entity.CrdtState_Flag{ + Flag: &entity.FlagState{ + Value: f.value, + }, + }, + } +} + +func (f *Flag) applyState(state *entity.CrdtState) error { + s := state.GetFlag() + if s == nil { + return fmt.Errorf("unable to apply state %+v to Flag", state) + } + f.value = s.GetValue() + return nil +} diff --git a/cloudstate/crdt/flag_test.go b/cloudstate/crdt/flag_test.go new file mode 100644 index 0000000..305dfda --- /dev/null +++ b/cloudstate/crdt/flag_test.go @@ -0,0 +1,131 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "testing" + + "github.com/cloudstateio/go-support/cloudstate/entity" +) + +func TestFlag(t *testing.T) { + delta := func(value bool) *entity.CrdtDelta { + return &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Flag{ + Flag: &entity.FlagDelta{ + Value: value, + }, + }, + } + } + state := func(value bool) *entity.CrdtState { + return &entity.CrdtState{ + State: &entity.CrdtState_Flag{ + Flag: &entity.FlagState{ + Value: value, + }, + }, + } + } + + t.Run("should be disabled when instantiated", func(t *testing.T) { + f := NewFlag() + if f.Value() { + t.Fatal("flag should be false but was not") + } + }) + t.Run("should reflect a state update", func(t *testing.T) { + f := NewFlag() + if err := f.applyState(encDecState(state(true))); err != nil { + t.Fatal(err) + } + if !f.Value() { + t.Fatal("flag should be true but was not") + } + }) + t.Run("should reflect a delta update", func(t *testing.T) { + f := NewFlag() + if err := f.applyDelta(delta(true)); err != nil { + t.Fatal(err) + } + if !f.Value() { + t.Fatal("flag should be true but was not") + } + }) + t.Run("should generate deltas", func(t *testing.T) { + f := NewFlag() + f.Enable() + if !encDecDelta(f.Delta()).GetFlag().GetValue() { + t.Fatal("flag delta should be true but was not") + } + f.resetDelta() + if f.HasDelta() { + t.Fatal("flag should have no delta") + } + }) + t.Run("should return its state", func(t *testing.T) { + f := NewFlag() + if encDecState(f.State()).GetFlag().GetValue() { + t.Fatal("value should be false but was not") + } + f.resetDelta() + f.Enable() + if !encDecState(f.State()).GetFlag().GetValue() { + t.Fatal("delta should be true but was not") + } + f.resetDelta() + if f.HasDelta() { + t.Fatal("flag should have no delta") + } + }) +} + +func TestFlagAdditional(t *testing.T) { + t.Run("should return correct delta on zero value", func(t *testing.T) { + f := NewFlag() + if f.Delta().GetFlag().GetValue() != false { + t.Fatal("flag delta should be false but was not") + } + f.Enable() + if f.Delta().GetFlag().GetValue() != true { + t.Fatal("flag delta should be true but was not") + } + }) + t.Run("apply invalid delta", func(t *testing.T) { + f := NewFlag() + if err := f.applyDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Gcounter{ + Gcounter: &entity.GCounterDelta{ + Increment: 11, + }, + }, + }); err == nil { + t.Fatal("flag applyDelta should err but did not") + } + }) + t.Run("apply invalid state", func(t *testing.T) { + f := NewFlag() + if err := f.applyState(&entity.CrdtState{ + State: &entity.CrdtState_Gcounter{ + Gcounter: &entity.GCounterState{ + Value: 11, + }, + }, + }); err == nil { + t.Fatal("flag applyDelta should err but did not") + } + }) +} diff --git a/cloudstate/crdt/gcounter.go b/cloudstate/crdt/gcounter.go new file mode 100644 index 0000000..0a748b0 --- /dev/null +++ b/cloudstate/crdt/gcounter.go @@ -0,0 +1,98 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/entity" +) + +// GCounter, or Grow-only Counter, is a counter that can only be incremented. +// It works by tracking a separate counter value for each node, and taking the +// sum of the values for all the nodes to get the current counter value. Since +// each node only updates its own counter value, each node can coordinate those +// updates to ensure they are consistent. Then the merge function, if it sees +// two different values for the same node, simply takes the highest value, +// because that has to be the most recent value that the node published. +type GCounter struct { + value uint64 + delta uint64 +} + +var _ CRDT = (*GCounter)(nil) + +func NewGCounter() *GCounter { + return &GCounter{} +} + +func (c *GCounter) Value() uint64 { + return c.value +} + +func (c *GCounter) Increment(i uint64) { + c.value += i + c.delta += i +} + +func (c *GCounter) State() *entity.CrdtState { + return &entity.CrdtState{ + State: &entity.CrdtState_Gcounter{ + Gcounter: &entity.GCounterState{ + Value: c.value, + }, + }, + } +} + +func (c GCounter) HasDelta() bool { + return c.delta > 0 +} + +func (c *GCounter) Delta() *entity.CrdtDelta { + if c.delta == 0 { + return nil + } + return &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Gcounter{ + Gcounter: &entity.GCounterDelta{ + Increment: c.delta, + }, + }, + } +} + +func (c *GCounter) resetDelta() { + c.delta = 0 +} + +func (c *GCounter) applyState(state *entity.CrdtState) error { + s := state.GetGcounter() + if s == nil { + return fmt.Errorf("unable to apply state %v to GCounter", state) + } + c.value = state.GetGcounter().GetValue() + return nil +} + +func (c *GCounter) applyDelta(delta *entity.CrdtDelta) error { + d := delta.GetGcounter() + if d == nil { + return fmt.Errorf("unable to apply delta %v to GCounter", delta) + } + c.value += d.GetIncrement() + return nil +} diff --git a/cloudstate/crdt/gcounter_test.go b/cloudstate/crdt/gcounter_test.go new file mode 100644 index 0000000..6a6f49b --- /dev/null +++ b/cloudstate/crdt/gcounter_test.go @@ -0,0 +1,156 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "testing" + + "github.com/cloudstateio/go-support/cloudstate/entity" +) + +func TestGCounter(t *testing.T) { + delta := func(incr uint64) *entity.CrdtDelta { + return &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Gcounter{ + Gcounter: &entity.GCounterDelta{ + Increment: incr, + }, + }, + } + } + state := func(val uint64) *entity.CrdtState { + return &entity.CrdtState{ + State: &entity.CrdtState_Gcounter{ + Gcounter: &entity.GCounterState{ + Value: val, + }, + }, + } + } + + t.Run("should reflect a state update", func(t *testing.T) { + c := GCounter{} + if err := c.applyState(encDecState(state(29))); err != nil { + t.Fatal(err) + } + if v := c.Value(); v != 29 { + t.Fatalf("c.Value: %v; want: %d", v, 29) + } + if err := c.applyState(encDecState(state(92))); err != nil { + t.Fatal(err) + } + if v := c.Value(); v != 92 { + t.Fatalf("c.Value: %v; want: %d", v, 92) + } + }) + + t.Run("should reflect a delta update", func(t *testing.T) { + c := NewGCounter() + if err := c.applyDelta(encDecDelta(delta(10))); err != nil { + t.Fatal(err) + } + if v := c.Value(); v != 10 { + t.Fatalf("c.Value: %v; want: %d", v, 10) + } + if err := c.applyDelta(encDecDelta(delta(5))); err != nil { + t.Fatal(err) + } + if v := c.Value(); v != 15 { + t.Fatalf("c.Value: %v; want: %d", v, 15) + } + }) + + t.Run("should generate deltas", func(t *testing.T) { + c := GCounter{} + c.Increment(10) + if c.Delta().GetGcounter().GetIncrement() != 10 { + t.Fatalf("counter increment: %v; want: %v", c.delta, 10) + } + c.resetDelta() + if c.Delta().GetGcounter().GetIncrement() != 0 { + t.Fatalf("counter increment: %v; want: %v", c.delta, 0) + } + c.Increment(3) + if c.Value() != 13 { + t.Fatalf("counter increment: %v; want: %v", c.delta, 13) + } + c.Increment(4) + if c.Value() != 17 { + t.Fatalf("counter increment: %v; want: %v", c.delta, 17) + } + // TODO: c.Delta().GetGcounter().GetIncrement() is 0 even if Delta() returns nil + if c.Delta().GetGcounter().GetIncrement() != 7 { + t.Fatalf("counter increment: %v; want: %v", c.delta, 7) + } + c.resetDelta() + if d := c.Delta(); d != nil { + t.Fatalf("c.Delta() should be nil, but was not") + } + }) + + t.Run("should return its state", func(t *testing.T) { + c := GCounter{} + c.Increment(10) + if v := encDecState(c.State()).GetGcounter().GetValue(); v != 10 { + t.Fatalf("c.Value: %v; want: %d", v, 10) + } + c.resetDelta() + if d := c.Delta(); d != nil { + t.Fatalf("c.Delta() should be nil, but was not") + } + }) +} + +func TestGCounterAdditional(t *testing.T) { + t.Run("should report hasDelta", func(t *testing.T) { + c := NewGCounter() + if c.HasDelta() { + t.Fatalf("c.HasDelta() but should not") + } + c.Increment(29) + if !c.HasDelta() { + t.Fatalf("c.HasDelta() is false, but should not") + } + }) + + t.Run("should catch illegal delta applied", func(t *testing.T) { + c := NewGCounter() + err := c.applyDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Pncounter{ + Pncounter: &entity.PNCounterDelta{ + Change: 11, + }, + }, + }) + if err == nil { + t.Fatalf("c.applyDelta() has to err, but did not") + } + }) + + t.Run("should catch illegal state applied", func(t *testing.T) { + c := NewGCounter() + err := c.applyState(&entity.CrdtState{ + State: &entity.CrdtState_Pncounter{ + Pncounter: &entity.PNCounterState{ + Value: 11, + }, + }, + }) + if err == nil { + t.Fatalf("c.applyState() has to err, but did not") + } + }) +} diff --git a/cloudstate/crdt/gset.go b/cloudstate/crdt/gset.go new file mode 100644 index 0000000..96bd589 --- /dev/null +++ b/cloudstate/crdt/gset.go @@ -0,0 +1,129 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/golang/protobuf/ptypes/any" +) + +// GSet, or Grow-only Set, is a set that can only have items added to it. +// A GSet is a very simple CRDT, its merge function is defined by taking +// the union of the two GSets being merged. +type GSet struct { + value map[uint64]*any.Any + added map[uint64]*any.Any + *anyHasher +} + +var _ CRDT = (*GSet)(nil) + +func NewGSet() *GSet { + return &GSet{ + value: make(map[uint64]*any.Any), + added: make(map[uint64]*any.Any), + anyHasher: &anyHasher{}, + } +} + +func (s GSet) Size() int { + return len(s.value) +} + +func (s *GSet) Add(a *any.Any) { + h := s.hashAny(a) + if _, exists := s.value[h]; exists { + return + } + s.value[h] = a + s.added[h] = a +} + +func (s GSet) State() *entity.CrdtState { + return &entity.CrdtState{ + State: &entity.CrdtState_Gset{ + Gset: &entity.GSetState{ + Items: s.Value(), + }, + }, + } +} + +func (s GSet) HasDelta() bool { + return len(s.added) > 0 +} + +func (s GSet) Value() []*any.Any { + val := make([]*any.Any, len(s.value)) + var i = 0 + for _, v := range s.value { + val[i] = v + i++ + } + return val +} + +func (s GSet) Added() []*any.Any { + val := make([]*any.Any, len(s.added)) + var i = 0 + for _, v := range s.added { + val[i] = v + i++ + } + return val +} + +func (s GSet) Delta() *entity.CrdtDelta { + if !s.HasDelta() { + return nil + } + return &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Gset{ + Gset: &entity.GSetDelta{ + Added: s.Added(), + }, + }, + } +} + +func (s *GSet) resetDelta() { + s.added = make(map[uint64]*any.Any) +} + +func (s *GSet) applyState(state *entity.CrdtState) error { + ss := state.GetGset() + if ss == nil { + return fmt.Errorf("unable to apply state %+v to GSet", state) + } + s.value = make(map[uint64]*any.Any) + for _, v := range ss.GetItems() { + s.value[s.hashAny(v)] = v + } + return nil +} + +func (s *GSet) applyDelta(delta *entity.CrdtDelta) error { + d := delta.GetGset() + if d == nil { + return fmt.Errorf("unable to apply state %+v to GSet", delta) + } + for _, v := range d.GetAdded() { + s.value[s.hashAny(v)] = v + } + return nil +} diff --git a/cloudstate/crdt/gset_test.go b/cloudstate/crdt/gset_test.go new file mode 100644 index 0000000..c85b029 --- /dev/null +++ b/cloudstate/crdt/gset_test.go @@ -0,0 +1,279 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "testing" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/golang/protobuf/ptypes/any" +) + +func TestGset(t *testing.T) { + state := func(x []*any.Any) *entity.CrdtState { + return &entity.CrdtState{ + State: &entity.CrdtState_Gset{ + Gset: &entity.GSetState{ + Items: x, + }, + }, + } + } + delta := func(x []*any.Any) *entity.CrdtDelta { + return &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Gset{ + Gset: &entity.GSetDelta{ + Added: x, + }, + }, + } + } + + t.Run("should have no elements when instantiated", func(t *testing.T) { + s := NewGSet() + if s.Size() != 0 { + t.FailNow() + } + if s.HasDelta() { + t.Fatal("has delta but should not") + } + itemsLen := len(encDecState(s.State()).GetGset().GetItems()) + if itemsLen != 0 { + t.Fatalf("len(items): %v; want: %v", itemsLen, 0) + } + }) + + t.Run("should reflect a state update", func(t *testing.T) { + s := NewGSet() + if err := s.applyState(state(append(make([]*any.Any, 0), + encoding.String("one"), + encoding.String("two")), + )); err != nil { + t.Fatal(err) + } + if size := s.Size(); size != 2 { + t.Fatalf("s.Size(): %v; want: %v", size, 2) + } + if !contains(s.Value(), "one", "two") { + t.Fatalf("set values should contain 'one' and 'two', but was: %v", s.Value()) + } + delta := s.Delta() + if delta != nil { + t.Fatalf("set delta should be nil but was not: %+v", delta) + } + s.resetDelta() + if slen := len(encDecState(s.State()).GetGset().GetItems()); slen != 2 { + t.Fatalf("set state length: %v; want: %v", s.Size(), 2) + } + }) + + t.Run("should generate an add delta", func(t *testing.T) { + s := NewGSet() + s.Add(encoding.String("one")) + if !contains(s.Value(), "one") { + t.Fatal("set should have a: one") + } + if s.Size() != 1 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 1) + } + delta := encDecDelta(s.Delta()) + s.resetDelta() + addedLen := len(delta.GetGset().GetAdded()) + if addedLen != 1 { + t.Fatalf("s.Size(): %v; want: %v", addedLen, 1) + } + if !contains(delta.GetGset().GetAdded(), "one") { + t.Fatalf("set should have a: one") + } + if s.HasDelta() { + t.Fatalf("has but should not") + } + s.Add(encoding.String("two")) + s.Add(encoding.String("three")) + if s.Size() != 3 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 3) + } + delta2 := encDecDelta(s.Delta()) + addedLen2 := len(delta2.GetGset().GetAdded()) + if addedLen2 != 2 { + t.Fatalf("s.Size(): %v; want: %v", addedLen2, 2) + } + if !contains(delta2.GetGset().GetAdded(), "two", "three") { + t.Fatalf("delta should include two, three") + } + s.resetDelta() + if s.HasDelta() { + t.Fatalf("has delta but should not") + } + }) + + t.Run("should not generate a delta when an already existing element is added", func(t *testing.T) { + s := NewGSet() + s.Add(encoding.String("one")) + s.resetDelta() + s.Add(encoding.String("one")) + if s.Size() != 1 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 1) + } + if s.HasDelta() { + t.Fatalf("has delta but should not") + } + }) + + t.Run("should reflect a delta add", func(t *testing.T) { + s := NewGSet() + s.Add(encoding.String("one")) + s.resetDelta() + if err := s.applyDelta(delta(append(make([]*any.Any, 0), encoding.String("two")))); err != nil { + t.Fatal(err) + } + if s.Size() != 2 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 2) + } + if !contains(s.Value(), "one", "two") { + t.Fatalf("delta should include two, three") + } + if s.HasDelta() { + t.Fatalf("has delta but should not") + } + state := encDecState(s.State()) + + if len(state.GetGset().GetItems()) != 2 { + t.Fatalf("state.GetItems(): %v; want: %v", state.GetGset().GetItems(), 2) + } + }) + + t.Run("should work with protobuf types", func(t *testing.T) { + s := NewGSet() + type Example struct { + Field1 string + } + field1, err := encoding.Struct(&Example{Field1: "one"}) + if err != nil { + t.Fatal(err) + } + s.Add(field1) + s.resetDelta() + s.Add(field1) + if s.Size() != 1 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 1) + } + field2, err := encoding.Struct(&Example{Field1: "two"}) + if err != nil { + t.Fatal(err) + } + s.Add(field2) + if s.Size() != 2 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 2) + } + delta := encDecDelta(s.Delta()) + if len(delta.GetGset().GetAdded()) != 1 { + t.Fatalf("s.Size(): %v; want: %v", len(delta.GetGset().GetAdded()), 1) + } + foundOne := false + for _, v := range delta.GetGset().GetAdded() { + e := Example{} + if err := encoding.UnmarshalJSON(v, &e); err != nil { + t.Fatal(err) + } + if e.Field1 == "two" { + foundOne = true + } + } + if !foundOne { + t.Fatalf("delta should include two") + } + }) + + type a struct { + B string + C int + } + + t.Run("add primitive type", func(t *testing.T) { + s := NewGSet() + s.Add(encoding.Int32(5)) + for _, any := range s.value { + p, err := encoding.UnmarshalPrimitive(any) + if err != nil { + t.FailNow() + } + i, ok := p.(int32) + if !ok { + t.FailNow() + } + if i != 5 { + t.FailNow() + } + } + }) + + t.Run("add struct stable", func(t *testing.T) { + s := NewGSet() + json, err := encoding.JSON( + a{ + B: "hupps", + C: 7, + }) + if err != nil { + t.Error(err) + } + s.Add(json) + if s.Size() != 1 { + t.Fatalf("s.Size %v; want: %v", s.Size(), 1) + } + json, err = encoding.JSON( + a{ + B: "hupps", + C: 7, + }) + if err != nil { + t.Error(err) + } + s.Add(json) + if s.Size() != 1 { + t.Fatalf("s.Size %v; want: %v", s.Size(), 1) + } + }) +} + +func TestGSetAdditional(t *testing.T) { + t.Run("apply invalid delta", func(t *testing.T) { + s := NewGSet() + if err := s.applyDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Flag{ + Flag: &entity.FlagDelta{ + Value: false, + }, + }, + }); err == nil { + t.Fatal("gset applyDelta should err but did not") + } + }) + t.Run("apply invalid state", func(t *testing.T) { + s := NewGSet() + if err := s.applyState(&entity.CrdtState{ + State: &entity.CrdtState_Flag{ + Flag: &entity.FlagState{ + Value: false, + }, + }, + }); err == nil { + t.Fatal("gset applyState should err but did not") + } + }) +} diff --git a/cloudstate/crdt/hash_any.go b/cloudstate/crdt/hash_any.go new file mode 100644 index 0000000..e2b3fd2 --- /dev/null +++ b/cloudstate/crdt/hash_any.go @@ -0,0 +1,33 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "hash/maphash" + + "github.com/golang/protobuf/ptypes/any" +) + +type anyHasher struct { + h maphash.Hash +} + +func (h *anyHasher) hashAny(a *any.Any) uint64 { + h.h.Reset() + _, _ = h.h.WriteString(a.GetTypeUrl()) // does never err + _, _ = h.h.Write(a.GetValue()) // does never err + return h.h.Sum64() +} diff --git a/cloudstate/crdt/lwwregister.go b/cloudstate/crdt/lwwregister.go new file mode 100644 index 0000000..6555d53 --- /dev/null +++ b/cloudstate/crdt/lwwregister.go @@ -0,0 +1,142 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/golang/protobuf/ptypes/any" +) + +// LWWRegister, or Last-Write-Wins Register, is a CRDT that can hold any value, +// along with a clock value and node id to indicate when it was updated by which +// node. If two nodes have two different versions of the value, the one with the +// highest clock value wins. If the clock values are equal, then a stable function +// on the nodes is used to determine it (eg, the node with the lowest address). +// Note that LWWRegisters do not support partial updates of their values. If the +// register holds a person object, and one node updates the age property, while +// another concurrently updates the name property, only one of those updates will +// eventually win. By default, LWWRegister’s are vulnerable to clock skew between +// nodes. Cloudstate supports optionally providing a custom clock value should a +// more trustworthy ordering for updates be available. +type LWWRegister struct { + value *any.Any + delta lwwRegisterDelta + clock Clock + customClockValue int64 +} + +type lwwRegisterDelta struct { + value *any.Any + clock Clock + customClockValue int64 +} + +var _ CRDT = (*LWWRegister)(nil) + +func NewLWWRegister(x *any.Any) *LWWRegister { + return NewLWWRegisterWithClock(x, Default, 0) +} + +// NewLWWRegisterWithClock uses the custom clock value if the clock selected +// is a custom clock. This is ignored if the clock is not a custom clock. +func NewLWWRegisterWithClock(x *any.Any, c Clock, customClockValue int64) *LWWRegister { + if c != Custom { + customClockValue = 0 + } + return &LWWRegister{ + value: x, + clock: c, + customClockValue: customClockValue, + delta: lwwRegisterDelta{}, + } +} + +func (r *LWWRegister) Value() *any.Any { + return r.value +} + +func (r *LWWRegister) Set(x *any.Any) { + r.SetWithClock(x, Default, 0) +} + +// SetWithClock uses the custom clock value to use if the clock selected +// is a custom clock. This is ignored if the clock is not a custom clock. +func (r *LWWRegister) SetWithClock(x *any.Any, c Clock, customClockValue int64) { + r.value = x + r.clock = c + if c == Custom { + r.customClockValue = customClockValue + } + r.delta = lwwRegisterDelta{ + value: x, + clock: c, + customClockValue: customClockValue, + } +} + +func (r *LWWRegister) Delta() *entity.CrdtDelta { + return &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Lwwregister{ + Lwwregister: &entity.LWWRegisterDelta{ + Value: r.delta.value, + Clock: r.delta.clock.toCrdtClock(), + CustomClockValue: r.delta.customClockValue, + }, + }, + } +} + +func (r *LWWRegister) HasDelta() bool { + return r.delta.value != nil +} + +func (r *LWWRegister) resetDelta() { + r.delta = lwwRegisterDelta{} +} + +func (r *LWWRegister) applyDelta(delta *entity.CrdtDelta) error { + d := delta.GetLwwregister() + if d == nil { + return fmt.Errorf("unable to apply state %+v to LWWRegister", delta) + } + r.value = d.GetValue() + return nil +} + +func (r *LWWRegister) State() *entity.CrdtState { + return &entity.CrdtState{ + State: &entity.CrdtState_Lwwregister{ + Lwwregister: &entity.LWWRegisterState{ + Value: r.value, + Clock: r.clock.toCrdtClock(), + CustomClockValue: r.customClockValue, + }, + }, + } +} + +func (r *LWWRegister) applyState(state *entity.CrdtState) error { + s := state.GetLwwregister() + if s == nil { + return fmt.Errorf("unable to apply state %+v to LWWRegister", state) + } + r.value = s.GetValue() + r.clock = fromCrdtClock(s.GetClock()) + r.customClockValue = s.GetCustomClockValue() + return nil +} diff --git a/cloudstate/crdt/lwwregister_clock.go b/cloudstate/crdt/lwwregister_clock.go new file mode 100644 index 0000000..3b3d9d9 --- /dev/null +++ b/cloudstate/crdt/lwwregister_clock.go @@ -0,0 +1,84 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import "github.com/cloudstateio/go-support/cloudstate/entity" + +type Clock uint64 + +const ( + // The Default clock, uses the current system time as the clock value. + Default Clock = iota + + // A Reverse clock, based on the system clock. Using this effectively + // achieves First-Write-Wins semantics. This is susceptible to the + // same clock skew problems as the default clock. + Reverse + + // A custom clock. + // The custom clock value is passed by using the customClockValue parameter on + // the `SetWithClock` method. The value should be a domain specific monotonically + // increasing value. For example, if the source of the value for this register + // is a single device, that device may attach a sequence number to each update, + // that sequence number can be used to guarantee that the register will converge + // to the last update emitted by that device. + Custom + + // CustomAutoIncrement is a custom clock, that automatically increments the + // custom value if the local clock value is greater than it. + // + // This is like `Custom`, however if when performing the update in the proxy, + // it's found that the clock value of the register is greater than the specified + // clock value for the update, the proxy will instead use the current clock + // value of the register plus one. + // + // This can guarantee that updates done on the same node will be causally + // ordered (addressing problems caused by the system clock being adjusted), + // but will not guarantee causal ordering for updates on different nodes, + // since it's possible that an update on a different node has not yet been + // replicated to this node. + CustomAutoIncrement +) + +func fromCrdtClock(clock entity.CrdtClock) Clock { + switch clock { + case entity.CrdtClock_DEFAULT: + return Default + case entity.CrdtClock_REVERSE: + return Reverse + case entity.CrdtClock_CUSTOM: + return Custom + case entity.CrdtClock_CUSTOM_AUTO_INCREMENT: + return CustomAutoIncrement + default: + return Default + } +} + +func (c Clock) toCrdtClock() entity.CrdtClock { + switch c { + case Default: + return entity.CrdtClock_DEFAULT + case Reverse: + return entity.CrdtClock_REVERSE + case Custom: + return entity.CrdtClock_CUSTOM + case CustomAutoIncrement: + return entity.CrdtClock_CUSTOM_AUTO_INCREMENT + default: + return entity.CrdtClock_DEFAULT + } +} diff --git a/cloudstate/crdt/lwwregister_test.go b/cloudstate/crdt/lwwregister_test.go new file mode 100644 index 0000000..12fe158 --- /dev/null +++ b/cloudstate/crdt/lwwregister_test.go @@ -0,0 +1,223 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "testing" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" +) + +func TestLWWRegister(t *testing.T) { + type Example struct { + Field1 string + } + + t.Run("should be instantiated with a value", func(t *testing.T) { + foo, err := encoding.Struct(Example{Field1: "foo"}) + if err != nil { + t.Fatal(err) + } + r := NewLWWRegister(foo) + example := Example{} + if err := encoding.UnmarshalJSON(r.Value(), &example); err != nil { + t.Fatal(err) + } + if example.Field1 != "foo" { + t.Fatalf("example.Field1: %v; want: %v", example.Field1, "foo") + } + if r.HasDelta() { + t.Fatalf("register has delta but should not") + } + state := encDecState(r.State()) + err = encoding.UnmarshalJSON(state.GetLwwregister().GetValue(), &example) + if err != nil { + t.Fatal(err) + } + r.resetDelta() + if example.Field1 != "foo" { + t.Fatalf("example.Field1: %v; want: %v", example.Field1, "foo") + } + if r.clock != Default { + t.Fatalf("r.clock: %v; want: %v", r.clock, Default) + } + }) + + t.Run("should reflect a state update", func(t *testing.T) { + bar, err := encoding.Struct(Example{Field1: "bar"}) + if err != nil { + t.Fatal(err) + } + r := LWWRegister{ + value: bar, + } + foo, err := encoding.Struct(Example{Field1: "foo"}) + if err != nil { + t.Fatal(err) + } + if err := r.applyState(encDecState( + &entity.CrdtState{ + State: &entity.CrdtState_Lwwregister{ + Lwwregister: &entity.LWWRegisterState{ + Value: foo, + }, + }, + }, + )); err != nil { + t.Fatal(err) + } + example := Example{} + if err := encoding.UnmarshalJSON(r.Value(), &example); err != nil { + t.Fatal(err) + } + if example.Field1 != "foo" { + t.Fatalf("example.Field1: %v; want: %v", example.Field1, "foo") + } + }) + + t.Run("should generate a delta", func(t *testing.T) { + foo, err := encoding.Struct(Example{Field1: "foo"}) + if err != nil { + t.Fatal(err) + } + r := NewLWWRegister(foo) + bar, err := encoding.Struct(Example{Field1: "bar"}) + if err != nil { + t.Fatal(err) + } + r.Set(bar) + example := Example{} + if err := encoding.UnmarshalJSON(r.value, &example); err != nil { + t.Fatal(err) + } + if example.Field1 != "bar" { + t.Fatalf("example.Field1: %v; want: %v", example.Field1, "bar") + } + d := encDecDelta(r.Delta()) + r.resetDelta() + e := Example{} + err = encoding.UnmarshalJSON(d.GetLwwregister().GetValue(), &e) + if err != nil { + t.Fatal(err) + } + if example.Field1 != "bar" { + t.Fatalf("example.Field1: %v; want: %v", example.Field1, "bar") + } + if r.clock != Default { + t.Fatalf("r.clock: %v; want: %v", r.clock, Default) + } + if r.HasDelta() { + t.Fatalf("register has delta but should not") + } + }) + + t.Run("should generate deltas with a custom clock", func(t *testing.T) { + foo, err := encoding.Struct(Example{Field1: "foo"}) + if err != nil { + t.Fatal(err) + } + r := NewLWWRegister(foo) + bar, err := encoding.Struct(Example{Field1: "bar"}) + if err != nil { + t.Fatal(err) + } + r.SetWithClock(bar, Custom, 10) + example := Example{} + if err := encoding.UnmarshalJSON(r.value, &example); err != nil { + t.Fatal(err) + } + if example.Field1 != "bar" { + t.Fatalf("example.Field1: %v; want: %v", example.Field1, "bar") + } + d := encDecDelta(r.Delta()) + r.resetDelta() + e := Example{} + err = encoding.UnmarshalJSON(d.GetLwwregister().GetValue(), &e) + if err != nil { + t.Fatal(err) + } + if example.Field1 != "bar" { + t.Fatalf("example.Field1: %v; want: %v", example.Field1, "bar") + } + if clock := d.GetLwwregister().GetClock(); clock != Custom.toCrdtClock() { + t.Fatalf("r.clock: %v; want: %v", clock, Custom) + } + if cv := d.GetLwwregister().GetCustomClockValue(); cv != 10 { + t.Fatalf("r.customClockValue: %v; want: %v", cv, 10) + } + if r.HasDelta() { + t.Fatalf("register has delta but should not") + } + }) + + t.Run("should reflect a delta update", func(t *testing.T) { + foo, err := encoding.Struct(Example{Field1: "foo"}) + if err != nil { + t.Fatal(err) + } + r := NewLWWRegister(foo) + // r.Set(encoding.Struct(Example{Field1: "foo"})) // TODO: this is not the same, check + bar, err := encoding.Struct(Example{Field1: "bar"}) + if err != nil { + t.Fatal(err) + } + if err := r.applyDelta(encDecDelta( + &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Lwwregister{ + Lwwregister: &entity.LWWRegisterDelta{ + Value: bar, + }, + }, + }, + )); err != nil { + t.Fatal(err) + } + e := Example{} + if err := encoding.UnmarshalJSON(r.Value(), &e); err != nil { + t.Fatal(err) + } + if e.Field1 != "bar" { + t.Fatalf("example.Field1: %v; want: %v", e.Field1, "bar") + } + if r.HasDelta() { + t.Fatalf("register has delta but should not") + } + e2 := Example{} + err = encoding.UnmarshalJSON(encDecState(r.State()).GetLwwregister().GetValue(), &e2) + if err != nil { + t.Fatal(err) + } + if e2.Field1 != "bar" { + t.Fatalf("example.Field1: %v; want: %v", e.Field1, "bar") + } + }) + + t.Run("should work with primitive types", func(t *testing.T) { + r := NewLWWRegister(encoding.String("momo")) + state := encDecState(r.State()) + r.resetDelta() + stateValue := encoding.DecodeString(state.GetLwwregister().GetValue()) + if stateValue != "momo" { + t.Fatalf("stateValue: %v; want: %v", stateValue, "momo") + } + r.Set(encoding.String("hello")) + rValue := encoding.DecodeString(r.Value()) + if rValue != "hello" { + t.Fatalf("r.Value(): %v; want: %v", rValue, "hello") + } + }) +} diff --git a/cloudstate/crdt/ormap.go b/cloudstate/crdt/ormap.go new file mode 100644 index 0000000..7d80627 --- /dev/null +++ b/cloudstate/crdt/ormap.go @@ -0,0 +1,280 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/golang/protobuf/ptypes/any" +) + +// ORMap, or Observed-Removed Map, is similar to an ORSet, with the addition +// that the values of the set serve as keys for a map, and the values of the +// map are themselves, CRDTs. When a value for the same key in an ORMap is +// modified concurrently on two different nodes, the values from the two nodes +// are merged together. +type ORMap struct { + value map[uint64]*orMapValue + delta orMapDelta + *anyHasher +} + +type orMapValue struct { + key *any.Any + value CRDT +} + +var _ CRDT = (*ORMap)(nil) + +type orMapDelta struct { + added map[uint64]*any.Any + removed map[uint64]*any.Any + cleared bool +} + +func NewORMap() *ORMap { + return &ORMap{ + value: make(map[uint64]*orMapValue), + delta: orMapDelta{ + added: make(map[uint64]*any.Any), + removed: make(map[uint64]*any.Any), + cleared: false, + }, + anyHasher: &anyHasher{}, + } +} + +func (m *ORMap) HasKey(x *any.Any) (hasKey bool) { + _, hasKey = m.value[m.hashAny(x)] + return +} + +func (m *ORMap) Size() int { + return len(m.value) +} + +func (m *ORMap) Values() []*entity.CrdtState { + values := make([]*entity.CrdtState, len(m.value)) + var i = 0 + for _, v := range m.value { + values[i] = v.value.State() + i++ + } + return values +} + +func (m *ORMap) Keys() []*any.Any { + keys := make([]*any.Any, len(m.value)) + var i = 0 + for _, v := range m.value { + keys[i] = v.key + i++ + } + return keys +} + +func (m *ORMap) Get(key *any.Any) CRDT { + if s, ok := m.value[m.hashAny(key)]; ok { + return s.value + } + return nil +} + +func (m *ORMap) Set(key *any.Any, value CRDT) { + k := m.hashAny(key) + // from ref. impl: Setting an existing key to a new value + // can have unintended effects, as the old value may end + // up being merged with the new. + if _, has := m.value[k]; has { + if _, has := m.delta.added[k]; !has { + m.delta.removed[k] = key + } + } + m.value[k] = &orMapValue{ + key: key, + value: value, + } + m.delta.added[k] = key +} + +func (m *ORMap) Delete(key *any.Any) { + k := m.hashAny(key) + if _, has := m.value[k]; !has { + return + } + if len(m.value) == 1 { + m.Clear() + return + } + delete(m.value, k) + if _, has := m.delta.added[k]; has { + delete(m.delta.added, k) + return + } + m.delta.removed[k] = key +} + +func (m *ORMap) Clear() { + if len(m.value) == 0 { + return + } + m.value = make(map[uint64]*orMapValue) + m.delta.clear() +} + +func (d *orMapDelta) clear() { + d.added = make(map[uint64]*any.Any) + d.removed = make(map[uint64]*any.Any) + d.cleared = true +} + +func (m *ORMap) HasDelta() bool { + if m.delta.cleared || len(m.delta.added) > 0 || len(m.delta.removed) > 0 { + return true + } + for _, v := range m.value { + if v.value.HasDelta() { + return true + } + } + return false +} + +func (m *ORMap) Delta() *entity.CrdtDelta { + if !m.HasDelta() { + return nil + } + added := make([]*entity.ORMapEntry, 0) + updated := make([]*entity.ORMapEntryDelta, 0) + for _, v := range m.value { + if _, has := m.delta.added[m.hashAny(v.key)]; has { + added = append(added, &entity.ORMapEntry{ + Key: v.key, + Value: v.value.State(), + }) + } else if v.value.HasDelta() { + updated = append(updated, &entity.ORMapEntryDelta{ + Key: v.key, + Delta: v.value.Delta(), + }) + } + } + removed := make([]*any.Any, len(m.delta.removed)) + var i = 0 + for _, e := range m.delta.removed { + removed[i] = e + i++ + } + return &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Ormap{ + Ormap: &entity.ORMapDelta{ + Cleared: m.delta.cleared, + Removed: removed, + Updated: updated, + Added: added, + }, + }, + } +} + +func (m *ORMap) applyDelta(delta *entity.CrdtDelta) error { + d := delta.GetOrmap() + if d == nil { + return fmt.Errorf("unable to apply delta %v to the ORMap", delta) + } + if d.GetCleared() { + m.value = make(map[uint64]*orMapValue) + } + for _, r := range d.GetRemoved() { + delete(m.value, m.hashAny(r)) + } + for _, a := range d.Added { + if m.HasKey(a.GetKey()) { + continue + } + state, err := newFor(a.GetValue()) + if err != nil { + return err + } + if err := state.applyState(a.GetValue()); err != nil { + return err + } + m.value[m.hashAny(a.GetKey())] = &orMapValue{ + key: a.GetKey(), + value: state, + } + } + for _, u := range d.Updated { + if v, has := m.value[m.hashAny(u.GetKey())]; has { + if err := v.value.applyDelta(u.GetDelta()); err != nil { + return err + } + } + } + return nil +} + +func (m *ORMap) resetDelta() { + for _, v := range m.value { + v.value.resetDelta() + } + m.delta.cleared = false // TODO: what's the thing with cleared to be different to orMapDelta.clear()? + m.delta.added = make(map[uint64]*any.Any) + m.delta.removed = make(map[uint64]*any.Any) +} + +func (m *ORMap) State() *entity.CrdtState { + entries := make([]*entity.ORMapEntry, len(m.value)) + var i = 0 + for _, v := range m.value { + entries[i] = &entity.ORMapEntry{ + Key: v.key, + Value: v.value.State(), + } + i++ + } + return &entity.CrdtState{ + State: &entity.CrdtState_Ormap{ + Ormap: &entity.ORMapState{ + Entries: entries, + }, + }, + } +} + +func (m *ORMap) applyState(state *entity.CrdtState) error { + s := state.GetOrmap() + if s == nil { + return fmt.Errorf("unable to apply state %v to the ORMap", state) + } + m.value = make(map[uint64]*orMapValue, len(s.GetEntries())) + for _, entry := range s.GetEntries() { + value, err := newFor(entry.GetValue()) + if err != nil { + return err + } + v := &orMapValue{ + key: entry.GetKey(), + value: value, + } + if err := v.value.applyState(entry.GetValue()); err != nil { + return err + } + m.value[m.hashAny(v.key)] = v + } + return nil +} diff --git a/cloudstate/crdt/ormap_enc_test.go b/cloudstate/crdt/ormap_enc_test.go new file mode 100644 index 0000000..2f85701 --- /dev/null +++ b/cloudstate/crdt/ormap_enc_test.go @@ -0,0 +1,87 @@ +package crdt + +import ( + "testing" + + "github.com/cloudstateio/go-support/cloudstate/encoding" +) + +func BenchmarkORMapEncoding(b *testing.B) { + b.Run("add and append decoded value", func(b *testing.B) { + b.ReportAllocs() + m := NewORMap() + m.Set(encoding.Int64(int64(1)), NewLWWRegister(encoding.String("one"))) + m.Set(encoding.Int64(int64(2)), NewLWWRegister(encoding.String("two"))) + m.Set(encoding.Int64(int64(3)), NewLWWRegister(encoding.String("three"))) + m.Set(encoding.Int64(int64(4)), NewLWWRegister(encoding.String("four"))) + v := make([]string, 0, m.Size()*b.N) + for i := 0; i < b.N; i++ { + for _, state := range m.Values() { + val := state.GetLwwregister().GetValue() + v = append(v, encoding.DecodeString(val)) + } + } + }) + b.Run("add and get value", func(b *testing.B) { + b.ReportAllocs() + m := NewORMap() + m.Set(encoding.Int64(int64(1)), NewLWWRegister(encoding.String("one"))) + m.Set(encoding.Int64(int64(2)), NewLWWRegister(encoding.String("two"))) + m.Set(encoding.Int64(int64(3)), NewLWWRegister(encoding.String("three"))) + m.Set(encoding.Int64(int64(4)), NewLWWRegister(encoding.String("four"))) + s0 := "" + for i := 0; i < b.N; i++ { + for _, state := range m.Values() { + s0 = encoding.DecodeString(state.GetLwwregister().GetValue()) + } + } + _ = s0 == "" // use any0 + }) + b.Run("set and delete unknown", func(b *testing.B) { + b.ReportAllocs() + m := NewORMap() + m.Set(encoding.Int64(int64(1)), NewLWWRegister(encoding.String("one"))) + m.Set(encoding.Int64(int64(2)), NewLWWRegister(encoding.String("two"))) + m.Set(encoding.Int64(int64(3)), NewLWWRegister(encoding.String("three"))) + m.Set(encoding.Int64(int64(4)), NewLWWRegister(encoding.String("four"))) + s0 := "" + for i := 0; i < b.N; i++ { + m.Set(encoding.Int64(int64(5)), NewLWWRegister(encoding.String("five"))) + m.Delete(encoding.Int64(int64(5))) + m.Values() + } + _ = s0 == "" // use any0 + }) + b.Run("set and delete known", func(b *testing.B) { + b.ReportAllocs() + m := NewORMap() + m.Set(encoding.Int64(int64(1)), NewLWWRegister(encoding.String("one"))) + m.Set(encoding.Int64(int64(2)), NewLWWRegister(encoding.String("two"))) + m.Set(encoding.Int64(int64(3)), NewLWWRegister(encoding.String("three"))) + m.Set(encoding.Int64(int64(4)), NewLWWRegister(encoding.String("four"))) + s0 := "" + for i := 0; i < b.N; i++ { + m.Set(encoding.Int64(int64(1)), NewLWWRegister(encoding.String("one"))) + m.Delete(encoding.Int64(int64(1))) + m.Values() + } + _ = s0 == "" // use any0 + }) + b.Run("set and delete pre-encoded", func(b *testing.B) { + b.ReportAllocs() + m := NewORMap() + m.Set(encoding.Int64(int64(1)), NewLWWRegister(encoding.String("one"))) + m.Set(encoding.Int64(int64(2)), NewLWWRegister(encoding.String("two"))) + m.Set(encoding.Int64(int64(3)), NewLWWRegister(encoding.String("three"))) + m.Set(encoding.Int64(int64(4)), NewLWWRegister(encoding.String("four"))) + s0 := "" + one := encoding.String("one") + oneInt := encoding.Int64(int64(1)) + for i := 0; i < b.N; i++ { + m.Set(oneInt, NewLWWRegister(one)) + m.Delete(oneInt) + m.Values() + } + _ = s0 == "" // use any0 + }) +} diff --git a/cloudstate/crdt/ormap_getter.go b/cloudstate/crdt/ormap_getter.go new file mode 100644 index 0000000..8e2455b --- /dev/null +++ b/cloudstate/crdt/ormap_getter.go @@ -0,0 +1,102 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "fmt" + + "github.com/golang/protobuf/ptypes/any" +) + +func (m *ORMap) Flag(key *any.Any) (*Flag, error) { + if v, has := m.value[m.hashAny(key)]; has { + if flag, ok := v.value.(*Flag); ok { + return flag, nil + } + return nil, fmt.Errorf("value at key: %v is not of type Flag but: %+v", key, v) + } + return nil, nil +} + +func (m *ORMap) GCounter(key *any.Any) (*GCounter, error) { + if v, has := m.value[m.hashAny(key)]; has { + if counter, ok := v.value.(*GCounter); ok { + return counter, nil + } + return nil, fmt.Errorf("value at key: %v is not of type GCounter but: %+v", key, v) + } + return nil, nil +} + +func (m *ORMap) GSet(key *any.Any) (*GSet, error) { + if v, has := m.value[m.hashAny(key)]; has { + if set, ok := v.value.(*GSet); ok { + return set, nil + } + return nil, fmt.Errorf("value at key: %v is not of type GSet but: %+v", key, v) + } + return nil, nil +} + +func (m *ORMap) LWWRegister(key *any.Any) (*LWWRegister, error) { + if v, has := m.value[m.hashAny(key)]; has { + if r, ok := v.value.(*LWWRegister); ok { + return r, nil + } + return nil, fmt.Errorf("value at key: %v is not of type LWWRegister but: %+v", key, v) + } + return nil, nil +} + +func (m *ORMap) ORMap(key *any.Any) (*ORMap, error) { + if v, has := m.value[m.hashAny(key)]; has { + if m, ok := v.value.(*ORMap); ok { + return m, nil + } + return nil, fmt.Errorf("value at key: %v is not of type ORMap but: %+v", key, v) + } + return nil, nil +} + +func (m *ORMap) ORSet(key *any.Any) (*ORSet, error) { + if v, has := m.value[m.hashAny(key)]; has { + if set, ok := v.value.(*ORSet); ok { + return set, nil + } + return nil, fmt.Errorf("value at key: %v is not of type ORSet but: %+v", key, v) + } + return nil, nil +} + +func (m *ORMap) PNCounter(key *any.Any) (*PNCounter, error) { + if v, has := m.value[m.hashAny(key)]; has { + if c, ok := v.value.(*PNCounter); ok { + return c, nil + } + return nil, fmt.Errorf("value at key: %v is not of type PNCounter but: %+v", key, v) + } + return nil, nil +} + +func (m *ORMap) Vote(key *any.Any) (*Vote, error) { + if v, has := m.value[m.hashAny(key)]; has { + if c, ok := v.value.(*Vote); ok { + return c, nil + } + return nil, fmt.Errorf("value at key: %v is not of type Vote but: %+v", key, v) + } + return nil, nil +} diff --git a/cloudstate/crdt/ormap_test.go b/cloudstate/crdt/ormap_test.go new file mode 100644 index 0000000..a5a4c1e --- /dev/null +++ b/cloudstate/crdt/ormap_test.go @@ -0,0 +1,535 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "testing" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/golang/protobuf/ptypes/any" +) + +func TestORMap(t *testing.T) { + t.Run("should have no elements when instantiated", func(t *testing.T) { + m := NewORMap() + if got, want := m.Size(), 0; got != want { + t.Fatalf("got: %v; want: %v", got, want) + } + if m.Delta() != nil { + t.Fatal("m.Delta() is not nil but should") + } + m.resetDelta() + if got, want := len(encDecState(m.State()).GetOrmap().Entries), 0; got != want { + t.Fatalf("got: %v; want: %v", got, want) + } + }) + t.Run("should reflect a state update", func(t *testing.T) { + m := NewORMap() + if err := m.applyState(encDecState( + &entity.CrdtState{ + State: &entity.CrdtState_Ormap{ + Ormap: &entity.ORMapState{ + Entries: append(make([]*entity.ORMapEntry, 0), + &entity.ORMapEntry{ + Key: encoding.String("one"), + Value: (&GCounter{ + value: 5, + }).State(), + }, + &entity.ORMapEntry{ + Key: encoding.String("two"), + Value: (&GCounter{ + value: 7, + }).State(), + }, + ), + }, + }, + }, + )); err != nil { + t.Fatal(err) + } + if got, want := m.Size(), 2; got != want { + t.Fatalf("got: %v; want: %v", got, want) + } + if got, want := m.Get(encoding.String("one")).State().GetGcounter().Value, uint64(5); got != want { + t.Fatalf("got: %v; want: %v", got, want) + } + if got, want := m.Get(encoding.String("two")).State().GetGcounter().Value, uint64(7); got != want { + t.Fatalf("got: %v; want: %v", got, want) + } + if d := m.Delta(); d != nil { + t.Fatalf("m.Delta(): %v; want: %v", d, nil) + } + m.resetDelta() + if l := len(encDecState(m.State()).GetOrmap().Entries); l != 2 { + t.Fatalf("len(map.Entries): %v; want: %v", l, 2) + } + }) + t.Run("should generate an add delta", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + if !m.HasKey(encoding.String("one")) { + t.Fatal("m has no 'one' key") + } + if s := m.Size(); s != 1 { + t.Fatalf("m.Size(): %v; want: %v", s, 1) + } + delta := m.Delta() + m.resetDelta() + if l := len(encDecDelta(delta).GetOrmap().GetAdded()); l != 1 { + t.Fatalf("delta added length: %v; want: %v", l, 1) + } + entry := delta.GetOrmap().GetAdded()[0] + if k := encoding.DecodeString(entry.GetKey()); k != "one" { + t.Fatalf("key: %v; want: %v", k, "one") + } + if v := entry.GetValue().GetGcounter().GetValue(); v != 0 { + t.Fatalf("GCounter.Value: %v; want: %v", v, 0) + } + if d := m.Delta(); d != nil { + t.Fatalf("m.Delta(): %v; want: %v", d, nil) + } + + m.Set(encoding.String("two"), NewGCounter()) + counter, err := m.GCounter(encoding.String("two")) + if err != nil { + t.Fatal(err) + } + counter.Increment(10) + if s := m.Size(); s != 2 { + t.Fatalf("m.Size(): %v; want: %v", s, 2) + } + delta2 := encDecDelta(m.Delta()) + m.resetDelta() + if l := len(delta2.GetOrmap().GetAdded()); l != 1 { + t.Fatalf("delta added length: %v; want: %v", l, 1) + } + entry2 := delta2.GetOrmap().GetAdded()[0] + if k := encoding.DecodeString(entry2.GetKey()); k != "two" { + t.Fatalf("key: %v; want: %v", k, "two") + } + if v := entry2.GetValue().GetGcounter().GetValue(); v != 10 { + t.Fatalf("GCounter.Value: %v; want: %v", v, 10) + } + if d := m.Delta(); d != nil { + t.Fatalf("m.Delta(): %v; want: %v", d, nil) + } + + if l := len(delta2.GetOrmap().GetUpdated()); l != 0 { + t.Fatalf("length of delta: %v; want: %v", l, 0) + } + }) + + t.Run("should generate a remove delta", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + m.Set(encoding.String("two"), NewGCounter()) + m.Set(encoding.String("three"), NewGCounter()) + m.Delta() + m.resetDelta() + if !m.HasKey(encoding.String("one")) { + t.Fatalf("map should have key: %v but had not", "one") + } + if !m.HasKey(encoding.String("two")) { + t.Fatalf("map should have key: %v but had not", "two") + } + if !m.HasKey(encoding.String("three")) { + t.Fatalf("map should have key: %v but had not", "three") + } + if s := m.Size(); s != 3 { + t.Fatalf("m.Size(): %v; want: %v", s, 3) + } + m.Delete(encoding.String("one")) + m.Delete(encoding.String("two")) + if s := m.Size(); s != 1 { + t.Fatalf("m.Size(): %v; want: %v", s, 1) + } + if m.HasKey(encoding.String("one")) { + t.Fatalf("map should not have key: %v but had", "one") + } + if m.HasKey(encoding.String("two")) { + t.Fatalf("map should not have key: %v but had", "two") + } + if !m.HasKey(encoding.String("three")) { + t.Fatalf("map should have key: %v but had not", "three") + } + delta := encDecDelta(m.Delta()) + m.resetDelta() + if l := len(delta.GetOrmap().GetRemoved()); l != 2 { + t.Fatalf("length of delta.removed: %v; want: %v", l, 2) + } + if !contains(delta.GetOrmap().GetRemoved(), "one", "two") { + t.Fatalf("delta.removed should contain keys 'one','two' but did not: %v", delta.GetOrmap().GetRemoved()) + } + if d := m.Delta(); d != nil { + t.Fatalf("m.Delta(): %v; want: %v", d, nil) + } + }) + t.Run("should generate an update delta", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + m.resetDelta() + counter, err := m.GCounter(encoding.String("one")) + if err != nil { + t.Fatal(err) + } + counter.Increment(5) + delta := encDecDelta(m.Delta()) + m.resetDelta() + if l := len(delta.GetOrmap().GetUpdated()); l != 1 { + t.Fatalf("length of delta.updated: %v; want: %v", l, 1) + } + entry := delta.GetOrmap().GetUpdated()[0] + if k := encoding.DecodeString(entry.GetKey()); k != "one" { + t.Fatalf("key of updated entry was: %v; want: %v", k, "one") + } + if i := entry.GetDelta().GetGcounter().GetIncrement(); i != 5 { + t.Fatalf("increment: %v; want: %v", i, 5) + } + if d := m.Delta(); d != nil { + t.Fatalf("m.Delta(): %v; want: %v", d, nil) + } + }) + t.Run("should generate a clear delta", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + m.Set(encoding.String("two"), NewGCounter()) + m.resetDelta() + m.Clear() + if s := m.Size(); s != 0 { + t.Fatalf("m.Size(): %v; want: %v", s, 0) + } + delta := encDecDelta(m.Delta()) + m.resetDelta() + if c := delta.GetOrmap().GetCleared(); !c { + t.Fatalf("delta cleared: %v; want: %v", c, true) + } + if d := m.Delta(); d != nil { + t.Fatalf("m.Delta(): %v; want: %v", d, nil) + } + }) + t.Run("should generate a clear delta when everything is removed", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + m.Set(encoding.String("two"), NewGCounter()) + m.resetDelta() + m.Delete(encoding.String("one")) + m.Delete(encoding.String("two")) + if s := m.Size(); s != 0 { + t.Fatalf("m.Size(): %v; want: %v", s, 0) + } + delta := encDecDelta(m.Delta()) + m.resetDelta() + if c := delta.GetOrmap().GetCleared(); !c { + t.Fatalf("delta cleared: %v; want: %v", c, true) + } + if d := m.Delta(); d != nil { + t.Fatalf("m.Delta(): %v; want: %v", d, nil) + } + }) + t.Run("should not generate a delta when an added element is removed", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + m.resetDelta() + m.Set(encoding.String("two"), NewGCounter()) + m.Delete(encoding.String("two")) + if s := m.Size(); s != 1 { + t.Fatalf("m.Size(): %v; want: %v", s, 1) + } + if d := m.Delta(); d != nil { + t.Fatalf("m.Delta(): %v; want: %v", d, nil) + } + }) + t.Run("should generate a delta when a removed element is added", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + m.Set(encoding.String("two"), NewGCounter()) + m.resetDelta() + m.Delete(encoding.String("two")) + m.Set(encoding.String("two"), NewGCounter()) + if s := m.Size(); s != 2 { + t.Fatalf("m.Size(): %v; want: %v", s, 2) + } + delta := encDecDelta(m.Delta()) + m.resetDelta() + if l := len(delta.GetOrmap().GetRemoved()); l != 1 { + t.Fatalf("length of delta.removed: %v; want: %v", l, 1) + } + if l := len(delta.GetOrmap().GetAdded()); l != 1 { + t.Fatalf("length of delta.added: %v; want: %v", l, 1) + } + if l := len(delta.GetOrmap().GetUpdated()); l != 0 { + t.Fatalf("length of delta.updated: %v; want: %v", l, 0) + } + }) + t.Run("should not generate a delta when a non existing element is removed", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + m.resetDelta() + m.Delete(encoding.String("two")) + if s := m.Size(); s != 1 { + t.Fatalf("m.Size(): %v; want: %v", s, 1) + } + if d := m.Delta(); d != nil { + t.Fatalf("m.Delta(): %v; want: %v", d, nil) + } + }) + t.Run("should generate a delta when an already existing element is set", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + m.resetDelta() + m.Set(encoding.String("one"), NewGCounter()) + if s := m.Size(); s != 1 { + t.Fatalf("m.Size(): %v; want: %v", s, 1) + } + delta := encDecDelta(m.Delta()) + m.resetDelta() + if l := len(delta.GetOrmap().GetRemoved()); l != 1 { + t.Fatalf("length of delta.removed: %v; want: %v", l, 1) + } + if l := len(delta.GetOrmap().GetAdded()); l != 1 { + t.Fatalf("length of delta.added: %v; want: %v", l, 1) + } + if l := len(delta.GetOrmap().GetUpdated()); l != 0 { + t.Fatalf("length of delta.updated: %v; want: %v", l, 0) + } + }) + t.Run("clear all other deltas when the set is cleared", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + m.Set(encoding.String("two"), NewGCounter()) + m.resetDelta() + counter, err := m.GCounter(encoding.String("two")) + if err != nil { + t.Fatal(err) + } + counter.Increment(10) + m.Set(encoding.String("one"), NewGCounter()) + if s := m.Size(); s != 2 { + t.Fatalf("m.Size(): %v; want: %v", s, 2) + } + m.Clear() + if s := m.Size(); s != 0 { + t.Fatalf("m.Size(): %v; want: %v", s, 0) + } + delta := encDecDelta(m.Delta()) + m.resetDelta() + if c := delta.GetOrmap().GetCleared(); !c { + t.Fatalf("ormap cleared: %v; want: %v", c, true) + } + if l := len(delta.GetOrmap().GetAdded()); l != 0 { + t.Fatalf("added len: %v; want: %v", l, 0) + } + if l := len(delta.GetOrmap().GetRemoved()); l != 0 { + t.Fatalf("added len: %v; want: %v", l, 0) + } + if l := len(delta.GetOrmap().GetUpdated()); l != 0 { + t.Fatalf("added len: %v; want: %v", l, 0) + } + }) + t.Run("should reflect a delta add", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + m.resetDelta() + err := m.applyDelta(encDecDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Ormap{Ormap: &entity.ORMapDelta{ + Added: append(make([]*entity.ORMapEntry, 0), &entity.ORMapEntry{ + Key: encoding.String("two"), + Value: &entity.CrdtState{ + State: &entity.CrdtState_Gcounter{ + Gcounter: &entity.GCounterState{ + Value: 4, + }, + }, + }, + }), + }}, + })) + if err != nil { + t.Fatal(err) + } + if s := m.Size(); s != 2 { + t.Fatalf("m.Size(): %v; want: %v", s, 2) + } + if !contains(m.Keys(), "one", "two") { + t.Fatalf("m.Keys() should include 'one','two' but did not: %v", m.Keys()) + } + counter, err := m.GCounter(encoding.String("two")) + if err != nil { + t.Fatal(err) + } + if v := counter.Value(); v != 4 { + t.Fatalf("counter.Value(): %v; want: %v", v, 4) + } + if d := m.Delta(); d != nil { + t.Fatalf("m.Delta(): %v; want: %v", d, nil) + } + m.resetDelta() + if l := len(encDecState(m.State()).GetOrmap().GetEntries()); l != 2 { + t.Fatalf("state entries len: %v; want: %v", l, 2) + } + }) + t.Run("should reflect a delta remove", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + m.Set(encoding.String("two"), NewGCounter()) + m.resetDelta() + err := m.applyDelta(encDecDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Ormap{ + Ormap: &entity.ORMapDelta{ + Removed: append(make([]*any.Any, 0), encoding.String("two")), + }}, + })) + if err != nil { + t.Fatal(err) + } + if s := m.Size(); s != 1 { + t.Fatalf("m.Size(): %v; want: %v", s, 1) + } + if !contains(m.Keys(), "one") { + t.Fatalf("m.Keys() should contain 'one' but did not: %v", m.Keys()) + } + if d := m.Delta(); d != nil { + t.Fatalf("m.Delta(): %v; want: %v", d, nil) + } + m.resetDelta() + if l := len(encDecState(m.State()).GetOrmap().GetEntries()); l != 1 { + t.Fatalf("state entries len: %v; want: %v", l, 1) + } + }) + t.Run("should reflect a delta clear", func(t *testing.T) { + m := NewORMap() + m.Set(encoding.String("one"), NewGCounter()) + m.Set(encoding.String("two"), NewGCounter()) + m.resetDelta() + err := m.applyDelta(encDecDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Ormap{ + Ormap: &entity.ORMapDelta{ + Cleared: true, + }}, + })) + if err != nil { + t.Fatal(err) + } + if s := m.Size(); s != 0 { + t.Fatalf("m.Size(): %v; want: %v", s, 0) + } + if d := m.Delta(); d != nil { + t.Fatalf("m.Delta(): %v; want: %v", d, nil) + } + m.resetDelta() + if l := len(encDecState(m.State()).GetOrmap().GetEntries()); l != 0 { + t.Fatalf("state entries len: %v; want: %v", l, 0) + } + }) + t.Run("should work with protobuf keys", func(t *testing.T) { + m := NewORMap() + type c struct { + Field1 string + } + one, err := encoding.Struct(&c{Field1: "one"}) + if err != nil { + t.Fatal(err) + } + m.Set(one, NewGCounter()) + two, err := encoding.Struct(&c{Field1: "two"}) + if err != nil { + t.Fatal(err) + } + m.Set(two, NewGCounter()) + m.resetDelta() + m.Delete(one) + if s := m.Size(); s != 1 { + t.Fatalf("m.Size(): %v; want: %v", s, 1) + } + delta := encDecDelta(m.Delta()) + if l := len(delta.GetOrmap().GetRemoved()); l != 1 { + t.Fatalf("added len: %v; want: %v", l, 1) + } + c0 := &c{} + if err := encoding.DecodeStruct(m.Delta().GetOrmap().GetRemoved()[0], c0); err != nil { + t.Fatal(err) + } + if f1 := c0.Field1; f1 != "one" { + t.Fatalf("c0.Field1: %v; want: %v", f1, "one") + } + }) + t.Run("should work with json types", func(t *testing.T) { + m := NewORMap() + bar, err := encoding.Struct(struct{ Foo string }{Foo: "bar"}) + if err != nil { + t.Fatal(err) + } + m.Set(bar, NewGCounter()) + baz, err := encoding.Struct(struct{ Foo string }{Foo: "baz"}) + if err != nil { + t.Fatal(err) + } + m.Set(baz, NewGCounter()) + m.resetDelta() + m.Delete(bar) + if s := m.Size(); s != 1 { + t.Fatalf("m.Size(): %v; want: %v", s, 1) + } + delta := encDecDelta(m.Delta()) + if l := len(delta.GetOrmap().GetRemoved()); l != 1 { + t.Fatalf("added len: %v; want: %v", l, 1) + } + c0 := &struct{ Foo string }{} + if err := encoding.DecodeStruct(m.Delta().GetOrmap().GetRemoved()[0], c0); err != nil { + t.Fatal(err) + } + if f1 := c0.Foo; f1 != "bar" { + t.Fatalf("c0.Field1: %v; want: %v", f1, "bar") + } + }) +} + +func TestORMapAdditional(t *testing.T) { + t.Run("should return values", func(t *testing.T) { + s := NewORMap() + s.Set(encoding.String("one"), NewFlag()) + s.Set(encoding.String("two"), NewFlag()) + s.Set(encoding.String("three"), NewFlag()) + s.Values() + }) + t.Run("apply invalid delta", func(t *testing.T) { + s := NewORMap() + if err := s.applyDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Flag{ + Flag: &entity.FlagDelta{ + Value: false, + }, + }, + }); err == nil { + t.Fatal("ormap applyDelta should err but did not") + } + }) + t.Run("apply invalid state", func(t *testing.T) { + s := NewORMap() + if err := s.applyState(&entity.CrdtState{ + State: &entity.CrdtState_Flag{ + Flag: &entity.FlagState{ + Value: false, + }, + }, + }); err == nil { + t.Fatal("ormap applyState should err but did not") + } + }) +} diff --git a/cloudstate/crdt/orset.go b/cloudstate/crdt/orset.go new file mode 100644 index 0000000..59efd07 --- /dev/null +++ b/cloudstate/crdt/orset.go @@ -0,0 +1,184 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/golang/protobuf/ptypes/any" +) + +// ORSet, or Observed-Removed Set, is a set that can have items both added +// and removed from it. It is implemented by maintaining a set of unique tags +// for each element which are generated on addition into the set. When an +// element is removed, all the tags that that node currently observes are added +// to the removal set, so as long as there haven’t been any new additions that +// the node hasn’t seen when it removed the element, the element will be removed. +type ORSet struct { + value map[uint64]*any.Any + added map[uint64]*any.Any + removed map[uint64]*any.Any + cleared bool + *anyHasher +} + +var _ CRDT = (*ORSet)(nil) + +func NewORSet() *ORSet { + return &ORSet{ + value: make(map[uint64]*any.Any), + added: make(map[uint64]*any.Any), + removed: make(map[uint64]*any.Any), + cleared: false, + anyHasher: &anyHasher{}, + } +} + +func (s *ORSet) Size() int { + return len(s.value) +} + +func (s *ORSet) Add(a *any.Any) { + h := s.hashAny(a) + if _, ok := s.value[h]; ok { + return + } + if _, ok := s.removed[h]; ok { + delete(s.removed, h) + } else { + s.added[h] = a + } + s.value[h] = a +} + +func (s *ORSet) Remove(a *any.Any) { + h := s.hashAny(a) + if _, ok := s.value[h]; !ok { + return + } + if len(s.value) == 1 { + s.Clear() + return + } + delete(s.value, h) + if _, ok := s.added[h]; ok { + delete(s.added, h) + } else { + s.removed[h] = a + } +} + +func (s *ORSet) Clear() { + s.value = make(map[uint64]*any.Any) + s.added = make(map[uint64]*any.Any) + s.removed = make(map[uint64]*any.Any) + s.cleared = true +} + +func (s ORSet) Value() []*any.Any { + val := make([]*any.Any, len(s.value)) + var i = 0 + for _, v := range s.value { + val[i] = v + i++ + } + return val +} + +func (s ORSet) Added() []*any.Any { + val := make([]*any.Any, len(s.added)) + var i = 0 + for _, v := range s.added { + val[i] = v + i++ + } + return val +} + +func (s ORSet) Removed() []*any.Any { + val := make([]*any.Any, len(s.removed)) + var i = 0 + for _, v := range s.removed { + val[i] = v + i++ + } + return val +} + +func (s *ORSet) State() *entity.CrdtState { + return &entity.CrdtState{ + State: &entity.CrdtState_Orset{ + Orset: &entity.ORSetState{ + Items: s.Value(), + }, + }, + } +} + +func (s *ORSet) applyState(state *entity.CrdtState) error { + set := state.GetOrset() + if set == nil { + return fmt.Errorf("unable to delta state %v to ORSet", state) + } + s.value = make(map[uint64]*any.Any, len(set.GetItems())) + for _, a := range set.GetItems() { + s.value[s.hashAny(a)] = a + } + return nil +} + +func (s *ORSet) Delta() *entity.CrdtDelta { + return &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Orset{ + Orset: &entity.ORSetDelta{ + Added: s.Added(), + Removed: s.Removed(), + Cleared: s.cleared, + }, + }, + } +} + +func (s *ORSet) HasDelta() bool { + return s.cleared || len(s.added) > 0 || len(s.removed) > 0 +} + +func (s *ORSet) resetDelta() { + s.cleared = false + s.added = make(map[uint64]*any.Any) + s.removed = make(map[uint64]*any.Any) +} + +func (s *ORSet) applyDelta(delta *entity.CrdtDelta) error { + d := delta.GetOrset() + if d == nil { + return fmt.Errorf("unable to delta %v to ORSet", delta) + } + if d.GetCleared() { + s.value = make(map[uint64]*any.Any) + } + for _, r := range d.GetRemoved() { + delete(s.value, s.hashAny(r)) + } + for _, a := range d.GetAdded() { + h := s.hashAny(a) + if _, ok := s.value[h]; !ok { + s.value[h] = a + } + } + return nil +} diff --git a/cloudstate/crdt/orset_test.go b/cloudstate/crdt/orset_test.go new file mode 100644 index 0000000..d3225fd --- /dev/null +++ b/cloudstate/crdt/orset_test.go @@ -0,0 +1,360 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "testing" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/golang/protobuf/ptypes/any" +) + +func TestORSet(t *testing.T) { + t.Run("should reflect a state update", func(t *testing.T) { + s := NewORSet() + err := s.applyState( + &entity.CrdtState{ + State: &entity.CrdtState_Orset{ + Orset: &entity.ORSetState{ + Items: append(make([]*any.Any, 0), encoding.String("one"), encoding.String("two")), + }, + }, + }, + ) + if err != nil { + t.Fatal(err) + } + if s.Size() != 2 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 2) + } + }) + + t.Run("should generate an add delta", func(t *testing.T) { + s := NewORSet() + s.Add(encoding.String("one")) + if s.Size() != 1 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 1) + } + delta := encDecDelta(s.Delta()) + s.resetDelta() + if alen := len(delta.GetOrset().GetAdded()); alen != 1 { + t.Fatalf("s.Delta()).GetAdded()): %v; want: %v", alen, 1) + } + if !contains(delta.GetOrset().GetAdded(), "one") { + t.Fatal("did not found one") + } + if s.HasDelta() { + t.Fatalf("set has delta") + } + s.Add(encoding.String("two")) + s.Add(encoding.String("three")) + if s.Size() != 3 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 3) + } + if alen := len(encDecDelta(s.Delta()).GetOrset().GetAdded()); alen != 2 { + t.Fatalf("len(GetAdded()): %v; want: %v", alen, 2) + } + if !contains(s.Added(), "two", "three") { + t.Fatal("did not found two and three") + } + s.resetDelta() + if s.HasDelta() { + t.Fatalf("set has delta") + } + }) + + t.Run("should generate a remove delta", func(t *testing.T) { + s := NewORSet() + s.Add(encoding.String("one")) + s.Add(encoding.String("two")) + s.Add(encoding.String("three")) + s.resetDelta() + if !contains(s.Value(), "one", "two", "three") { + t.Fatalf("removed does not include: one, two, three") + } + s.Remove(encoding.String("one")) + s.Remove(encoding.String("two")) + if s.Size() != 1 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 1) + } + if contains(s.Value(), "one") { + t.Fatalf("set should not include one") + } + if contains(s.Value(), "two") { + t.Fatalf("set should not include two") + } + if !contains(s.Value(), "three") { + t.Fatalf("set should include three") + } + if dlen := len(encDecDelta(s.Delta()).GetOrset().GetRemoved()); dlen != 2 { + t.Fatalf("len(delta.GetRemoved()): %v; want: %v", dlen, 2) + } + if !contains(s.Removed(), "one", "two") { + t.Fatalf("removed does not include: one, two") + } + }) + + t.Run("should generate a clear delta", func(t *testing.T) { + s := NewORSet() + s.Add(encoding.String("one")) + s.Add(encoding.String("two")) + _ = s.Delta() + s.resetDelta() + s.Clear() + if s.Size() != 0 { + t.Fatalf("s.Size(): %v; want: %v", len(s.Removed()), 0) + } + delta := encDecDelta(s.Delta()) + s.resetDelta() + if !delta.GetOrset().GetCleared() { + t.Fail() + } + s.Delta() + if s.HasDelta() { + t.Fatalf("set has delta") + } + }) + + t.Run("should generate a clear delta when everything is removed", func(t *testing.T) { + s := NewORSet() + s.Add(encoding.String("one")) + s.Add(encoding.String("two")) + s.resetDelta() + s.Remove(encoding.String("one")) + s.Remove(encoding.String("two")) + if s.Size() != 0 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 0) + } + delta := encDecDelta(s.Delta()) + s.resetDelta() + if cleared := delta.GetOrset().GetCleared(); !cleared { + t.Fatalf("delta.Cleared: %v; want: %v", cleared, true) + } + if s.HasDelta() { + t.Fatalf("set has delta") + } + }) + + t.Run("should not generate a delta when an added element is removed", func(t *testing.T) { + s := NewORSet() + s.Add(encoding.String("one")) + s.Add(encoding.String("two")) + s.Delta() + s.resetDelta() + s.Add(encoding.String("two")) + s.Remove(encoding.String("two")) + if s.Size() != 1 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 1) + } + // delta := encDecDelta(s.Delta()) + s.resetDelta() + if s.HasDelta() { + t.Fatalf("set has delta") + } + }) + + t.Run("should not generate a delta when a removed element is added", func(t *testing.T) { + s := NewORSet() + s.Add(encoding.String("one")) + s.Add(encoding.String("two")) + s.Delta() + s.resetDelta() + s.Remove(encoding.String("two")) + s.Add(encoding.String("two")) + if s.Size() != 2 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 2) + } + if s.HasDelta() { + t.Fatalf("set has delta") + } + }) + + t.Run("should not generate a delta when an already existing element is added", func(t *testing.T) { + s := NewORSet() + s.Add(encoding.String("one")) + s.resetDelta() + s.Add(encoding.String("one")) + if s.Size() != 1 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 1) + } + if s.HasDelta() { + t.Fatalf("set has delta") + } + }) + + t.Run("should not generate a delta when a non existing element is removed", func(t *testing.T) { + s := NewORSet() + s.Add(encoding.String("one")) + s.resetDelta() + s.Remove(encoding.String("two")) + if s.Size() != 1 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 1) + } + if s.HasDelta() { + t.Fatalf("set has delta") + } + }) + + t.Run("clear all other deltas when the set is cleared", func(t *testing.T) { + s := NewORSet() + s.Add(encoding.String("one")) + s.resetDelta() + s.Add(encoding.String("two")) + s.Remove(encoding.String("one")) + s.Clear() + if s.Size() != 0 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 0) + } + delta := encDecDelta(s.Delta()) + if cleared := delta.GetOrset().GetCleared(); !cleared { + t.Fatalf("delta.Cleared: %v; want: %v", cleared, 0) + } + if alen := len(delta.GetOrset().GetAdded()); alen != 0 { + t.Fatalf("len(delta.GetAdded()): %v; want: %v", alen, 0) + } + if rlen := len(delta.GetOrset().GetRemoved()); rlen != 0 { + t.Fatalf("len(delta.GetRemoved): %v; want: %v", rlen, 0) + } + }) + t.Run("should reflect a delta add", func(t *testing.T) { + s := NewORSet() + s.Add(encoding.String("one")) + s.resetDelta() + if err := s.applyDelta(encDecDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Orset{ + Orset: &entity.ORSetDelta{ + Added: append(make([]*any.Any, 0), encoding.String("two")), + }, + }, + })); err != nil { + t.Fatal(err) + } + if s.Size() != 2 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 2) + } + s.resetDelta() + if s.HasDelta() { + t.Fatalf("set has delta") + } + stateLen := len(encDecState(s.State()).GetOrset().GetItems()) + if stateLen != 2 { + t.Fatalf("len(GetItems()): %v; want: %v", stateLen, 2) + } + }) + + t.Run("should reflect a delta remove", func(t *testing.T) { + s := NewORSet() + s.Add(encoding.String("one")) + s.Add(encoding.String("two")) + if err := s.applyDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Orset{ + Orset: &entity.ORSetDelta{ + Removed: append(make([]*any.Any, 0), encoding.String("two")), + }, + }, + }); err != nil { + t.Fatal(err) + } + if s.Size() != 1 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 1) + } + + if slen := len(encDecState(s.State()).GetOrset().GetItems()); slen != 1 { + t.Fatalf("len(GetItems()): %v; want: %v", slen, 1) + } + }) + + t.Run("should reflect a delta clear", func(t *testing.T) { + s := NewORSet() + s.Add(encoding.String("one")) + s.Add(encoding.String("two")) + s.resetDelta() + if err := s.applyDelta(encDecDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Orset{ + Orset: &entity.ORSetDelta{ + Cleared: true, + }, + }, + })); err != nil { + t.Fatal(err) + } + if s.Size() != 0 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 0) + } + if slen := len(encDecState(s.State()).GetOrset().GetItems()); slen != 0 { + t.Fatalf("len(GetItems()): %v; want: %v", slen, 0) + } + }) + + t.Run("should work with protobuf types", func(t *testing.T) { + s := NewORSet() + type Example struct { + Field1 string + } + one, err := encoding.Struct(Example{Field1: "one"}) + if err != nil { + t.Fatal(err) + } + s.Add(one) + two, err := encoding.Struct(Example{Field1: "two"}) + if err != nil { + t.Fatal(err) + } + s.Add(two) + s.resetDelta() + s.Remove(one) + if s.Size() != 1 { + t.Fatalf("s.Size(): %v; want: %v", s.Size(), 1) + } + delta := encDecDelta(s.Delta()) + + if rlen := len(delta.GetOrset().GetRemoved()); rlen != 1 { + t.Fatalf("rlen: %v; want: %v", rlen, 1) + } + e := &Example{} + if err := encoding.UnmarshalJSON(delta.GetOrset().GetRemoved()[0], e); err != nil || e.Field1 != "one" { + t.Fail() + } + }) +} + +func TestORSetAdditional(t *testing.T) { + t.Run("apply invalid delta", func(t *testing.T) { + s := NewORSet() + if err := s.applyDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Flag{ + Flag: &entity.FlagDelta{ + Value: false, + }, + }, + }); err == nil { + t.Fatal("orset applyDelta should err but did not") + } + }) + t.Run("apply invalid state", func(t *testing.T) { + s := NewORSet() + if err := s.applyState(&entity.CrdtState{ + State: &entity.CrdtState_Flag{ + Flag: &entity.FlagState{ + Value: false, + }, + }, + }); err == nil { + t.Fatal("orset applyState should err but did not") + } + }) +} diff --git a/cloudstate/crdt/pncounter.go b/cloudstate/crdt/pncounter.go new file mode 100644 index 0000000..6a5eda7 --- /dev/null +++ b/cloudstate/crdt/pncounter.go @@ -0,0 +1,100 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/entity" +) + +// PNCounter, or Positive-Negative Counter, is a counter that can both be incremented +// and decremented. It works by combining two GCounters, a positive one, that tracks +// increments, and a negative one, that tracks decrements. The final counter value is +// computed by subtracting the negative GCounter from the positive GCounter. +type PNCounter struct { + value int64 + delta int64 +} + +var _ CRDT = (*PNCounter)(nil) + +func NewPNCounter() *PNCounter { + return &PNCounter{} +} + +func (c *PNCounter) Value() int64 { + return c.value +} + +func (c *PNCounter) Increment(i int64) { + c.value += i + c.delta += i +} + +func (c *PNCounter) Decrement(d int64) { + c.value -= d + c.delta -= d +} + +func (c *PNCounter) State() *entity.CrdtState { + return &entity.CrdtState{ + State: &entity.CrdtState_Pncounter{ + Pncounter: &entity.PNCounterState{ + Value: c.value, + }, + }, + } +} + +func (c *PNCounter) HasDelta() bool { + return c.delta != 0 +} + +func (c *PNCounter) Delta() *entity.CrdtDelta { + if c.delta == 0 { + return nil + } + return &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Pncounter{ + Pncounter: &entity.PNCounterDelta{ + Change: c.delta, + }, + }, + } +} + +func (c *PNCounter) resetDelta() { + c.delta = 0 +} + +func (c *PNCounter) applyState(state *entity.CrdtState) error { + s := state.GetPncounter() + if s == nil { + return fmt.Errorf("unable to apply state %v to PNCounter", state) + } + c.value = s.GetValue() + return nil +} + +func (c *PNCounter) applyDelta(delta *entity.CrdtDelta) error { + d := delta.GetPncounter() + if d == nil { + return fmt.Errorf("unable to apply delta %v to PNCounter", delta) + } + c.value += d.GetChange() + return nil +} diff --git a/cloudstate/crdt/pncounter_test.go b/cloudstate/crdt/pncounter_test.go new file mode 100644 index 0000000..37230f0 --- /dev/null +++ b/cloudstate/crdt/pncounter_test.go @@ -0,0 +1,164 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "testing" + + "github.com/cloudstateio/go-support/cloudstate/entity" +) + +func TestPNCounter(t *testing.T) { + state := func(v int64) *entity.CrdtState { + return &entity.CrdtState{ + State: &entity.CrdtState_Pncounter{ + Pncounter: &entity.PNCounterState{ + Value: v, + }, + }, + } + } + delta := func(v int64) *entity.CrdtDelta { + return &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Pncounter{ + Pncounter: &entity.PNCounterDelta{ + Change: v, + }, + }, + } + } + + t.Run("should have a value of zero when instantiated", func(t *testing.T) { + c := NewPNCounter() + if v := c.Value(); v != 0 { + t.Fatalf("c.Value: %v; want: %v", v, 0) + } + }) + t.Run("should reflect a state update", func(t *testing.T) { + c := NewPNCounter() + if err := c.applyState(encDecState(state(10))); err != nil { + t.Fatal(err) + } + if v := c.Value(); v != 10 { + t.Fatalf("c.Value: %v; want: %v", v, 10) + } + if err := c.applyState(encDecState(state(-5))); err != nil { + t.Fatal(err) + } + if v := c.Value(); v != -5 { + t.Fatalf("c.Value: %v; want: %v", v, -5) + } + }) + t.Run("should reflect a delta update", func(t *testing.T) { + c := NewPNCounter() + if err := c.applyDelta(encDecDelta(delta(10))); err != nil { + t.Fatal(err) + } + if v := c.Value(); v != 10 { + t.Fatalf("c.Value: %v; want: %v", v, 10) + } + if err := c.applyDelta(encDecDelta(delta(-3))); err != nil { + t.Fatal(err) + } + if v := c.Value(); v != 7 { + t.Fatalf("c.Value: %v; want: %v", v, 7) + } + }) + t.Run("should generate deltas", func(t *testing.T) { + c := NewPNCounter() + c.Increment(10) + if v := c.Value(); v != 10 { + t.Fatalf("c.Value: %v; want: %v", v, 10) + } + if d := encDecDelta(c.Delta()).GetPncounter().GetChange(); d != 10 { + t.Fatalf("c.Delta: %v; want: %v", d, 10) + } + c.resetDelta() + if d := c.Delta(); d != nil { + t.Fatalf("c.Delta() should have been nil but was not: %+v", d) + } + c.Decrement(3) + if v := c.Value(); v != 7 { + t.Fatalf("c.Value: %v; want: %v", v, 7) + } + c.Decrement(4) + if v := c.Value(); v != 3 { + t.Fatalf("c.Value: %v; want: %v", v, 3) + } + if d := encDecDelta(c.Delta()).GetPncounter().GetChange(); d != -7 { + t.Fatalf("c.Delta: %v; want: %v", d, -7) + } + c.resetDelta() + if d := c.Delta(); d != nil { + t.Fatalf("c.Delta() should have been nil but was not: %+v", d) + } + }) + t.Run("should return its state", func(t *testing.T) { + c := NewPNCounter() + c.Increment(10) + if v := c.Value(); v != 10 { + t.Fatalf("c.Value: %v; want: %v", v, 10) + } + if v := encDecState(c.State()).GetPncounter().GetValue(); v != 10 { + t.Fatalf("c.Value: %v; want: %v", v, 10) + } + c.resetDelta() + if d := c.Delta(); d != nil { + t.Fatalf("c.Delta() should have been nil but was not: %+v", d) + } + }) +} + +func TestPNCounterAdditional(t *testing.T) { + t.Run("should report hasDelta", func(t *testing.T) { + c := NewPNCounter() + if c.HasDelta() { + t.Fatalf("c.HasDelta() but should not") + } + c.Increment(29) + if !c.HasDelta() { + t.Fatalf("c.HasDelta() is false, but should not") + } + }) + + t.Run("should catch illegal delta applied", func(t *testing.T) { + c := NewPNCounter() + err := c.applyDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Flag{ + Flag: &entity.FlagDelta{ + Value: false, + }, + }, + }) + if err == nil { + t.Fatalf("c.applyDelta() has to err, but did not") + } + }) + + t.Run("should catch illegal state applied", func(t *testing.T) { + c := NewPNCounter() + err := c.applyState(&entity.CrdtState{ + State: &entity.CrdtState_Flag{ + Flag: &entity.FlagState{ + Value: true, + }, + }, + }) + if err == nil { + t.Fatalf("c.applyState() has to err, but did not") + } + }) +} diff --git a/cloudstate/crdt/runner.go b/cloudstate/crdt/runner.go new file mode 100644 index 0000000..509a9e7 --- /dev/null +++ b/cloudstate/crdt/runner.go @@ -0,0 +1,241 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "errors" + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/cloudstate/protocol" +) + +// runner runs a stream with the help of a context. +type runner struct { + stream entity.Crdt_HandleServer + context *Context +} + +// handleState handles an incoming state message to be applied to the current state. +// A entity.CrdtState message is sent to indicate the user function should replace its +// current value with this value. If the user function does not have a current +// value, either because the commandContextFor function didn't send one and the +// user function hasn't updated the value itself in response to a command, or +// because the value was deleted, this must be sent before any deltas. +func (r *runner) handleState(state *entity.CrdtState) error { + if r.context.crdt == nil { + s, err := newFor(state) + if err != nil { + return err + } + r.context.crdt = s + } + // state has to match the state type, applyState will err if not. + if err := r.context.crdt.applyState(state); err != nil { + return err + } + return r.context.Instance.Set(r.context, r.context.crdt) +} + +// handleDelta handles an incoming delta message to be applied to the current state. +// A delta to be applied to the current value. It may be sent at any time as long +// as the user function already has value. +func (r *runner) handleDelta(delta *entity.CrdtDelta) error { + if r.context.crdt == nil { + return fmt.Errorf("received delta for crdt before it was created: %v", r.context.Entity) + } + return r.context.crdt.applyDelta(delta) +} + +// handleCancellation handles an incoming cancellation message to be applied to +// the current state. A stream has been cancelled. A command handler may also +// register an onCancel callback to be notified when the stream is cancelled. +// The cancellation callback handler may update the crdt. This is useful if +// the crdt is being used to track connections, for example, when using Vote +// CRDTs to track a users online status. +func (r *runner) handleCancellation(cancelled *protocol.StreamCancelled) error { + id := CommandID(cancelled.GetId()) + ctx := r.context.streamedCtx[id] + // The cancelled stream is not allowed to handle changes, so we remove it. + delete(r.context.streamedCtx, id) + if ctx.cancel == nil { + return r.sendCancelledMessage(&entity.CrdtStreamCancelledResponse{ + CommandId: id.Value(), + }) + } + // Notify the user about the cancellation. + if err := ctx.cancelled(); err != nil { + return err + } + stateAction := ctx.stateAction() + err := r.sendCancelledMessage(&entity.CrdtStreamCancelledResponse{ + CommandId: id.Value(), + StateAction: stateAction, + SideEffects: ctx.sideEffects, + }) + if err != nil { + return err + } + // The state has been changed therefore streamed change handlers get + // informed. + if stateAction != nil { + return r.handleChange() + } + return nil +} + +// handleCommand handles the received command. +// Cloudstate CRDTs support handling server streamed calls, that is, when the +// gRPC service call for a CRDT marks the return type as streamed. When a user +// function receives a streamed message, it is allowed to update the CRDT, on +// two occasions - when the call is first received, and when the client cancels +// the stream. If it wishes to make updates at other times, it can do so by +// emitting effects with the streamed messages that it sends down the stream. +// A user function can send a message down a stream in response to anything, +// however the Cloudstate supplied support libraries only allow sending messages +// in response to the CRDT changing. In this way, use cases that require monitoring +// the state of a CRDT can be implemented. +func (r *runner) handleCommand(cmd *protocol.Command) (streamError error) { + if r.context.EntityID != EntityID(cmd.EntityId) { + return fmt.Errorf("the command entity id: %s does not match the initialized entity id: %s", cmd.EntityId, r.context.EntityID) + } + ctx := r.context.commandContextFor(cmd) + reply, err := ctx.runCommand(cmd) + if err != nil && !errors.Is(err, protocol.ClientError{}) { + return err + } + // TODO: error handling has to be clarified. + // It seems, CRDT streams stopped for any error, even client failures. + // see: https://github.com/cloudstateio/cloudstate/pull/392 + if err != nil { + ctx.fail(err) + } + // If the user function has failed, a client action failure will be sent. + if ctx.failed != nil { + reply = nil + } else if err != nil { + // On any other error, we return and close the stream. + return err + } + clientAction, err := ctx.clientActionFor(reply) + if err != nil { + return err + } + if ctx.failed != nil { + return r.sendCrdtReply(&entity.CrdtReply{ + CommandId: ctx.CommandID.Value(), + ClientAction: clientAction, // this is a ClientAction_Failure + }) + } + stateAction := ctx.stateAction() + err = r.sendCrdtReply(&entity.CrdtReply{ + CommandId: ctx.CommandID.Value(), + ClientAction: clientAction, + SideEffects: ctx.sideEffects, + StateAction: stateAction, + // TODO: Does a user choose to have a command streamed? + // Marking the reply streamed while having a stream flag on the command seems superfluous. + // According to the JVM implementation this means "stream accepted" and therefore shows the proxy if + // there are commands handling a streamed method. + // TODO(spec): feedback on spec about this. + Streamed: ctx.Streamed(), + }) + if err != nil { + return err + } + ctx.clearSideEffect() + if stateAction != nil { + if err := r.handleChange(); err != nil { + return err + } + } + if ctx.Streamed() { + ctx.trackChanges() + } + return nil +} + +func (r *runner) handleChange() error { + for _, ctx := range r.context.streamedCtx { + if ctx.change == nil { + continue + } + reply, err := ctx.changed() + + // TODO: we have to clarify error path from here on. + if errors.Is(err, ErrCtxFailCalled) { + // ctx.clientActionFor will report a failure for that. + reply = nil + } else if err != nil { + return err + } + clientAction, err := ctx.clientActionFor(reply) + if err != nil { + return err + } + if ctx.failed != nil { + delete(ctx.streamedCtx, ctx.CommandID) + if err := r.sendStreamedMessage(&entity.CrdtStreamedMessage{ + CommandId: ctx.CommandID.Value(), + ClientAction: clientAction, + }); err != nil { + return err + } + continue + } + if clientAction != nil || ctx.ended || len(ctx.sideEffects) > 0 { + if ctx.ended { + delete(ctx.streamedCtx, ctx.CommandID) + } + msg := &entity.CrdtStreamedMessage{ + CommandId: ctx.CommandID.Value(), + ClientAction: clientAction, + SideEffects: ctx.sideEffects, + EndStream: ctx.ended, + } + if err := r.sendStreamedMessage(msg); err != nil { + return err + } + ctx.clearSideEffect() + continue + } + } + return nil +} + +func (r *runner) sendStreamedMessage(msg *entity.CrdtStreamedMessage) error { + return r.stream.Send(&entity.CrdtStreamOut{ + Message: &entity.CrdtStreamOut_StreamedMessage{ + StreamedMessage: msg, + }, + }) +} + +func (r *runner) sendCancelledMessage(msg *entity.CrdtStreamCancelledResponse) error { + return r.stream.Send(&entity.CrdtStreamOut{ + Message: &entity.CrdtStreamOut_StreamCancelledResponse{ + StreamCancelledResponse: msg, + }, + }) +} + +func (r *runner) sendCrdtReply(reply *entity.CrdtReply) error { + return r.stream.Send(&entity.CrdtStreamOut{ + Message: &entity.CrdtStreamOut_Reply{ + Reply: reply, + }, + }) +} diff --git a/cloudstate/crdt/server.go b/cloudstate/crdt/server.go new file mode 100644 index 0000000..ee84684 --- /dev/null +++ b/cloudstate/crdt/server.go @@ -0,0 +1,205 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "errors" + "fmt" + "io" + "log" + "sync" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +// Server is the implementation of the Server server API for the CRDT service. +type Server struct { + // mu protects the map below. + mu sync.RWMutex + // entities has descriptions of entities registered by service names + entities map[ServiceName]*Entity +} + +// NewServer returns an initialized Server. +func NewServer() *Server { + return &Server{ + entities: make(map[ServiceName]*Entity), + } +} + +// CrdtEntities can be registered to a server that handles crdt entities by a ServiceName. +// Whenever a internalCRDT.Server receives an CrdInit for an instance of a crdt entity identified by its +// EntityID and a ServiceName, the internalCRDT.Server handles such entities through their lifecycle. +// The handled entities value are captured by a context that is held fo each of them. +func (s *Server) Register(e *Entity) error { + if e.EntityFunc == nil { + return errors.New("the entity has to define an EntityFunc but did not") + } + s.mu.Lock() + defer s.mu.Unlock() + if _, exists := s.entities[e.ServiceName]; exists { + return fmt.Errorf("an entity with service name: %q is already registered", e.ServiceName) + } + s.entities[e.ServiceName] = e + return nil +} + +// After invoking handle, the first message sent will always be a CrdtInit message, +// containing the entity ID, and, if it exists or is available, the current value of +// the entity. After that, one or more commands may be sent, as well as deltas as +// they arrive, and the entire value if either the entity is created, or the proxy +// wishes the user function to replace its entire value. The user function must +// respond with one reply per command in. They do not necessarily have to be sent +// in the same order that the commands were sent, the command ID is used to correlate +// commands to replies. +func (s *Server) Handle(stream entity.Crdt_HandleServer) error { + defer func() { + if r := recover(); r != nil { + _ = sendFailure(fmt.Errorf("CrdtServer.Handle panic-ked with: %v", r), stream) + panic(r) + } + }() + for { + err := s.handle(stream) + if err == nil { + continue + } + if err == io.EOF { + return nil + } + if status.Code(err) == codes.Canceled { + return err + } + log.Print(err) + if sendErr := sendFailure(err, stream); sendErr != nil { + log.Print(sendErr) + } + return status.Error(codes.Aborted, err.Error()) + } +} + +// handle handles a streams messages to be received. +// io.EOF returned will close the stream gracefully, other errors will be sent +// to the proxy as a failure and a nil error value restarts the stream to be +// reused. +func (s *Server) handle(stream entity.Crdt_HandleServer) error { + first, err := stream.Recv() + if err != nil { + return err + } + r := &runner{stream: stream} + switch m := first.GetMessage().(type) { + case *entity.CrdtStreamIn_Init: + // First, always a CrdtInit message must be received. + if err = s.handleInit(m.Init, r); err != nil { + return fmt.Errorf("handling of CrdtInit failed with: %w", err) + } + default: + return fmt.Errorf("a message was received without having a CrdtInit message first: %v", m) + } + // Handle all other messages after a CrdtInit message has been received. + for { + if r.context.deleted { + // With a context flagged deleted, a CrdtDelete + // was received or delete state action was sent. + // Here we return no error and left the stream open. + return nil + } + if r.context.failed != nil { + // failed means deactivated. We may never get this far. + return nil + } + msg, err := r.stream.Recv() + if err != nil { + return err + } + switch m := msg.GetMessage().(type) { + case *entity.CrdtStreamIn_State: + if err := r.handleState(m.State); err != nil { + return err + } + if err := r.handleChange(); err != nil { + return err + } + case *entity.CrdtStreamIn_Changed: + if err := r.handleDelta(m.Changed); err != nil { + return err + } + if err := r.handleChange(); err != nil { + return err + } + case *entity.CrdtStreamIn_Deleted: + // Delete the entity. May be sent at any time. The user function should clear its value when it receives this. + // A proxy may decide to terminate the stream after sending this. + r.context.Delete() + case *entity.CrdtStreamIn_Command: + // A command, may be sent at any time. + // The CRDT is allowed to be changed. + if err := r.handleCommand(m.Command); err != nil { + return err + } + case *entity.CrdtStreamIn_StreamCancelled: + // The CRDT is allowed to be changed. + if err := r.handleCancellation(m.StreamCancelled); err != nil { + return err + } + case *entity.CrdtStreamIn_Init: + if EntityID(m.Init.EntityId) == r.context.EntityID { + return errors.New("duplicate init message for the same entity") + } + return fmt.Errorf("duplicate init message for a new entity: %q", m.Init.EntityId) + case nil: + return errors.New("empty message received") + default: + return fmt.Errorf("unknown message received: %+v", msg.GetMessage()) + } + } +} + +func (s *Server) handleInit(init *entity.CrdtInit, r *runner) error { + if init.GetServiceName() == "" || init.GetEntityId() == "" { + return fmt.Errorf("no service name or entity id was defined for init: %+v", init) + } + serviceName := ServiceName(init.GetServiceName()) + s.mu.RLock() + entity, ok := s.entities[serviceName] + s.mu.RUnlock() + if !ok { + return fmt.Errorf("received CrdtInit for an unknown crdt service: %q", serviceName) + } + if entity.EntityFunc == nil { + return fmt.Errorf("entity.EntityFunc is not defined for service: %q", serviceName) + } + id := EntityID(init.GetEntityId()) + r.context = &Context{ + EntityID: id, + Entity: entity, + Instance: entity.EntityFunc(id), + created: false, + ctx: r.stream.Context(), // This context is stable as long as the runner runs. + streamedCtx: make(map[CommandID]*CommandContext), + } + // The init message may have an initial state. + if state := init.GetState(); state != nil { + if err := r.handleState(state); err != nil { + return err + } + } + // The user entity can provide a CRDT through a default function if none is set. + return r.context.initDefault() +} diff --git a/cloudstate/crdt/state.go b/cloudstate/crdt/state.go new file mode 100644 index 0000000..8ac5f02 --- /dev/null +++ b/cloudstate/crdt/state.go @@ -0,0 +1,45 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/entity" +) + +func newFor(state *entity.CrdtState) (CRDT, error) { + switch t := state.GetState().(type) { + case *entity.CrdtState_Flag: + return NewFlag(), nil + case *entity.CrdtState_Gcounter: + return NewGCounter(), nil + case *entity.CrdtState_Gset: + return NewGSet(), nil + case *entity.CrdtState_Lwwregister: + return NewLWWRegister(nil), nil + case *entity.CrdtState_Ormap: + return NewORMap(), nil + case *entity.CrdtState_Orset: + return NewORSet(), nil + case *entity.CrdtState_Pncounter: + return NewPNCounter(), nil + case *entity.CrdtState_Vote: + return NewVote(), nil + default: + return nil, fmt.Errorf("no CRDT type matched: %v", t) + } +} diff --git a/cloudstate/crdt/state_test.go b/cloudstate/crdt/state_test.go new file mode 100644 index 0000000..9070b5c --- /dev/null +++ b/cloudstate/crdt/state_test.go @@ -0,0 +1,58 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "reflect" + "testing" + + "github.com/cloudstateio/go-support/cloudstate/entity" +) + +func Test_newFor(t *testing.T) { + type args struct { + state *entity.CrdtState + } + tests := []struct { + name string + args args + want CRDT + }{ + {"newForFlag", args{state: &entity.CrdtState{State: &entity.CrdtState_Flag{}}}, NewFlag()}, + {"newForGCounter", args{state: &entity.CrdtState{State: &entity.CrdtState_Gcounter{}}}, NewGCounter()}, + {"newForGset", args{state: &entity.CrdtState{State: &entity.CrdtState_Gset{}}}, NewGSet()}, + {"newForLWWRegister", args{state: &entity.CrdtState{State: &entity.CrdtState_Lwwregister{}}}, NewLWWRegister(nil)}, + {"newForORMap", args{state: &entity.CrdtState{State: &entity.CrdtState_Ormap{}}}, NewORMap()}, + {"newForORSet", args{state: &entity.CrdtState{State: &entity.CrdtState_Orset{}}}, NewORSet()}, + {"newForPNCounter", args{state: &entity.CrdtState{State: &entity.CrdtState_Pncounter{}}}, NewPNCounter()}, + {"newForVote", args{state: &entity.CrdtState{State: &entity.CrdtState_Vote{}}}, NewVote()}, + {"newForNil", args{state: &entity.CrdtState{State: nil}}, nil}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + state, err := newFor(tt.args.state) + if err != nil { + if tt.want == nil { + return + } + t.Fatal(err) + } + if got := state; !reflect.DeepEqual(got, tt.want) { + t.Errorf("newFor() = %+v, want %+v", got, tt.want) + } + }) + } +} diff --git a/cloudstate/crdt/stream_failure.go b/cloudstate/crdt/stream_failure.go new file mode 100644 index 0000000..e4b4420 --- /dev/null +++ b/cloudstate/crdt/stream_failure.go @@ -0,0 +1,31 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/cloudstate/protocol" +) + +func sendFailure(e error, stream entity.Crdt_HandleServer) error { + return stream.Send(&entity.CrdtStreamOut{ + Message: &entity.CrdtStreamOut_Failure{ + Failure: &protocol.Failure{ + Description: e.Error(), + }, + }, + }) +} diff --git a/cloudstate/crdt/support_test.go b/cloudstate/crdt/support_test.go new file mode 100644 index 0000000..76b923e --- /dev/null +++ b/cloudstate/crdt/support_test.go @@ -0,0 +1,65 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" +) + +func contains(in []*any.Any, all ...string) bool { + seen := 0 + for _, x := range in { + dec := encoding.DecodeString(x) + for _, one := range all { + if dec == one { + seen++ + } + if seen == len(all) { + return true + } + } + } + return false +} + +func encDecState(s *entity.CrdtState) *entity.CrdtState { + marshal, err := proto.Marshal(s) + if err != nil { + // we panic for convenience in test + panic(err) + } + out := &entity.CrdtState{} + if err := proto.Unmarshal(marshal, out); err != nil { + panic(err) + } + return out +} + +func encDecDelta(s *entity.CrdtDelta) *entity.CrdtDelta { + marshal, err := proto.Marshal(s) + if err != nil { + // we panic for convenience in test + panic(err) + } + out := &entity.CrdtDelta{} + if err := proto.Unmarshal(marshal, out); err != nil { + panic(err) + } + return out +} diff --git a/cloudstate/crdt/type.go b/cloudstate/crdt/type.go new file mode 100644 index 0000000..fc7f147 --- /dev/null +++ b/cloudstate/crdt/type.go @@ -0,0 +1,28 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import "github.com/cloudstateio/go-support/cloudstate/entity" + +type CRDT interface { + State() *entity.CrdtState + Delta() *entity.CrdtDelta + HasDelta() bool + + applyState(*entity.CrdtState) error + applyDelta(*entity.CrdtDelta) error + resetDelta() +} diff --git a/cloudstate/crdt/types.go b/cloudstate/crdt/types.go new file mode 100644 index 0000000..b66ea6c --- /dev/null +++ b/cloudstate/crdt/types.go @@ -0,0 +1,34 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +type ( + ServiceName string + EntityID string + CommandID int64 +) + +func (i EntityID) String() string { + return string(i) +} + +func (sn ServiceName) String() string { + return string(sn) +} + +func (id CommandID) Value() int64 { + return int64(id) +} diff --git a/cloudstate/crdt/vote.go b/cloudstate/crdt/vote.go new file mode 100644 index 0000000..76b1c3e --- /dev/null +++ b/cloudstate/crdt/vote.go @@ -0,0 +1,144 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/entity" +) + +// A Vote is a CRDT which allows nodes to vote on a condition. It’s similar +// to a GCounter, each node has its own counter, and an odd value is considered +// a vote for the condition, while an even value is considered a vote against. +// The result of the vote is decided by taking the votes of all nodes that are +// currently members of the cluster (when a node leave, its vote is discarded). +// Multiple decision strategies can be used to decide the result of the vote, +// such as at least one, majority and all. +type Vote struct { + selfVote bool + selfVoteChanged bool // delta seen + voters uint32 + votesFor uint32 +} + +var _ CRDT = (*Vote)(nil) + +func NewVote() *Vote { + return &Vote{ + selfVote: false, + selfVoteChanged: false, + voters: 1, + votesFor: 0, + } +} + +// SelfVote is the vote of the current node, +// which is included in Voters and VotesFor. +func (v *Vote) SelfVote() bool { + return v.selfVote +} + +// Voters is the total number of voters. +func (v *Vote) Voters() uint32 { + return v.voters +} + +// VotesFor is the number of votes for. +func (v *Vote) VotesFor() uint32 { + return v.votesFor +} + +// AtLeastOne returns true if there is at least one voter for the condition. +func (v *Vote) AtLeastOne() bool { + return v.votesFor > 0 +} + +// Majority returns true if the number of votes for is more than half the number of voters. +func (v *Vote) Majority() bool { + return v.votesFor > v.voters/2 +} + +// All returns true if the number of votes for equals the number of voters. +func (v *Vote) All() bool { + return v.votesFor == v.voters +} + +// Vote votes with the given boolean for a condition. +func (v *Vote) Vote(vote bool) { + if v.selfVote == vote { + return + } + v.selfVoteChanged = !v.selfVoteChanged + v.selfVote = vote + if v.selfVote { + v.votesFor += 1 + } else { + v.votesFor -= 1 + } +} + +func (v *Vote) HasDelta() bool { + return v.selfVoteChanged +} + +func (v *Vote) Delta() *entity.CrdtDelta { + if !v.selfVoteChanged { + return nil + } + return &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Vote{Vote: &entity.VoteDelta{ + SelfVote: v.selfVote, + VotesFor: int32(v.votesFor), // TODO, we never overflow, yes? + TotalVoters: int32(v.voters), + }}, + } +} + +func (v *Vote) resetDelta() { + v.selfVoteChanged = false +} + +func (v *Vote) State() *entity.CrdtState { + return &entity.CrdtState{ + State: &entity.CrdtState_Vote{Vote: &entity.VoteState{ + VotesFor: v.votesFor, + TotalVoters: v.voters, + SelfVote: v.selfVote, + }}, + } +} + +func (v *Vote) applyDelta(delta *entity.CrdtDelta) error { + d := delta.GetVote() + if d == nil { + return fmt.Errorf("unable to apply delta %+v to the Vote", delta) + } + v.voters = uint32(d.TotalVoters) + v.votesFor = uint32(d.VotesFor) + return nil +} + +func (v *Vote) applyState(state *entity.CrdtState) error { + s := state.GetVote() + if s == nil { + return fmt.Errorf("unable to apply state %+v to the Vote", state) + } + v.selfVote = s.SelfVote + v.voters = s.TotalVoters + v.votesFor = s.VotesFor + return nil +} diff --git a/cloudstate/crdt/vote_test.go b/cloudstate/crdt/vote_test.go new file mode 100644 index 0000000..81bbab9 --- /dev/null +++ b/cloudstate/crdt/vote_test.go @@ -0,0 +1,226 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "testing" + + "github.com/cloudstateio/go-support/cloudstate/entity" +) + +func TestVote(t *testing.T) { + t.Run("should have zero voters, votes and no self vote when instantiated", func(t *testing.T) { + v := NewVote() + if v.VotesFor() != 0 { + t.Fatalf("v.VotesFor(): %v; want: %v", v.VotesFor(), 0) + } + if v.Voters() != 1 { + t.Fatalf("v.Voters(): %v; want: %v", v.Voters(), 1) + } + if v.SelfVote() != false { + t.Fatalf("v.SelfVote(): %v; want: %v", v.SelfVote(), false) + } + }) + t.Run("should reflect a state update", func(t *testing.T) { + v := NewVote() + err := v.applyState(encDecState(&entity.CrdtState{ + State: &entity.CrdtState_Vote{ + Vote: &entity.VoteState{ + TotalVoters: 5, + VotesFor: 3, + SelfVote: true, + }}, + })) + if err != nil { + t.Fatal(err) + } + if v.VotesFor() != 3 { + t.Fatalf("v.VotesFor(): %v; want: %v", v.VotesFor(), 3) + } + if v.Voters() != 5 { + t.Fatalf("v.Voters(): %v; want: %v", v.Voters(), 5) + } + if v.SelfVote() != true { + t.Fatalf("v.SelfVote(): %v; want: %v", v.SelfVote(), true) + } + }) + t.Run("should reflect a delta update", func(t *testing.T) { + v := NewVote() + if err := v.applyState(encDecState(&entity.CrdtState{ + State: &entity.CrdtState_Vote{ + Vote: &entity.VoteState{ + TotalVoters: 5, + VotesFor: 3, + SelfVote: false, + }}, + })); err != nil { + t.Fatal(err) + } + if err := v.applyDelta(encDecDelta(&entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Vote{ + Vote: &entity.VoteDelta{ + TotalVoters: 4, + VotesFor: 2, + }}, + })); err != nil { + t.Fatal(err) + } + if v.VotesFor() != 2 { + t.Fatalf("v.VotesFor(): %v; want: %v", v.VotesFor(), 2) + } + if v.Voters() != 4 { + t.Fatalf("v.Voters(): %v; want: %v", v.Voters(), 4) + } + if v.SelfVote() != false { + t.Fatalf("v.SelfVote(): %v; want: %v", v.SelfVote(), false) + } + }) + t.Run("should generate deltas", func(t *testing.T) { + v := NewVote() + v.Vote(true) + delta := encDecDelta(v.Delta()) + v.resetDelta() + if dv := delta.GetVote().GetSelfVote(); dv != true { + t.Fatalf("delta.SelfVote(): %v; want: %v", dv, true) + } + if delta2 := v.Delta(); delta2 != nil { + t.Fatalf("v.Delta(): %v; want: %v", delta2, nil) + } + if v.VotesFor() != 1 { + t.Fatalf("v.VotesFor(): %v; want: %v", v.VotesFor(), 1) + } + if v.SelfVote() != true { + t.Fatalf("v.SelfVote(): %v; want: %v", v.SelfVote(), true) + } + + v.Vote(false) + delta = encDecDelta(v.Delta()) + v.resetDelta() + if dv := delta.GetVote().GetSelfVote(); dv != false { + t.Fatalf("delta.SelfVote(): %v; want: %v", dv, false) + } + if d := v.Delta(); d != nil { + t.Fatalf("v.Delta(): %v; want: %v", d, nil) + } + if v.VotesFor() != 0 { + t.Fatalf("v.VotesFor(): %v; want: %v", v.VotesFor(), 0) + } + if v.SelfVote() != false { + t.Fatalf("v.SelfVote(): %v; want: %v", v.SelfVote(), false) + } + }) + t.Run("should return its state", func(t *testing.T) { + v := NewVote() + state1 := encDecState(v.State()) + v.resetDelta() + if sv := state1.GetVote().GetSelfVote(); sv != false { + t.Fatalf("state.GetSelfVote(): %v; want: %v", sv, false) + } + if vf := state1.GetVote().GetVotesFor(); vf != 0 { + t.Fatalf("state.GetVotesFor(): %v; want: %v", vf, 0) + } + if tv := state1.GetVote().GetTotalVoters(); tv != 1 { + t.Fatalf("state.GetTotalVoters(): %v; want: %v", tv, 1) + } + + v.Vote(true) + state2 := encDecState(v.State()) + v.resetDelta() + if sv := state2.GetVote().GetSelfVote(); sv != true { + t.Fatalf("state.GetSelfVote(): %v; want: %v", sv, true) + } + if vf := state2.GetVote().GetVotesFor(); vf != 1 { + t.Fatalf("state.GetVotesFor(): %v; want: %v", vf, 1) + } + if tv := state2.GetVote().GetTotalVoters(); tv != 1 { + t.Fatalf("state.GetTotalVoters(): %v; want: %v", tv, 1) + } + + if d := v.Delta(); d != nil { + t.Fatalf("v.Delta(): %v; want: %v", d, nil) + } + }) + + voteState := func(vs *entity.VoteState) *entity.CrdtState { + return encDecState(&entity.CrdtState{ + State: &entity.CrdtState_Vote{Vote: vs}, + }) + } + t.Run("should correctly calculate a majority vote", func(t *testing.T) { + var tests = []struct { + vs *entity.VoteState + maj bool + }{ + {&entity.VoteState{TotalVoters: 5, VotesFor: 3, SelfVote: true}, true}, + {&entity.VoteState{TotalVoters: 5, VotesFor: 2, SelfVote: true}, false}, + {&entity.VoteState{TotalVoters: 6, VotesFor: 3, SelfVote: true}, false}, + {&entity.VoteState{TotalVoters: 6, VotesFor: 4, SelfVote: true}, true}, + {&entity.VoteState{TotalVoters: 1, VotesFor: 0, SelfVote: false}, false}, + {&entity.VoteState{TotalVoters: 1, VotesFor: 1, SelfVote: true}, true}, + } + v := NewVote() + for _, test := range tests { + if err := v.applyState(voteState(test.vs)); err != nil { + t.Fatal(err) + } + if v.Majority() != test.maj { + t.Fatalf("test: %+v, v.Majority(): %v; want: %v", test.vs, v.Majority(), test.maj) + } + } + }) + t.Run("should correctly calculate an at least one vote", func(t *testing.T) { + var tests = []struct { + vs *entity.VoteState + atLeast bool + }{ + {&entity.VoteState{TotalVoters: 1, VotesFor: 0, SelfVote: false}, false}, + {&entity.VoteState{TotalVoters: 5, VotesFor: 0, SelfVote: false}, false}, + {&entity.VoteState{TotalVoters: 1, VotesFor: 1, SelfVote: true}, true}, + {&entity.VoteState{TotalVoters: 5, VotesFor: 1, SelfVote: true}, true}, + {&entity.VoteState{TotalVoters: 5, VotesFor: 3, SelfVote: true}, true}, + } + v := NewVote() + for _, test := range tests { + if err := v.applyState(voteState(test.vs)); err != nil { + t.Fatal(err) + } + if v.AtLeastOne() != test.atLeast { + t.Fatalf("test: %+v, v.AtLeastOne(): %v; want: %v", test.vs, v.AtLeastOne(), test.atLeast) + } + } + }) + t.Run("should correctly calculate an all votes", func(t *testing.T) { + var tests = []struct { + vs *entity.VoteState + all bool + }{ + {&entity.VoteState{TotalVoters: 1, VotesFor: 0, SelfVote: false}, false}, + {&entity.VoteState{TotalVoters: 5, VotesFor: 0, SelfVote: false}, false}, + {&entity.VoteState{TotalVoters: 1, VotesFor: 1, SelfVote: true}, true}, + {&entity.VoteState{TotalVoters: 5, VotesFor: 3, SelfVote: true}, false}, + {&entity.VoteState{TotalVoters: 5, VotesFor: 5, SelfVote: true}, true}, + } + v := NewVote() + for _, test := range tests { + if err := v.applyState(voteState(test.vs)); err != nil { + t.Fatal(err) + } + if v.All() != test.all { + t.Fatalf("test: %+v, v.All(): %v; want: %v", test.vs, v.All(), test.all) + } + } + }) +} diff --git a/cloudstate/protosupport.go b/cloudstate/discovery/protosupport.go similarity index 95% rename from cloudstate/protosupport.go rename to cloudstate/discovery/protosupport.go index d5c07d3..465ad5b 100644 --- a/cloudstate/protosupport.go +++ b/cloudstate/discovery/protosupport.go @@ -13,19 +13,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cloudstate +package discovery import ( "bytes" "compress/gzip" "errors" + "io/ioutil" + "github.com/golang/protobuf/proto" filedescr "github.com/golang/protobuf/protoc-gen-go/descriptor" - "io/ioutil" ) -const protoAnyBase = "type.googleapis.com" - func unpackFile(gz []byte) (*filedescr.FileDescriptorProto, error) { r, err := gzip.NewReader(bytes.NewReader(gz)) if err != nil { diff --git a/cloudstate/discovery/server.go b/cloudstate/discovery/server.go new file mode 100644 index 0000000..327c055 --- /dev/null +++ b/cloudstate/discovery/server.go @@ -0,0 +1,181 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package discovery implements the Cloudstate entity discovery server. +package discovery + +import ( + "context" + "errors" + "fmt" + "log" + "runtime" + "sync" + + "github.com/cloudstateio/go-support/cloudstate/crdt" + "github.com/cloudstateio/go-support/cloudstate/eventsourced" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/golang/protobuf/descriptor" + "github.com/golang/protobuf/proto" + filedescr "github.com/golang/protobuf/protoc-gen-go/descriptor" + "github.com/golang/protobuf/ptypes/empty" +) + +const ( + SupportLibraryName = "cloudstate-go-support" + SupportLibraryVersion = "0.2.0" + ProtocolMajorVersion = 0 + ProtocolMinorVersion = 2 +) + +// EntityDiscoveryServer implements the Cloudstate discovery protocol. +type EntityDiscoveryServer struct { + mu sync.RWMutex + fileDescriptorSet *filedescr.FileDescriptorSet + entitySpec *protocol.EntitySpec +} + +// NewServer returns a new and initialized EntityDiscoveryServer. +func NewServer(config protocol.Config) *EntityDiscoveryServer { + return &EntityDiscoveryServer{ + entitySpec: &protocol.EntitySpec{ + Entities: make([]*protocol.Entity, 0), + ServiceInfo: &protocol.ServiceInfo{ + ServiceName: config.ServiceName, + ServiceVersion: config.ServiceVersion, + ServiceRuntime: fmt.Sprintf("%s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH), + SupportLibraryName: SupportLibraryName, + SupportLibraryVersion: SupportLibraryVersion, + ProtocolMajorVersion: ProtocolMajorVersion, + ProtocolMinorVersion: ProtocolMinorVersion, + }, + }, + fileDescriptorSet: &filedescr.FileDescriptorSet{ + File: make([]*filedescr.FileDescriptorProto, 0), + }, + } +} + +// Discover returns an entity spec for registered entities. +func (s *EntityDiscoveryServer) Discover(_ context.Context, info *protocol.ProxyInfo) (*protocol.EntitySpec, error) { + log.Printf("Received discovery call from sidecar [%s %s] supporting Cloudstate %v.%v\n", + info.ProxyName, + info.ProxyVersion, + info.ProtocolMajorVersion, + info.ProtocolMinorVersion, + ) + log.Printf("Responding with: %v\n", s.entitySpec.GetServiceInfo()) + // TODO: s.entitySpec can be written potentially but should not after we started to run the server; + // check how to enforce that after protocol.Run has started. + return s.entitySpec, nil +} + +// ReportError logs any user function error reported by the Cloudstate proxy. +func (s *EntityDiscoveryServer) ReportError(_ context.Context, error *protocol.UserFunctionError) (*empty.Empty, error) { + log.Printf("ReportError: %v\n", error) + return &empty.Empty{}, nil +} + +func (s *EntityDiscoveryServer) updateSpec() (err error) { + protoBytes, err := proto.Marshal(s.fileDescriptorSet) + if err != nil { + return errors.New("unable to Marshal FileDescriptorSet") + } + s.entitySpec.Proto = protoBytes + return nil +} + +func (s *EntityDiscoveryServer) resolveFileDescriptors(config protocol.DescriptorConfig) error { + if config.Service != "" { + if err := s.registerFileDescriptorProto(config.Service); err != nil { + return err + } + } + // Add dependent domain descriptors. + for _, dp := range config.Domain { + if err := s.registerFileDescriptorProto(dp); err != nil { + return err + } + } + for _, dm := range config.DomainMessages { + if err := s.registerFileDescriptor(dm); err != nil { + return err + } + } + return nil +} + +func (s *EntityDiscoveryServer) RegisterEventSourcedEntity(entity *eventsourced.Entity, config protocol.DescriptorConfig) error { + s.mu.Lock() + defer s.mu.Unlock() + if err := s.resolveFileDescriptors(config); err != nil { + return fmt.Errorf("failed to resolve FileDescriptor for DescriptorConfig: %+v: %w", config, err) + } + s.entitySpec.Entities = append(s.entitySpec.Entities, &protocol.Entity{ + EntityType: protocol.EventSourced, + ServiceName: entity.ServiceName.String(), + PersistenceId: entity.PersistenceID, + }) + return s.updateSpec() +} + +func (s *EntityDiscoveryServer) RegisterCRDTEntity(entity *crdt.Entity, config protocol.DescriptorConfig) error { + s.mu.Lock() + defer s.mu.Unlock() + if err := s.resolveFileDescriptors(config); err != nil { + return fmt.Errorf("failed to resolveFileDescriptor for DescriptorConfig: %+v: %w", config, err) + } + s.entitySpec.Entities = append(s.entitySpec.Entities, &protocol.Entity{ + EntityType: protocol.CRDT, + ServiceName: entity.ServiceName.String(), + }) + return s.updateSpec() +} + +func (s *EntityDiscoveryServer) hasRegistered(filename string) bool { + for _, f := range s.fileDescriptorSet.File { + if f.GetName() == filename { + return true + } + } + return false +} + +func (s *EntityDiscoveryServer) registerFileDescriptorProto(filename string) error { + if s.hasRegistered(filename) { + return nil + } + desc, err := unpackFile(proto.FileDescriptor(filename)) + if err != nil { + return fmt.Errorf("failed to registerFileDescriptorProto for filename: %s: %w", filename, err) + } + s.fileDescriptorSet.File = append(s.fileDescriptorSet.File, desc) + for _, dep := range desc.Dependency { + err := s.registerFileDescriptorProto(dep) + if err != nil { + return err + } + } + return s.updateSpec() +} + +func (s *EntityDiscoveryServer) registerFileDescriptor(msg descriptor.Message) (err error) { + fd, _ := descriptor.ForMessage(msg) // this can panic. + if s.hasRegistered(fd.GetName()) { + return nil + } + s.fileDescriptorSet.File = append(s.fileDescriptorSet.File, fd) + return nil +} diff --git a/cloudstate/encoding/any.go b/cloudstate/encoding/any.go index affc75c..86ea465 100644 --- a/cloudstate/encoding/any.go +++ b/cloudstate/encoding/any.go @@ -15,7 +15,17 @@ package encoding -import "errors" +import ( + "errors" + + "github.com/golang/protobuf/ptypes/any" + "github.com/golang/protobuf/ptypes/empty" +) var ErrNotMarshalled = errors.New("not marshalled") var ErrNotUnmarshalled = errors.New("not unmarshalled") + +var Empty, _ = MarshalAny(&empty.Empty{}) + +type AnyEncFunc func(i interface{}) (*any.Any, error) +type AnyDecFunc func(any *any.Any, target interface{}) error diff --git a/cloudstate/encoding/any_encoding.go b/cloudstate/encoding/any_encoding.go new file mode 100644 index 0000000..0e9ee90 --- /dev/null +++ b/cloudstate/encoding/any_encoding.go @@ -0,0 +1,89 @@ +package encoding + +import "github.com/golang/protobuf/ptypes/any" + +func Int32(i int32) *any.Any { + primitive, _ := MarshalPrimitive(i) + return primitive +} + +func DecodeInt32(a *any.Any) int32 { + i, _ := UnmarshalPrimitive(a) + return i.(int32) +} + +func Int64(i int64) *any.Any { + primitive, _ := MarshalPrimitive(i) + return primitive +} + +func DecodeInt64(a *any.Any) int64 { + i, _ := UnmarshalPrimitive(a) + return i.(int64) +} + +func StringMust(s string) *any.Any { + primitive, err := MarshalPrimitive(s) + if err != nil { + panic(err) + } + return primitive +} + +func String(s string) *any.Any { + primitive, _ := MarshalPrimitive(s) + return primitive +} + +func Struct(s interface{}) (*any.Any, error) { + return MarshalJSON(s) +} + +func DecodeStruct(a *any.Any, s interface{}) error { + return UnmarshalJSON(a, s) +} + +func DecodeString(a *any.Any) string { + i, _ := UnmarshalPrimitive(a) + return i.(string) +} + +func Float32(f float32) *any.Any { + primitive, _ := MarshalPrimitive(f) + return primitive +} + +func DecodeFloat32(a *any.Any) float32 { + i, _ := UnmarshalPrimitive(a) + return i.(float32) +} + +func Float64(f float64) *any.Any { + primitive, _ := MarshalPrimitive(f) + return primitive +} + +func DecodeFloat64(a *any.Any) float64 { + i, _ := UnmarshalPrimitive(a) + return i.(float64) +} + +func Bool(b bool) *any.Any { + primitive, _ := MarshalPrimitive(b) + return primitive +} + +func DecodeBool(a *any.Any) bool { + i, _ := UnmarshalPrimitive(a) + return i.(bool) +} + +func Bytes(b []byte) *any.Any { + primitive, _ := MarshalPrimitive(b) + return primitive +} + +func DecodeBytes(a *any.Any) []byte { + i, _ := UnmarshalPrimitive(a) + return i.([]byte) +} diff --git a/cloudstate/encoding/any_json.go b/cloudstate/encoding/any_json.go index 014066a..8c0eafd 100644 --- a/cloudstate/encoding/any_json.go +++ b/cloudstate/encoding/any_json.go @@ -17,24 +17,31 @@ package encoding import ( "encoding/json" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/any" + "fmt" "reflect" "strings" + + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" ) const ( - jsonTypeURLPrefix = "json.cloudstate.io" + JSONTypeURLPrefix = "json.cloudstate.io" ) +func JSON(value interface{}) (*any.Any, error) { + return MarshalJSON(value) +} + +// MarshalJSON encodes a struct type into its Cloudstate Any JSON value. func MarshalJSON(value interface{}) (*any.Any, error) { typeOf := reflect.TypeOf(value) - if typeOf.Kind() != reflect.Struct { - return nil, ErrNotMarshalled + if typeOf.Kind() == reflect.Ptr { + typeOf = reflect.ValueOf(value).Elem().Type() } buffer := proto.NewBuffer(make([]byte, 0)) buffer.SetDeterministic(true) - typeUrl := jsonTypeURLPrefix + "/" + typeOf.PkgPath() + "." + typeOf.Name() + typeURL := fmt.Sprintf("%s/%s.%s", JSONTypeURLPrefix, typeOf.PkgPath(), typeOf.Name()) _ = buffer.EncodeVarint(fieldKey | proto.WireBytes) bytes, err := json.Marshal(value) if err != nil { @@ -42,15 +49,14 @@ func MarshalJSON(value interface{}) (*any.Any, error) { } _ = buffer.EncodeRawBytes(bytes) return &any.Any{ - TypeUrl: typeUrl, + TypeUrl: typeURL, Value: buffer.Bytes(), }, nil } -// UnmarshalPrimitive decodes a CloudState Any proto message -// into its JSON value. +// UnmarshalPrimitive decodes a Cloudstate Any protobuf message into its JSON value. func UnmarshalJSON(any *any.Any, target interface{}) error { - if !strings.HasPrefix(any.GetTypeUrl(), jsonTypeURLPrefix) { + if !strings.HasPrefix(any.GetTypeUrl(), JSONTypeURLPrefix) { return ErrNotMarshalled } buffer := proto.NewBuffer(any.GetValue()) diff --git a/cloudstate/encoding/any_json_test.go b/cloudstate/encoding/any_json_test.go index e9e3c18..51289f7 100644 --- a/cloudstate/encoding/any_json_test.go +++ b/cloudstate/encoding/any_json_test.go @@ -16,12 +16,75 @@ package encoding import ( - "fmt" - "github.com/golang/protobuf/ptypes/any" - "reflect" "testing" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/golang/protobuf/ptypes/any" ) +func TestMarshalling(t *testing.T) { + t.Run("marshals to cloudstate any.Any", func(t *testing.T) { + s := &a{B: "29", C: 29} + x, err := MarshalJSON(s) + if err != nil { + t.Fail() + } + url := "json.cloudstate.io/github.com/cloudstateio/go-support/cloudstate/encoding.a" + if x.GetTypeUrl() != url { + t.Fail() + } + }) + t.Run("marshal/unmarshal pointer struct", func(t *testing.T) { + s := &a{B: "29", C: 29} + x, err := MarshalJSON(s) + if err != nil { + t.Error(err) + } + s1 := &a{} + err = UnmarshalJSON(x, s1) + if err != nil { + t.Error(err) + } + if *s != *s1 { + t.Fail() + } + }) + t.Run("marshal/unmarshal struct", func(t *testing.T) { + s := a{B: "29", C: 29} + x, err := MarshalJSON(s) + if err != nil { + t.Error(err) + } + s1 := a{} + err = UnmarshalJSON(x, &s1) + if err != nil { + t.Error(err) + } + if s != s1 { + t.Fail() + } + }) + t.Run("marshal/unmarshal proto message", func(t *testing.T) { + s := entity.CrdtState_Flag{Flag: &entity.FlagState{ + Value: true, + }} + x, err := MarshalJSON(s) + if err != nil { + t.Error(err) + } + s1 := entity.CrdtState_Flag{Flag: &entity.FlagState{ + Value: true, + }} + err = UnmarshalJSON(x, &s1) + if err != nil { + t.Fatal(err) + } + if s.Flag.Value != s1.Flag.Value { + t.Fatal() + } + }) +} + var testsJSON = []struct { name string value interface{} @@ -29,41 +92,12 @@ var testsJSON = []struct { typeURL string shouldFail bool }{ - {jsonTypeURLPrefix + "/github.com/cloudstateio/go-support/cloudstate/encoding.a", - a{B: "29", C: 29}, a{}, jsonTypeURLPrefix + "/github.com/cloudstateio/go-support/cloudstate/encoding.a", false}, - {jsonTypeURLPrefix + "/github.com/cloudstateio/go-support/cloudstate/encoding.aDefault" + "_defaultValue", - aDefault{}, aDefault{}, jsonTypeURLPrefix + "/github.com/cloudstateio/go-support/cloudstate/encoding.aDefault", false}, -} - -func TestMarshallerJSON(t *testing.T) { - for _, test := range testsJSON { - test0 := test - t.Run(fmt.Sprintf("%v", test0.name), func(t *testing.T) { - any0, err := MarshalJSON(test0.value) - hasErr := err != nil - if hasErr && !test0.shouldFail { - t.Errorf("err: %v, got: %+v, expected: %+v", err, any0, test0) - return - } else if !hasErr && test0.shouldFail { - t.Errorf("err: %v, got: %+v, expected: %+v", err, any0, test0) - return - } - failed := any0.GetTypeUrl() != test0.typeURL - if failed && !test0.shouldFail { - t.Errorf("err: %v, got: %+v, expected: %+v", err, any0, test0) - } else if !failed && test0.shouldFail { - t.Errorf("err: %v, got: %+v, expected: %+v", err, any0, test0) - } - value := reflect.New(reflect.TypeOf(test0.value)) - err = UnmarshalJSON(any0, value.Interface()) - if err != nil { - t.Error(err) - } - if test0.value != value.Elem().Interface() { - t.Errorf("err: %v. got: %+v, expected: %+v", err, value.Elem().Interface(), test0.value) - } - }) - } + {JSONTypeURLPrefix + "/github.com/cloudstateio/go-support/cloudstate/encoding.a", + &a{B: "29", C: 29}, &a{}, JSONTypeURLPrefix + "/github.com/cloudstateio/go-support/cloudstate/encoding.a", false}, + {JSONTypeURLPrefix + "/github.com/cloudstateio/go-support/cloudstate/encoding.a", + a{B: "29", C: 29}, a{}, JSONTypeURLPrefix + "/github.com/cloudstateio/go-support/cloudstate/encoding.a", false}, + {JSONTypeURLPrefix + "/github.com/cloudstateio/go-support/cloudstate/encoding.aDefault" + "_defaultValue", + aDefault{}, aDefault{}, JSONTypeURLPrefix + "/github.com/cloudstateio/go-support/cloudstate/encoding.aDefault", false}, } func BenchmarkMarshallerJSON(b *testing.B) { @@ -84,9 +118,9 @@ func BenchmarkMarshallerJSON(b *testing.B) { b.Error(err) } } - any0 = any1 //prevent the call optimized away + any0 = any1 // prevent the call optimized away }) } } - _ = any0 == nil //use any0 + _ = any0 == nil // use any0 } diff --git a/cloudstate/encoding/any_primitive.go b/cloudstate/encoding/any_primitive.go index 8cde6d0..8b5294a 100644 --- a/cloudstate/encoding/any_primitive.go +++ b/cloudstate/encoding/any_primitive.go @@ -16,56 +16,57 @@ package encoding import ( + "math" + "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes/any" - "math" ) const ( PrimitiveTypeURLPrefix = "p.cloudstate.io" + ProtoAnyBase = "type.googleapis.com" - primitiveTypeURLPrefixInt32 = PrimitiveTypeURLPrefix + "/int32" - primitiveTypeURLPrefixInt64 = PrimitiveTypeURLPrefix + "/int64" - primitiveTypeURLPrefixString = PrimitiveTypeURLPrefix + "/string" - primitiveTypeURLPrefixFloat = PrimitiveTypeURLPrefix + "/float" - primitiveTypeURLPrefixDouble = PrimitiveTypeURLPrefix + "/double" - primitiveTypeURLPrefixBool = PrimitiveTypeURLPrefix + "/bool" - primitiveTypeURLPrefixBytes = PrimitiveTypeURLPrefix + "/bytes" + PrimitiveTypeURLPrefixInt32 = PrimitiveTypeURLPrefix + "/int32" + PrimitiveTypeURLPrefixInt64 = PrimitiveTypeURLPrefix + "/int64" + PrimitiveTypeURLPrefixString = PrimitiveTypeURLPrefix + "/string" + PrimitiveTypeURLPrefixFloat = PrimitiveTypeURLPrefix + "/float" + PrimitiveTypeURLPrefixDouble = PrimitiveTypeURLPrefix + "/double" + PrimitiveTypeURLPrefixBool = PrimitiveTypeURLPrefix + "/bool" + PrimitiveTypeURLPrefixBytes = PrimitiveTypeURLPrefix + "/bytes" ) const fieldKey = 1 << 3 func MarshalPrimitive(i interface{}) (*any.Any, error) { - buf := make([]byte, 0) - buffer := proto.NewBuffer(buf) + buffer := proto.NewBuffer(make([]byte, 0)) buffer.SetDeterministic(true) // see https://developers.google.com/protocol-buffers/docs/encoding#structure - var typeUrl string + var typeURL string switch val := i.(type) { case int32: - typeUrl = primitiveTypeURLPrefixInt32 + typeURL = PrimitiveTypeURLPrefixInt32 _ = buffer.EncodeVarint(fieldKey | proto.WireVarint) _ = buffer.EncodeVarint(uint64(val)) case int64: - typeUrl = primitiveTypeURLPrefixInt64 + typeURL = PrimitiveTypeURLPrefixInt64 _ = buffer.EncodeVarint(fieldKey | proto.WireVarint) _ = buffer.EncodeVarint(uint64(val)) case string: - typeUrl = primitiveTypeURLPrefixString + typeURL = PrimitiveTypeURLPrefixString _ = buffer.EncodeVarint(fieldKey | proto.WireBytes) if err := buffer.EncodeStringBytes(val); err != nil { return nil, err } case float32: - typeUrl = primitiveTypeURLPrefixFloat + typeURL = PrimitiveTypeURLPrefixFloat _ = buffer.EncodeVarint(fieldKey | proto.WireFixed32) _ = buffer.EncodeFixed32(uint64(math.Float32bits(val))) case float64: - typeUrl = primitiveTypeURLPrefixDouble + typeURL = PrimitiveTypeURLPrefixDouble _ = buffer.EncodeVarint(fieldKey | proto.WireFixed64) _ = buffer.EncodeFixed64(math.Float64bits(val)) case bool: - typeUrl = primitiveTypeURLPrefixBool + typeURL = PrimitiveTypeURLPrefixBool _ = buffer.EncodeVarint(fieldKey | proto.WireVarint) switch val { case true: @@ -74,7 +75,7 @@ func MarshalPrimitive(i interface{}) (*any.Any, error) { _ = buffer.EncodeVarint(0) } case []byte: - typeUrl = primitiveTypeURLPrefixBytes + typeURL = PrimitiveTypeURLPrefixBytes _ = buffer.EncodeVarint(fieldKey | proto.WireBytes) if err := buffer.EncodeRawBytes(val); err != nil { return nil, err @@ -83,7 +84,7 @@ func MarshalPrimitive(i interface{}) (*any.Any, error) { return nil, ErrNotMarshalled } return &any.Any{ - TypeUrl: typeUrl, + TypeUrl: typeURL, Value: buffer.Bytes(), }, nil } @@ -92,7 +93,7 @@ func MarshalPrimitive(i interface{}) (*any.Any, error) { // into its primitive value. func UnmarshalPrimitive(any *any.Any) (interface{}, error) { buffer := proto.NewBuffer(any.GetValue()) - if any.GetTypeUrl() == primitiveTypeURLPrefixInt32 { + if any.GetTypeUrl() == PrimitiveTypeURLPrefixInt32 { _, err := buffer.DecodeVarint() if err != nil { return nil, ErrNotUnmarshalled @@ -103,7 +104,7 @@ func UnmarshalPrimitive(any *any.Any) (interface{}, error) { } return int32(value), nil } - if any.GetTypeUrl() == primitiveTypeURLPrefixInt64 { + if any.GetTypeUrl() == PrimitiveTypeURLPrefixInt64 { _, err := buffer.DecodeVarint() if err != nil { return nil, ErrNotUnmarshalled @@ -114,7 +115,7 @@ func UnmarshalPrimitive(any *any.Any) (interface{}, error) { } return int64(value), nil } - if any.GetTypeUrl() == primitiveTypeURLPrefixString { + if any.GetTypeUrl() == PrimitiveTypeURLPrefixString { _, err := buffer.DecodeVarint() if err != nil { return nil, ErrNotUnmarshalled @@ -125,7 +126,7 @@ func UnmarshalPrimitive(any *any.Any) (interface{}, error) { } return value, nil } - if any.GetTypeUrl() == primitiveTypeURLPrefixFloat { + if any.GetTypeUrl() == PrimitiveTypeURLPrefixFloat { _, err := buffer.DecodeVarint() if err != nil { return nil, ErrNotUnmarshalled @@ -136,7 +137,7 @@ func UnmarshalPrimitive(any *any.Any) (interface{}, error) { } return math.Float32frombits(uint32(value)), nil } - if any.GetTypeUrl() == primitiveTypeURLPrefixDouble { + if any.GetTypeUrl() == PrimitiveTypeURLPrefixDouble { _, err := buffer.DecodeVarint() if err != nil { return nil, ErrNotUnmarshalled @@ -147,7 +148,7 @@ func UnmarshalPrimitive(any *any.Any) (interface{}, error) { } return math.Float64frombits(value), nil } - if any.GetTypeUrl() == primitiveTypeURLPrefixBool { + if any.GetTypeUrl() == PrimitiveTypeURLPrefixBool { _, err := buffer.DecodeVarint() if err != nil { return nil, ErrNotUnmarshalled @@ -158,7 +159,7 @@ func UnmarshalPrimitive(any *any.Any) (interface{}, error) { } return value == 1, nil } - if any.GetTypeUrl() == primitiveTypeURLPrefixBytes { + if any.GetTypeUrl() == PrimitiveTypeURLPrefixBytes { _, err := buffer.DecodeVarint() if err != nil { return nil, ErrNotUnmarshalled diff --git a/cloudstate/encoding/any_primitive_test.go b/cloudstate/encoding/any_primitive_test.go index 9b97298..e680ca2 100644 --- a/cloudstate/encoding/any_primitive_test.go +++ b/cloudstate/encoding/any_primitive_test.go @@ -18,8 +18,9 @@ package encoding import ( "bytes" "fmt" - "github.com/golang/protobuf/ptypes/any" "testing" + + "github.com/golang/protobuf/ptypes/any" ) type a struct { @@ -36,23 +37,23 @@ var tests = []struct { typeURL string shouldFail bool }{ - {primitiveTypeURLPrefixInt32, uint32(28), primitiveTypeURLPrefixInt32, true}, - {primitiveTypeURLPrefixInt32 + "_defaultValue", uint32(0), primitiveTypeURLPrefixInt32, true}, - {primitiveTypeURLPrefixInt32, int32(29), primitiveTypeURLPrefixInt32, false}, - {primitiveTypeURLPrefixInt32 + "_defaultValue", int32(0), primitiveTypeURLPrefixInt32, false}, - {primitiveTypeURLPrefixInt64, int64(29), primitiveTypeURLPrefixInt64, false}, - {primitiveTypeURLPrefixInt64 + "_defaultValue", int64(0), primitiveTypeURLPrefixInt64, false}, - {primitiveTypeURLPrefixFloat, float32(2.9), primitiveTypeURLPrefixFloat, false}, - {primitiveTypeURLPrefixFloat + "_defaultValue", float32(2.9), primitiveTypeURLPrefixFloat, false}, - {primitiveTypeURLPrefixDouble, float64(2.9), primitiveTypeURLPrefixDouble, false}, - {primitiveTypeURLPrefixDouble + "_defaultValue", float64(0), primitiveTypeURLPrefixDouble, false}, - {primitiveTypeURLPrefixString, "29", primitiveTypeURLPrefixString, false}, - {primitiveTypeURLPrefixString + "_defaultValue", "", primitiveTypeURLPrefixString, false}, - {primitiveTypeURLPrefixBool + "_true", true, primitiveTypeURLPrefixBool, false}, - {primitiveTypeURLPrefixBool + "_false", false, primitiveTypeURLPrefixBool, false}, - {primitiveTypeURLPrefixBool + "_defaultValue", false, primitiveTypeURLPrefixBool, false}, - {primitiveTypeURLPrefixBytes, make([]byte, 29), primitiveTypeURLPrefixBytes, false}, - {primitiveTypeURLPrefixBytes + "_defaultValue", make([]byte, 0), primitiveTypeURLPrefixBytes, false}, + {PrimitiveTypeURLPrefixInt32, uint32(28), PrimitiveTypeURLPrefixInt32, true}, + {PrimitiveTypeURLPrefixInt32 + "_defaultValue", uint32(0), PrimitiveTypeURLPrefixInt32, true}, + {PrimitiveTypeURLPrefixInt32, int32(29), PrimitiveTypeURLPrefixInt32, false}, + {PrimitiveTypeURLPrefixInt32 + "_defaultValue", int32(0), PrimitiveTypeURLPrefixInt32, false}, + {PrimitiveTypeURLPrefixInt64, int64(29), PrimitiveTypeURLPrefixInt64, false}, + {PrimitiveTypeURLPrefixInt64 + "_defaultValue", int64(0), PrimitiveTypeURLPrefixInt64, false}, + {PrimitiveTypeURLPrefixFloat, float32(2.9), PrimitiveTypeURLPrefixFloat, false}, + {PrimitiveTypeURLPrefixFloat + "_defaultValue", float32(2.9), PrimitiveTypeURLPrefixFloat, false}, + {PrimitiveTypeURLPrefixDouble, float64(2.9), PrimitiveTypeURLPrefixDouble, false}, + {PrimitiveTypeURLPrefixDouble + "_defaultValue", float64(0), PrimitiveTypeURLPrefixDouble, false}, + {PrimitiveTypeURLPrefixString, "29", PrimitiveTypeURLPrefixString, false}, + {PrimitiveTypeURLPrefixString + "_defaultValue", "", PrimitiveTypeURLPrefixString, false}, + {PrimitiveTypeURLPrefixBool + "_true", true, PrimitiveTypeURLPrefixBool, false}, + {PrimitiveTypeURLPrefixBool + "_false", false, PrimitiveTypeURLPrefixBool, false}, + {PrimitiveTypeURLPrefixBool + "_defaultValue", false, PrimitiveTypeURLPrefixBool, false}, + {PrimitiveTypeURLPrefixBytes, make([]byte, 29), PrimitiveTypeURLPrefixBytes, false}, + {PrimitiveTypeURLPrefixBytes + "_defaultValue", make([]byte, 0), PrimitiveTypeURLPrefixBytes, false}, } func TestMarshallerPrimitives(t *testing.T) { @@ -96,7 +97,7 @@ func TestMarshalUnmarshalPrimitive(t *testing.T) { switch ut := u.(type) { case []byte: byt := tc.value.([]byte) - if bytes.Compare(byt, ut) != 0 { + if !bytes.Equal(byt, ut) { t.Errorf("err: %v. got: %+v, expected: %+v", err, u, tc.value) } default: @@ -119,11 +120,11 @@ func BenchmarkMarshallerPrimitives(b *testing.B) { for i := 0; i < b.N; i++ { any1, _ = MarshalPrimitive(tc.value) } - any0 = any1 //prevent the call optimized away + any0 = any1 // prevent the call optimized away }) } } - _ = any0 == nil //use any0 + _ = any0 == nil // use any0 } func BenchmarkMarshalUnmarshal(b *testing.B) { @@ -146,7 +147,7 @@ func BenchmarkMarshalUnmarshal(b *testing.B) { switch ut := u.(type) { case []byte: byt := tc.value.([]byte) - if bytes.Compare(byt, ut) != 0 { + if !bytes.Equal(byt, ut) { b.Errorf("err: %v. got: %+v, expected: %+v", err, u, tc.value) } default: @@ -155,9 +156,9 @@ func BenchmarkMarshalUnmarshal(b *testing.B) { } } } - any0 = any1 //prevent the call optimized away + any0 = any1 // prevent the call optimized away }) } } - _ = any0 == nil //use any0 + _ = any0 == nil // use any0 } diff --git a/cloudstate/encoding/doc.go b/cloudstate/encoding/doc.go new file mode 100644 index 0000000..12ce662 --- /dev/null +++ b/cloudstate/encoding/doc.go @@ -0,0 +1,17 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package encoding implements the cloudstate Any encoding support. +package encoding diff --git a/cloudstate/marshal_proto.go b/cloudstate/encoding/marshal_proto.go similarity index 56% rename from cloudstate/marshal_proto.go rename to cloudstate/encoding/marshal_proto.go index 3893b30..4508af0 100644 --- a/cloudstate/marshal_proto.go +++ b/cloudstate/encoding/marshal_proto.go @@ -13,16 +13,20 @@ // See the License for the specific language governing permissions and // limitations under the License. -package cloudstate +package encoding import ( + "errors" "fmt" + "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes/any" ) -// marshalAny marshals a proto.Message to a any.Any value. -func marshalAny(pb interface{}) (*any.Any, error) { +var ErrMarshal = errors.New("unable to marshal a message") + +// MarshalAny marshals a proto.Message to an any.Any value. +func MarshalAny(pb interface{}) (*any.Any, error) { // TODO: protobufs are expected here, but Cloudstate supports other formats message, ok := pb.(proto.Message) if !ok { @@ -30,27 +34,14 @@ func marshalAny(pb interface{}) (*any.Any, error) { } bytes, err := proto.Marshal(message) if err != nil { - return nil, fmt.Errorf("%s, %w", err, ErrMarshal) + return nil, fmt.Errorf("%s: %w", err, ErrMarshal) } return &any.Any{ - TypeUrl: fmt.Sprintf("%s/%s", protoAnyBase, proto.MessageName(message)), + TypeUrl: fmt.Sprintf("%s/%s", ProtoAnyBase, proto.MessageName(message)), Value: bytes, }, nil } -// marshalEventsAny receives the events emitted through the handling of a command -// and marshals them to the event serialized form. -func marshalEventsAny(entityContext *EntityInstanceContext) ([]*any.Any, error) { - events := make([]*any.Any, 0) - if emitter, ok := entityContext.EntityInstance.Instance.(EventEmitter); ok { - for _, evt := range emitter.Events() { - event, err := marshalAny(evt) - if err != nil { - return nil, err - } - events = append(events, event) - } - emitter.Clear() - } - return events, nil +func UnmarshalAny(x *any.Any, p proto.Message) error { + return proto.Unmarshal(x.Value, p) } diff --git a/cloudstate/encoding/marshal_proto_test.go b/cloudstate/encoding/marshal_proto_test.go new file mode 100644 index 0000000..2adb4bb --- /dev/null +++ b/cloudstate/encoding/marshal_proto_test.go @@ -0,0 +1,35 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package encoding + +// func TestMarshalAnyProto(t *testing.T) { +// event := eventsourced.IncrementByEvent{Value: 29} +// any, err := MarshalAny(&event) +// if err != nil { +// t.Fatalf("failed to MarshalAny: %v", err) +// } +// expected := fmt.Sprintf("%s/%s", cloudstate.protoAnyBase, "IncrementByEvent") +// if expected != any.GetTypeUrl() { +// t.Fatalf("any.GetTypeUrl: %s is not: %s", any.GetTypeUrl(), expected) +// } +// event2 := &eventsourced.IncrementByEvent{} +// if err := proto.Unmarshal(any.Value, event2); err != nil { +// t.Fatalf("%v", err) +// } +// if event2.Value != event.Value { +// t.Fatalf("event2.Value: %d != event.Value: %d", event2.Value, event.Value) +// } +// } diff --git a/cloudstate/entity/crdt.pb.go b/cloudstate/entity/crdt.pb.go new file mode 100644 index 0000000..619256e --- /dev/null +++ b/cloudstate/entity/crdt.pb.go @@ -0,0 +1,3136 @@ +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// gRPC interface for CRDT Entity user functions. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: crdt.proto + +package entity + +import ( + context "context" + protocol "github.com/cloudstateio/go-support/cloudstate/protocol" + proto "github.com/golang/protobuf/proto" + any "github.com/golang/protobuf/ptypes/any" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type CrdtWriteConsistency int32 + +const ( + CrdtWriteConsistency_LOCAL CrdtWriteConsistency = 0 + CrdtWriteConsistency_MAJORITY CrdtWriteConsistency = 1 + CrdtWriteConsistency_ALL CrdtWriteConsistency = 2 +) + +// Enum value maps for CrdtWriteConsistency. +var ( + CrdtWriteConsistency_name = map[int32]string{ + 0: "LOCAL", + 1: "MAJORITY", + 2: "ALL", + } + CrdtWriteConsistency_value = map[string]int32{ + "LOCAL": 0, + "MAJORITY": 1, + "ALL": 2, + } +) + +func (x CrdtWriteConsistency) Enum() *CrdtWriteConsistency { + p := new(CrdtWriteConsistency) + *p = x + return p +} + +func (x CrdtWriteConsistency) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CrdtWriteConsistency) Descriptor() protoreflect.EnumDescriptor { + return file_crdt_proto_enumTypes[0].Descriptor() +} + +func (CrdtWriteConsistency) Type() protoreflect.EnumType { + return &file_crdt_proto_enumTypes[0] +} + +func (x CrdtWriteConsistency) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CrdtWriteConsistency.Descriptor instead. +func (CrdtWriteConsistency) EnumDescriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{0} +} + +type CrdtClock int32 + +const ( + // Use the default clock for deciding the last write, which is the system clocks + // milliseconds since epoch. + CrdtClock_DEFAULT CrdtClock = 0 + // Use the reverse semantics with the default clock, to enable first write wins. + CrdtClock_REVERSE CrdtClock = 1 + // Use a custom clock value, set using custom_clock_value. + CrdtClock_CUSTOM CrdtClock = 2 + // Use a custom clock value, but automatically increment it by one if the clock + // value from the current value is equal to the custom_clock_value. + CrdtClock_CUSTOM_AUTO_INCREMENT CrdtClock = 3 +) + +// Enum value maps for CrdtClock. +var ( + CrdtClock_name = map[int32]string{ + 0: "DEFAULT", + 1: "REVERSE", + 2: "CUSTOM", + 3: "CUSTOM_AUTO_INCREMENT", + } + CrdtClock_value = map[string]int32{ + "DEFAULT": 0, + "REVERSE": 1, + "CUSTOM": 2, + "CUSTOM_AUTO_INCREMENT": 3, + } +) + +func (x CrdtClock) Enum() *CrdtClock { + p := new(CrdtClock) + *p = x + return p +} + +func (x CrdtClock) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CrdtClock) Descriptor() protoreflect.EnumDescriptor { + return file_crdt_proto_enumTypes[1].Descriptor() +} + +func (CrdtClock) Type() protoreflect.EnumType { + return &file_crdt_proto_enumTypes[1] +} + +func (x CrdtClock) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CrdtClock.Descriptor instead. +func (CrdtClock) EnumDescriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{1} +} + +// Message for the Crdt handle stream in. +type CrdtStreamIn struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Message: + // *CrdtStreamIn_Init + // *CrdtStreamIn_State + // *CrdtStreamIn_Changed + // *CrdtStreamIn_Deleted + // *CrdtStreamIn_Command + // *CrdtStreamIn_StreamCancelled + Message isCrdtStreamIn_Message `protobuf_oneof:"message"` +} + +func (x *CrdtStreamIn) Reset() { + *x = CrdtStreamIn{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CrdtStreamIn) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CrdtStreamIn) ProtoMessage() {} + +func (x *CrdtStreamIn) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CrdtStreamIn.ProtoReflect.Descriptor instead. +func (*CrdtStreamIn) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{0} +} + +func (m *CrdtStreamIn) GetMessage() isCrdtStreamIn_Message { + if m != nil { + return m.Message + } + return nil +} + +func (x *CrdtStreamIn) GetInit() *CrdtInit { + if x, ok := x.GetMessage().(*CrdtStreamIn_Init); ok { + return x.Init + } + return nil +} + +func (x *CrdtStreamIn) GetState() *CrdtState { + if x, ok := x.GetMessage().(*CrdtStreamIn_State); ok { + return x.State + } + return nil +} + +func (x *CrdtStreamIn) GetChanged() *CrdtDelta { + if x, ok := x.GetMessage().(*CrdtStreamIn_Changed); ok { + return x.Changed + } + return nil +} + +func (x *CrdtStreamIn) GetDeleted() *CrdtDelete { + if x, ok := x.GetMessage().(*CrdtStreamIn_Deleted); ok { + return x.Deleted + } + return nil +} + +func (x *CrdtStreamIn) GetCommand() *protocol.Command { + if x, ok := x.GetMessage().(*CrdtStreamIn_Command); ok { + return x.Command + } + return nil +} + +func (x *CrdtStreamIn) GetStreamCancelled() *protocol.StreamCancelled { + if x, ok := x.GetMessage().(*CrdtStreamIn_StreamCancelled); ok { + return x.StreamCancelled + } + return nil +} + +type isCrdtStreamIn_Message interface { + isCrdtStreamIn_Message() +} + +type CrdtStreamIn_Init struct { + // Always sent first, and only once. + Init *CrdtInit `protobuf:"bytes,1,opt,name=init,proto3,oneof"` +} + +type CrdtStreamIn_State struct { + // Sent to indicate the user function should replace its current state with this state. If the user function + // does not have a current state, either because the init function didn't send one and the user function hasn't + // updated the state itself in response to a command, or because the state was deleted, this must be sent before + // any deltas. + State *CrdtState `protobuf:"bytes,2,opt,name=state,proto3,oneof"` +} + +type CrdtStreamIn_Changed struct { + // A delta to be applied to the current state. May be sent at any time as long as the user function already has + // state. + Changed *CrdtDelta `protobuf:"bytes,3,opt,name=changed,proto3,oneof"` +} + +type CrdtStreamIn_Deleted struct { + // Delete the entity. May be sent at any time. The user function should clear its state when it receives this. + // A proxy may decide to terminate the stream after sending this. + Deleted *CrdtDelete `protobuf:"bytes,4,opt,name=deleted,proto3,oneof"` +} + +type CrdtStreamIn_Command struct { + // A command, may be sent at any time. + Command *protocol.Command `protobuf:"bytes,5,opt,name=command,proto3,oneof"` +} + +type CrdtStreamIn_StreamCancelled struct { + // A stream has been cancelled. + StreamCancelled *protocol.StreamCancelled `protobuf:"bytes,6,opt,name=stream_cancelled,json=streamCancelled,proto3,oneof"` +} + +func (*CrdtStreamIn_Init) isCrdtStreamIn_Message() {} + +func (*CrdtStreamIn_State) isCrdtStreamIn_Message() {} + +func (*CrdtStreamIn_Changed) isCrdtStreamIn_Message() {} + +func (*CrdtStreamIn_Deleted) isCrdtStreamIn_Message() {} + +func (*CrdtStreamIn_Command) isCrdtStreamIn_Message() {} + +func (*CrdtStreamIn_StreamCancelled) isCrdtStreamIn_Message() {} + +// Message for the Crdt handle stream out. +type CrdtStreamOut struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Message: + // *CrdtStreamOut_Reply + // *CrdtStreamOut_StreamedMessage + // *CrdtStreamOut_StreamCancelledResponse + // *CrdtStreamOut_Failure + Message isCrdtStreamOut_Message `protobuf_oneof:"message"` +} + +func (x *CrdtStreamOut) Reset() { + *x = CrdtStreamOut{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CrdtStreamOut) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CrdtStreamOut) ProtoMessage() {} + +func (x *CrdtStreamOut) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CrdtStreamOut.ProtoReflect.Descriptor instead. +func (*CrdtStreamOut) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{1} +} + +func (m *CrdtStreamOut) GetMessage() isCrdtStreamOut_Message { + if m != nil { + return m.Message + } + return nil +} + +func (x *CrdtStreamOut) GetReply() *CrdtReply { + if x, ok := x.GetMessage().(*CrdtStreamOut_Reply); ok { + return x.Reply + } + return nil +} + +func (x *CrdtStreamOut) GetStreamedMessage() *CrdtStreamedMessage { + if x, ok := x.GetMessage().(*CrdtStreamOut_StreamedMessage); ok { + return x.StreamedMessage + } + return nil +} + +func (x *CrdtStreamOut) GetStreamCancelledResponse() *CrdtStreamCancelledResponse { + if x, ok := x.GetMessage().(*CrdtStreamOut_StreamCancelledResponse); ok { + return x.StreamCancelledResponse + } + return nil +} + +func (x *CrdtStreamOut) GetFailure() *protocol.Failure { + if x, ok := x.GetMessage().(*CrdtStreamOut_Failure); ok { + return x.Failure + } + return nil +} + +type isCrdtStreamOut_Message interface { + isCrdtStreamOut_Message() +} + +type CrdtStreamOut_Reply struct { + // A reply to an incoming command. Either one reply, or one failure, must be sent in response to each command. + Reply *CrdtReply `protobuf:"bytes,1,opt,name=reply,proto3,oneof"` +} + +type CrdtStreamOut_StreamedMessage struct { + // A streamed message. + StreamedMessage *CrdtStreamedMessage `protobuf:"bytes,2,opt,name=streamed_message,json=streamedMessage,proto3,oneof"` +} + +type CrdtStreamOut_StreamCancelledResponse struct { + // A stream cancelled response, may be sent in response to stream_cancelled. + StreamCancelledResponse *CrdtStreamCancelledResponse `protobuf:"bytes,3,opt,name=stream_cancelled_response,json=streamCancelledResponse,proto3,oneof"` +} + +type CrdtStreamOut_Failure struct { + // A failure. Either sent in response to a command, or sent if some other error occurs. + Failure *protocol.Failure `protobuf:"bytes,4,opt,name=failure,proto3,oneof"` +} + +func (*CrdtStreamOut_Reply) isCrdtStreamOut_Message() {} + +func (*CrdtStreamOut_StreamedMessage) isCrdtStreamOut_Message() {} + +func (*CrdtStreamOut_StreamCancelledResponse) isCrdtStreamOut_Message() {} + +func (*CrdtStreamOut_Failure) isCrdtStreamOut_Message() {} + +// The CRDT state. This represents the full state of a CRDT. When received, a user function should replace the current +// state with this, not apply it as a delta. This includes both for the top level CRDT, and embedded CRDTs, such as +// the values of an ORMap. +type CrdtState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to State: + // *CrdtState_Gcounter + // *CrdtState_Pncounter + // *CrdtState_Gset + // *CrdtState_Orset + // *CrdtState_Lwwregister + // *CrdtState_Flag + // *CrdtState_Ormap + // *CrdtState_Vote + State isCrdtState_State `protobuf_oneof:"state"` +} + +func (x *CrdtState) Reset() { + *x = CrdtState{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CrdtState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CrdtState) ProtoMessage() {} + +func (x *CrdtState) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CrdtState.ProtoReflect.Descriptor instead. +func (*CrdtState) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{2} +} + +func (m *CrdtState) GetState() isCrdtState_State { + if m != nil { + return m.State + } + return nil +} + +func (x *CrdtState) GetGcounter() *GCounterState { + if x, ok := x.GetState().(*CrdtState_Gcounter); ok { + return x.Gcounter + } + return nil +} + +func (x *CrdtState) GetPncounter() *PNCounterState { + if x, ok := x.GetState().(*CrdtState_Pncounter); ok { + return x.Pncounter + } + return nil +} + +func (x *CrdtState) GetGset() *GSetState { + if x, ok := x.GetState().(*CrdtState_Gset); ok { + return x.Gset + } + return nil +} + +func (x *CrdtState) GetOrset() *ORSetState { + if x, ok := x.GetState().(*CrdtState_Orset); ok { + return x.Orset + } + return nil +} + +func (x *CrdtState) GetLwwregister() *LWWRegisterState { + if x, ok := x.GetState().(*CrdtState_Lwwregister); ok { + return x.Lwwregister + } + return nil +} + +func (x *CrdtState) GetFlag() *FlagState { + if x, ok := x.GetState().(*CrdtState_Flag); ok { + return x.Flag + } + return nil +} + +func (x *CrdtState) GetOrmap() *ORMapState { + if x, ok := x.GetState().(*CrdtState_Ormap); ok { + return x.Ormap + } + return nil +} + +func (x *CrdtState) GetVote() *VoteState { + if x, ok := x.GetState().(*CrdtState_Vote); ok { + return x.Vote + } + return nil +} + +type isCrdtState_State interface { + isCrdtState_State() +} + +type CrdtState_Gcounter struct { + // A Grow-only Counter + Gcounter *GCounterState `protobuf:"bytes,1,opt,name=gcounter,proto3,oneof"` +} + +type CrdtState_Pncounter struct { + // A Positve-Negative Counter + Pncounter *PNCounterState `protobuf:"bytes,2,opt,name=pncounter,proto3,oneof"` +} + +type CrdtState_Gset struct { + // A Grow-only Set + Gset *GSetState `protobuf:"bytes,3,opt,name=gset,proto3,oneof"` +} + +type CrdtState_Orset struct { + // An Observed-Removed Set + Orset *ORSetState `protobuf:"bytes,4,opt,name=orset,proto3,oneof"` +} + +type CrdtState_Lwwregister struct { + // A Last-Write-Wins Register + Lwwregister *LWWRegisterState `protobuf:"bytes,5,opt,name=lwwregister,proto3,oneof"` +} + +type CrdtState_Flag struct { + // A Flag + Flag *FlagState `protobuf:"bytes,6,opt,name=flag,proto3,oneof"` +} + +type CrdtState_Ormap struct { + // An Observed-Removed Map + Ormap *ORMapState `protobuf:"bytes,7,opt,name=ormap,proto3,oneof"` +} + +type CrdtState_Vote struct { + // A vote + Vote *VoteState `protobuf:"bytes,8,opt,name=vote,proto3,oneof"` +} + +func (*CrdtState_Gcounter) isCrdtState_State() {} + +func (*CrdtState_Pncounter) isCrdtState_State() {} + +func (*CrdtState_Gset) isCrdtState_State() {} + +func (*CrdtState_Orset) isCrdtState_State() {} + +func (*CrdtState_Lwwregister) isCrdtState_State() {} + +func (*CrdtState_Flag) isCrdtState_State() {} + +func (*CrdtState_Ormap) isCrdtState_State() {} + +func (*CrdtState_Vote) isCrdtState_State() {} + +// A Grow-only counter +// +// A G-Counter can only be incremented, it can't be decremented. +type GCounterState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The current value of the counter. + Value uint64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *GCounterState) Reset() { + *x = GCounterState{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GCounterState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GCounterState) ProtoMessage() {} + +func (x *GCounterState) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GCounterState.ProtoReflect.Descriptor instead. +func (*GCounterState) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{3} +} + +func (x *GCounterState) GetValue() uint64 { + if x != nil { + return x.Value + } + return 0 +} + +// A Positve-Negative Counter +// +// A PN-Counter can be both incremented and decremented. +type PNCounterState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The current value of the counter. + Value int64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *PNCounterState) Reset() { + *x = PNCounterState{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PNCounterState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PNCounterState) ProtoMessage() {} + +func (x *PNCounterState) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PNCounterState.ProtoReflect.Descriptor instead. +func (*PNCounterState) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{4} +} + +func (x *PNCounterState) GetValue() int64 { + if x != nil { + return x.Value + } + return 0 +} + +// A Grow-only Set +// +// A G-Set can only have items added, items cannot be removed. +type GSetState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The current items in the set. + Items []*any.Any `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` +} + +func (x *GSetState) Reset() { + *x = GSetState{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GSetState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GSetState) ProtoMessage() {} + +func (x *GSetState) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GSetState.ProtoReflect.Descriptor instead. +func (*GSetState) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{5} +} + +func (x *GSetState) GetItems() []*any.Any { + if x != nil { + return x.Items + } + return nil +} + +// An Observed-Removed Set +// +// An OR-Set may have items added and removed, with the condition that an item must be observed to be in the set before +// it is removed. +type ORSetState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The current items in the set. + Items []*any.Any `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` +} + +func (x *ORSetState) Reset() { + *x = ORSetState{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORSetState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORSetState) ProtoMessage() {} + +func (x *ORSetState) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORSetState.ProtoReflect.Descriptor instead. +func (*ORSetState) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{6} +} + +func (x *ORSetState) GetItems() []*any.Any { + if x != nil { + return x.Items + } + return nil +} + +// A Last-Write-Wins Register +// +// A LWW-Register holds a single value, with the current value being selected based on when it was last written. +// The time of the last write may either be determined using the proxies clock, or may be based on a custom, domain +// specific value. +type LWWRegisterState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The current value of the register. + Value *any.Any `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + // The clock to use if this state needs to be merged with another one. + Clock CrdtClock `protobuf:"varint,2,opt,name=clock,proto3,enum=cloudstate.crdt.CrdtClock" json:"clock,omitempty"` + // The clock value if the clock in use is a custom clock. + CustomClockValue int64 `protobuf:"varint,3,opt,name=custom_clock_value,json=customClockValue,proto3" json:"custom_clock_value,omitempty"` +} + +func (x *LWWRegisterState) Reset() { + *x = LWWRegisterState{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LWWRegisterState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LWWRegisterState) ProtoMessage() {} + +func (x *LWWRegisterState) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LWWRegisterState.ProtoReflect.Descriptor instead. +func (*LWWRegisterState) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{7} +} + +func (x *LWWRegisterState) GetValue() *any.Any { + if x != nil { + return x.Value + } + return nil +} + +func (x *LWWRegisterState) GetClock() CrdtClock { + if x != nil { + return x.Clock + } + return CrdtClock_DEFAULT +} + +func (x *LWWRegisterState) GetCustomClockValue() int64 { + if x != nil { + return x.CustomClockValue + } + return 0 +} + +// A Flag +// +// A Flag is a boolean value, that once set to true, stays true. +type FlagState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The current value of the flag. + Value bool `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *FlagState) Reset() { + *x = FlagState{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FlagState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FlagState) ProtoMessage() {} + +func (x *FlagState) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FlagState.ProtoReflect.Descriptor instead. +func (*FlagState) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{8} +} + +func (x *FlagState) GetValue() bool { + if x != nil { + return x.Value + } + return false +} + +// An Observed-Removed Map +// +// Like an OR-Set, an OR-Map may have items added and removed, with the condition that an item must be observed to be +// in the map before it is removed. The values of the map are CRDTs themselves. Different keys are allowed to use +// different CRDTs, and if an item is removed, and then replaced, the new value may be a different CRDT. +type ORMapState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The entries of the map. + Entries []*ORMapEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` +} + +func (x *ORMapState) Reset() { + *x = ORMapState{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapState) ProtoMessage() {} + +func (x *ORMapState) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapState.ProtoReflect.Descriptor instead. +func (*ORMapState) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{9} +} + +func (x *ORMapState) GetEntries() []*ORMapEntry { + if x != nil { + return x.Entries + } + return nil +} + +// An OR-Map entry. +type ORMapEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The entry key. + Key *any.Any `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // The value of the entry, a CRDT itself. + Value *CrdtState `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *ORMapEntry) Reset() { + *x = ORMapEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapEntry) ProtoMessage() {} + +func (x *ORMapEntry) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapEntry.ProtoReflect.Descriptor instead. +func (*ORMapEntry) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{10} +} + +func (x *ORMapEntry) GetKey() *any.Any { + if x != nil { + return x.Key + } + return nil +} + +func (x *ORMapEntry) GetValue() *CrdtState { + if x != nil { + return x.Value + } + return nil +} + +// A Vote. This allows nodes to vote on something. +type VoteState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The number of votes for + VotesFor uint32 `protobuf:"varint,1,opt,name=votes_for,json=votesFor,proto3" json:"votes_for,omitempty"` + // The total number of voters + TotalVoters uint32 `protobuf:"varint,2,opt,name=total_voters,json=totalVoters,proto3" json:"total_voters,omitempty"` + // The vote of the current node, which is included in the above two numbers + SelfVote bool `protobuf:"varint,3,opt,name=self_vote,json=selfVote,proto3" json:"self_vote,omitempty"` +} + +func (x *VoteState) Reset() { + *x = VoteState{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VoteState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VoteState) ProtoMessage() {} + +func (x *VoteState) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VoteState.ProtoReflect.Descriptor instead. +func (*VoteState) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{11} +} + +func (x *VoteState) GetVotesFor() uint32 { + if x != nil { + return x.VotesFor + } + return 0 +} + +func (x *VoteState) GetTotalVoters() uint32 { + if x != nil { + return x.TotalVoters + } + return 0 +} + +func (x *VoteState) GetSelfVote() bool { + if x != nil { + return x.SelfVote + } + return false +} + +// A CRDT delta +// +// Deltas only carry the change in value, not the full value (unless +type CrdtDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Delta: + // *CrdtDelta_Gcounter + // *CrdtDelta_Pncounter + // *CrdtDelta_Gset + // *CrdtDelta_Orset + // *CrdtDelta_Lwwregister + // *CrdtDelta_Flag + // *CrdtDelta_Ormap + // *CrdtDelta_Vote + Delta isCrdtDelta_Delta `protobuf_oneof:"delta"` +} + +func (x *CrdtDelta) Reset() { + *x = CrdtDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CrdtDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CrdtDelta) ProtoMessage() {} + +func (x *CrdtDelta) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CrdtDelta.ProtoReflect.Descriptor instead. +func (*CrdtDelta) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{12} +} + +func (m *CrdtDelta) GetDelta() isCrdtDelta_Delta { + if m != nil { + return m.Delta + } + return nil +} + +func (x *CrdtDelta) GetGcounter() *GCounterDelta { + if x, ok := x.GetDelta().(*CrdtDelta_Gcounter); ok { + return x.Gcounter + } + return nil +} + +func (x *CrdtDelta) GetPncounter() *PNCounterDelta { + if x, ok := x.GetDelta().(*CrdtDelta_Pncounter); ok { + return x.Pncounter + } + return nil +} + +func (x *CrdtDelta) GetGset() *GSetDelta { + if x, ok := x.GetDelta().(*CrdtDelta_Gset); ok { + return x.Gset + } + return nil +} + +func (x *CrdtDelta) GetOrset() *ORSetDelta { + if x, ok := x.GetDelta().(*CrdtDelta_Orset); ok { + return x.Orset + } + return nil +} + +func (x *CrdtDelta) GetLwwregister() *LWWRegisterDelta { + if x, ok := x.GetDelta().(*CrdtDelta_Lwwregister); ok { + return x.Lwwregister + } + return nil +} + +func (x *CrdtDelta) GetFlag() *FlagDelta { + if x, ok := x.GetDelta().(*CrdtDelta_Flag); ok { + return x.Flag + } + return nil +} + +func (x *CrdtDelta) GetOrmap() *ORMapDelta { + if x, ok := x.GetDelta().(*CrdtDelta_Ormap); ok { + return x.Ormap + } + return nil +} + +func (x *CrdtDelta) GetVote() *VoteDelta { + if x, ok := x.GetDelta().(*CrdtDelta_Vote); ok { + return x.Vote + } + return nil +} + +type isCrdtDelta_Delta interface { + isCrdtDelta_Delta() +} + +type CrdtDelta_Gcounter struct { + Gcounter *GCounterDelta `protobuf:"bytes,1,opt,name=gcounter,proto3,oneof"` +} + +type CrdtDelta_Pncounter struct { + Pncounter *PNCounterDelta `protobuf:"bytes,2,opt,name=pncounter,proto3,oneof"` +} + +type CrdtDelta_Gset struct { + Gset *GSetDelta `protobuf:"bytes,3,opt,name=gset,proto3,oneof"` +} + +type CrdtDelta_Orset struct { + Orset *ORSetDelta `protobuf:"bytes,4,opt,name=orset,proto3,oneof"` +} + +type CrdtDelta_Lwwregister struct { + Lwwregister *LWWRegisterDelta `protobuf:"bytes,5,opt,name=lwwregister,proto3,oneof"` +} + +type CrdtDelta_Flag struct { + Flag *FlagDelta `protobuf:"bytes,6,opt,name=flag,proto3,oneof"` +} + +type CrdtDelta_Ormap struct { + Ormap *ORMapDelta `protobuf:"bytes,7,opt,name=ormap,proto3,oneof"` +} + +type CrdtDelta_Vote struct { + Vote *VoteDelta `protobuf:"bytes,8,opt,name=vote,proto3,oneof"` +} + +func (*CrdtDelta_Gcounter) isCrdtDelta_Delta() {} + +func (*CrdtDelta_Pncounter) isCrdtDelta_Delta() {} + +func (*CrdtDelta_Gset) isCrdtDelta_Delta() {} + +func (*CrdtDelta_Orset) isCrdtDelta_Delta() {} + +func (*CrdtDelta_Lwwregister) isCrdtDelta_Delta() {} + +func (*CrdtDelta_Flag) isCrdtDelta_Delta() {} + +func (*CrdtDelta_Ormap) isCrdtDelta_Delta() {} + +func (*CrdtDelta_Vote) isCrdtDelta_Delta() {} + +type GCounterDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Increment uint64 `protobuf:"varint,1,opt,name=increment,proto3" json:"increment,omitempty"` +} + +func (x *GCounterDelta) Reset() { + *x = GCounterDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GCounterDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GCounterDelta) ProtoMessage() {} + +func (x *GCounterDelta) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GCounterDelta.ProtoReflect.Descriptor instead. +func (*GCounterDelta) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{13} +} + +func (x *GCounterDelta) GetIncrement() uint64 { + if x != nil { + return x.Increment + } + return 0 +} + +type PNCounterDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Change int64 `protobuf:"zigzag64,1,opt,name=change,proto3" json:"change,omitempty"` +} + +func (x *PNCounterDelta) Reset() { + *x = PNCounterDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PNCounterDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PNCounterDelta) ProtoMessage() {} + +func (x *PNCounterDelta) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PNCounterDelta.ProtoReflect.Descriptor instead. +func (*PNCounterDelta) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{14} +} + +func (x *PNCounterDelta) GetChange() int64 { + if x != nil { + return x.Change + } + return 0 +} + +type GSetDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Added []*any.Any `protobuf:"bytes,1,rep,name=added,proto3" json:"added,omitempty"` +} + +func (x *GSetDelta) Reset() { + *x = GSetDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GSetDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GSetDelta) ProtoMessage() {} + +func (x *GSetDelta) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GSetDelta.ProtoReflect.Descriptor instead. +func (*GSetDelta) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{15} +} + +func (x *GSetDelta) GetAdded() []*any.Any { + if x != nil { + return x.Added + } + return nil +} + +type ORSetDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // If cleared is set, the set must be cleared before added is processed. + Cleared bool `protobuf:"varint,1,opt,name=cleared,proto3" json:"cleared,omitempty"` + Removed []*any.Any `protobuf:"bytes,2,rep,name=removed,proto3" json:"removed,omitempty"` + Added []*any.Any `protobuf:"bytes,3,rep,name=added,proto3" json:"added,omitempty"` +} + +func (x *ORSetDelta) Reset() { + *x = ORSetDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORSetDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORSetDelta) ProtoMessage() {} + +func (x *ORSetDelta) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORSetDelta.ProtoReflect.Descriptor instead. +func (*ORSetDelta) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{16} +} + +func (x *ORSetDelta) GetCleared() bool { + if x != nil { + return x.Cleared + } + return false +} + +func (x *ORSetDelta) GetRemoved() []*any.Any { + if x != nil { + return x.Removed + } + return nil +} + +func (x *ORSetDelta) GetAdded() []*any.Any { + if x != nil { + return x.Added + } + return nil +} + +type LWWRegisterDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value *any.Any `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` + Clock CrdtClock `protobuf:"varint,2,opt,name=clock,proto3,enum=cloudstate.crdt.CrdtClock" json:"clock,omitempty"` + CustomClockValue int64 `protobuf:"varint,3,opt,name=custom_clock_value,json=customClockValue,proto3" json:"custom_clock_value,omitempty"` +} + +func (x *LWWRegisterDelta) Reset() { + *x = LWWRegisterDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LWWRegisterDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LWWRegisterDelta) ProtoMessage() {} + +func (x *LWWRegisterDelta) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LWWRegisterDelta.ProtoReflect.Descriptor instead. +func (*LWWRegisterDelta) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{17} +} + +func (x *LWWRegisterDelta) GetValue() *any.Any { + if x != nil { + return x.Value + } + return nil +} + +func (x *LWWRegisterDelta) GetClock() CrdtClock { + if x != nil { + return x.Clock + } + return CrdtClock_DEFAULT +} + +func (x *LWWRegisterDelta) GetCustomClockValue() int64 { + if x != nil { + return x.CustomClockValue + } + return 0 +} + +type FlagDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value bool `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *FlagDelta) Reset() { + *x = FlagDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FlagDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FlagDelta) ProtoMessage() {} + +func (x *FlagDelta) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FlagDelta.ProtoReflect.Descriptor instead. +func (*FlagDelta) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{18} +} + +func (x *FlagDelta) GetValue() bool { + if x != nil { + return x.Value + } + return false +} + +type ORMapDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Cleared bool `protobuf:"varint,1,opt,name=cleared,proto3" json:"cleared,omitempty"` + Removed []*any.Any `protobuf:"bytes,2,rep,name=removed,proto3" json:"removed,omitempty"` + Updated []*ORMapEntryDelta `protobuf:"bytes,3,rep,name=updated,proto3" json:"updated,omitempty"` + Added []*ORMapEntry `protobuf:"bytes,4,rep,name=added,proto3" json:"added,omitempty"` +} + +func (x *ORMapDelta) Reset() { + *x = ORMapDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapDelta) ProtoMessage() {} + +func (x *ORMapDelta) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapDelta.ProtoReflect.Descriptor instead. +func (*ORMapDelta) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{19} +} + +func (x *ORMapDelta) GetCleared() bool { + if x != nil { + return x.Cleared + } + return false +} + +func (x *ORMapDelta) GetRemoved() []*any.Any { + if x != nil { + return x.Removed + } + return nil +} + +func (x *ORMapDelta) GetUpdated() []*ORMapEntryDelta { + if x != nil { + return x.Updated + } + return nil +} + +func (x *ORMapDelta) GetAdded() []*ORMapEntry { + if x != nil { + return x.Added + } + return nil +} + +type ORMapEntryDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The entry key. + Key *any.Any `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Delta *CrdtDelta `protobuf:"bytes,2,opt,name=delta,proto3" json:"delta,omitempty"` +} + +func (x *ORMapEntryDelta) Reset() { + *x = ORMapEntryDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapEntryDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapEntryDelta) ProtoMessage() {} + +func (x *ORMapEntryDelta) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapEntryDelta.ProtoReflect.Descriptor instead. +func (*ORMapEntryDelta) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{20} +} + +func (x *ORMapEntryDelta) GetKey() *any.Any { + if x != nil { + return x.Key + } + return nil +} + +func (x *ORMapEntryDelta) GetDelta() *CrdtDelta { + if x != nil { + return x.Delta + } + return nil +} + +type VoteDelta struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Only set by the user function to change the nodes current vote. + SelfVote bool `protobuf:"varint,1,opt,name=self_vote,json=selfVote,proto3" json:"self_vote,omitempty"` + // Only set by the proxy to change the votes for and total voters. + VotesFor int32 `protobuf:"varint,2,opt,name=votes_for,json=votesFor,proto3" json:"votes_for,omitempty"` + TotalVoters int32 `protobuf:"varint,3,opt,name=total_voters,json=totalVoters,proto3" json:"total_voters,omitempty"` +} + +func (x *VoteDelta) Reset() { + *x = VoteDelta{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VoteDelta) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VoteDelta) ProtoMessage() {} + +func (x *VoteDelta) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VoteDelta.ProtoReflect.Descriptor instead. +func (*VoteDelta) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{21} +} + +func (x *VoteDelta) GetSelfVote() bool { + if x != nil { + return x.SelfVote + } + return false +} + +func (x *VoteDelta) GetVotesFor() int32 { + if x != nil { + return x.VotesFor + } + return 0 +} + +func (x *VoteDelta) GetTotalVoters() int32 { + if x != nil { + return x.TotalVoters + } + return 0 +} + +type CrdtInit struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` + EntityId string `protobuf:"bytes,2,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` + State *CrdtState `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` +} + +func (x *CrdtInit) Reset() { + *x = CrdtInit{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CrdtInit) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CrdtInit) ProtoMessage() {} + +func (x *CrdtInit) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CrdtInit.ProtoReflect.Descriptor instead. +func (*CrdtInit) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{22} +} + +func (x *CrdtInit) GetServiceName() string { + if x != nil { + return x.ServiceName + } + return "" +} + +func (x *CrdtInit) GetEntityId() string { + if x != nil { + return x.EntityId + } + return "" +} + +func (x *CrdtInit) GetState() *CrdtState { + if x != nil { + return x.State + } + return nil +} + +type CrdtDelete struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CrdtDelete) Reset() { + *x = CrdtDelete{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CrdtDelete) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CrdtDelete) ProtoMessage() {} + +func (x *CrdtDelete) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CrdtDelete.ProtoReflect.Descriptor instead. +func (*CrdtDelete) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{23} +} + +type CrdtReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CommandId int64 `protobuf:"varint,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + ClientAction *protocol.ClientAction `protobuf:"bytes,2,opt,name=client_action,json=clientAction,proto3" json:"client_action,omitempty"` + SideEffects []*protocol.SideEffect `protobuf:"bytes,4,rep,name=side_effects,json=sideEffects,proto3" json:"side_effects,omitempty"` + StateAction *CrdtStateAction `protobuf:"bytes,5,opt,name=state_action,json=stateAction,proto3" json:"state_action,omitempty"` + // If the request was streamed, setting this to true indicates that the command should + // be handled as a stream. Subsequently, the user function may send CrdtStreamedMessage, + // and a CrdtStreamCancelled message will be sent if the stream is cancelled (though + // not if the a CrdtStreamedMessage ends the stream first). + Streamed bool `protobuf:"varint,6,opt,name=streamed,proto3" json:"streamed,omitempty"` +} + +func (x *CrdtReply) Reset() { + *x = CrdtReply{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CrdtReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CrdtReply) ProtoMessage() {} + +func (x *CrdtReply) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CrdtReply.ProtoReflect.Descriptor instead. +func (*CrdtReply) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{24} +} + +func (x *CrdtReply) GetCommandId() int64 { + if x != nil { + return x.CommandId + } + return 0 +} + +func (x *CrdtReply) GetClientAction() *protocol.ClientAction { + if x != nil { + return x.ClientAction + } + return nil +} + +func (x *CrdtReply) GetSideEffects() []*protocol.SideEffect { + if x != nil { + return x.SideEffects + } + return nil +} + +func (x *CrdtReply) GetStateAction() *CrdtStateAction { + if x != nil { + return x.StateAction + } + return nil +} + +func (x *CrdtReply) GetStreamed() bool { + if x != nil { + return x.Streamed + } + return false +} + +type CrdtStateAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Action: + // *CrdtStateAction_Create + // *CrdtStateAction_Update + // *CrdtStateAction_Delete + Action isCrdtStateAction_Action `protobuf_oneof:"action"` + WriteConsistency CrdtWriteConsistency `protobuf:"varint,8,opt,name=write_consistency,json=writeConsistency,proto3,enum=cloudstate.crdt.CrdtWriteConsistency" json:"write_consistency,omitempty"` +} + +func (x *CrdtStateAction) Reset() { + *x = CrdtStateAction{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CrdtStateAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CrdtStateAction) ProtoMessage() {} + +func (x *CrdtStateAction) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CrdtStateAction.ProtoReflect.Descriptor instead. +func (*CrdtStateAction) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{25} +} + +func (m *CrdtStateAction) GetAction() isCrdtStateAction_Action { + if m != nil { + return m.Action + } + return nil +} + +func (x *CrdtStateAction) GetCreate() *CrdtState { + if x, ok := x.GetAction().(*CrdtStateAction_Create); ok { + return x.Create + } + return nil +} + +func (x *CrdtStateAction) GetUpdate() *CrdtDelta { + if x, ok := x.GetAction().(*CrdtStateAction_Update); ok { + return x.Update + } + return nil +} + +func (x *CrdtStateAction) GetDelete() *CrdtDelete { + if x, ok := x.GetAction().(*CrdtStateAction_Delete); ok { + return x.Delete + } + return nil +} + +func (x *CrdtStateAction) GetWriteConsistency() CrdtWriteConsistency { + if x != nil { + return x.WriteConsistency + } + return CrdtWriteConsistency_LOCAL +} + +type isCrdtStateAction_Action interface { + isCrdtStateAction_Action() +} + +type CrdtStateAction_Create struct { + Create *CrdtState `protobuf:"bytes,5,opt,name=create,proto3,oneof"` +} + +type CrdtStateAction_Update struct { + Update *CrdtDelta `protobuf:"bytes,6,opt,name=update,proto3,oneof"` +} + +type CrdtStateAction_Delete struct { + Delete *CrdtDelete `protobuf:"bytes,7,opt,name=delete,proto3,oneof"` +} + +func (*CrdtStateAction_Create) isCrdtStateAction_Action() {} + +func (*CrdtStateAction_Update) isCrdtStateAction_Action() {} + +func (*CrdtStateAction_Delete) isCrdtStateAction_Action() {} + +// May be sent as often as liked if the first reply set streamed to true +type CrdtStreamedMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CommandId int64 `protobuf:"varint,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + ClientAction *protocol.ClientAction `protobuf:"bytes,2,opt,name=client_action,json=clientAction,proto3" json:"client_action,omitempty"` + SideEffects []*protocol.SideEffect `protobuf:"bytes,3,rep,name=side_effects,json=sideEffects,proto3" json:"side_effects,omitempty"` + // Indicates the stream should end, no messages may be sent for this command after this. + EndStream bool `protobuf:"varint,4,opt,name=end_stream,json=endStream,proto3" json:"end_stream,omitempty"` +} + +func (x *CrdtStreamedMessage) Reset() { + *x = CrdtStreamedMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CrdtStreamedMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CrdtStreamedMessage) ProtoMessage() {} + +func (x *CrdtStreamedMessage) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CrdtStreamedMessage.ProtoReflect.Descriptor instead. +func (*CrdtStreamedMessage) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{26} +} + +func (x *CrdtStreamedMessage) GetCommandId() int64 { + if x != nil { + return x.CommandId + } + return 0 +} + +func (x *CrdtStreamedMessage) GetClientAction() *protocol.ClientAction { + if x != nil { + return x.ClientAction + } + return nil +} + +func (x *CrdtStreamedMessage) GetSideEffects() []*protocol.SideEffect { + if x != nil { + return x.SideEffects + } + return nil +} + +func (x *CrdtStreamedMessage) GetEndStream() bool { + if x != nil { + return x.EndStream + } + return false +} + +type CrdtStreamCancelledResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CommandId int64 `protobuf:"varint,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + SideEffects []*protocol.SideEffect `protobuf:"bytes,2,rep,name=side_effects,json=sideEffects,proto3" json:"side_effects,omitempty"` + StateAction *CrdtStateAction `protobuf:"bytes,3,opt,name=state_action,json=stateAction,proto3" json:"state_action,omitempty"` +} + +func (x *CrdtStreamCancelledResponse) Reset() { + *x = CrdtStreamCancelledResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_crdt_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CrdtStreamCancelledResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CrdtStreamCancelledResponse) ProtoMessage() {} + +func (x *CrdtStreamCancelledResponse) ProtoReflect() protoreflect.Message { + mi := &file_crdt_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CrdtStreamCancelledResponse.ProtoReflect.Descriptor instead. +func (*CrdtStreamCancelledResponse) Descriptor() ([]byte, []int) { + return file_crdt_proto_rawDescGZIP(), []int{27} +} + +func (x *CrdtStreamCancelledResponse) GetCommandId() int64 { + if x != nil { + return x.CommandId + } + return 0 +} + +func (x *CrdtStreamCancelledResponse) GetSideEffects() []*protocol.SideEffect { + if x != nil { + return x.SideEffects + } + return nil +} + +func (x *CrdtStreamCancelledResponse) GetStateAction() *CrdtStateAction { + if x != nil { + return x.StateAction + } + return nil +} + +var File_crdt_proto protoreflect.FileDescriptor + +var file_crdt_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x1a, 0x19, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, + 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x2f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0xea, 0x02, 0x0a, 0x0c, 0x43, 0x72, 0x64, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x49, 0x6e, 0x12, 0x2f, 0x0a, 0x04, 0x69, 0x6e, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, + 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, 0x49, 0x6e, 0x69, 0x74, 0x48, 0x00, 0x52, 0x04, 0x69, + 0x6e, 0x69, 0x74, 0x12, 0x32, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, + 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, + 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x36, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, 0x44, + 0x65, 0x6c, 0x74, 0x61, 0x48, 0x00, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, + 0x37, 0x0a, 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, + 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, + 0x07, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x12, 0x2f, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, + 0x61, 0x6e, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x48, 0x00, + 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x48, 0x0a, 0x10, 0x73, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x5f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, + 0x48, 0x00, 0x52, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x6c, 0x65, 0x64, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xbe, + 0x02, 0x0a, 0x0d, 0x43, 0x72, 0x64, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4f, 0x75, 0x74, + 0x12, 0x32, 0x0a, 0x05, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, + 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x05, 0x72, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x51, 0x0a, 0x10, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x64, + 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, + 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, + 0x2e, 0x43, 0x72, 0x64, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x64, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x48, 0x00, 0x52, 0x0f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x64, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x6a, 0x0a, 0x19, 0x73, 0x74, 0x72, 0x65, 0x61, + 0x6d, 0x5f, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, + 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, 0x17, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x07, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x48, 0x00, 0x52, 0x07, 0x66, 0x61, 0x69, + 0x6c, 0x75, 0x72, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0xda, 0x03, 0x0a, 0x09, 0x43, 0x72, 0x64, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x3c, 0x0a, + 0x08, 0x67, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1e, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, + 0x74, 0x2e, 0x47, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, + 0x00, 0x52, 0x08, 0x67, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x09, 0x70, + 0x6e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, + 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, + 0x2e, 0x50, 0x4e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, + 0x00, 0x52, 0x09, 0x70, 0x6e, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x04, + 0x67, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x53, 0x65, + 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x67, 0x73, 0x65, 0x74, 0x12, 0x33, + 0x0a, 0x05, 0x6f, 0x72, 0x73, 0x65, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, + 0x4f, 0x52, 0x53, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x72, + 0x73, 0x65, 0x74, 0x12, 0x45, 0x0a, 0x0b, 0x6c, 0x77, 0x77, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4c, 0x57, 0x57, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x6c, + 0x77, 0x77, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x04, 0x66, 0x6c, + 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x12, 0x33, 0x0a, 0x05, + 0x6f, 0x72, 0x6d, 0x61, 0x70, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, + 0x4d, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x72, 0x6d, 0x61, + 0x70, 0x12, 0x30, 0x0a, 0x04, 0x76, 0x6f, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, + 0x74, 0x2e, 0x56, 0x6f, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x76, + 0x6f, 0x74, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x25, 0x0a, 0x0d, + 0x47, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x22, 0x26, 0x0a, 0x0e, 0x50, 0x4e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x37, 0x0a, 0x09, 0x47, + 0x53, 0x65, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x69, + 0x74, 0x65, 0x6d, 0x73, 0x22, 0x38, 0x0a, 0x0a, 0x4f, 0x52, 0x53, 0x65, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, 0x9e, + 0x01, 0x0a, 0x10, 0x4c, 0x57, 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x30, 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, + 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, + 0x2e, 0x43, 0x72, 0x64, 0x74, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x63, + 0x6b, 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x63, 0x6c, 0x6f, 0x63, + 0x6b, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x63, + 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0x21, 0x0a, 0x09, 0x46, 0x6c, 0x61, 0x67, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x22, 0x43, 0x0a, 0x0a, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x12, 0x35, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, + 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, + 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x66, 0x0a, 0x0a, 0x4f, 0x52, 0x4d, 0x61, 0x70, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x26, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, + 0x72, 0x64, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0x68, 0x0a, 0x09, 0x56, 0x6f, 0x74, 0x65, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, + 0x76, 0x6f, 0x74, 0x65, 0x73, 0x5f, 0x66, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x08, 0x76, 0x6f, 0x74, 0x65, 0x73, 0x46, 0x6f, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x5f, 0x76, 0x6f, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x56, 0x6f, 0x74, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x0a, 0x09, + 0x73, 0x65, 0x6c, 0x66, 0x5f, 0x76, 0x6f, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x08, 0x73, 0x65, 0x6c, 0x66, 0x56, 0x6f, 0x74, 0x65, 0x22, 0xda, 0x03, 0x0a, 0x09, 0x43, 0x72, + 0x64, 0x74, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x3c, 0x0a, 0x08, 0x67, 0x63, 0x6f, 0x75, 0x6e, + 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x65, 0x72, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x48, 0x00, 0x52, 0x08, 0x67, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x09, 0x70, 0x6e, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x50, 0x4e, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x65, 0x72, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x48, 0x00, 0x52, 0x09, 0x70, 0x6e, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x04, 0x67, 0x73, 0x65, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x53, 0x65, 0x74, 0x44, 0x65, 0x6c, 0x74, 0x61, + 0x48, 0x00, 0x52, 0x04, 0x67, 0x73, 0x65, 0x74, 0x12, 0x33, 0x0a, 0x05, 0x6f, 0x72, 0x73, 0x65, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x53, 0x65, 0x74, 0x44, + 0x65, 0x6c, 0x74, 0x61, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x72, 0x73, 0x65, 0x74, 0x12, 0x45, 0x0a, + 0x0b, 0x6c, 0x77, 0x77, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, + 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4c, 0x57, 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x44, 0x65, 0x6c, 0x74, 0x61, 0x48, 0x00, 0x52, 0x0b, 0x6c, 0x77, 0x77, 0x72, 0x65, 0x67, 0x69, + 0x73, 0x74, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, + 0x63, 0x72, 0x64, 0x74, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x48, 0x00, + 0x52, 0x04, 0x66, 0x6c, 0x61, 0x67, 0x12, 0x33, 0x0a, 0x05, 0x6f, 0x72, 0x6d, 0x61, 0x70, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x44, 0x65, 0x6c, + 0x74, 0x61, 0x48, 0x00, 0x52, 0x05, 0x6f, 0x72, 0x6d, 0x61, 0x70, 0x12, 0x30, 0x0a, 0x04, 0x76, + 0x6f, 0x74, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x56, 0x6f, 0x74, 0x65, + 0x44, 0x65, 0x6c, 0x74, 0x61, 0x48, 0x00, 0x52, 0x04, 0x76, 0x6f, 0x74, 0x65, 0x42, 0x07, 0x0a, + 0x05, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x22, 0x2d, 0x0a, 0x0d, 0x47, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x65, 0x72, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x1c, 0x0a, 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, + 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6e, 0x63, 0x72, + 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x28, 0x0a, 0x0e, 0x50, 0x4e, 0x43, 0x6f, 0x75, 0x6e, 0x74, + 0x65, 0x72, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x16, 0x0a, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x12, 0x52, 0x06, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x22, + 0x37, 0x0a, 0x09, 0x47, 0x53, 0x65, 0x74, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x2a, 0x0a, 0x05, + 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, + 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x22, 0x82, 0x01, 0x0a, 0x0a, 0x4f, 0x52, 0x53, + 0x65, 0x74, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, 0x65, 0x61, 0x72, + 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x65, + 0x64, 0x12, 0x2e, 0x0a, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, + 0x64, 0x12, 0x2a, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x22, 0x9e, 0x01, + 0x0a, 0x10, 0x4c, 0x57, 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x44, 0x65, 0x6c, + 0x74, 0x61, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x30, + 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1a, 0x2e, + 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, + 0x43, 0x72, 0x64, 0x74, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x63, 0x6b, + 0x12, 0x2c, 0x0a, 0x12, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x63, 0x6c, 0x6f, 0x63, 0x6b, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x63, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x21, + 0x0a, 0x09, 0x46, 0x6c, 0x61, 0x67, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x22, 0xc5, 0x01, 0x0a, 0x0a, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x44, 0x65, 0x6c, 0x74, 0x61, + 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x07, 0x72, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, + 0x79, 0x52, 0x07, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x12, 0x3a, 0x0a, 0x07, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, + 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x52, 0x07, 0x75, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x05, 0x61, 0x64, 0x64, 0x65, 0x64, 0x22, 0x6b, 0x0a, 0x0f, 0x4f, 0x52, 0x4d, + 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x26, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x30, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x52, + 0x05, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x22, 0x68, 0x0a, 0x09, 0x56, 0x6f, 0x74, 0x65, 0x44, 0x65, + 0x6c, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x5f, 0x76, 0x6f, 0x74, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x65, 0x6c, 0x66, 0x56, 0x6f, 0x74, 0x65, + 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x6f, 0x74, 0x65, 0x73, 0x5f, 0x66, 0x6f, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x08, 0x76, 0x6f, 0x74, 0x65, 0x73, 0x46, 0x6f, 0x72, 0x12, 0x21, 0x0a, + 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x76, 0x6f, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x56, 0x6f, 0x74, 0x65, 0x72, 0x73, + 0x22, 0x7c, 0x0a, 0x08, 0x43, 0x72, 0x64, 0x74, 0x49, 0x6e, 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0c, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, + 0x64, 0x74, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x0c, + 0x0a, 0x0a, 0x43, 0x72, 0x64, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x22, 0x85, 0x02, 0x0a, + 0x09, 0x43, 0x72, 0x64, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, + 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x3d, 0x0a, 0x0d, 0x63, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x43, 0x6c, + 0x69, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, + 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, 0x0a, 0x0c, 0x73, 0x69, 0x64, 0x65, + 0x5f, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x69, 0x64, 0x65, + 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x52, 0x0b, 0x73, 0x69, 0x64, 0x65, 0x45, 0x66, 0x66, 0x65, + 0x63, 0x74, 0x73, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x65, 0x64, 0x22, 0x92, 0x02, 0x0a, 0x0f, 0x43, 0x72, 0x64, 0x74, 0x53, 0x74, 0x61, + 0x74, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x06, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x06, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x34, + 0x0a, 0x06, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, + 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, + 0x2e, 0x43, 0x72, 0x64, 0x74, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x48, 0x00, 0x52, 0x06, 0x75, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x52, 0x0a, 0x11, 0x77, + 0x72, 0x69, 0x74, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, + 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, 0x57, 0x72, 0x69, + 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x52, 0x10, 0x77, + 0x72, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, 0x42, + 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xcd, 0x01, 0x0a, 0x13, 0x43, 0x72, + 0x64, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x64, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, + 0x12, 0x3d, 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x39, 0x0a, 0x0c, 0x73, 0x69, 0x64, 0x65, 0x5f, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x2e, 0x53, 0x69, 0x64, 0x65, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x52, 0x0b, 0x73, + 0x69, 0x64, 0x65, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x6e, + 0x64, 0x5f, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, + 0x65, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x22, 0xbc, 0x01, 0x0a, 0x1b, 0x43, 0x72, + 0x64, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, + 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, + 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, + 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x0c, 0x73, 0x69, 0x64, 0x65, + 0x5f, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x69, 0x64, 0x65, + 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x52, 0x0b, 0x73, 0x69, 0x64, 0x65, 0x45, 0x66, 0x66, 0x65, + 0x63, 0x74, 0x73, 0x12, 0x43, 0x0a, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2a, 0x38, 0x0a, 0x14, 0x43, 0x72, 0x64, 0x74, + 0x57, 0x72, 0x69, 0x74, 0x65, 0x43, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x79, + 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0c, 0x0a, 0x08, 0x4d, + 0x41, 0x4a, 0x4f, 0x52, 0x49, 0x54, 0x59, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4c, 0x4c, + 0x10, 0x02, 0x2a, 0x4c, 0x0a, 0x09, 0x43, 0x72, 0x64, 0x74, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x12, + 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, + 0x52, 0x45, 0x56, 0x45, 0x52, 0x53, 0x45, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x55, 0x53, + 0x54, 0x4f, 0x4d, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x5f, + 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x49, 0x4e, 0x43, 0x52, 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x03, + 0x32, 0x53, 0x0a, 0x04, 0x43, 0x72, 0x64, 0x74, 0x12, 0x4b, 0x0a, 0x06, 0x68, 0x61, 0x6e, 0x64, + 0x6c, 0x65, 0x12, 0x1d, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, + 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x49, + 0x6e, 0x1a, 0x1e, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x63, + 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4f, 0x75, + 0x74, 0x28, 0x01, 0x30, 0x01, 0x42, 0x55, 0x0a, 0x16, 0x69, 0x6f, 0x2e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5a, + 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x3b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_crdt_proto_rawDescOnce sync.Once + file_crdt_proto_rawDescData = file_crdt_proto_rawDesc +) + +func file_crdt_proto_rawDescGZIP() []byte { + file_crdt_proto_rawDescOnce.Do(func() { + file_crdt_proto_rawDescData = protoimpl.X.CompressGZIP(file_crdt_proto_rawDescData) + }) + return file_crdt_proto_rawDescData +} + +var file_crdt_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_crdt_proto_msgTypes = make([]protoimpl.MessageInfo, 28) +var file_crdt_proto_goTypes = []interface{}{ + (CrdtWriteConsistency)(0), // 0: cloudstate.crdt.CrdtWriteConsistency + (CrdtClock)(0), // 1: cloudstate.crdt.CrdtClock + (*CrdtStreamIn)(nil), // 2: cloudstate.crdt.CrdtStreamIn + (*CrdtStreamOut)(nil), // 3: cloudstate.crdt.CrdtStreamOut + (*CrdtState)(nil), // 4: cloudstate.crdt.CrdtState + (*GCounterState)(nil), // 5: cloudstate.crdt.GCounterState + (*PNCounterState)(nil), // 6: cloudstate.crdt.PNCounterState + (*GSetState)(nil), // 7: cloudstate.crdt.GSetState + (*ORSetState)(nil), // 8: cloudstate.crdt.ORSetState + (*LWWRegisterState)(nil), // 9: cloudstate.crdt.LWWRegisterState + (*FlagState)(nil), // 10: cloudstate.crdt.FlagState + (*ORMapState)(nil), // 11: cloudstate.crdt.ORMapState + (*ORMapEntry)(nil), // 12: cloudstate.crdt.ORMapEntry + (*VoteState)(nil), // 13: cloudstate.crdt.VoteState + (*CrdtDelta)(nil), // 14: cloudstate.crdt.CrdtDelta + (*GCounterDelta)(nil), // 15: cloudstate.crdt.GCounterDelta + (*PNCounterDelta)(nil), // 16: cloudstate.crdt.PNCounterDelta + (*GSetDelta)(nil), // 17: cloudstate.crdt.GSetDelta + (*ORSetDelta)(nil), // 18: cloudstate.crdt.ORSetDelta + (*LWWRegisterDelta)(nil), // 19: cloudstate.crdt.LWWRegisterDelta + (*FlagDelta)(nil), // 20: cloudstate.crdt.FlagDelta + (*ORMapDelta)(nil), // 21: cloudstate.crdt.ORMapDelta + (*ORMapEntryDelta)(nil), // 22: cloudstate.crdt.ORMapEntryDelta + (*VoteDelta)(nil), // 23: cloudstate.crdt.VoteDelta + (*CrdtInit)(nil), // 24: cloudstate.crdt.CrdtInit + (*CrdtDelete)(nil), // 25: cloudstate.crdt.CrdtDelete + (*CrdtReply)(nil), // 26: cloudstate.crdt.CrdtReply + (*CrdtStateAction)(nil), // 27: cloudstate.crdt.CrdtStateAction + (*CrdtStreamedMessage)(nil), // 28: cloudstate.crdt.CrdtStreamedMessage + (*CrdtStreamCancelledResponse)(nil), // 29: cloudstate.crdt.CrdtStreamCancelledResponse + (*protocol.Command)(nil), // 30: cloudstate.Command + (*protocol.StreamCancelled)(nil), // 31: cloudstate.StreamCancelled + (*protocol.Failure)(nil), // 32: cloudstate.Failure + (*any.Any)(nil), // 33: google.protobuf.Any + (*protocol.ClientAction)(nil), // 34: cloudstate.ClientAction + (*protocol.SideEffect)(nil), // 35: cloudstate.SideEffect +} +var file_crdt_proto_depIdxs = []int32{ + 24, // 0: cloudstate.crdt.CrdtStreamIn.init:type_name -> cloudstate.crdt.CrdtInit + 4, // 1: cloudstate.crdt.CrdtStreamIn.state:type_name -> cloudstate.crdt.CrdtState + 14, // 2: cloudstate.crdt.CrdtStreamIn.changed:type_name -> cloudstate.crdt.CrdtDelta + 25, // 3: cloudstate.crdt.CrdtStreamIn.deleted:type_name -> cloudstate.crdt.CrdtDelete + 30, // 4: cloudstate.crdt.CrdtStreamIn.command:type_name -> cloudstate.Command + 31, // 5: cloudstate.crdt.CrdtStreamIn.stream_cancelled:type_name -> cloudstate.StreamCancelled + 26, // 6: cloudstate.crdt.CrdtStreamOut.reply:type_name -> cloudstate.crdt.CrdtReply + 28, // 7: cloudstate.crdt.CrdtStreamOut.streamed_message:type_name -> cloudstate.crdt.CrdtStreamedMessage + 29, // 8: cloudstate.crdt.CrdtStreamOut.stream_cancelled_response:type_name -> cloudstate.crdt.CrdtStreamCancelledResponse + 32, // 9: cloudstate.crdt.CrdtStreamOut.failure:type_name -> cloudstate.Failure + 5, // 10: cloudstate.crdt.CrdtState.gcounter:type_name -> cloudstate.crdt.GCounterState + 6, // 11: cloudstate.crdt.CrdtState.pncounter:type_name -> cloudstate.crdt.PNCounterState + 7, // 12: cloudstate.crdt.CrdtState.gset:type_name -> cloudstate.crdt.GSetState + 8, // 13: cloudstate.crdt.CrdtState.orset:type_name -> cloudstate.crdt.ORSetState + 9, // 14: cloudstate.crdt.CrdtState.lwwregister:type_name -> cloudstate.crdt.LWWRegisterState + 10, // 15: cloudstate.crdt.CrdtState.flag:type_name -> cloudstate.crdt.FlagState + 11, // 16: cloudstate.crdt.CrdtState.ormap:type_name -> cloudstate.crdt.ORMapState + 13, // 17: cloudstate.crdt.CrdtState.vote:type_name -> cloudstate.crdt.VoteState + 33, // 18: cloudstate.crdt.GSetState.items:type_name -> google.protobuf.Any + 33, // 19: cloudstate.crdt.ORSetState.items:type_name -> google.protobuf.Any + 33, // 20: cloudstate.crdt.LWWRegisterState.value:type_name -> google.protobuf.Any + 1, // 21: cloudstate.crdt.LWWRegisterState.clock:type_name -> cloudstate.crdt.CrdtClock + 12, // 22: cloudstate.crdt.ORMapState.entries:type_name -> cloudstate.crdt.ORMapEntry + 33, // 23: cloudstate.crdt.ORMapEntry.key:type_name -> google.protobuf.Any + 4, // 24: cloudstate.crdt.ORMapEntry.value:type_name -> cloudstate.crdt.CrdtState + 15, // 25: cloudstate.crdt.CrdtDelta.gcounter:type_name -> cloudstate.crdt.GCounterDelta + 16, // 26: cloudstate.crdt.CrdtDelta.pncounter:type_name -> cloudstate.crdt.PNCounterDelta + 17, // 27: cloudstate.crdt.CrdtDelta.gset:type_name -> cloudstate.crdt.GSetDelta + 18, // 28: cloudstate.crdt.CrdtDelta.orset:type_name -> cloudstate.crdt.ORSetDelta + 19, // 29: cloudstate.crdt.CrdtDelta.lwwregister:type_name -> cloudstate.crdt.LWWRegisterDelta + 20, // 30: cloudstate.crdt.CrdtDelta.flag:type_name -> cloudstate.crdt.FlagDelta + 21, // 31: cloudstate.crdt.CrdtDelta.ormap:type_name -> cloudstate.crdt.ORMapDelta + 23, // 32: cloudstate.crdt.CrdtDelta.vote:type_name -> cloudstate.crdt.VoteDelta + 33, // 33: cloudstate.crdt.GSetDelta.added:type_name -> google.protobuf.Any + 33, // 34: cloudstate.crdt.ORSetDelta.removed:type_name -> google.protobuf.Any + 33, // 35: cloudstate.crdt.ORSetDelta.added:type_name -> google.protobuf.Any + 33, // 36: cloudstate.crdt.LWWRegisterDelta.value:type_name -> google.protobuf.Any + 1, // 37: cloudstate.crdt.LWWRegisterDelta.clock:type_name -> cloudstate.crdt.CrdtClock + 33, // 38: cloudstate.crdt.ORMapDelta.removed:type_name -> google.protobuf.Any + 22, // 39: cloudstate.crdt.ORMapDelta.updated:type_name -> cloudstate.crdt.ORMapEntryDelta + 12, // 40: cloudstate.crdt.ORMapDelta.added:type_name -> cloudstate.crdt.ORMapEntry + 33, // 41: cloudstate.crdt.ORMapEntryDelta.key:type_name -> google.protobuf.Any + 14, // 42: cloudstate.crdt.ORMapEntryDelta.delta:type_name -> cloudstate.crdt.CrdtDelta + 4, // 43: cloudstate.crdt.CrdtInit.state:type_name -> cloudstate.crdt.CrdtState + 34, // 44: cloudstate.crdt.CrdtReply.client_action:type_name -> cloudstate.ClientAction + 35, // 45: cloudstate.crdt.CrdtReply.side_effects:type_name -> cloudstate.SideEffect + 27, // 46: cloudstate.crdt.CrdtReply.state_action:type_name -> cloudstate.crdt.CrdtStateAction + 4, // 47: cloudstate.crdt.CrdtStateAction.create:type_name -> cloudstate.crdt.CrdtState + 14, // 48: cloudstate.crdt.CrdtStateAction.update:type_name -> cloudstate.crdt.CrdtDelta + 25, // 49: cloudstate.crdt.CrdtStateAction.delete:type_name -> cloudstate.crdt.CrdtDelete + 0, // 50: cloudstate.crdt.CrdtStateAction.write_consistency:type_name -> cloudstate.crdt.CrdtWriteConsistency + 34, // 51: cloudstate.crdt.CrdtStreamedMessage.client_action:type_name -> cloudstate.ClientAction + 35, // 52: cloudstate.crdt.CrdtStreamedMessage.side_effects:type_name -> cloudstate.SideEffect + 35, // 53: cloudstate.crdt.CrdtStreamCancelledResponse.side_effects:type_name -> cloudstate.SideEffect + 27, // 54: cloudstate.crdt.CrdtStreamCancelledResponse.state_action:type_name -> cloudstate.crdt.CrdtStateAction + 2, // 55: cloudstate.crdt.Crdt.handle:input_type -> cloudstate.crdt.CrdtStreamIn + 3, // 56: cloudstate.crdt.Crdt.handle:output_type -> cloudstate.crdt.CrdtStreamOut + 56, // [56:57] is the sub-list for method output_type + 55, // [55:56] is the sub-list for method input_type + 55, // [55:55] is the sub-list for extension type_name + 55, // [55:55] is the sub-list for extension extendee + 0, // [0:55] is the sub-list for field type_name +} + +func init() { file_crdt_proto_init() } +func file_crdt_proto_init() { + if File_crdt_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_crdt_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CrdtStreamIn); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CrdtStreamOut); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CrdtState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GCounterState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PNCounterState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GSetState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORSetState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LWWRegisterState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlagState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapEntry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VoteState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CrdtDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GCounterDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PNCounterDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GSetDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORSetDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LWWRegisterDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlagDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapEntryDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VoteDelta); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CrdtInit); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CrdtDelete); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CrdtReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CrdtStateAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CrdtStreamedMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_crdt_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CrdtStreamCancelledResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_crdt_proto_msgTypes[0].OneofWrappers = []interface{}{ + (*CrdtStreamIn_Init)(nil), + (*CrdtStreamIn_State)(nil), + (*CrdtStreamIn_Changed)(nil), + (*CrdtStreamIn_Deleted)(nil), + (*CrdtStreamIn_Command)(nil), + (*CrdtStreamIn_StreamCancelled)(nil), + } + file_crdt_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*CrdtStreamOut_Reply)(nil), + (*CrdtStreamOut_StreamedMessage)(nil), + (*CrdtStreamOut_StreamCancelledResponse)(nil), + (*CrdtStreamOut_Failure)(nil), + } + file_crdt_proto_msgTypes[2].OneofWrappers = []interface{}{ + (*CrdtState_Gcounter)(nil), + (*CrdtState_Pncounter)(nil), + (*CrdtState_Gset)(nil), + (*CrdtState_Orset)(nil), + (*CrdtState_Lwwregister)(nil), + (*CrdtState_Flag)(nil), + (*CrdtState_Ormap)(nil), + (*CrdtState_Vote)(nil), + } + file_crdt_proto_msgTypes[12].OneofWrappers = []interface{}{ + (*CrdtDelta_Gcounter)(nil), + (*CrdtDelta_Pncounter)(nil), + (*CrdtDelta_Gset)(nil), + (*CrdtDelta_Orset)(nil), + (*CrdtDelta_Lwwregister)(nil), + (*CrdtDelta_Flag)(nil), + (*CrdtDelta_Ormap)(nil), + (*CrdtDelta_Vote)(nil), + } + file_crdt_proto_msgTypes[25].OneofWrappers = []interface{}{ + (*CrdtStateAction_Create)(nil), + (*CrdtStateAction_Update)(nil), + (*CrdtStateAction_Delete)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_crdt_proto_rawDesc, + NumEnums: 2, + NumMessages: 28, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_crdt_proto_goTypes, + DependencyIndexes: file_crdt_proto_depIdxs, + EnumInfos: file_crdt_proto_enumTypes, + MessageInfos: file_crdt_proto_msgTypes, + }.Build() + File_crdt_proto = out.File + file_crdt_proto_rawDesc = nil + file_crdt_proto_goTypes = nil + file_crdt_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// CrdtClient is the client API for Crdt service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type CrdtClient interface { + // After invoking handle, the first message sent will always be a CrdtInit message, containing the entity ID, and, + // if it exists or is available, the current state of the entity. After that, one or more commands may be sent, + // as well as deltas as they arrive, and the entire state if either the entity is created, or the proxy wishes the + // user function to replace its entire state. + // + // The user function must respond with one reply per command in. They do not necessarily have to be sent in the same + // order that the commands were sent, the command ID is used to correlate commands to replies. + Handle(ctx context.Context, opts ...grpc.CallOption) (Crdt_HandleClient, error) +} + +type crdtClient struct { + cc grpc.ClientConnInterface +} + +func NewCrdtClient(cc grpc.ClientConnInterface) CrdtClient { + return &crdtClient{cc} +} + +func (c *crdtClient) Handle(ctx context.Context, opts ...grpc.CallOption) (Crdt_HandleClient, error) { + stream, err := c.cc.NewStream(ctx, &_Crdt_serviceDesc.Streams[0], "/cloudstate.crdt.Crdt/handle", opts...) + if err != nil { + return nil, err + } + x := &crdtHandleClient{stream} + return x, nil +} + +type Crdt_HandleClient interface { + Send(*CrdtStreamIn) error + Recv() (*CrdtStreamOut, error) + grpc.ClientStream +} + +type crdtHandleClient struct { + grpc.ClientStream +} + +func (x *crdtHandleClient) Send(m *CrdtStreamIn) error { + return x.ClientStream.SendMsg(m) +} + +func (x *crdtHandleClient) Recv() (*CrdtStreamOut, error) { + m := new(CrdtStreamOut) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// CrdtServer is the server API for Crdt service. +type CrdtServer interface { + // After invoking handle, the first message sent will always be a CrdtInit message, containing the entity ID, and, + // if it exists or is available, the current state of the entity. After that, one or more commands may be sent, + // as well as deltas as they arrive, and the entire state if either the entity is created, or the proxy wishes the + // user function to replace its entire state. + // + // The user function must respond with one reply per command in. They do not necessarily have to be sent in the same + // order that the commands were sent, the command ID is used to correlate commands to replies. + Handle(Crdt_HandleServer) error +} + +// UnimplementedCrdtServer can be embedded to have forward compatible implementations. +type UnimplementedCrdtServer struct { +} + +func (*UnimplementedCrdtServer) Handle(Crdt_HandleServer) error { + return status.Errorf(codes.Unimplemented, "method Handle not implemented") +} + +func RegisterCrdtServer(s *grpc.Server, srv CrdtServer) { + s.RegisterService(&_Crdt_serviceDesc, srv) +} + +func _Crdt_Handle_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(CrdtServer).Handle(&crdtHandleServer{stream}) +} + +type Crdt_HandleServer interface { + Send(*CrdtStreamOut) error + Recv() (*CrdtStreamIn, error) + grpc.ServerStream +} + +type crdtHandleServer struct { + grpc.ServerStream +} + +func (x *crdtHandleServer) Send(m *CrdtStreamOut) error { + return x.ServerStream.SendMsg(m) +} + +func (x *crdtHandleServer) Recv() (*CrdtStreamIn, error) { + m := new(CrdtStreamIn) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +var _Crdt_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cloudstate.crdt.Crdt", + HandlerType: (*CrdtServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "handle", + Handler: _Crdt_Handle_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "crdt.proto", +} diff --git a/cloudstate/entity/event_sourced.pb.go b/cloudstate/entity/event_sourced.pb.go new file mode 100644 index 0000000..6b7ab4f --- /dev/null +++ b/cloudstate/entity/event_sourced.pb.go @@ -0,0 +1,872 @@ +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// gRPC interface for Event Sourced Entity user functions. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: event_sourced.proto + +package entity + +import ( + context "context" + protocol "github.com/cloudstateio/go-support/cloudstate/protocol" + proto "github.com/golang/protobuf/proto" + any "github.com/golang/protobuf/ptypes/any" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// The init message. This will always be the first message sent to the entity when +// it is loaded. +type EventSourcedInit struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` + // The ID of the entity. + EntityId string `protobuf:"bytes,2,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` + // If present the entity should initialise its state using this snapshot. + Snapshot *EventSourcedSnapshot `protobuf:"bytes,3,opt,name=snapshot,proto3" json:"snapshot,omitempty"` +} + +func (x *EventSourcedInit) Reset() { + *x = EventSourcedInit{} + if protoimpl.UnsafeEnabled { + mi := &file_event_sourced_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventSourcedInit) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventSourcedInit) ProtoMessage() {} + +func (x *EventSourcedInit) ProtoReflect() protoreflect.Message { + mi := &file_event_sourced_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventSourcedInit.ProtoReflect.Descriptor instead. +func (*EventSourcedInit) Descriptor() ([]byte, []int) { + return file_event_sourced_proto_rawDescGZIP(), []int{0} +} + +func (x *EventSourcedInit) GetServiceName() string { + if x != nil { + return x.ServiceName + } + return "" +} + +func (x *EventSourcedInit) GetEntityId() string { + if x != nil { + return x.EntityId + } + return "" +} + +func (x *EventSourcedInit) GetSnapshot() *EventSourcedSnapshot { + if x != nil { + return x.Snapshot + } + return nil +} + +// A snapshot +type EventSourcedSnapshot struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The sequence number when the snapshot was taken. + SnapshotSequence int64 `protobuf:"varint,1,opt,name=snapshot_sequence,json=snapshotSequence,proto3" json:"snapshot_sequence,omitempty"` + // The snapshot. + Snapshot *any.Any `protobuf:"bytes,2,opt,name=snapshot,proto3" json:"snapshot,omitempty"` +} + +func (x *EventSourcedSnapshot) Reset() { + *x = EventSourcedSnapshot{} + if protoimpl.UnsafeEnabled { + mi := &file_event_sourced_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventSourcedSnapshot) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventSourcedSnapshot) ProtoMessage() {} + +func (x *EventSourcedSnapshot) ProtoReflect() protoreflect.Message { + mi := &file_event_sourced_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventSourcedSnapshot.ProtoReflect.Descriptor instead. +func (*EventSourcedSnapshot) Descriptor() ([]byte, []int) { + return file_event_sourced_proto_rawDescGZIP(), []int{1} +} + +func (x *EventSourcedSnapshot) GetSnapshotSequence() int64 { + if x != nil { + return x.SnapshotSequence + } + return 0 +} + +func (x *EventSourcedSnapshot) GetSnapshot() *any.Any { + if x != nil { + return x.Snapshot + } + return nil +} + +// An event. These will be sent to the entity when the entity starts up. +type EventSourcedEvent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The sequence number of the event. + Sequence int64 `protobuf:"varint,1,opt,name=sequence,proto3" json:"sequence,omitempty"` + // The event payload. + Payload *any.Any `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` +} + +func (x *EventSourcedEvent) Reset() { + *x = EventSourcedEvent{} + if protoimpl.UnsafeEnabled { + mi := &file_event_sourced_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventSourcedEvent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventSourcedEvent) ProtoMessage() {} + +func (x *EventSourcedEvent) ProtoReflect() protoreflect.Message { + mi := &file_event_sourced_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventSourcedEvent.ProtoReflect.Descriptor instead. +func (*EventSourcedEvent) Descriptor() ([]byte, []int) { + return file_event_sourced_proto_rawDescGZIP(), []int{2} +} + +func (x *EventSourcedEvent) GetSequence() int64 { + if x != nil { + return x.Sequence + } + return 0 +} + +func (x *EventSourcedEvent) GetPayload() *any.Any { + if x != nil { + return x.Payload + } + return nil +} + +// A reply to a command. +type EventSourcedReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The id of the command being replied to. Must match the input command. + CommandId int64 `protobuf:"varint,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` + // The action to take + ClientAction *protocol.ClientAction `protobuf:"bytes,2,opt,name=client_action,json=clientAction,proto3" json:"client_action,omitempty"` + // Any side effects to perform + SideEffects []*protocol.SideEffect `protobuf:"bytes,3,rep,name=side_effects,json=sideEffects,proto3" json:"side_effects,omitempty"` + // A list of events to persist - these will be persisted before the reply + // is sent. + Events []*any.Any `protobuf:"bytes,4,rep,name=events,proto3" json:"events,omitempty"` + // An optional snapshot to persist. It is assumed that this snapshot will have + // the state of any events in the events field applied to it. It is illegal to + // send a snapshot without sending any events. + Snapshot *any.Any `protobuf:"bytes,5,opt,name=snapshot,proto3" json:"snapshot,omitempty"` +} + +func (x *EventSourcedReply) Reset() { + *x = EventSourcedReply{} + if protoimpl.UnsafeEnabled { + mi := &file_event_sourced_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventSourcedReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventSourcedReply) ProtoMessage() {} + +func (x *EventSourcedReply) ProtoReflect() protoreflect.Message { + mi := &file_event_sourced_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventSourcedReply.ProtoReflect.Descriptor instead. +func (*EventSourcedReply) Descriptor() ([]byte, []int) { + return file_event_sourced_proto_rawDescGZIP(), []int{3} +} + +func (x *EventSourcedReply) GetCommandId() int64 { + if x != nil { + return x.CommandId + } + return 0 +} + +func (x *EventSourcedReply) GetClientAction() *protocol.ClientAction { + if x != nil { + return x.ClientAction + } + return nil +} + +func (x *EventSourcedReply) GetSideEffects() []*protocol.SideEffect { + if x != nil { + return x.SideEffects + } + return nil +} + +func (x *EventSourcedReply) GetEvents() []*any.Any { + if x != nil { + return x.Events + } + return nil +} + +func (x *EventSourcedReply) GetSnapshot() *any.Any { + if x != nil { + return x.Snapshot + } + return nil +} + +// Input message type for the gRPC stream in. +type EventSourcedStreamIn struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Message: + // *EventSourcedStreamIn_Init + // *EventSourcedStreamIn_Event + // *EventSourcedStreamIn_Command + Message isEventSourcedStreamIn_Message `protobuf_oneof:"message"` +} + +func (x *EventSourcedStreamIn) Reset() { + *x = EventSourcedStreamIn{} + if protoimpl.UnsafeEnabled { + mi := &file_event_sourced_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventSourcedStreamIn) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventSourcedStreamIn) ProtoMessage() {} + +func (x *EventSourcedStreamIn) ProtoReflect() protoreflect.Message { + mi := &file_event_sourced_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventSourcedStreamIn.ProtoReflect.Descriptor instead. +func (*EventSourcedStreamIn) Descriptor() ([]byte, []int) { + return file_event_sourced_proto_rawDescGZIP(), []int{4} +} + +func (m *EventSourcedStreamIn) GetMessage() isEventSourcedStreamIn_Message { + if m != nil { + return m.Message + } + return nil +} + +func (x *EventSourcedStreamIn) GetInit() *EventSourcedInit { + if x, ok := x.GetMessage().(*EventSourcedStreamIn_Init); ok { + return x.Init + } + return nil +} + +func (x *EventSourcedStreamIn) GetEvent() *EventSourcedEvent { + if x, ok := x.GetMessage().(*EventSourcedStreamIn_Event); ok { + return x.Event + } + return nil +} + +func (x *EventSourcedStreamIn) GetCommand() *protocol.Command { + if x, ok := x.GetMessage().(*EventSourcedStreamIn_Command); ok { + return x.Command + } + return nil +} + +type isEventSourcedStreamIn_Message interface { + isEventSourcedStreamIn_Message() +} + +type EventSourcedStreamIn_Init struct { + Init *EventSourcedInit `protobuf:"bytes,1,opt,name=init,proto3,oneof"` +} + +type EventSourcedStreamIn_Event struct { + Event *EventSourcedEvent `protobuf:"bytes,2,opt,name=event,proto3,oneof"` +} + +type EventSourcedStreamIn_Command struct { + Command *protocol.Command `protobuf:"bytes,3,opt,name=command,proto3,oneof"` +} + +func (*EventSourcedStreamIn_Init) isEventSourcedStreamIn_Message() {} + +func (*EventSourcedStreamIn_Event) isEventSourcedStreamIn_Message() {} + +func (*EventSourcedStreamIn_Command) isEventSourcedStreamIn_Message() {} + +// Output message type for the gRPC stream out. +type EventSourcedStreamOut struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Message: + // *EventSourcedStreamOut_Reply + // *EventSourcedStreamOut_Failure + Message isEventSourcedStreamOut_Message `protobuf_oneof:"message"` +} + +func (x *EventSourcedStreamOut) Reset() { + *x = EventSourcedStreamOut{} + if protoimpl.UnsafeEnabled { + mi := &file_event_sourced_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EventSourcedStreamOut) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EventSourcedStreamOut) ProtoMessage() {} + +func (x *EventSourcedStreamOut) ProtoReflect() protoreflect.Message { + mi := &file_event_sourced_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EventSourcedStreamOut.ProtoReflect.Descriptor instead. +func (*EventSourcedStreamOut) Descriptor() ([]byte, []int) { + return file_event_sourced_proto_rawDescGZIP(), []int{5} +} + +func (m *EventSourcedStreamOut) GetMessage() isEventSourcedStreamOut_Message { + if m != nil { + return m.Message + } + return nil +} + +func (x *EventSourcedStreamOut) GetReply() *EventSourcedReply { + if x, ok := x.GetMessage().(*EventSourcedStreamOut_Reply); ok { + return x.Reply + } + return nil +} + +func (x *EventSourcedStreamOut) GetFailure() *protocol.Failure { + if x, ok := x.GetMessage().(*EventSourcedStreamOut_Failure); ok { + return x.Failure + } + return nil +} + +type isEventSourcedStreamOut_Message interface { + isEventSourcedStreamOut_Message() +} + +type EventSourcedStreamOut_Reply struct { + Reply *EventSourcedReply `protobuf:"bytes,1,opt,name=reply,proto3,oneof"` +} + +type EventSourcedStreamOut_Failure struct { + Failure *protocol.Failure `protobuf:"bytes,2,opt,name=failure,proto3,oneof"` +} + +func (*EventSourcedStreamOut_Reply) isEventSourcedStreamOut_Message() {} + +func (*EventSourcedStreamOut_Failure) isEventSourcedStreamOut_Message() {} + +var File_event_sourced_proto protoreflect.FileDescriptor + +var file_event_sourced_proto_rawDesc = []byte{ + 0x0a, 0x13, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x17, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x1a, 0x19, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0x9d, 0x01, 0x0a, 0x10, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x64, 0x49, 0x6e, 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x49, 0x0a, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x64, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, + 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, + 0x6f, 0x74, 0x22, 0x75, 0x0a, 0x14, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x64, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x2b, 0x0a, 0x11, 0x73, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x53, + 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x30, 0x0a, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, + 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x22, 0x5f, 0x0a, 0x11, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x1a, + 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x70, 0x61, + 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, + 0x79, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x8c, 0x02, 0x0a, 0x11, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, + 0x3d, 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x39, + 0x0a, 0x0c, 0x73, 0x69, 0x64, 0x65, 0x5f, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x53, 0x69, 0x64, 0x65, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x52, 0x0b, 0x73, 0x69, + 0x64, 0x65, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, 0x12, 0x2c, 0x0a, 0x06, 0x65, 0x76, 0x65, + 0x6e, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, + 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x30, 0x0a, 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, + 0x08, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x22, 0xd7, 0x01, 0x0a, 0x14, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x49, 0x6e, 0x12, 0x3f, 0x0a, 0x04, 0x69, 0x6e, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x49, 0x6e, 0x69, 0x74, 0x48, 0x00, 0x52, 0x04, 0x69, + 0x6e, 0x69, 0x74, 0x12, 0x42, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, + 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x2e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, + 0x52, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x2f, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x48, 0x00, 0x52, + 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x22, 0x97, 0x01, 0x0a, 0x15, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x64, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x4f, 0x75, 0x74, 0x12, 0x42, 0x0a, + 0x05, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x64, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x05, 0x72, 0x65, 0x70, 0x6c, + 0x79, 0x12, 0x2f, 0x0a, 0x07, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, + 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x48, 0x00, 0x52, 0x07, 0x66, 0x61, 0x69, 0x6c, 0x75, + 0x72, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x7d, 0x0a, + 0x0c, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x12, 0x6d, 0x0a, + 0x06, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x2d, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x64, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x53, 0x74, + 0x72, 0x65, 0x61, 0x6d, 0x49, 0x6e, 0x1a, 0x2e, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x53, 0x74, 0x72, + 0x65, 0x61, 0x6d, 0x4f, 0x75, 0x74, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x55, 0x0a, 0x16, + 0x69, 0x6f, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5a, 0x3b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, + 0x67, 0x6f, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x3b, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_event_sourced_proto_rawDescOnce sync.Once + file_event_sourced_proto_rawDescData = file_event_sourced_proto_rawDesc +) + +func file_event_sourced_proto_rawDescGZIP() []byte { + file_event_sourced_proto_rawDescOnce.Do(func() { + file_event_sourced_proto_rawDescData = protoimpl.X.CompressGZIP(file_event_sourced_proto_rawDescData) + }) + return file_event_sourced_proto_rawDescData +} + +var file_event_sourced_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_event_sourced_proto_goTypes = []interface{}{ + (*EventSourcedInit)(nil), // 0: cloudstate.eventsourced.EventSourcedInit + (*EventSourcedSnapshot)(nil), // 1: cloudstate.eventsourced.EventSourcedSnapshot + (*EventSourcedEvent)(nil), // 2: cloudstate.eventsourced.EventSourcedEvent + (*EventSourcedReply)(nil), // 3: cloudstate.eventsourced.EventSourcedReply + (*EventSourcedStreamIn)(nil), // 4: cloudstate.eventsourced.EventSourcedStreamIn + (*EventSourcedStreamOut)(nil), // 5: cloudstate.eventsourced.EventSourcedStreamOut + (*any.Any)(nil), // 6: google.protobuf.Any + (*protocol.ClientAction)(nil), // 7: cloudstate.ClientAction + (*protocol.SideEffect)(nil), // 8: cloudstate.SideEffect + (*protocol.Command)(nil), // 9: cloudstate.Command + (*protocol.Failure)(nil), // 10: cloudstate.Failure +} +var file_event_sourced_proto_depIdxs = []int32{ + 1, // 0: cloudstate.eventsourced.EventSourcedInit.snapshot:type_name -> cloudstate.eventsourced.EventSourcedSnapshot + 6, // 1: cloudstate.eventsourced.EventSourcedSnapshot.snapshot:type_name -> google.protobuf.Any + 6, // 2: cloudstate.eventsourced.EventSourcedEvent.payload:type_name -> google.protobuf.Any + 7, // 3: cloudstate.eventsourced.EventSourcedReply.client_action:type_name -> cloudstate.ClientAction + 8, // 4: cloudstate.eventsourced.EventSourcedReply.side_effects:type_name -> cloudstate.SideEffect + 6, // 5: cloudstate.eventsourced.EventSourcedReply.events:type_name -> google.protobuf.Any + 6, // 6: cloudstate.eventsourced.EventSourcedReply.snapshot:type_name -> google.protobuf.Any + 0, // 7: cloudstate.eventsourced.EventSourcedStreamIn.init:type_name -> cloudstate.eventsourced.EventSourcedInit + 2, // 8: cloudstate.eventsourced.EventSourcedStreamIn.event:type_name -> cloudstate.eventsourced.EventSourcedEvent + 9, // 9: cloudstate.eventsourced.EventSourcedStreamIn.command:type_name -> cloudstate.Command + 3, // 10: cloudstate.eventsourced.EventSourcedStreamOut.reply:type_name -> cloudstate.eventsourced.EventSourcedReply + 10, // 11: cloudstate.eventsourced.EventSourcedStreamOut.failure:type_name -> cloudstate.Failure + 4, // 12: cloudstate.eventsourced.EventSourced.handle:input_type -> cloudstate.eventsourced.EventSourcedStreamIn + 5, // 13: cloudstate.eventsourced.EventSourced.handle:output_type -> cloudstate.eventsourced.EventSourcedStreamOut + 13, // [13:14] is the sub-list for method output_type + 12, // [12:13] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name +} + +func init() { file_event_sourced_proto_init() } +func file_event_sourced_proto_init() { + if File_event_sourced_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_event_sourced_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventSourcedInit); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_event_sourced_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventSourcedSnapshot); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_event_sourced_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventSourcedEvent); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_event_sourced_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventSourcedReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_event_sourced_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventSourcedStreamIn); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_event_sourced_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EventSourcedStreamOut); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_event_sourced_proto_msgTypes[4].OneofWrappers = []interface{}{ + (*EventSourcedStreamIn_Init)(nil), + (*EventSourcedStreamIn_Event)(nil), + (*EventSourcedStreamIn_Command)(nil), + } + file_event_sourced_proto_msgTypes[5].OneofWrappers = []interface{}{ + (*EventSourcedStreamOut_Reply)(nil), + (*EventSourcedStreamOut_Failure)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_event_sourced_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_event_sourced_proto_goTypes, + DependencyIndexes: file_event_sourced_proto_depIdxs, + MessageInfos: file_event_sourced_proto_msgTypes, + }.Build() + File_event_sourced_proto = out.File + file_event_sourced_proto_rawDesc = nil + file_event_sourced_proto_goTypes = nil + file_event_sourced_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// EventSourcedClient is the client API for EventSourced service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type EventSourcedClient interface { + // The stream. One stream will be established per active entity. + // Once established, the first message sent will be Init, which contains the entity ID, and, + // if the entity has previously persisted a snapshot, it will contain that snapshot. It will + // then send zero to many event messages, one for each event previously persisted. The entity + // is expected to apply these to its state in a deterministic fashion. Once all the events + // are sent, one to many commands are sent, with new commands being sent as new requests for + // the entity come in. The entity is expected to reply to each command with exactly one reply + // message. The entity should reply in order, and any events that the entity requests to be + // persisted the entity should handle itself, applying them to its own state, as if they had + // arrived as events when the event stream was being replayed on load. + Handle(ctx context.Context, opts ...grpc.CallOption) (EventSourced_HandleClient, error) +} + +type eventSourcedClient struct { + cc grpc.ClientConnInterface +} + +func NewEventSourcedClient(cc grpc.ClientConnInterface) EventSourcedClient { + return &eventSourcedClient{cc} +} + +func (c *eventSourcedClient) Handle(ctx context.Context, opts ...grpc.CallOption) (EventSourced_HandleClient, error) { + stream, err := c.cc.NewStream(ctx, &_EventSourced_serviceDesc.Streams[0], "/cloudstate.eventsourced.EventSourced/handle", opts...) + if err != nil { + return nil, err + } + x := &eventSourcedHandleClient{stream} + return x, nil +} + +type EventSourced_HandleClient interface { + Send(*EventSourcedStreamIn) error + Recv() (*EventSourcedStreamOut, error) + grpc.ClientStream +} + +type eventSourcedHandleClient struct { + grpc.ClientStream +} + +func (x *eventSourcedHandleClient) Send(m *EventSourcedStreamIn) error { + return x.ClientStream.SendMsg(m) +} + +func (x *eventSourcedHandleClient) Recv() (*EventSourcedStreamOut, error) { + m := new(EventSourcedStreamOut) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// EventSourcedServer is the server API for EventSourced service. +type EventSourcedServer interface { + // The stream. One stream will be established per active entity. + // Once established, the first message sent will be Init, which contains the entity ID, and, + // if the entity has previously persisted a snapshot, it will contain that snapshot. It will + // then send zero to many event messages, one for each event previously persisted. The entity + // is expected to apply these to its state in a deterministic fashion. Once all the events + // are sent, one to many commands are sent, with new commands being sent as new requests for + // the entity come in. The entity is expected to reply to each command with exactly one reply + // message. The entity should reply in order, and any events that the entity requests to be + // persisted the entity should handle itself, applying them to its own state, as if they had + // arrived as events when the event stream was being replayed on load. + Handle(EventSourced_HandleServer) error +} + +// UnimplementedEventSourcedServer can be embedded to have forward compatible implementations. +type UnimplementedEventSourcedServer struct { +} + +func (*UnimplementedEventSourcedServer) Handle(EventSourced_HandleServer) error { + return status.Errorf(codes.Unimplemented, "method Handle not implemented") +} + +func RegisterEventSourcedServer(s *grpc.Server, srv EventSourcedServer) { + s.RegisterService(&_EventSourced_serviceDesc, srv) +} + +func _EventSourced_Handle_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(EventSourcedServer).Handle(&eventSourcedHandleServer{stream}) +} + +type EventSourced_HandleServer interface { + Send(*EventSourcedStreamOut) error + Recv() (*EventSourcedStreamIn, error) + grpc.ServerStream +} + +type eventSourcedHandleServer struct { + grpc.ServerStream +} + +func (x *eventSourcedHandleServer) Send(m *EventSourcedStreamOut) error { + return x.ServerStream.SendMsg(m) +} + +func (x *eventSourcedHandleServer) Recv() (*EventSourcedStreamIn, error) { + m := new(EventSourcedStreamIn) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +var _EventSourced_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cloudstate.eventsourced.EventSourced", + HandlerType: (*EventSourcedServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "handle", + Handler: _EventSourced_Handle_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "event_sourced.proto", +} diff --git a/cloudstate/entity/function.pb.go b/cloudstate/entity/function.pb.go new file mode 100644 index 0000000..6c62cd6 --- /dev/null +++ b/cloudstate/entity/function.pb.go @@ -0,0 +1,804 @@ +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// gRPC interface for Stateless Entity user functions. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: function.proto + +package entity + +import ( + context "context" + protocol "github.com/cloudstateio/go-support/cloudstate/protocol" + proto "github.com/golang/protobuf/proto" + any "github.com/golang/protobuf/ptypes/any" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// A function command. +// +// For unary and streamed out calls, the service name, command name and payload will always be set. +// +// For streamed in and duplex streamed calls, the first command sent will just contain the service +// name and command name, but no payload. This will indicate that the function has been invoked. +// Subsequent commands on the stream will only have the payload set, the service name and command +// name will not be set. +type FunctionCommand struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of the service this function is on. + ServiceName string `protobuf:"bytes,2,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` + // Command name + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + // The command payload. + Payload *any.Any `protobuf:"bytes,4,opt,name=payload,proto3" json:"payload,omitempty"` + // Metadata + Metadata *protocol.Metadata `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"` +} + +func (x *FunctionCommand) Reset() { + *x = FunctionCommand{} + if protoimpl.UnsafeEnabled { + mi := &file_function_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FunctionCommand) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FunctionCommand) ProtoMessage() {} + +func (x *FunctionCommand) ProtoReflect() protoreflect.Message { + mi := &file_function_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FunctionCommand.ProtoReflect.Descriptor instead. +func (*FunctionCommand) Descriptor() ([]byte, []int) { + return file_function_proto_rawDescGZIP(), []int{0} +} + +func (x *FunctionCommand) GetServiceName() string { + if x != nil { + return x.ServiceName + } + return "" +} + +func (x *FunctionCommand) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *FunctionCommand) GetPayload() *any.Any { + if x != nil { + return x.Payload + } + return nil +} + +func (x *FunctionCommand) GetMetadata() *protocol.Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +type FunctionReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Response: + // *FunctionReply_Failure + // *FunctionReply_Reply + // *FunctionReply_Forward + Response isFunctionReply_Response `protobuf_oneof:"response"` + SideEffects []*protocol.SideEffect `protobuf:"bytes,4,rep,name=side_effects,json=sideEffects,proto3" json:"side_effects,omitempty"` +} + +func (x *FunctionReply) Reset() { + *x = FunctionReply{} + if protoimpl.UnsafeEnabled { + mi := &file_function_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FunctionReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FunctionReply) ProtoMessage() {} + +func (x *FunctionReply) ProtoReflect() protoreflect.Message { + mi := &file_function_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FunctionReply.ProtoReflect.Descriptor instead. +func (*FunctionReply) Descriptor() ([]byte, []int) { + return file_function_proto_rawDescGZIP(), []int{1} +} + +func (m *FunctionReply) GetResponse() isFunctionReply_Response { + if m != nil { + return m.Response + } + return nil +} + +func (x *FunctionReply) GetFailure() *protocol.Failure { + if x, ok := x.GetResponse().(*FunctionReply_Failure); ok { + return x.Failure + } + return nil +} + +func (x *FunctionReply) GetReply() *protocol.Reply { + if x, ok := x.GetResponse().(*FunctionReply_Reply); ok { + return x.Reply + } + return nil +} + +func (x *FunctionReply) GetForward() *protocol.Forward { + if x, ok := x.GetResponse().(*FunctionReply_Forward); ok { + return x.Forward + } + return nil +} + +func (x *FunctionReply) GetSideEffects() []*protocol.SideEffect { + if x != nil { + return x.SideEffects + } + return nil +} + +type isFunctionReply_Response interface { + isFunctionReply_Response() +} + +type FunctionReply_Failure struct { + Failure *protocol.Failure `protobuf:"bytes,1,opt,name=failure,proto3,oneof"` +} + +type FunctionReply_Reply struct { + Reply *protocol.Reply `protobuf:"bytes,2,opt,name=reply,proto3,oneof"` +} + +type FunctionReply_Forward struct { + Forward *protocol.Forward `protobuf:"bytes,3,opt,name=forward,proto3,oneof"` +} + +func (*FunctionReply_Failure) isFunctionReply_Response() {} + +func (*FunctionReply_Reply) isFunctionReply_Response() {} + +func (*FunctionReply_Forward) isFunctionReply_Response() {} + +var File_function_proto protoreflect.FileDescriptor + +var file_function_proto_rawDesc = []byte{ + 0x0a, 0x0e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x13, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x66, 0x75, 0x6e, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x1a, 0x17, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xaa, 0x01, 0x0a, 0x0f, 0x46, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x21, 0x0a, + 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x70, 0x61, 0x79, + 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x30, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xe3, 0x01, 0x0a, 0x0d, 0x46, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2f, 0x0a, 0x07, 0x66, 0x61, 0x69, 0x6c, + 0x75, 0x72, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x48, 0x00, + 0x52, 0x07, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x72, 0x65, 0x70, + 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x05, 0x72, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2f, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x48, 0x00, 0x52, 0x07, 0x66, 0x6f, + 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x39, 0x0a, 0x0c, 0x73, 0x69, 0x64, 0x65, 0x5f, 0x65, 0x66, + 0x66, 0x65, 0x63, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x53, 0x69, 0x64, 0x65, 0x45, 0x66, 0x66, + 0x65, 0x63, 0x74, 0x52, 0x0b, 0x73, 0x69, 0x64, 0x65, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x73, + 0x42, 0x0a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x95, 0x03, 0x0a, + 0x11, 0x53, 0x74, 0x61, 0x74, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x12, 0x59, 0x0a, 0x0b, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x55, 0x6e, 0x61, 0x72, + 0x79, 0x12, 0x24, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x22, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x46, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x60, 0x0a, + 0x10, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x64, 0x49, + 0x6e, 0x12, 0x24, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x66, + 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x22, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x46, 0x75, + 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x28, 0x01, 0x12, + 0x61, 0x0a, 0x11, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, + 0x64, 0x4f, 0x75, 0x74, 0x12, 0x24, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x22, 0x2e, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, + 0x30, 0x01, 0x12, 0x60, 0x0a, 0x0e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x53, 0x74, 0x72, 0x65, + 0x61, 0x6d, 0x65, 0x64, 0x12, 0x24, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x1a, 0x22, 0x2e, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x2e, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, + 0x28, 0x01, 0x30, 0x01, 0x42, 0x55, 0x0a, 0x16, 0x69, 0x6f, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5a, 0x3b, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x3b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_function_proto_rawDescOnce sync.Once + file_function_proto_rawDescData = file_function_proto_rawDesc +) + +func file_function_proto_rawDescGZIP() []byte { + file_function_proto_rawDescOnce.Do(func() { + file_function_proto_rawDescData = protoimpl.X.CompressGZIP(file_function_proto_rawDescData) + }) + return file_function_proto_rawDescData +} + +var file_function_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_function_proto_goTypes = []interface{}{ + (*FunctionCommand)(nil), // 0: cloudstate.function.FunctionCommand + (*FunctionReply)(nil), // 1: cloudstate.function.FunctionReply + (*any.Any)(nil), // 2: google.protobuf.Any + (*protocol.Metadata)(nil), // 3: cloudstate.Metadata + (*protocol.Failure)(nil), // 4: cloudstate.Failure + (*protocol.Reply)(nil), // 5: cloudstate.Reply + (*protocol.Forward)(nil), // 6: cloudstate.Forward + (*protocol.SideEffect)(nil), // 7: cloudstate.SideEffect +} +var file_function_proto_depIdxs = []int32{ + 2, // 0: cloudstate.function.FunctionCommand.payload:type_name -> google.protobuf.Any + 3, // 1: cloudstate.function.FunctionCommand.metadata:type_name -> cloudstate.Metadata + 4, // 2: cloudstate.function.FunctionReply.failure:type_name -> cloudstate.Failure + 5, // 3: cloudstate.function.FunctionReply.reply:type_name -> cloudstate.Reply + 6, // 4: cloudstate.function.FunctionReply.forward:type_name -> cloudstate.Forward + 7, // 5: cloudstate.function.FunctionReply.side_effects:type_name -> cloudstate.SideEffect + 0, // 6: cloudstate.function.StatelessFunction.handleUnary:input_type -> cloudstate.function.FunctionCommand + 0, // 7: cloudstate.function.StatelessFunction.handleStreamedIn:input_type -> cloudstate.function.FunctionCommand + 0, // 8: cloudstate.function.StatelessFunction.handleStreamedOut:input_type -> cloudstate.function.FunctionCommand + 0, // 9: cloudstate.function.StatelessFunction.handleStreamed:input_type -> cloudstate.function.FunctionCommand + 1, // 10: cloudstate.function.StatelessFunction.handleUnary:output_type -> cloudstate.function.FunctionReply + 1, // 11: cloudstate.function.StatelessFunction.handleStreamedIn:output_type -> cloudstate.function.FunctionReply + 1, // 12: cloudstate.function.StatelessFunction.handleStreamedOut:output_type -> cloudstate.function.FunctionReply + 1, // 13: cloudstate.function.StatelessFunction.handleStreamed:output_type -> cloudstate.function.FunctionReply + 10, // [10:14] is the sub-list for method output_type + 6, // [6:10] is the sub-list for method input_type + 6, // [6:6] is the sub-list for extension type_name + 6, // [6:6] is the sub-list for extension extendee + 0, // [0:6] is the sub-list for field type_name +} + +func init() { file_function_proto_init() } +func file_function_proto_init() { + if File_function_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_function_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FunctionCommand); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_function_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FunctionReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_function_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*FunctionReply_Failure)(nil), + (*FunctionReply_Reply)(nil), + (*FunctionReply_Forward)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_function_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_function_proto_goTypes, + DependencyIndexes: file_function_proto_depIdxs, + MessageInfos: file_function_proto_msgTypes, + }.Build() + File_function_proto = out.File + file_function_proto_rawDesc = nil + file_function_proto_goTypes = nil + file_function_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// StatelessFunctionClient is the client API for StatelessFunction service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type StatelessFunctionClient interface { + // Handle a unary command. + // + // The input command will contain the service name, command name, request metadata and the command + // payload. The reply may contain a direct reply, a forward or a failure, and it may contain many + // side effects. + HandleUnary(ctx context.Context, in *FunctionCommand, opts ...grpc.CallOption) (*FunctionReply, error) + // Handle a streamed in command. + // + // The first message in will contain the request metadata, including the service name and command + // name. It will not have an associated payload set. This will be followed by zero to many messages + // in with a payload, but no service name or command name set. + // + // If the underlying transport supports per stream metadata, rather than per message metadata, then + // that metadata will only be included in the metadata of the first message. In contrast, if the + // underlying transport supports per message metadata, there will be no metadata on the first message, + // the metadata will instead be found on each subsequent message. + // + // The semantics of stream closure in this protocol map 1:1 with the semantics of gRPC stream closure, + // that is, when the client closes the stream, the stream is considered half closed, and the server + // should eventually, but not necessarily immediately, send a response message with a status code and + // trailers. + // + // If however the server sends a response message before the client closes the stream, the stream is + // completely closed, and the client should handle this and stop sending more messages. + // + // Either the client or the server may cancel the stream at any time, cancellation is indicated + // through an HTTP2 stream RST message. + HandleStreamedIn(ctx context.Context, opts ...grpc.CallOption) (StatelessFunction_HandleStreamedInClient, error) + // Handle a streamed out command. + // + // The input command will contain the service name, command name, request metadata and the command + // payload. Zero or more replies may be sent, each containing either a direct reply, a forward or a + // failure, and each may contain many side effects. The stream to the client will be closed when the + // this stream is closed, with the same status as this stream is closed with. + // + // Either the client or the server may cancel the stream at any time, cancellation is indicated + // through an HTTP2 stream RST message. + HandleStreamedOut(ctx context.Context, in *FunctionCommand, opts ...grpc.CallOption) (StatelessFunction_HandleStreamedOutClient, error) + // Handle a full duplex streamed command. + // + // The first message in will contain the request metadata, including the service name and command + // name. It will not have an associated payload set. This will be followed by zero to many messages + // in with a payload, but no service name or command name set. + // + // Zero or more replies may be sent, each containing either a direct reply, a forward or a failure, + // and each may contain many side effects. + // + // If the underlying transport supports per stream metadata, rather than per message metadata, then + // that metadata will only be included in the metadata of the first message. In contrast, if the + // underlying transport supports per message metadata, there will be no metadata on the first message, + // the metadata will instead be found on each subsequent message. + // + // The semantics of stream closure in this protocol map 1:1 with the semantics of gRPC stream closure, + // that is, when the client closes the stream, the stream is considered half closed, and the server + // should eventually, but not necessarily immediately, close the stream with a status code and + // trailers. + // + // If however the server closes the stream with a status code and trailers, the stream is immediately + // considered completely closed, and no further messages sent by the client will be handled by the + // server. + // + // Either the client or the server may cancel the stream at any time, cancellation is indicated + // through an HTTP2 stream RST message. + HandleStreamed(ctx context.Context, opts ...grpc.CallOption) (StatelessFunction_HandleStreamedClient, error) +} + +type statelessFunctionClient struct { + cc grpc.ClientConnInterface +} + +func NewStatelessFunctionClient(cc grpc.ClientConnInterface) StatelessFunctionClient { + return &statelessFunctionClient{cc} +} + +func (c *statelessFunctionClient) HandleUnary(ctx context.Context, in *FunctionCommand, opts ...grpc.CallOption) (*FunctionReply, error) { + out := new(FunctionReply) + err := c.cc.Invoke(ctx, "/cloudstate.function.StatelessFunction/handleUnary", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *statelessFunctionClient) HandleStreamedIn(ctx context.Context, opts ...grpc.CallOption) (StatelessFunction_HandleStreamedInClient, error) { + stream, err := c.cc.NewStream(ctx, &_StatelessFunction_serviceDesc.Streams[0], "/cloudstate.function.StatelessFunction/handleStreamedIn", opts...) + if err != nil { + return nil, err + } + x := &statelessFunctionHandleStreamedInClient{stream} + return x, nil +} + +type StatelessFunction_HandleStreamedInClient interface { + Send(*FunctionCommand) error + CloseAndRecv() (*FunctionReply, error) + grpc.ClientStream +} + +type statelessFunctionHandleStreamedInClient struct { + grpc.ClientStream +} + +func (x *statelessFunctionHandleStreamedInClient) Send(m *FunctionCommand) error { + return x.ClientStream.SendMsg(m) +} + +func (x *statelessFunctionHandleStreamedInClient) CloseAndRecv() (*FunctionReply, error) { + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + m := new(FunctionReply) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *statelessFunctionClient) HandleStreamedOut(ctx context.Context, in *FunctionCommand, opts ...grpc.CallOption) (StatelessFunction_HandleStreamedOutClient, error) { + stream, err := c.cc.NewStream(ctx, &_StatelessFunction_serviceDesc.Streams[1], "/cloudstate.function.StatelessFunction/handleStreamedOut", opts...) + if err != nil { + return nil, err + } + x := &statelessFunctionHandleStreamedOutClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type StatelessFunction_HandleStreamedOutClient interface { + Recv() (*FunctionReply, error) + grpc.ClientStream +} + +type statelessFunctionHandleStreamedOutClient struct { + grpc.ClientStream +} + +func (x *statelessFunctionHandleStreamedOutClient) Recv() (*FunctionReply, error) { + m := new(FunctionReply) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *statelessFunctionClient) HandleStreamed(ctx context.Context, opts ...grpc.CallOption) (StatelessFunction_HandleStreamedClient, error) { + stream, err := c.cc.NewStream(ctx, &_StatelessFunction_serviceDesc.Streams[2], "/cloudstate.function.StatelessFunction/handleStreamed", opts...) + if err != nil { + return nil, err + } + x := &statelessFunctionHandleStreamedClient{stream} + return x, nil +} + +type StatelessFunction_HandleStreamedClient interface { + Send(*FunctionCommand) error + Recv() (*FunctionReply, error) + grpc.ClientStream +} + +type statelessFunctionHandleStreamedClient struct { + grpc.ClientStream +} + +func (x *statelessFunctionHandleStreamedClient) Send(m *FunctionCommand) error { + return x.ClientStream.SendMsg(m) +} + +func (x *statelessFunctionHandleStreamedClient) Recv() (*FunctionReply, error) { + m := new(FunctionReply) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// StatelessFunctionServer is the server API for StatelessFunction service. +type StatelessFunctionServer interface { + // Handle a unary command. + // + // The input command will contain the service name, command name, request metadata and the command + // payload. The reply may contain a direct reply, a forward or a failure, and it may contain many + // side effects. + HandleUnary(context.Context, *FunctionCommand) (*FunctionReply, error) + // Handle a streamed in command. + // + // The first message in will contain the request metadata, including the service name and command + // name. It will not have an associated payload set. This will be followed by zero to many messages + // in with a payload, but no service name or command name set. + // + // If the underlying transport supports per stream metadata, rather than per message metadata, then + // that metadata will only be included in the metadata of the first message. In contrast, if the + // underlying transport supports per message metadata, there will be no metadata on the first message, + // the metadata will instead be found on each subsequent message. + // + // The semantics of stream closure in this protocol map 1:1 with the semantics of gRPC stream closure, + // that is, when the client closes the stream, the stream is considered half closed, and the server + // should eventually, but not necessarily immediately, send a response message with a status code and + // trailers. + // + // If however the server sends a response message before the client closes the stream, the stream is + // completely closed, and the client should handle this and stop sending more messages. + // + // Either the client or the server may cancel the stream at any time, cancellation is indicated + // through an HTTP2 stream RST message. + HandleStreamedIn(StatelessFunction_HandleStreamedInServer) error + // Handle a streamed out command. + // + // The input command will contain the service name, command name, request metadata and the command + // payload. Zero or more replies may be sent, each containing either a direct reply, a forward or a + // failure, and each may contain many side effects. The stream to the client will be closed when the + // this stream is closed, with the same status as this stream is closed with. + // + // Either the client or the server may cancel the stream at any time, cancellation is indicated + // through an HTTP2 stream RST message. + HandleStreamedOut(*FunctionCommand, StatelessFunction_HandleStreamedOutServer) error + // Handle a full duplex streamed command. + // + // The first message in will contain the request metadata, including the service name and command + // name. It will not have an associated payload set. This will be followed by zero to many messages + // in with a payload, but no service name or command name set. + // + // Zero or more replies may be sent, each containing either a direct reply, a forward or a failure, + // and each may contain many side effects. + // + // If the underlying transport supports per stream metadata, rather than per message metadata, then + // that metadata will only be included in the metadata of the first message. In contrast, if the + // underlying transport supports per message metadata, there will be no metadata on the first message, + // the metadata will instead be found on each subsequent message. + // + // The semantics of stream closure in this protocol map 1:1 with the semantics of gRPC stream closure, + // that is, when the client closes the stream, the stream is considered half closed, and the server + // should eventually, but not necessarily immediately, close the stream with a status code and + // trailers. + // + // If however the server closes the stream with a status code and trailers, the stream is immediately + // considered completely closed, and no further messages sent by the client will be handled by the + // server. + // + // Either the client or the server may cancel the stream at any time, cancellation is indicated + // through an HTTP2 stream RST message. + HandleStreamed(StatelessFunction_HandleStreamedServer) error +} + +// UnimplementedStatelessFunctionServer can be embedded to have forward compatible implementations. +type UnimplementedStatelessFunctionServer struct { +} + +func (*UnimplementedStatelessFunctionServer) HandleUnary(context.Context, *FunctionCommand) (*FunctionReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method HandleUnary not implemented") +} +func (*UnimplementedStatelessFunctionServer) HandleStreamedIn(StatelessFunction_HandleStreamedInServer) error { + return status.Errorf(codes.Unimplemented, "method HandleStreamedIn not implemented") +} +func (*UnimplementedStatelessFunctionServer) HandleStreamedOut(*FunctionCommand, StatelessFunction_HandleStreamedOutServer) error { + return status.Errorf(codes.Unimplemented, "method HandleStreamedOut not implemented") +} +func (*UnimplementedStatelessFunctionServer) HandleStreamed(StatelessFunction_HandleStreamedServer) error { + return status.Errorf(codes.Unimplemented, "method HandleStreamed not implemented") +} + +func RegisterStatelessFunctionServer(s *grpc.Server, srv StatelessFunctionServer) { + s.RegisterService(&_StatelessFunction_serviceDesc, srv) +} + +func _StatelessFunction_HandleUnary_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FunctionCommand) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(StatelessFunctionServer).HandleUnary(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cloudstate.function.StatelessFunction/HandleUnary", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(StatelessFunctionServer).HandleUnary(ctx, req.(*FunctionCommand)) + } + return interceptor(ctx, in, info, handler) +} + +func _StatelessFunction_HandleStreamedIn_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(StatelessFunctionServer).HandleStreamedIn(&statelessFunctionHandleStreamedInServer{stream}) +} + +type StatelessFunction_HandleStreamedInServer interface { + SendAndClose(*FunctionReply) error + Recv() (*FunctionCommand, error) + grpc.ServerStream +} + +type statelessFunctionHandleStreamedInServer struct { + grpc.ServerStream +} + +func (x *statelessFunctionHandleStreamedInServer) SendAndClose(m *FunctionReply) error { + return x.ServerStream.SendMsg(m) +} + +func (x *statelessFunctionHandleStreamedInServer) Recv() (*FunctionCommand, error) { + m := new(FunctionCommand) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func _StatelessFunction_HandleStreamedOut_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(FunctionCommand) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(StatelessFunctionServer).HandleStreamedOut(m, &statelessFunctionHandleStreamedOutServer{stream}) +} + +type StatelessFunction_HandleStreamedOutServer interface { + Send(*FunctionReply) error + grpc.ServerStream +} + +type statelessFunctionHandleStreamedOutServer struct { + grpc.ServerStream +} + +func (x *statelessFunctionHandleStreamedOutServer) Send(m *FunctionReply) error { + return x.ServerStream.SendMsg(m) +} + +func _StatelessFunction_HandleStreamed_Handler(srv interface{}, stream grpc.ServerStream) error { + return srv.(StatelessFunctionServer).HandleStreamed(&statelessFunctionHandleStreamedServer{stream}) +} + +type StatelessFunction_HandleStreamedServer interface { + Send(*FunctionReply) error + Recv() (*FunctionCommand, error) + grpc.ServerStream +} + +type statelessFunctionHandleStreamedServer struct { + grpc.ServerStream +} + +func (x *statelessFunctionHandleStreamedServer) Send(m *FunctionReply) error { + return x.ServerStream.SendMsg(m) +} + +func (x *statelessFunctionHandleStreamedServer) Recv() (*FunctionCommand, error) { + m := new(FunctionCommand) + if err := x.ServerStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +var _StatelessFunction_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cloudstate.function.StatelessFunction", + HandlerType: (*StatelessFunctionServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "handleUnary", + Handler: _StatelessFunction_HandleUnary_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "handleStreamedIn", + Handler: _StatelessFunction_HandleStreamedIn_Handler, + ClientStreams: true, + }, + { + StreamName: "handleStreamedOut", + Handler: _StatelessFunction_HandleStreamedOut_Handler, + ServerStreams: true, + }, + { + StreamName: "handleStreamed", + Handler: _StatelessFunction_HandleStreamed_Handler, + ServerStreams: true, + ClientStreams: true, + }, + }, + Metadata: "function.proto", +} diff --git a/cloudstate/entity_key.pb.go b/cloudstate/entity_key.pb.go index b0094a9..a167d4a 100644 --- a/cloudstate/entity_key.pb.go +++ b/cloudstate/entity_key.pb.go @@ -1,52 +1,117 @@ +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Extension for specifying which field in a message is to be considered an +// entity key, for the purposes associating gRPC calls with entities and +// sharding. + // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 // source: cloudstate/entity_key.proto package cloudstate import ( - fmt "fmt" proto "github.com/golang/protobuf/proto" descriptor "github.com/golang/protobuf/protoc-gen-go/descriptor" - math "math" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -var E_EntityKey = &proto.ExtensionDesc{ - ExtendedType: (*descriptor.FieldOptions)(nil), - ExtensionType: (*bool)(nil), - Field: 50002, - Name: "cloudstate.entity_key", - Tag: "varint,50002,opt,name=entity_key", - Filename: "cloudstate/entity_key.proto", +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +var file_cloudstate_entity_key_proto_extTypes = []protoimpl.ExtensionInfo{ + { + ExtendedType: (*descriptor.FieldOptions)(nil), + ExtensionType: (*bool)(nil), + Field: 50002, + Name: "cloudstate.entity_key", + Tag: "varint,50002,opt,name=entity_key", + Filename: "cloudstate/entity_key.proto", + }, } -func init() { - proto.RegisterExtension(E_EntityKey) +// Extension fields to descriptor.FieldOptions. +var ( + // optional bool entity_key = 50002; + E_EntityKey = &file_cloudstate_entity_key_proto_extTypes[0] +) + +var File_cloudstate_entity_key_proto protoreflect.FileDescriptor + +var file_cloudstate_entity_key_proto_rawDesc = []byte{ + 0x0a, 0x1b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x3a, 0x3e, 0x0a, 0x0a, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, + 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0xd2, 0x86, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x4b, 0x65, 0x79, 0x42, 0x49, 0x0a, 0x0d, 0x69, + 0x6f, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5a, 0x38, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x3b, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var file_cloudstate_entity_key_proto_goTypes = []interface{}{ + (*descriptor.FieldOptions)(nil), // 0: google.protobuf.FieldOptions +} +var file_cloudstate_entity_key_proto_depIdxs = []int32{ + 0, // 0: cloudstate.entity_key:extendee -> google.protobuf.FieldOptions + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 0, // [0:1] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } -func init() { proto.RegisterFile("cloudstate/entity_key.proto", fileDescriptor_7bcabc3af9eb79b9) } - -var fileDescriptor_7bcabc3af9eb79b9 = []byte{ - // 174 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x4e, 0xce, 0xc9, 0x2f, - 0x4d, 0x29, 0x2e, 0x49, 0x2c, 0x49, 0xd5, 0x4f, 0xcd, 0x2b, 0xc9, 0x2c, 0xa9, 0x8c, 0xcf, 0x4e, - 0xad, 0xd4, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0xe2, 0x42, 0x48, 0x4a, 0x29, 0xa4, 0xe7, 0xe7, - 0xa7, 0xe7, 0xa4, 0xea, 0x83, 0x65, 0x92, 0x4a, 0xd3, 0xf4, 0x53, 0x52, 0x8b, 0x93, 0x8b, 0x32, - 0x0b, 0x4a, 0xf2, 0x8b, 0x20, 0xaa, 0xad, 0xec, 0xb8, 0xb8, 0x10, 0x26, 0x08, 0xc9, 0xea, 0x41, - 0x34, 0xe8, 0xc1, 0x34, 0xe8, 0xb9, 0x65, 0xa6, 0xe6, 0xa4, 0xf8, 0x17, 0x94, 0x64, 0xe6, 0xe7, - 0x15, 0x4b, 0x5c, 0x6a, 0x63, 0x56, 0x60, 0xd4, 0xe0, 0x08, 0xe2, 0x84, 0x68, 0xf1, 0x4e, 0xad, - 0x74, 0xf2, 0xe2, 0xe2, 0xcd, 0xcc, 0xd7, 0x43, 0x58, 0x19, 0x65, 0x99, 0x9e, 0x59, 0x92, 0x51, - 0x9a, 0xa4, 0x97, 0x9c, 0x9f, 0xab, 0x8f, 0x10, 0xce, 0xcc, 0xd7, 0x4f, 0xcf, 0xd7, 0x2d, 0x2e, - 0x2d, 0x28, 0xc8, 0x2f, 0x2a, 0x41, 0x12, 0xd7, 0xb7, 0x46, 0xb0, 0x93, 0xd8, 0xc0, 0xb6, 0x1a, - 0x03, 0x02, 0x00, 0x00, 0xff, 0xff, 0xd9, 0xd8, 0x72, 0x17, 0xdf, 0x00, 0x00, 0x00, +func init() { file_cloudstate_entity_key_proto_init() } +func file_cloudstate_entity_key_proto_init() { + if File_cloudstate_entity_key_proto != nil { + return + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_cloudstate_entity_key_proto_rawDesc, + NumEnums: 0, + NumMessages: 0, + NumExtensions: 1, + NumServices: 0, + }, + GoTypes: file_cloudstate_entity_key_proto_goTypes, + DependencyIndexes: file_cloudstate_entity_key_proto_depIdxs, + ExtensionInfos: file_cloudstate_entity_key_proto_extTypes, + }.Build() + File_cloudstate_entity_key_proto = out.File + file_cloudstate_entity_key_proto_rawDesc = nil + file_cloudstate_entity_key_proto_goTypes = nil + file_cloudstate_entity_key_proto_depIdxs = nil } diff --git a/cloudstate/event.go b/cloudstate/event.go deleted file mode 100644 index c29d20d..0000000 --- a/cloudstate/event.go +++ /dev/null @@ -1,115 +0,0 @@ -// -// Copyright 2019 Lightbend Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cloudstate - -import ( - "context" - "fmt" -) - -type OnNext func(event interface{}) error -type OnErr func(err error) -type Subscription struct { - OnNext - OnErr - active bool -} - -func (s *Subscription) Unsubscribe() { - s.active = false -} - -type EventEmitter interface { - Emit(event interface{}) - Subscribe(subs *Subscription) *Subscription - Events() []interface{} - Clear() -} - -func NewEmitter() *eventEmitter { - return &eventEmitter{ - events: make([]interface{}, 0), - subscriptions: make([]*Subscription, 0), - } -} - -type eventEmitter struct { - events []interface{} - subscriptions []*Subscription -} - -// Emit will immediately invoke the associated event handler for that event. -// This both validates that the event can be applied to the current state, as well as -// updates the state so that subsequent processing in the command handler can use it. -func (e *eventEmitter) Emit(event interface{}) { - for _, subs := range e.subscriptions { - if !subs.active { - continue - } - err := subs.OnNext(event) - if r := recover(); r != nil { - subs.OnErr(fmt.Errorf("panicked with: %v", r)) - continue - } - if err != nil && subs.OnErr != nil { - subs.OnErr(err) - // TODO: we have no context here to fail to the proxy - } - } - e.events = append(e.events, event) -} - -func (e *eventEmitter) Events() []interface{} { - return e.events -} - -func (e *eventEmitter) Subscribe(subs *Subscription) *Subscription { - subs.active = true - e.subscriptions = append(e.subscriptions, subs) - return subs -} - -func (e *eventEmitter) Clear() { - e.events = make([]interface{}, 0) -} - -// tag::event-handler[] -type EventHandler interface { - HandleEvent(ctx context.Context, event interface{}) (handled bool, err error) -} - -// end::event-handler[] - -// tag::command-handler[] -type CommandHandler interface { - HandleCommand(ctx context.Context, command interface{}) (handled bool, reply interface{}, err error) -} - -// end::command-handler[] - -// tag::snapshotter[] -type Snapshotter interface { - Snapshot() (snapshot interface{}, err error) -} - -// end::snapshotter[] - -// tag::snapshot-handler[] -type SnapshotHandler interface { - HandleSnapshot(snapshot interface{}) (handled bool, err error) -} - -// end::snapshot-handler[] diff --git a/cloudstate/event_test.go b/cloudstate/event_test.go deleted file mode 100644 index bec88db..0000000 --- a/cloudstate/event_test.go +++ /dev/null @@ -1,115 +0,0 @@ -// -// Copyright 2019 Lightbend Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cloudstate - -import ( - "fmt" - "sync/atomic" - "testing" -) - -type AnEntity struct { - EventEmitter -} - -func TestMultipleSubscribers(t *testing.T) { - e := AnEntity{EventEmitter: NewEmitter()} - n := int64(0) - e.Subscribe(&Subscription{ - OnNext: func(event interface{}) error { - atomic.AddInt64(&n, 1) - return nil - }, - }) - e.Emit(1) - if n != 1 { - t.Fail() - } - e.Emit(1) - if n != 2 { - t.Fail() - } - e.Subscribe(&Subscription{ - OnNext: func(event interface{}) error { - atomic.AddInt64(&n, 1) - return nil - }, - }) - e.Emit(1) - if n != 4 { - t.Fail() - } -} - -func TestUnsubscribe(t *testing.T) { - e := AnEntity{EventEmitter: NewEmitter()} - n := int64(0) - sub1 := &Subscription{ - OnNext: func(event interface{}) error { - atomic.AddInt64(&n, 1) - return nil - }, - } - e.Subscribe(sub1) - e.Emit(1) - if n != 1 { - t.Fail() - } - e.Emit(1) - if n != 2 { - t.Fail() - } - e.Subscribe(&Subscription{ - OnNext: func(event interface{}) error { - atomic.AddInt64(&n, 1) - return nil - }, - }) - sub1.Unsubscribe() - e.Emit(1) - if n != 3 { - t.Fail() - } -} - -func TestEventEmitter(t *testing.T) { - e := AnEntity{EventEmitter: NewEmitter()} - s := make([]string, 0) - ee := fmt.Errorf("int types are no supported") - e.Subscribe(&Subscription{ - OnNext: func(event interface{}) error { - switch v := event.(type) { - case int: - return ee - case string: - s = append(s, v) - } - return nil - }, - OnErr: func(err error) { - if err != ee { - t.Errorf("received unexpected error: %v", err) - } - }, - }) - // emit something that triggers an error we'd expect to happen - e.Emit(1) - // emit a string that gets to the list - e.Emit("john") - if len(s) != 1 || s[0] != "john" { - t.Errorf("john was not in the list: %+v", s) - } -} diff --git a/cloudstate/eventsourced.go b/cloudstate/eventsourced.go deleted file mode 100644 index 6c5c75c..0000000 --- a/cloudstate/eventsourced.go +++ /dev/null @@ -1,447 +0,0 @@ -// -// Copyright 2019 Lightbend Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cloudstate - -import ( - "context" - "fmt" - "io" - "net/url" - "reflect" - "strings" - "sync" - - "github.com/cloudstateio/go-support/cloudstate/encoding" - "github.com/cloudstateio/go-support/cloudstate/protocol" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/any" -) - -// Entity -type Entity interface { - CommandHandler - EventHandler -} - -const snapshotEveryDefault = 100 - -// EventSourcedEntity captures an Entity, its ServiceName and PersistenceID. -// It is used to be registered as an event sourced entity on a CloudState instance. -// tag::event-sourced-entity-type[] -type EventSourcedEntity struct { - // ServiceName is the fully qualified name of the service that implements this entities interface. - // Setting it is mandatory. - ServiceName string - // PersistenceID is used to namespace events in the journal, useful for - // when you share the same database between multiple entities. It defaults to - // the simple name for the entity type. - // It’s good practice to select one explicitly, this means your database - // isn’t depend on type names in your code. - // Setting it is mandatory. - PersistenceID string - // The snapshotEvery parameter controls how often snapshots are taken, - // so that the entity doesn't need to be recovered from the whole journal - // each time it’s loaded. If left unset, it defaults to 100. - // Setting it to a negative number will result in snapshots never being taken. - SnapshotEvery int64 - - // EntityFactory is a factory method which generates a new Entity. - // tag::event-sourced-entity-func[] - EntityFunc func() Entity - // end::event-sourced-entity-func[] - - // internal - registerOnce sync.Once -} - -// end::event-sourced-entity-type[] - -// init get its Entity type and Zero-Value it to -// something we can use as an initializer. -func (e *EventSourcedEntity) init() error { - e.SnapshotEvery = snapshotEveryDefault - return nil -} - -// The EntityInstance represents a concrete instance of -// a event sourced entity -type EntityInstance struct { - // Instance is an instance of the EventSourcedEntity.Entity - Instance interface{} - // EventSourcedEntity describes the instance - EventSourcedEntity *EventSourcedEntity - - eventSequence int64 -} - -func (e *EntityInstance) shouldSnapshot() bool { - return e.eventSequence >= e.EventSourcedEntity.SnapshotEvery -} - -func (e *EntityInstance) resetSnapshotEvery() { - e.eventSequence = 0 -} - -// A EntityInstanceContext represents a event sourced entity together with its -// associated service. -// Commands are dispatched through this context. -type EntityInstanceContext struct { // TODO: EntityInstanceContext might be actually a EntityInstance - // EntityInstance is the entity instance of this context - EntityInstance *EntityInstance - // active indicates if this context is active - active bool // TODO: inactivate a context in case of errors -} - -// ServiceName returns the contexts service name. -func (c EntityInstanceContext) ServiceName() string { - return c.EntityInstance.EventSourcedEntity.ServiceName -} - -// EventSourcedServer is the implementation of the EventSourcedServer server API for EventSourced service. -type EventSourcedServer struct { - // entities are indexed by their service name - entities map[string]*EventSourcedEntity - // contexts are entity instance contexts indexed by their entity ids - contexts map[string]*EntityInstanceContext -} - -// newEventSourcedServer returns an initialized EventSourcedServer -func newEventSourcedServer() *EventSourcedServer { - return &EventSourcedServer{ - entities: make(map[string]*EventSourcedEntity), - contexts: make(map[string]*EntityInstanceContext), - } -} - -func (esh *EventSourcedServer) registerEntity(ese *EventSourcedEntity) error { - if _, exists := esh.entities[ese.ServiceName]; exists { - return fmt.Errorf("EventSourcedEntity with service name: %s is already registered", ese.ServiceName) - } - esh.entities[ese.ServiceName] = ese - return nil -} - -// Handle handles the stream. One stream will be established per active entity. -// Once established, the first message sent will be Init, which contains the entity ID, and, -// if the entity has previously persisted a snapshot, it will contain that snapshot. It will -// then send zero to many event messages, one for each event previously persisted. The entity -// is expected to apply these to its state in a deterministic fashion. Once all the events -// are sent, one to many commands are sent, with new commands being sent as new requests for -// the entity come in. The entity is expected to reply to each command with exactly one reply -// message. The entity should reply in order, and any events that the entity requests to be -// persisted the entity should handle itself, applying them to its own state, as if they had -// arrived as events when the event stream was being replayed on load. -func (esh *EventSourcedServer) Handle(stream protocol.EventSourced_HandleServer) error { - var entityId string - var failed error - - // "fix" for https://github.com/cloudstateio/go-support/issues/27 - // v0.2.x will contain the proper handling for the case of a closed stream. - defer func() { - delete(esh.contexts, entityId) - }() - for { - if failed != nil { - return failed - } - msg, recvErr := stream.Recv() - if recvErr == io.EOF { - return nil - } - if recvErr != nil { - return recvErr - } - if cmd := msg.GetCommand(); cmd != nil { - if err := esh.handleCommand(cmd, stream); err != nil { - // TODO: in general, what happens with the stream here if an error happens? - failed = handleFailure(err, stream, cmd.GetId()) - } - continue - } - if event := msg.GetEvent(); event != nil { - // TODO spec: Why does command carry the entityId and an event not? - if err := esh.handleEvent(entityId, event); err != nil { - failed = handleFailure(err, stream, 0) - } - continue - } - if init := msg.GetInit(); init != nil { - if err := esh.handleInit(init); err != nil { - failed = handleFailure(err, stream, 0) - } - entityId = init.GetEntityId() - continue - } - } -} - -func (esh *EventSourcedServer) handleInit(init *protocol.EventSourcedInit) error { - eid := init.GetEntityId() - if _, present := esh.contexts[eid]; present { - return NewFailureError("unable to server.Send") - } - entity := esh.entities[init.GetServiceName()] - esh.contexts[eid] = &EntityInstanceContext{ - EntityInstance: &EntityInstance{ - Instance: entity.EntityFunc(), - EventSourcedEntity: entity, - }, - active: true, - } - - if err := esh.handleInitSnapshot(init); err != nil { - return NewFailureError("unable to server.Send. %w", err) - } - esh.subscribeEvents(esh.contexts[eid].EntityInstance) - return nil -} - -func (esh *EventSourcedServer) handleInitSnapshot(init *protocol.EventSourcedInit) error { - if init.Snapshot == nil { - return nil - } - entityId := init.GetEntityId() - if snapshotHandler, ok := esh.contexts[entityId].EntityInstance.Instance.(SnapshotHandler); ok { - snapshot, err := esh.unmarshalSnapshot(init) - if snapshot == nil || err != nil { - return NewFailureError("handling snapshot failed with: %v", err) - } - handled, err := snapshotHandler.HandleSnapshot(snapshot) - if err != nil { - return NewFailureError("handling snapshot failed with: %v", err) - } - if handled { - esh.contexts[entityId].EntityInstance.eventSequence = init.GetSnapshot().SnapshotSequence - } - return nil - } - return nil -} - -func (EventSourcedServer) unmarshalSnapshot(init *protocol.EventSourcedInit) (interface{}, error) { - // see: https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/any#typeurl - typeUrl := init.Snapshot.Snapshot.GetTypeUrl() - if !strings.Contains(typeUrl, "://") { - typeUrl = "https://" + typeUrl - } - typeURL, err := url.Parse(typeUrl) - if err != nil { - return nil, err - } - switch typeURL.Host { - case encoding.PrimitiveTypeURLPrefix: - snapshot, err := encoding.UnmarshalPrimitive(init.Snapshot.Snapshot) - if err != nil { - return nil, fmt.Errorf("unmarshalling snapshot failed with: %v", err) - } - return snapshot, nil - case protoAnyBase: - msgName := strings.TrimPrefix(init.Snapshot.Snapshot.GetTypeUrl(), protoAnyBase+"/") // TODO: this might be something else than a proto message - messageType := proto.MessageType(msgName) - if messageType.Kind() == reflect.Ptr { - if message, ok := reflect.New(messageType.Elem()).Interface().(proto.Message); ok { - err := proto.Unmarshal(init.Snapshot.Snapshot.Value, message) - if err != nil { - return nil, fmt.Errorf("unmarshalling snapshot failed with: %v", err) - } - return message, nil - } - } - } - return nil, fmt.Errorf("unmarshalling snapshot failed with: no snapshot unmarshaller found for: %v", typeURL.String()) -} - -func (esh *EventSourcedServer) subscribeEvents(instance *EntityInstance) { - if emitter, ok := instance.Instance.(EventEmitter); ok { - emitter.Subscribe(&Subscription{ - OnNext: func(event interface{}) error { - err := esh.applyEvent(instance, event) - if err == nil { - instance.eventSequence++ - } - return err - }, - OnErr: func(err error) { - }, // TODO: investigate what to report to the proxy - }) - } -} - -func (esh *EventSourcedServer) handleEvent(entityId string, event *protocol.EventSourcedEvent) error { - if entityId == "" { - return NewFailureError("no entityId was found from a previous init message for event sequence: %v", event.Sequence) - } - entityContext := esh.contexts[entityId] - if entityContext == nil { - return NewFailureError("no entity with entityId registered: %v", entityId) - } - err := esh.handleEvents(entityContext.EntityInstance, event) - if err != nil { - return NewFailureError("handle event failed: %v", err) - } - return err -} - -// handleCommand handles a command received from the Cloudstate proxy. -// -// TODO: remove these following lines of comment -// "Unary RPCs where the client sends a single request to the server and -// gets a single response back, just like a normal function call." are supported right now. -// -// to handle a command we need -// - the entity id, which identifies the entity (its instance) uniquely(?) for this user function instance -// - the service name, like "com.example.shoppingcart.ShoppingCart" -// - a command id -// - a command name, which is one of the gRPC service rpcs defined by this entities service -// - the command payload, which is the message sent for the command as a protobuf.Any blob -// - a streamed flag, (TODO: for what?) -// -// together, these properties allow to call a method of the entities registered service and -// return its response as a reply to the Cloudstate proxy. -// -// Events: -// Beside calling the service method, we have to collect "events" the service might emit. -// These events afterwards have to be handled by a EventHandler to update the state of the -// entity. The Cloudstate proxy can re-play these events at any time -func (esh *EventSourcedServer) handleCommand(cmd *protocol.Command, server protocol.EventSourced_HandleServer) error { - msgName := strings.TrimPrefix(cmd.Payload.GetTypeUrl(), protoAnyBase+"/") - messageType := proto.MessageType(msgName) - if messageType.Kind() != reflect.Ptr { - return fmt.Errorf("messageType: %s is of non Ptr kind", messageType) - } - // get a zero-ed message of this type - if message, ok := reflect.New(messageType.Elem()).Interface().(proto.Message); ok { - // and marshal onto it what we got as an any.Any onto it - err := proto.Unmarshal(cmd.Payload.Value, message) - if err != nil { - return fmt.Errorf("%s, %w", err, ErrMarshal) - } else { - // we're ready to handle the proto message - entityContext := esh.contexts[cmd.GetEntityId()] - if commandHandler, ok := entityContext.EntityInstance.Instance.(CommandHandler); ok { - // The gRPC implementation returns the rpc return method - // and an error as a second return value. - _, reply, errReturned := commandHandler.HandleCommand(server.Context(), message) - // the error - if errReturned != nil { - // TCK says: TODO Expects entity.Failure, but gets lientAction.Action.Failure(Failure(commandId, msg))) - return NewProtocolFailure(protocol.Failure{ - CommandId: cmd.GetId(), - Description: errReturned.Error(), - }) - } - // the reply - callReply, err := marshalAny(reply) - if err != nil { // this should never happen - return NewProtocolFailure(protocol.Failure{ - CommandId: cmd.GetId(), - Description: fmt.Errorf("called return value at index 0 is no proto.Message. %w", err).Error(), - }) - } - // emitted events - events, err := marshalEventsAny(entityContext) - if err != nil { - return NewProtocolFailure(protocol.Failure{ - CommandId: cmd.GetId(), - Description: err.Error(), - }) - } - // snapshot - snapshot, err := esh.handleSnapshots(entityContext) - if err != nil { - return NewProtocolFailure(protocol.Failure{ - CommandId: cmd.GetId(), - Description: err.Error(), - }) - } - return sendEventSourcedReply(&protocol.EventSourcedReply{ - CommandId: cmd.GetId(), - ClientAction: &protocol.ClientAction{ - Action: &protocol.ClientAction_Reply{ - Reply: &protocol.Reply{ - Payload: callReply, - }, - }, - }, - Events: events, - Snapshot: snapshot, - }, server) - } - } - } - return nil -} - -func (*EventSourcedServer) handleSnapshots(entityContext *EntityInstanceContext) (*any.Any, error) { - if !entityContext.EntityInstance.shouldSnapshot() { - return nil, nil - } - if snapshotter, canSnapshot := entityContext.EntityInstance.Instance.(Snapshotter); canSnapshot { - snap, err := snapshotter.Snapshot() - if err != nil { - return nil, fmt.Errorf("getting a snapshot has failed: %v. %w", err, ErrFailure) - } - // TODO: we expect a proto.Message but should support other formats - snapshot, err := marshalAny(snap) - if err != nil { - return nil, err - } - entityContext.EntityInstance.resetSnapshotEvery() - return snapshot, nil - } else { - // TODO: every entity should implement snapshotting, right? - } - return nil, nil -} - -// applyEvent applies an event to a local entity -func (esh EventSourcedServer) applyEvent(entityInstance *EntityInstance, event interface{}) error { - payload, err := marshalAny(event) - if err != nil { - return err - } - return esh.handleEvents(entityInstance, &protocol.EventSourcedEvent{Payload: payload}) -} - -func (EventSourcedServer) handleEvents(entityInstance *EntityInstance, events ...*protocol.EventSourcedEvent) error { - eventHandler, implementsEventHandler := entityInstance.Instance.(EventHandler) - for _, event := range events { - // TODO: here's the point where events can be protobufs, serialized as json or other formats - msgName := strings.TrimPrefix(event.Payload.GetTypeUrl(), protoAnyBase+"/") - messageType := proto.MessageType(msgName) - - if messageType.Kind() == reflect.Ptr { - // get a zero-ed message of this type - if message, ok := reflect.New(messageType.Elem()).Interface().(proto.Message); ok { - // and marshal onto it what we got as an any.Any onto it - err := proto.Unmarshal(event.Payload.Value, message) - if err != nil { - return fmt.Errorf("%s, %w", err, ErrMarshal) - } else { - // we're ready to handle the proto message - // and we might have a handler - if implementsEventHandler { - _, err = eventHandler.HandleEvent(context.Background(), message) // TODO: propagate ctx from callee - if err != nil { - return err // FIXME/TODO: is this correct? if we fail here, nothing is safe afterwards. - } - } - } - } - } // TODO: what do we do if we haven't handled the events? - } - return nil -} diff --git a/cloudstate/eventsourced/context.go b/cloudstate/eventsourced/context.go new file mode 100644 index 0000000..11581b8 --- /dev/null +++ b/cloudstate/eventsourced/context.go @@ -0,0 +1,113 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package eventsourced + +import ( + "context" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/golang/protobuf/ptypes/any" +) + +type Context struct { + EntityID EntityID + // EventSourcedEntity describes the instance hold by the EntityInstance. + EventSourcedEntity *Entity + // Instance is an instance of the registered entity. + Instance EntityHandler + + ctx context.Context + events []interface{} + failed error + eventSequence int64 + shouldSnapshot bool + forward *protocol.Forward + sideEffects []*protocol.SideEffect +} + +// Emit is called by a command handler. +func (c *Context) Emit(event interface{}) { + if c.failed != nil { + // We can't fail sooner but won't handle events after one failed anymore. + return + } + if err := c.Instance.HandleEvent(c, event); err != nil { + c.fail(err) + return + } + c.events = append(c.events, event) + c.eventSequence++ + c.shouldSnapshot = c.shouldSnapshot || (c.eventSequence%c.EventSourcedEntity.SnapshotEvery == 0) +} + +// Effect adds a side effect to be emitted. An effect is something whose +// result has no impact on the result of the current command - if it fails, +// the current command still succeeds. The result of the effect is therefore +// ignored. Effects are only performed after the successful completion of any +// state actions requested by the command handler. +// +// Effects may be declared as synchronous or asynchronous. Asynchronous commands +// run in a "fire and forget" fashion. The code flow of the caller (the command +// handler of the entity which emitted the async command) continues while the +// command is being asynchronously processed. Meanwhile, synchronous commands +// run in "blocking" mode, ie. the commands are processed in order, one at a time. +// The final result of the command handler, either a reply or a forward, is not +// sent until all synchronous commands are completed. +func (c *Context) Effect(effect *protocol.SideEffect) { + c.sideEffects = append(c.sideEffects, effect) +} + +// Forward sets a protocol.Forward to where a command is forwarded to. +// +// An entity may, rather than sending a reply to a command, forward it to another entity. +// This is done by sending a forward message back to the proxy, instructing the proxy which +// call on which entity should be invoked, and passing the message to invoke it with. +// +// The command won’t be forwarded until any state actions requested by the command handler +// have successfully completed. It is the responsibility of the forwarded action to return +// a reply that matches the type of the original command handler. Forwards can be chained +// arbitrarily long. +func (c *Context) Forward(forward *protocol.Forward) { + c.forward = forward +} + +// StreamCtx returns the context.Context for the contexts' current running stream. +func (c *Context) StreamCtx() context.Context { + return c.ctx +} + +func (c *Context) fail(err error) { + c.failed = err +} + +func (c *Context) resetSnapshotEvery() { + c.shouldSnapshot = false +} + +// marshalEventsAny marshals and the clears events emitted through the context. +func (c *Context) marshalEventsAny() ([]*any.Any, error) { + events := make([]*any.Any, len(c.events)) + for i, evt := range c.events { + event, err := encoding.MarshalAny(evt) + if err != nil { + return nil, err + } + events[i] = event + } + c.events = make([]interface{}, 0) + return events, nil +} diff --git a/cloudstate/eventsourced/doc.go b/cloudstate/eventsourced/doc.go new file mode 100644 index 0000000..2f17a16 --- /dev/null +++ b/cloudstate/eventsourced/doc.go @@ -0,0 +1,17 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package eventsourced implements the Cloudstate eventsourcing state model. +package eventsourced diff --git a/cloudstate/eventsourced/entity.go b/cloudstate/eventsourced/entity.go new file mode 100644 index 0000000..831dd6c --- /dev/null +++ b/cloudstate/eventsourced/entity.go @@ -0,0 +1,93 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package eventsourced + +import ( + "github.com/golang/protobuf/proto" +) + +// Entity describes an event sourced entity. It is used to be registered as +// an event sourced entity on a CloudState instance. +type Entity struct { + // ServiceName is the fully qualified name of the service that implements this + // entities interface. + // Setting it is mandatory. + ServiceName ServiceName + // PersistenceID is used to namespace events in the journal, useful for + // when you share the same database between multiple entities. It defaults to + // the simple name for the entity type. + // It’s good practice to select one explicitly, this means your database + // isn’t depend on type names in your code. + // Setting it is mandatory. + PersistenceID string + // SnapshotEvery controls how often snapshots are taken, + // so that the entity doesn't need to be recovered from the whole journal + // each time it’s loaded. If left unset, it defaults to 100. + // Setting it to a negative number will result in snapshots never being taken. + SnapshotEvery int64 + // EntityFunc is a factory method which generates a new Entity. + EntityFunc func(id EntityID) EntityHandler +} + +type ( + ServiceName string + EntityID string + CommandID int64 +) + +func (sn ServiceName) String() string { + return string(sn) +} + +func (id CommandID) Value() int64 { + return int64(id) +} + +// tag::entity-type[] +// An EntityHandler implements methods to handle commands and events. +type EntityHandler interface { + // HandleCommand is the code that handles a command. It + // may validate the command using the current state, and + // may emit events as part of its processing. A command + // handler must not update the state of the entity directly, + // only indirectly by emitting events. If a command handler + // does update the state, then when the entity is passivated + // (removed from memory), those updates will be lost. + HandleCommand(ctx *Context, name string, cmd proto.Message) (reply proto.Message, err error) + // HandleEvent is the only piece of code that is allowed + // to update the state of the entity. It receives events, + // and, according to the event, updates the state. + HandleEvent(ctx *Context, event interface{}) error +} + +// end::entity-type[] + +// tag::snapshooter[] +// A Snapshooter enables eventsourced snapshots to be taken and as well +// handling snapshots provided. +type Snapshooter interface { + // Snapshot is a recording of the entire current state of an entity, + // persisted periodically (eg, every 100 events), as an optimization. + // With snapshots, when the entity is reloaded from the journal, the + // entire journal doesn't need to be replayed, just the changes since + // the last snapshot. + Snapshot(ctx *Context) (snapshot interface{}, err error) + // HandleSnapshot is used to apply snapshots provided by the Cloudstate + // proxy. + HandleSnapshot(ctx *Context, snapshot interface{}) error +} + +// end::snapshooter[] diff --git a/cloudstate/eventsourced/eventsourced_test.go b/cloudstate/eventsourced/eventsourced_test.go new file mode 100644 index 0000000..c4b7c0f --- /dev/null +++ b/cloudstate/eventsourced/eventsourced_test.go @@ -0,0 +1,242 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package eventsourced + +import ( + "context" + "os" + "testing" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/empty" + "google.golang.org/grpc" +) + +type TestEntity struct { + Value int64 +} + +func (e *TestEntity) HandleCommand(ctx *Context, name string, msg proto.Message) (reply proto.Message, err error) { + switch cmd := msg.(type) { + case *IncrementByCommand: + return e.IncrementByCommand(ctx, cmd) + case *DecrementByCommand: + return e.DecrementByCommand(ctx, cmd) + } + return +} + +func (e TestEntity) String() string { + return proto.CompactTextString(e) +} + +func (e TestEntity) ProtoMessage() { +} + +func (e TestEntity) Reset() { +} + +func (e *TestEntity) Snapshot(*Context) (snapshot interface{}, err error) { + return encoding.MarshalPrimitive(e.Value) +} + +func (e *TestEntity) HandleSnapshot(_ *Context, snapshot interface{}) error { + switch v := snapshot.(type) { + case int64: + e.Value = v + } + return nil +} + +func (e *TestEntity) IncrementBy(n int64) (int64, error) { + e.Value += n + return e.Value, nil +} + +func (e *TestEntity) DecrementBy(n int64) (int64, error) { + e.Value -= n + return e.Value, nil +} + +// Initialize value to <0 let us check whether an initCommand works. +var testEntity = &TestEntity{ + Value: -1, +} + +func resetTestEntity() { + testEntity = &TestEntity{ + Value: -1, + } +} + +// IncrementByCommand with value receiver. +func (e *TestEntity) IncrementByCommand(ctx *Context, ibc *IncrementByCommand) (*empty.Empty, error) { + ctx.Emit(&IncrementByEvent{ + Value: ibc.Amount, + }) + return &empty.Empty{}, nil +} + +// DecrementByCommand with pointer receiver. +func (e *TestEntity) DecrementByCommand(ctx *Context, ibc *DecrementByCommand) (*empty.Empty, error) { + ctx.Emit(&DecrementByEvent{ + Value: ibc.Amount, + }) + return &empty.Empty{}, nil +} + +type IncrementByEvent struct { + Value int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` +} + +func (inc IncrementByEvent) String() string { + return proto.CompactTextString(inc) +} + +func (inc IncrementByEvent) ProtoMessage() { +} + +func (inc IncrementByEvent) Reset() { +} + +type DecrementByEvent struct { + Value int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` +} + +func (inc DecrementByEvent) String() string { + return proto.CompactTextString(inc) +} + +func (inc DecrementByEvent) ProtoMessage() { +} + +func (inc DecrementByEvent) Reset() { +} + +func (e *TestEntity) DecrementByEvent(d *DecrementByEvent) error { + _, err := e.DecrementBy(d.Value) + return err +} + +func (e *TestEntity) HandleEvent(_ *Context, event interface{}) error { + switch evt := event.(type) { + case *IncrementByEvent: + _, err := e.IncrementBy(evt.Value) + return err + case *DecrementByEvent: + _, err := e.DecrementBy(evt.Value) + return err + default: + return nil + } +} + +type IncrementByCommand struct { + Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` +} + +func (inc IncrementByCommand) String() string { + return proto.CompactTextString(inc) +} + +func (inc IncrementByCommand) ProtoMessage() { +} + +func (inc IncrementByCommand) Reset() { +} + +type DecrementByCommand struct { + Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` +} + +func (inc DecrementByCommand) String() string { + return proto.CompactTextString(inc) +} + +func (inc DecrementByCommand) ProtoMessage() { +} + +func (inc DecrementByCommand) Reset() { +} + +// TestEventSourcedHandleServer is a grpc.ServerStream mock. +type TestEventSourcedHandleServer struct { + grpc.ServerStream +} + +func (t TestEventSourcedHandleServer) Context() context.Context { + return context.Background() +} + +func (t TestEventSourcedHandleServer) Send(out *entity.EventSourcedStreamOut) error { + return nil +} +func (t TestEventSourcedHandleServer) Recv() (*entity.EventSourcedStreamIn, error) { + return nil, nil +} + +func newHandler(t *testing.T) *Server { + handler := NewServer() + entity := Entity{ + EntityFunc: func(id EntityID) EntityHandler { + resetTestEntity() + testEntity.Value = 0 + return testEntity + }, + ServiceName: "TestEventSourcedServer-Service", + SnapshotEvery: 0, + } + if err := handler.Register(&entity); err != nil { + t.Errorf("%v", err) + } + return handler +} + +func TestMain(m *testing.M) { + proto.RegisterType((*IncrementByEvent)(nil), "IncrementByEvent") + proto.RegisterType((*DecrementByEvent)(nil), "DecrementByEvent") + proto.RegisterType((*TestEntity)(nil), "TestEntity") + proto.RegisterType((*IncrementByCommand)(nil), "IncrementByCommand") + proto.RegisterType((*DecrementByCommand)(nil), "DecrementByCommand") + defer resetTestEntity() + os.Exit(m.Run()) +} + +func TestSnapshot(t *testing.T) { + resetTestEntity() + handler := newHandler(t) + primitive, err := encoding.MarshalPrimitive(int64(987)) + if err != nil { + t.Fatalf("%v", err) + } + r := &runner{stream: TestEventSourcedHandleServer{}} + err = handler.handleInit(&entity.EventSourcedInit{ + ServiceName: "TestEventSourcedServer-Service", + EntityId: "entity-0", + Snapshot: &entity.EventSourcedSnapshot{ + SnapshotSequence: 0, + Snapshot: primitive, + }, + }, r) + if err != nil { + t.Fatalf("%v", err) + } + if testEntity.Value != 987 { + t.Fatalf("testEntity.Value should be 0 but was not: %+v", testEntity) + } +} diff --git a/cloudstate/eventsourced/runner.go b/cloudstate/eventsourced/runner.go new file mode 100644 index 0000000..b1dee3a --- /dev/null +++ b/cloudstate/eventsourced/runner.go @@ -0,0 +1,250 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package eventsourced + +import ( + "errors" + "fmt" + "net/url" + "reflect" + "strings" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" +) + +// runner attaches a eventsourced.Context to a stream and runs it. +type runner struct { + stream entity.EventSourced_HandleServer + context *Context +} + +// handleCommand handles a command received from the Cloudstate proxy. +func (r *runner) handleCommand(cmd *protocol.Command) error { + msgName := strings.TrimPrefix(cmd.Payload.GetTypeUrl(), encoding.ProtoAnyBase+"/") + msgType := proto.MessageType(msgName) + if msgType.Kind() != reflect.Ptr { + return fmt.Errorf("msgType: %s is of non Ptr kind", msgType) + } + // Get a zero-ed message of this type. + message, ok := reflect.New(msgType.Elem()).Interface().(proto.Message) + if !ok { + return fmt.Errorf("msgType is no proto.Message: %v", msgType) + } + // Unmarshal the payload onto the zero-ed message. + err := proto.Unmarshal(cmd.Payload.Value, message) + if err != nil { + return fmt.Errorf("%s, %w", err, encoding.ErrMarshal) + } + // The gRPC implementation returns the service method return and an error as a second return value. + cmdReply, errReturned := r.context.Instance.HandleCommand(r.context, cmd.Name, message) + // We the take error returned as a client failure except if it's a protocol.ServerError. + if errReturned != nil { + // If the error is a ServerError, we return this error and the stream will end. + if _, ok := errReturned.(protocol.ServerError); ok { + return errReturned + } + r.context.failed = nil + return r.sendClientActionFailure(&protocol.Failure{ + CommandId: cmd.Id, + Description: errReturned.Error(), + Restart: len(r.context.events) > 0, + }) + } + // The context may have failed. + if r.context.failed != nil { + return r.context.failed + } + // Get the reply. + reply, err := encoding.MarshalAny(cmdReply) + if err != nil { // this should never happen + return protocol.ServerError{ + Failure: &protocol.Failure{CommandId: cmd.GetId()}, + Err: fmt.Errorf("marshalling of reply failed: %w", err), + } + } + // Get the events emitted. + events, err := r.context.marshalEventsAny() + if err != nil { + return protocol.ServerError{ + Failure: &protocol.Failure{CommandId: cmd.GetId()}, + Err: fmt.Errorf("marshalling of events failed: %w", err), + } + } + // Handle the snapshot. + snapshot, err := r.handleSnapshot() + if err != nil { + return protocol.ServerError{ + Failure: &protocol.Failure{CommandId: cmd.GetId()}, + Err: fmt.Errorf("marshalling of the snapshot failed: %w", err), + } + } + // Spec: It is illegal to send a snapshot without sending any events. + if snapshot != nil && len(events) == 0 { + return errors.New("it is illegal to send a snapshot without sending any events") + } + if r.context.forward != nil { + return r.sendEventSourcedReply(&entity.EventSourcedReply{ + CommandId: cmd.GetId(), + ClientAction: &protocol.ClientAction{ + Action: &protocol.ClientAction_Forward{ + Forward: r.context.forward, + }, + }, + Events: events, + Snapshot: snapshot, + SideEffects: r.context.sideEffects, + }) + } + return r.sendEventSourcedReply(&entity.EventSourcedReply{ + CommandId: cmd.GetId(), + ClientAction: &protocol.ClientAction{ + Action: &protocol.ClientAction_Reply{ + Reply: &protocol.Reply{ + Payload: reply, + }, + }, + }, + Events: events, + Snapshot: snapshot, + SideEffects: r.context.sideEffects, + }) +} + +func (r *runner) handleInitSnapshot(snapshot *entity.EventSourcedSnapshot) error { + s, err := r.unmarshalSnapshot(snapshot) + if s == nil || err != nil { + return fmt.Errorf("handling snapshot failed with: %w", err) + } + sh, ok := r.context.Instance.(Snapshooter) + if !ok { + return fmt.Errorf("entity instance does not implement eventsourced.Snapshooter") + } + err = sh.HandleSnapshot(r.context, s) + if err != nil { + return fmt.Errorf("handling snapshot failed with: %w", err) + } + r.context.eventSequence = snapshot.SnapshotSequence + return nil +} + +func (r *runner) handleSnapshot() (*any.Any, error) { + if !r.context.shouldSnapshot { + return nil, nil + } + sh, ok := r.context.Instance.(Snapshooter) + if !ok { + return nil, nil + } + s, err := sh.Snapshot(r.context) + if err != nil { + return nil, fmt.Errorf("getting a snapshot has failed: %w", err) + } + // TODO: we expect a proto.Message but can support other format. + snapshot, err := encoding.MarshalAny(s) + if err != nil { + return nil, err + } + r.context.resetSnapshotEvery() + return snapshot, nil +} + +func (r *runner) handleEvent(event *entity.EventSourcedEvent) error { + // TODO: here's the point where events can be protobufs, serialized as json or other formats + msgName := strings.TrimPrefix(event.Payload.GetTypeUrl(), encoding.ProtoAnyBase+"/") + msgType := proto.MessageType(msgName) + if msgType.Kind() != reflect.Ptr { + return fmt.Errorf("msgType.Kind() is not a pointer type: %v", msgType) + } + // Get a zero-ed message of this type. + message, ok := reflect.New(msgType.Elem()).Interface().(proto.Message) + if !ok { + return fmt.Errorf("unable to create a new zero-ed message of type: %v", msgType) + } + // Marshal what we got as an any.Any onto it. + if err := proto.Unmarshal(event.Payload.Value, message); err != nil { + return fmt.Errorf("%s: %w", err, encoding.ErrMarshal) + } + // We're ready to handle the proto message. + if err := r.context.Instance.HandleEvent(r.context, message); err != nil { + return err + } + r.context.eventSequence = event.Sequence + return r.context.failed +} + +// applyEvent applies an event to a local entity. +func (r *runner) applyEvent(event interface{}) error { + payload, err := encoding.MarshalAny(event) + if err != nil { + return err + } + return r.handleEvent(&entity.EventSourcedEvent{Payload: payload}) +} + +func (*runner) unmarshalSnapshot(snapshot *entity.EventSourcedSnapshot) (interface{}, error) { + // see: https://developers.google.com/protocol-buffers/docs/reference/csharp/class/google/protobuf/well-known-types/any#typeurl + typeURL := snapshot.Snapshot.GetTypeUrl() + if !strings.Contains(typeURL, "://") { + typeURL = "https://" + typeURL + } + parsedURL, err := url.Parse(typeURL) + if err != nil { + return nil, err + } + switch parsedURL.Host { + case encoding.PrimitiveTypeURLPrefix: + return encoding.UnmarshalPrimitive(snapshot.Snapshot) + case encoding.ProtoAnyBase: + // TODO: this might be something else than a proto message + msgName := strings.TrimPrefix(snapshot.Snapshot.GetTypeUrl(), encoding.ProtoAnyBase+"/") + msgType := proto.MessageType(msgName) + if msgType.Kind() != reflect.Ptr { + return nil, err + } + message, ok := reflect.New(msgType.Elem()).Interface().(proto.Message) + if !ok { + return nil, err + } + if err := proto.Unmarshal(snapshot.Snapshot.Value, message); err != nil { + return nil, err + } + return message, nil + } + return nil, fmt.Errorf("no snapshot unmarshaller found for: %q", parsedURL.String()) +} + +func (r *runner) sendEventSourcedReply(reply *entity.EventSourcedReply) error { + return r.stream.Send(&entity.EventSourcedStreamOut{ + Message: &entity.EventSourcedStreamOut_Reply{ + Reply: reply, + }, + }) +} + +func (r *runner) sendClientActionFailure(failure *protocol.Failure) error { + return r.sendEventSourcedReply(&entity.EventSourcedReply{ + CommandId: failure.CommandId, + ClientAction: &protocol.ClientAction{ + Action: &protocol.ClientAction_Failure{ + Failure: failure, + }, + }, + }) +} diff --git a/cloudstate/eventsourced/server.go b/cloudstate/eventsourced/server.go new file mode 100644 index 0000000..c4eec13 --- /dev/null +++ b/cloudstate/eventsourced/server.go @@ -0,0 +1,193 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package eventsourced + +import ( + "errors" + "fmt" + "io" + "log" + "sync" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const snapshotEveryDefault = 100 + +// Server is the implementation of the Server server API for the EventSourced service. +type Server struct { + // mu protects the map below. + mu sync.RWMutex + // entities are indexed by their service name. + entities map[ServiceName]*Entity +} + +// NewServer returns a new event sourced server. +func NewServer() *Server { + return &Server{ + entities: make(map[ServiceName]*Entity), + } +} + +// Register registers an Entity a an event sourced entity for CloudState. +func (s *Server) Register(entity *Entity) error { + if entity.EntityFunc == nil { + return errors.New("the entity has to define an EntityFunc but did not") + } + s.mu.Lock() + defer s.mu.Unlock() + if _, exists := s.entities[entity.ServiceName]; exists { + return fmt.Errorf("an entity with service name: %s is already registered", entity.ServiceName) + } + if entity.SnapshotEvery == 0 { + entity.SnapshotEvery = snapshotEveryDefault + } + s.entities[entity.ServiceName] = entity + return nil +} + +// Handle handles the stream. One stream will be established per active entity. +// Once established, the first message sent will be Init, which contains the entity ID, and, +// if the entity has previously persisted a snapshot, it will contain that snapshot. It will +// then send zero to many event messages, one for each event previously persisted. The entity +// is expected to apply these to its state in a deterministic fashion. Once all the events +// are sent, one to many commands are sent, with new commands being sent as new requests for +// the entity come in. The entity is expected to reply to each command with exactly one reply +// message. The entity should reply in order, and any events that the entity requests to be +// persisted the entity should handle itself, applying them to its own state, as if they had +// arrived as events when the event stream was being replayed on load. +// +// ClientError handling is done so that any error returned, triggers the stream to be closed. +// If an error is a client failure, a ClientAction_Failure is sent with a command id set +// if provided by the error. If an error is a protocol failure or any other error, a +// EventSourcedStreamOut_Failure is sent. A protocol failure might provide a command id to +// be included. +// TODO: rephrase this to the new atomic failure pattern. +func (s *Server) Handle(stream entity.EventSourced_HandleServer) error { + defer func() { + if r := recover(); r != nil { + // on a panic we try to tell the proxy and panic again. + _ = sendProtocolFailure(fmt.Errorf("Server.Handle panic-ked with: %v", r), stream) + panic(r) + } + }() + // For any error we get other than codes.Canceled, + // we send a protocol.Failure and close the stream. + if err := s.handle(stream); err != nil { + if status.Code(err) == codes.Canceled { + return err + } + log.Print(err) + if sendErr := sendProtocolFailure(err, stream); sendErr != nil { + log.Print(sendErr) + } + return status.Error(codes.Aborted, err.Error()) + } + return nil +} + +func (s *Server) handle(stream entity.EventSourced_HandleServer) error { + first, err := stream.Recv() + switch err { + case nil: + break + case io.EOF: + return nil + default: + return err + } + r := &runner{stream: stream} + switch m := first.GetMessage().(type) { + case *entity.EventSourcedStreamIn_Init: + if err := s.handleInit(m.Init, r); err != nil { + return err + } + default: + return fmt.Errorf("a message was received without having an EventSourcedInit message handled before: %+v", first.GetMessage()) + } + for { + if r.context.failed != nil { + // failed means deactivated. We may never get this far. + // context.failed should have been sent as a client reply failure. + // see: https://github.com/cloudstateio/cloudstate/pull/119#discussion_r444851439 + return fmt.Errorf("failed context was not reported: %w", r.context.failed) + } + msg, err := r.stream.Recv() + switch err { + case nil: + break + case io.EOF: + return nil + default: + return err + } + switch m := msg.GetMessage().(type) { + case *entity.EventSourcedStreamIn_Command: + err := r.handleCommand(m.Command) + if err == nil { + continue + } + if _, ok := err.(protocol.ServerError); !ok { + return protocol.ServerError{ + Failure: &protocol.Failure{CommandId: m.Command.Id}, + Err: err, + } + } + return err + case *entity.EventSourcedStreamIn_Event: + if err := r.handleEvent(m.Event); err != nil { + return err + } + case *entity.EventSourcedStreamIn_Init: + return errors.New("duplicate init message for the same entity") + case nil: + return errors.New("empty message received") + default: + return fmt.Errorf("unknown message received: %+v", msg.GetMessage()) + } + } +} + +func (s *Server) handleInit(init *entity.EventSourcedInit, r *runner) error { + service := ServiceName(init.GetServiceName()) + s.mu.RLock() + e, exists := s.entities[service] + s.mu.RUnlock() + if !exists { + return fmt.Errorf("received a command for an unknown eventsourced service: %q", service) + } + if e.EntityFunc == nil { + return fmt.Errorf("entity.EntityFunc not defined: %q", service) + } + + id := EntityID(init.GetEntityId()) + r.context = &Context{ + EntityID: id, + EventSourcedEntity: e, + Instance: e.EntityFunc(id), + eventSequence: 0, + ctx: r.stream.Context(), + } + if snapshot := init.GetSnapshot(); snapshot != nil { + if err := r.handleInitSnapshot(snapshot); err != nil { + return err + } + } + return nil +} diff --git a/cloudstate/eventsourced/stream_failure.go b/cloudstate/eventsourced/stream_failure.go new file mode 100644 index 0000000..0a3a680 --- /dev/null +++ b/cloudstate/eventsourced/stream_failure.go @@ -0,0 +1,65 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package eventsourced + +import ( + "errors" + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/cloudstate/protocol" +) + +// sendProtocolFailure sends a given error to the proxy. If the error is a protocol.ServerError a corresponding +// commandId is unwrapped and added to the failure. Any other failure is sent as a protocol failure. +// +// we send protocol.ClientError as a protocol.ClientAction_Failure for everything the user function would like to inform the client about. +// we send protocol.ServerError as a protocol.Failure for everything else that is not originated by the user function. +// whenever possible, the command id is set. +// +// failure semantics are defined here: +// - https://github.com/cloudstateio/cloudstate/issues/375#issuecomment-672336020 +// - https://github.com/cloudstateio/cloudstate/pull/119#discussion_r375619440 +// - https://github.com/cloudstateio/cloudstate/pull/392 +// - https://github.com/cloudstateio/cloudstate/issues/375#issuecomment-671108797 +// +// Any error coming not from context.fail, closes the stream, independently if it's a protocol error or an entity error. +func sendProtocolFailure(e error, s entity.EventSourced_HandleServer) error { + var commandID int64 = 0 + var desc = e.Error() + var se protocol.ServerError + if errors.As(e, &se) { + commandID = se.Failure.CommandId + desc = se.Failure.Description + if desc == "" { + if u := errors.Unwrap(e); u != nil { + desc = u.Error() + } + } + } + err := s.Send(&entity.EventSourcedStreamOut{ + Message: &entity.EventSourcedStreamOut_Failure{ + Failure: &protocol.Failure{ + CommandId: commandID, + Description: desc, + }, + }, + }) + if err != nil { + return fmt.Errorf("send of EventSourcedStreamOut.Failure failed with: %w", err) + } + return nil +} diff --git a/cloudstate/eventsourced_reply.go b/cloudstate/eventsourced_reply.go deleted file mode 100644 index 0d1efe0..0000000 --- a/cloudstate/eventsourced_reply.go +++ /dev/null @@ -1,132 +0,0 @@ -// -// Copyright 2019 Lightbend Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cloudstate - -import ( - "errors" - "fmt" - "github.com/cloudstateio/go-support/cloudstate/protocol" -) - -var ErrSendFailure = errors.New("unable to send a failure message") -var ErrSend = errors.New("unable to send a message") -var ErrMarshal = errors.New("unable to marshal a message") - -var ErrFailure = errors.New("cloudstate failure") -var ErrClientActionFailure = errors.New("cloudstate client action failure") - -func NewFailureError(format string, a ...interface{}) error { - if len(a) != 0 { - return fmt.Errorf(fmt.Sprintf(format, a...)+". %w", ErrFailure) - } else { - return fmt.Errorf(format+". %w", ErrFailure) - } -} - -func NewClientActionFailureError(format string, a ...interface{}) error { - if len(a) != 0 { - return fmt.Errorf(fmt.Sprintf(format, a...)+". %w", ErrClientActionFailure) - } else { - return fmt.Errorf(format+". %w", ErrClientActionFailure) - } -} - -type ProtocolFailure struct { - protocol.Failure - err error -} - -func (f ProtocolFailure) Error() string { - return f.err.Error() -} - -func (f ProtocolFailure) Unwrap() error { - return f.err -} - -func NewProtocolFailure(failure protocol.Failure) error { - return ProtocolFailure{ - Failure: failure, - err: ErrFailure, - } -} - -// handleFailure checks if a CloudState failure or client action failure should -// be sent to the proxy, otherwise handleFailure returns the original failure -func handleFailure(failure error, server protocol.EventSourced_HandleServer, cmdId int64) error { - if errors.Is(failure, ErrFailure) { - // FIXME: why not getting the failure from the ProtocolFailure - // TCK says: Failure was not received, or not well-formed: Failure(Failure(0,cloudstate failure)) was not reply (CloudStateTCK.scala:339) - //return sendFailure(&protocol.Failure{Description: failure.Error()}, server) - return sendClientActionFailure(&protocol.Failure{ - CommandId: cmdId, - Description: failure.Error(), - }, server) - } - if errors.Is(failure, ErrClientActionFailure) { - return sendClientActionFailure(&protocol.Failure{ - CommandId: cmdId, - Description: failure.Error(), - }, server) - } - return failure -} - -// sendEventSourcedReply sends a given EventSourcedReply and if it fails, handles the error wrapping -func sendEventSourcedReply(reply *protocol.EventSourcedReply, server protocol.EventSourced_HandleServer) error { - err := server.Send(&protocol.EventSourcedStreamOut{ - Message: &protocol.EventSourcedStreamOut_Reply{ - Reply: reply, - }, - }) - if err != nil { - return fmt.Errorf("%s, %w", err, ErrSend) - } - return err -} - -// sendFailure sends a given EventSourcedReply and if it fails, handles the error wrapping -func sendFailure(failure *protocol.Failure, server protocol.EventSourced_HandleServer) error { - err := server.Send(&protocol.EventSourcedStreamOut{ - Message: &protocol.EventSourcedStreamOut_Failure{ - Failure: failure, - }, - }) - if err != nil { - err = fmt.Errorf("%s, %w", err, ErrSendFailure) - } - return err -} - -// sendClientActionFailure sends a given EventSourcedReply and if it fails, handles the error wrapping -func sendClientActionFailure(failure *protocol.Failure, server protocol.EventSourced_HandleServer) error { - err := server.Send(&protocol.EventSourcedStreamOut{ - Message: &protocol.EventSourcedStreamOut_Reply{ - Reply: &protocol.EventSourcedReply{ - CommandId: failure.CommandId, - ClientAction: &protocol.ClientAction{ - Action: &protocol.ClientAction_Failure{ - Failure: failure, - }, - }, - }, - }, - }) - if err != nil { - err = fmt.Errorf("%s, %w", err, ErrSendFailure) - } - return err -} diff --git a/cloudstate/eventsourced_test.go b/cloudstate/eventsourced_test.go deleted file mode 100644 index 8349cfe..0000000 --- a/cloudstate/eventsourced_test.go +++ /dev/null @@ -1,327 +0,0 @@ -// -// Copyright 2019 Lightbend Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cloudstate - -import ( - "context" - "errors" - "fmt" - "os" - "sync" - "testing" - - "github.com/cloudstateio/go-support/cloudstate/encoding" - "github.com/cloudstateio/go-support/cloudstate/protocol" - "github.com/golang/protobuf/proto" - "github.com/golang/protobuf/ptypes/any" - "github.com/golang/protobuf/ptypes/empty" - "google.golang.org/grpc" -) - -type TestEntity struct { - Value int64 - EventEmitter -} - -func (inc TestEntity) HandleCommand(_ context.Context, command interface{}) (handled bool, reply interface{}, err error) { - switch cmd := command.(type) { - case *IncrementByCommand: - reply, err := inc.IncrementByCommand(nil, cmd) - return true, reply, err - case *DecrementByCommand: - reply, err := inc.DecrementByCommand(nil, cmd) - return true, reply, err - } - return -} - -func (inc TestEntity) String() string { - return proto.CompactTextString(inc) -} - -func (inc TestEntity) ProtoMessage() { -} - -func (inc TestEntity) Reset() { -} - -func (te *TestEntity) Snapshot() (snapshot interface{}, err error) { - return encoding.MarshalPrimitive(te.Value) -} - -func (te *TestEntity) HandleSnapshot(snapshot interface{}) (handled bool, err error) { - switch v := snapshot.(type) { - case int64: - te.Value = v - } - return true, nil -} - -func (te *TestEntity) IncrementBy(n int64) (int64, error) { - te.Value += n - return te.Value, nil -} - -func (te *TestEntity) DecrementBy(n int64) (int64, error) { - te.Value -= n - return te.Value, nil -} - -// initialize value to <0 let us check whether an initCommand works -var testEntity = &TestEntity{ - Value: -1, - EventEmitter: NewEmitter(), -} - -func resetTestEntity() { - testEntity = &TestEntity{ - Value: -1, - EventEmitter: NewEmitter(), - } -} - -// IncrementByCommand with value receiver -func (te TestEntity) IncrementByCommand(_ context.Context, ibc *IncrementByCommand) (*empty.Empty, error) { - te.Emit(&IncrementByEvent{ - Value: ibc.Amount, - }) - return &empty.Empty{}, nil -} - -// DecrementByCommand with pointer receiver -func (te *TestEntity) DecrementByCommand(_ context.Context, ibc *DecrementByCommand) (*empty.Empty, error) { - te.Emit(&DecrementByEvent{ - Value: ibc.Amount, - }) - return &empty.Empty{}, nil -} - -type IncrementByEvent struct { - Value int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` -} - -func (inc IncrementByEvent) String() string { - return proto.CompactTextString(inc) -} - -func (inc IncrementByEvent) ProtoMessage() { -} - -func (inc IncrementByEvent) Reset() { -} - -type DecrementByEvent struct { - Value int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` -} - -func (inc DecrementByEvent) String() string { - return proto.CompactTextString(inc) -} - -func (inc DecrementByEvent) ProtoMessage() { -} - -func (inc DecrementByEvent) Reset() { -} - -func (te *TestEntity) DecrementByEvent(d *DecrementByEvent) error { - _, err := te.DecrementBy(d.Value) - return err -} - -func (te *TestEntity) HandleEvent(_ context.Context, event interface{}) (handled bool, err error) { - switch e := event.(type) { - case *IncrementByEvent: - _, err := te.IncrementBy(e.Value) - return true, err - case *DecrementByEvent: - _, err := te.DecrementBy(e.Value) - return true, err - default: - return false, nil - } -} - -type IncrementByCommand struct { - Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` -} - -func (inc IncrementByCommand) String() string { - return proto.CompactTextString(inc) -} - -func (inc IncrementByCommand) ProtoMessage() { -} - -func (inc IncrementByCommand) Reset() { -} - -type DecrementByCommand struct { - Amount int64 `protobuf:"varint,2,opt,name=amount,proto3" json:"amount,omitempty"` -} - -func (inc DecrementByCommand) String() string { - return proto.CompactTextString(inc) -} - -func (inc DecrementByCommand) ProtoMessage() { -} - -func (inc DecrementByCommand) Reset() { -} - -// TestEventSourcedHandleServer is a grpc.ServerStream mock -type TestEventSourcedHandleServer struct { - grpc.ServerStream -} - -func (t TestEventSourcedHandleServer) Context() context.Context { - return context.Background() -} - -func (t TestEventSourcedHandleServer) Send(out *protocol.EventSourcedStreamOut) error { - return nil -} -func (t TestEventSourcedHandleServer) Recv() (*protocol.EventSourcedStreamIn, error) { - return nil, nil -} - -func newHandler(t *testing.T) *EventSourcedServer { - handler := newEventSourcedServer() - entity := EventSourcedEntity{ - EntityFunc: func() Entity { - resetTestEntity() - testEntity.Value = 0 - return testEntity - }, - ServiceName: "TestEventSourcedServer-Service", - SnapshotEvery: 0, - registerOnce: sync.Once{}, - } - err := entity.init() - if err != nil { - t.Errorf("%v", err) - } - err = handler.registerEntity(&entity) - if err != nil { - t.Errorf("%v", err) - } - return handler -} - -func initHandler(handler *EventSourcedServer, t *testing.T) { - err := handler.handleInit(&protocol.EventSourcedInit{ - ServiceName: "TestEventSourcedServer-Service", - EntityId: "entity-0", - }) - if err != nil { - t.Errorf("%v", err) - t.Fail() - } -} - -func marshal(msg proto.Message, t *testing.T) ([]byte, error) { - cmd, err := proto.Marshal(msg) - if err != nil { - t.Errorf("%v", err) - } - return cmd, err -} - -func TestMain(m *testing.M) { - proto.RegisterType((*IncrementByEvent)(nil), "IncrementByEvent") - proto.RegisterType((*DecrementByEvent)(nil), "DecrementByEvent") - proto.RegisterType((*TestEntity)(nil), "TestEntity") - proto.RegisterType((*IncrementByCommand)(nil), "IncrementByCommand") - proto.RegisterType((*DecrementByCommand)(nil), "DecrementByCommand") - defer resetTestEntity() - os.Exit(m.Run()) -} - -func TestErrSend(t *testing.T) { - err0 := ErrSendFailure - err1 := fmt.Errorf("on reply: %w", ErrSendFailure) - if !errors.Is(err1, err0) { - t.Fatalf("err1 is no err0 but should") - } -} -func TestSnapshot(t *testing.T) { - resetTestEntity() - handler := newHandler(t) - primitive, err := encoding.MarshalPrimitive(int64(987)) - if err != nil { - t.Fatalf("%v", err) - } - err = handler.handleInit(&protocol.EventSourcedInit{ - ServiceName: "TestEventSourcedServer-Service", - EntityId: "entity-0", - Snapshot: &protocol.EventSourcedSnapshot{ - SnapshotSequence: 0, - Snapshot: primitive, - }, - }) - if err != nil { - t.Fatalf("%v", err) - } - if testEntity.Value != 987 { - t.Fatalf("testEntity.Value should be 0 but was not: %+v", testEntity) - } -} - -func TestEventSourcedServerHandlesCommandAndEvents(t *testing.T) { - resetTestEntity() - handler := newHandler(t) - initHandler(handler, t) - incrementedTo := int64(7) - incrCmdValue, err := marshal(&IncrementByCommand{Amount: incrementedTo}, t) - incrCommand := protocol.Command{ - EntityId: "entity-0", - Id: 1, - Name: "IncrementByCommand", - Payload: &any.Any{ - TypeUrl: "type.googleapis.com/IncrementByCommand", - Value: incrCmdValue, - }, - } - err = handler.handleCommand(&incrCommand, TestEventSourcedHandleServer{}) - if err != nil { - t.Fatalf("%v", err) - } - if testEntity.Value != incrementedTo { - t.Fatalf("testEntity.Value: (%v) != incrementedTo: (%v)", testEntity.Value, incrementedTo) - } - - decrCmdValue, err := proto.Marshal(&DecrementByCommand{Amount: incrementedTo}) - if err != nil { - t.Fatalf("%v", err) - } - decrCommand := protocol.Command{ - EntityId: "entity-0", - Id: 1, - Name: "DecrementByCommand", - Payload: &any.Any{ - TypeUrl: "type.googleapis.com/DecrementByCommand", - Value: decrCmdValue, - }, - } - err = handler.handleCommand(&decrCommand, TestEventSourcedHandleServer{}) - if err != nil { - t.Fatalf("%v", err) - } - if testEntity.Value != 0 { - t.Fatalf("testEntity.Value != 0") - } -} diff --git a/cloudstate/marshal_proto_test.go b/cloudstate/marshal_proto_test.go deleted file mode 100644 index 2903054..0000000 --- a/cloudstate/marshal_proto_test.go +++ /dev/null @@ -1,41 +0,0 @@ -// -// Copyright 2019 Lightbend Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cloudstate - -import ( - "fmt" - "github.com/golang/protobuf/proto" - "testing" -) - -func TestMarshalAnyProto(t *testing.T) { - event := IncrementByEvent{Value: 29} - any, err := marshalAny(&event) - if err != nil { - t.Fatalf("failed to marshalAny: %v", err) - } - expected := fmt.Sprintf("%s/%s", protoAnyBase, "IncrementByEvent") - if expected != any.GetTypeUrl() { - t.Fatalf("any.GetTypeUrl: %s is not: %s", any.GetTypeUrl(), expected) - } - event2 := &IncrementByEvent{} - if err := proto.Unmarshal(any.Value, event2); err != nil { - t.Fatalf("%v", err) - } - if event2.Value != event.Value { - t.Fatalf("event2.Value: %d != event.Value: %d", event2.Value, event.Value) - } -} diff --git a/cloudstate/protocol/descriptor.go b/cloudstate/protocol/descriptor.go new file mode 100644 index 0000000..ddcd49e --- /dev/null +++ b/cloudstate/protocol/descriptor.go @@ -0,0 +1,26 @@ +package protocol + +import "github.com/golang/protobuf/descriptor" + +// Config go get a CloudState instance configured. +type Config struct { + ServiceName string + ServiceVersion string +} + +// DescriptorConfig configures service and dependent descriptors. +type DescriptorConfig struct { + Service string + Domain []string + DomainMessages []descriptor.Message +} + +func (dc DescriptorConfig) AddDomainMessage(m descriptor.Message) DescriptorConfig { + dc.DomainMessages = append(dc.DomainMessages, m) + return dc +} + +func (dc DescriptorConfig) AddDomainDescriptor(filename ...string) DescriptorConfig { + dc.Domain = append(dc.Domain, filename...) + return dc +} diff --git a/cloudstate/protocol/entity.pb.go b/cloudstate/protocol/entity.pb.go index 0e4297f..074f594 100644 --- a/cloudstate/protocol/entity.pb.go +++ b/cloudstate/protocol/entity.pb.go @@ -1,11 +1,29 @@ +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// gRPC interface for common messages and services for Entity user functions. + // Code generated by protoc-gen-go. DO NOT EDIT. -// source: cloudstate/entity.proto +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: entity.proto package protocol import ( context "context" - fmt "fmt" proto "github.com/golang/protobuf/proto" _ "github.com/golang/protobuf/protoc-gen-go/descriptor" any "github.com/golang/protobuf/ptypes/any" @@ -13,178 +31,395 @@ import ( grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" - math "math" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 -// A reply to the sender. -type Reply struct { - // The reply payload - Payload *any.Any `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +// Transport-specific metadata associated with a message. +// +// The semantics of the metadata are not defined in this protocol, but rather, depend on the transport on which a +// particular instance of the metadata maps to. What keys or values are allowed or disallowed, whether duplicate values +// for the same key are allowed and how they are handled, and whether key names are case sensitive or not, are all +// undefined in the context of the Cloudstate protocol. +// +// If a metadata entry associated with a message can't be expressed in an underlying transport, for example, due to +// invalid characters in a key or value, the behavior of the proxy is undefined. This is because metadata is transport +// specific, so if the user function chooses to use metadata, it is choosing to be specific to a particular transport, +// which is beyond the scope of the Cloudstate protocol, and it's therefore the user function's responsibility to adhere +// to the semantics of that transport. The proxy MAY decide to drop metadata entries if it knows they are invalid or +// unsupported. If a metadata entry is dropped, the proxy MAY inform the user function that the entry was dropped by +// sending an error message to the EntityDiscovery.ReportError gRPC call. +// +// The metadata MAY also contain CloudEvent metadata. If a message comes from a Cloudstate event source, the Cloudstate +// proxy MUST attach CloudEvent metadata to it if the event doesn't already have CloudEvent metadata attached to it. +// This metadata SHALL be encoded according to the binary mode of the CloudEvent HTTP protocol binding, which can be +// found here: +// +// https://github.com/cloudevents/spec/blob/master/http-protocol-binding.md +// +// The Cloudstate proxy MAY synthesize appropriate values for Cloudstate metadata if no equivalent metadata exists in +// the event source, for example, if there is no type, the Cloudstate proxy MAY use the name of the gRPC message as the +// CloudEvent type, and if there is no source, the Cloudstate proxy MAY use the name of the topic as the source. +// +// If an incoming message does have CloudEvent metadata attached to it, the Cloudstate proxy MUST transcode that +// CloudEvent metadata to the HTTP protocol binding as described above. +// +// Messages sent from the user function to an event destination MAY include CloudEvent metadata. If they include any +// CloudEvent metadata, they MUST include all required CloudEvent attributes, including id, source, specversion and +// type. The behavior of the proxy is undefined if some of these attributes, but not others, are included - the proxy +// MAY ignore them all, or MAY generate values itself, but SHOULD NOT fail sending the message. If the destination for +// the message is an event destination, the Cloudstate proxy MUST transcode the supplied Cloudstate metadata to a +// binding appropriate for the underlying transport for that event destination, it MUST NOT pass the CloudEvent +// metadata as is unless the transport uses the same binding rules. +type Metadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The metadata entries. + Entries []*MetadataEntry `protobuf:"bytes,1,rep,name=entries,proto3" json:"entries,omitempty"` +} + +func (x *Metadata) Reset() { + *x = Metadata{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Reply) Reset() { *m = Reply{} } -func (m *Reply) String() string { return proto.CompactTextString(m) } -func (*Reply) ProtoMessage() {} -func (*Reply) Descriptor() ([]byte, []int) { - return fileDescriptor_a4a280e6d8a8fec2, []int{0} +func (x *Metadata) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Reply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Reply.Unmarshal(m, b) +func (*Metadata) ProtoMessage() {} + +func (x *Metadata) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -func (m *Reply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Reply.Marshal(b, m, deterministic) + +// Deprecated: Use Metadata.ProtoReflect.Descriptor instead. +func (*Metadata) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{0} } -func (m *Reply) XXX_Merge(src proto.Message) { - xxx_messageInfo_Reply.Merge(m, src) + +func (x *Metadata) GetEntries() []*MetadataEntry { + if x != nil { + return x.Entries + } + return nil } -func (m *Reply) XXX_Size() int { - return xxx_messageInfo_Reply.Size(m) + +// A metadata entry. +type MetadataEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Key for the entry. Valid keys depend on the transport from or to which this metadata is sent. + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + // The value. + // + // Types that are assignable to Value: + // *MetadataEntry_StringValue + // *MetadataEntry_BytesValue + Value isMetadataEntry_Value `protobuf_oneof:"value"` +} + +func (x *MetadataEntry) Reset() { + *x = MetadataEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Reply) XXX_DiscardUnknown() { - xxx_messageInfo_Reply.DiscardUnknown(m) + +func (x *MetadataEntry) String() string { + return protoimpl.X.MessageStringOf(x) } -var xxx_messageInfo_Reply proto.InternalMessageInfo +func (*MetadataEntry) ProtoMessage() {} -func (m *Reply) GetPayload() *any.Any { +func (x *MetadataEntry) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MetadataEntry.ProtoReflect.Descriptor instead. +func (*MetadataEntry) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{1} +} + +func (x *MetadataEntry) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (m *MetadataEntry) GetValue() isMetadataEntry_Value { if m != nil { - return m.Payload + return m.Value } return nil } -// Forwards handling of this request to another entity. -type Forward struct { - // The name of the service to forward to. - ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` - // The name of the command. - CommandName string `protobuf:"bytes,2,opt,name=command_name,json=commandName,proto3" json:"command_name,omitempty"` - // The payload. - Payload *any.Any `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +func (x *MetadataEntry) GetStringValue() string { + if x, ok := x.GetValue().(*MetadataEntry_StringValue); ok { + return x.StringValue + } + return "" } -func (m *Forward) Reset() { *m = Forward{} } -func (m *Forward) String() string { return proto.CompactTextString(m) } -func (*Forward) ProtoMessage() {} -func (*Forward) Descriptor() ([]byte, []int) { - return fileDescriptor_a4a280e6d8a8fec2, []int{1} +func (x *MetadataEntry) GetBytesValue() []byte { + if x, ok := x.GetValue().(*MetadataEntry_BytesValue); ok { + return x.BytesValue + } + return nil } -func (m *Forward) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Forward.Unmarshal(m, b) +type isMetadataEntry_Value interface { + isMetadataEntry_Value() } -func (m *Forward) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Forward.Marshal(b, m, deterministic) + +type MetadataEntry_StringValue struct { + // A string value. Valid values depend on the transport from or which this metadata is sent. + // + // If the transport does not support string values, the behavior of the Cloudstate proxy is undefined from the + // point of view of this protocol. If there is a convention in the protocol for encoding string values as + // UTF-8 bytes, then the Cloudstate proxy MAY do that. + StringValue string `protobuf:"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof"` } -func (m *Forward) XXX_Merge(src proto.Message) { - xxx_messageInfo_Forward.Merge(m, src) + +type MetadataEntry_BytesValue struct { + // A bytes value. Valid values depend on the transport from or which this metadata is sent. + // + // If the transport does not support bytes values, the behavior of the Cloudstate proxy is undefined from the + // point of view of this protocol. If there is a convention in the protocol for encoding bytes values as + // Base64 encoded strings, then the Cloudstate proxy MAY do that. + BytesValue []byte `protobuf:"bytes,3,opt,name=bytes_value,json=bytesValue,proto3,oneof"` } -func (m *Forward) XXX_Size() int { - return xxx_messageInfo_Forward.Size(m) + +func (*MetadataEntry_StringValue) isMetadataEntry_Value() {} + +func (*MetadataEntry_BytesValue) isMetadataEntry_Value() {} + +// A reply to the sender. +type Reply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The reply payload + Payload *any.Any `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` + // Metadata for the reply + // + // Not all transports support per message metadata, for example, gRPC doesn't. The Cloudstate proxy MAY ignore the + // metadata in this case, or it MAY lift the metadata into another place, for example, in gRPC, a unary call MAY + // have its reply metadata placed in the headers of the HTTP response, or the first reply to a streamed call MAY + // have its metadata placed in the headers of the HTTP response. + // + // If the metadata is ignored, the Cloudstate proxy MAY notify the user function by sending an error message to the + // EntityDiscovery.ReportError gRPC call. + Metadata *Metadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata,omitempty"` +} + +func (x *Reply) Reset() { + *x = Reply{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Forward) XXX_DiscardUnknown() { - xxx_messageInfo_Forward.DiscardUnknown(m) + +func (x *Reply) String() string { + return protoimpl.X.MessageStringOf(x) } -var xxx_messageInfo_Forward proto.InternalMessageInfo +func (*Reply) ProtoMessage() {} -func (m *Forward) GetServiceName() string { - if m != nil { - return m.ServiceName +func (x *Reply) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } - return "" + return mi.MessageOf(x) } -func (m *Forward) GetCommandName() string { - if m != nil { - return m.CommandName +// Deprecated: Use Reply.ProtoReflect.Descriptor instead. +func (*Reply) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{2} +} + +func (x *Reply) GetPayload() *any.Any { + if x != nil { + return x.Payload } - return "" + return nil } -func (m *Forward) GetPayload() *any.Any { - if m != nil { - return m.Payload +func (x *Reply) GetMetadata() *Metadata { + if x != nil { + return x.Metadata } return nil } -// An action for the client -type ClientAction struct { - // Types that are valid to be assigned to Action: - // *ClientAction_Reply - // *ClientAction_Forward - // *ClientAction_Failure - Action isClientAction_Action `protobuf_oneof:"action"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` +// Forwards handling of this request to another entity. +type Forward struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The name of the service to forward to. + ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` + // The name of the command. + CommandName string `protobuf:"bytes,2,opt,name=command_name,json=commandName,proto3" json:"command_name,omitempty"` + // The payload. + Payload *any.Any `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` + // The metadata to include with the forward + Metadata *Metadata `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` } -func (m *ClientAction) Reset() { *m = ClientAction{} } -func (m *ClientAction) String() string { return proto.CompactTextString(m) } -func (*ClientAction) ProtoMessage() {} -func (*ClientAction) Descriptor() ([]byte, []int) { - return fileDescriptor_a4a280e6d8a8fec2, []int{2} +func (x *Forward) Reset() { + *x = Forward{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ClientAction) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ClientAction.Unmarshal(m, b) +func (x *Forward) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ClientAction) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ClientAction.Marshal(b, m, deterministic) + +func (*Forward) ProtoMessage() {} + +func (x *Forward) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -func (m *ClientAction) XXX_Merge(src proto.Message) { - xxx_messageInfo_ClientAction.Merge(m, src) + +// Deprecated: Use Forward.ProtoReflect.Descriptor instead. +func (*Forward) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{3} } -func (m *ClientAction) XXX_Size() int { - return xxx_messageInfo_ClientAction.Size(m) + +func (x *Forward) GetServiceName() string { + if x != nil { + return x.ServiceName + } + return "" } -func (m *ClientAction) XXX_DiscardUnknown() { - xxx_messageInfo_ClientAction.DiscardUnknown(m) + +func (x *Forward) GetCommandName() string { + if x != nil { + return x.CommandName + } + return "" } -var xxx_messageInfo_ClientAction proto.InternalMessageInfo +func (x *Forward) GetPayload() *any.Any { + if x != nil { + return x.Payload + } + return nil +} -type isClientAction_Action interface { - isClientAction_Action() +func (x *Forward) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil } -type ClientAction_Reply struct { - Reply *Reply `protobuf:"bytes,1,opt,name=reply,proto3,oneof"` +// An action for the client +type ClientAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Action: + // *ClientAction_Reply + // *ClientAction_Forward + // *ClientAction_Failure + Action isClientAction_Action `protobuf_oneof:"action"` } -type ClientAction_Forward struct { - Forward *Forward `protobuf:"bytes,2,opt,name=forward,proto3,oneof"` +func (x *ClientAction) Reset() { + *x = ClientAction{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -type ClientAction_Failure struct { - Failure *Failure `protobuf:"bytes,3,opt,name=failure,proto3,oneof"` +func (x *ClientAction) String() string { + return protoimpl.X.MessageStringOf(x) } -func (*ClientAction_Reply) isClientAction_Action() {} +func (*ClientAction) ProtoMessage() {} -func (*ClientAction_Forward) isClientAction_Action() {} +func (x *ClientAction) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} -func (*ClientAction_Failure) isClientAction_Action() {} +// Deprecated: Use ClientAction.ProtoReflect.Descriptor instead. +func (*ClientAction) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{4} +} func (m *ClientAction) GetAction() isClientAction_Action { if m != nil { @@ -193,38 +428,58 @@ func (m *ClientAction) GetAction() isClientAction_Action { return nil } -func (m *ClientAction) GetReply() *Reply { - if x, ok := m.GetAction().(*ClientAction_Reply); ok { +func (x *ClientAction) GetReply() *Reply { + if x, ok := x.GetAction().(*ClientAction_Reply); ok { return x.Reply } return nil } -func (m *ClientAction) GetForward() *Forward { - if x, ok := m.GetAction().(*ClientAction_Forward); ok { +func (x *ClientAction) GetForward() *Forward { + if x, ok := x.GetAction().(*ClientAction_Forward); ok { return x.Forward } return nil } -func (m *ClientAction) GetFailure() *Failure { - if x, ok := m.GetAction().(*ClientAction_Failure); ok { +func (x *ClientAction) GetFailure() *Failure { + if x, ok := x.GetAction().(*ClientAction_Failure); ok { return x.Failure } return nil } -// XXX_OneofWrappers is for the internal use of the proto package. -func (*ClientAction) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*ClientAction_Reply)(nil), - (*ClientAction_Forward)(nil), - (*ClientAction_Failure)(nil), - } +type isClientAction_Action interface { + isClientAction_Action() +} + +type ClientAction_Reply struct { + // Send a reply + Reply *Reply `protobuf:"bytes,1,opt,name=reply,proto3,oneof"` +} + +type ClientAction_Forward struct { + // Forward to another entity + Forward *Forward `protobuf:"bytes,2,opt,name=forward,proto3,oneof"` +} + +type ClientAction_Failure struct { + // Send a failure to the client + Failure *Failure `protobuf:"bytes,3,opt,name=failure,proto3,oneof"` } +func (*ClientAction_Reply) isClientAction_Action() {} + +func (*ClientAction_Forward) isClientAction_Action() {} + +func (*ClientAction_Failure) isClientAction_Action() {} + // A side effect to be done after this command is handled. type SideEffect struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + // The name of the service to perform the side effect on. ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` // The name of the command. @@ -233,67 +488,84 @@ type SideEffect struct { Payload *any.Any `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"` // Whether this side effect should be performed synchronously, ie, before the reply is eventually // sent, or not. - Synchronous bool `protobuf:"varint,4,opt,name=synchronous,proto3" json:"synchronous,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Synchronous bool `protobuf:"varint,4,opt,name=synchronous,proto3" json:"synchronous,omitempty"` + // The metadata to include with the side effect + Metadata *Metadata `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"` } -func (m *SideEffect) Reset() { *m = SideEffect{} } -func (m *SideEffect) String() string { return proto.CompactTextString(m) } -func (*SideEffect) ProtoMessage() {} -func (*SideEffect) Descriptor() ([]byte, []int) { - return fileDescriptor_a4a280e6d8a8fec2, []int{3} +func (x *SideEffect) Reset() { + *x = SideEffect{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *SideEffect) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_SideEffect.Unmarshal(m, b) -} -func (m *SideEffect) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_SideEffect.Marshal(b, m, deterministic) -} -func (m *SideEffect) XXX_Merge(src proto.Message) { - xxx_messageInfo_SideEffect.Merge(m, src) -} -func (m *SideEffect) XXX_Size() int { - return xxx_messageInfo_SideEffect.Size(m) +func (x *SideEffect) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *SideEffect) XXX_DiscardUnknown() { - xxx_messageInfo_SideEffect.DiscardUnknown(m) + +func (*SideEffect) ProtoMessage() {} + +func (x *SideEffect) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_SideEffect proto.InternalMessageInfo +// Deprecated: Use SideEffect.ProtoReflect.Descriptor instead. +func (*SideEffect) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{5} +} -func (m *SideEffect) GetServiceName() string { - if m != nil { - return m.ServiceName +func (x *SideEffect) GetServiceName() string { + if x != nil { + return x.ServiceName } return "" } -func (m *SideEffect) GetCommandName() string { - if m != nil { - return m.CommandName +func (x *SideEffect) GetCommandName() string { + if x != nil { + return x.CommandName } return "" } -func (m *SideEffect) GetPayload() *any.Any { - if m != nil { - return m.Payload +func (x *SideEffect) GetPayload() *any.Any { + if x != nil { + return x.Payload } return nil } -func (m *SideEffect) GetSynchronous() bool { - if m != nil { - return m.Synchronous +func (x *SideEffect) GetSynchronous() bool { + if x != nil { + return x.Synchronous } return false } +func (x *SideEffect) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + // A command. For each command received, a reply must be sent with a matching command id. type Command struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + // The ID of the entity. EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` // A command id. @@ -303,117 +575,143 @@ type Command struct { // The command payload. Payload *any.Any `protobuf:"bytes,4,opt,name=payload,proto3" json:"payload,omitempty"` // Whether the command is streamed or not - Streamed bool `protobuf:"varint,5,opt,name=streamed,proto3" json:"streamed,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Streamed bool `protobuf:"varint,5,opt,name=streamed,proto3" json:"streamed,omitempty"` + // The command metadata. + // + // Not all transports support per message metadata, for example, gRPC doesn't. The Cloudstate proxy MAY include + // metadata from other locations in this case, for example, in gRPC, a unary call MAY have the HTTP request headers + // attached to the command, while a streamed call MAY have the HTTP request headers attached as the metadata for + // either the first command, or every command. This specification leaves this behavior undefined. + Metadata *Metadata `protobuf:"bytes,6,opt,name=metadata,proto3" json:"metadata,omitempty"` +} + +func (x *Command) Reset() { + *x = Command{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Command) Reset() { *m = Command{} } -func (m *Command) String() string { return proto.CompactTextString(m) } -func (*Command) ProtoMessage() {} -func (*Command) Descriptor() ([]byte, []int) { - return fileDescriptor_a4a280e6d8a8fec2, []int{4} +func (x *Command) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Command) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Command.Unmarshal(m, b) -} -func (m *Command) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Command.Marshal(b, m, deterministic) -} -func (m *Command) XXX_Merge(src proto.Message) { - xxx_messageInfo_Command.Merge(m, src) -} -func (m *Command) XXX_Size() int { - return xxx_messageInfo_Command.Size(m) -} -func (m *Command) XXX_DiscardUnknown() { - xxx_messageInfo_Command.DiscardUnknown(m) +func (*Command) ProtoMessage() {} + +func (x *Command) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Command proto.InternalMessageInfo +// Deprecated: Use Command.ProtoReflect.Descriptor instead. +func (*Command) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{6} +} -func (m *Command) GetEntityId() string { - if m != nil { - return m.EntityId +func (x *Command) GetEntityId() string { + if x != nil { + return x.EntityId } return "" } -func (m *Command) GetId() int64 { - if m != nil { - return m.Id +func (x *Command) GetId() int64 { + if x != nil { + return x.Id } return 0 } -func (m *Command) GetName() string { - if m != nil { - return m.Name +func (x *Command) GetName() string { + if x != nil { + return x.Name } return "" } -func (m *Command) GetPayload() *any.Any { - if m != nil { - return m.Payload +func (x *Command) GetPayload() *any.Any { + if x != nil { + return x.Payload } return nil } -func (m *Command) GetStreamed() bool { - if m != nil { - return m.Streamed +func (x *Command) GetStreamed() bool { + if x != nil { + return x.Streamed } return false } +func (x *Command) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + type StreamCancelled struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + // The ID of the entity EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` // The command id - Id int64 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Id int64 `protobuf:"varint,2,opt,name=id,proto3" json:"id,omitempty"` } -func (m *StreamCancelled) Reset() { *m = StreamCancelled{} } -func (m *StreamCancelled) String() string { return proto.CompactTextString(m) } -func (*StreamCancelled) ProtoMessage() {} -func (*StreamCancelled) Descriptor() ([]byte, []int) { - return fileDescriptor_a4a280e6d8a8fec2, []int{5} +func (x *StreamCancelled) Reset() { + *x = StreamCancelled{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *StreamCancelled) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_StreamCancelled.Unmarshal(m, b) -} -func (m *StreamCancelled) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_StreamCancelled.Marshal(b, m, deterministic) -} -func (m *StreamCancelled) XXX_Merge(src proto.Message) { - xxx_messageInfo_StreamCancelled.Merge(m, src) +func (x *StreamCancelled) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *StreamCancelled) XXX_Size() int { - return xxx_messageInfo_StreamCancelled.Size(m) -} -func (m *StreamCancelled) XXX_DiscardUnknown() { - xxx_messageInfo_StreamCancelled.DiscardUnknown(m) + +func (*StreamCancelled) ProtoMessage() {} + +func (x *StreamCancelled) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_StreamCancelled proto.InternalMessageInfo +// Deprecated: Use StreamCancelled.ProtoReflect.Descriptor instead. +func (*StreamCancelled) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{7} +} -func (m *StreamCancelled) GetEntityId() string { - if m != nil { - return m.EntityId +func (x *StreamCancelled) GetEntityId() string { + if x != nil { + return x.EntityId } return "" } -func (m *StreamCancelled) GetId() int64 { - if m != nil { - return m.Id +func (x *StreamCancelled) GetId() int64 { + if x != nil { + return x.Id } return 0 } @@ -421,55 +719,76 @@ func (m *StreamCancelled) GetId() int64 { // A failure reply. If this is returned, it will be translated into a gRPC unknown // error with the corresponding description if supplied. type Failure struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + // The id of the command being replied to. Must match the input command. CommandId int64 `protobuf:"varint,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` // A description of the error. - Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Description string `protobuf:"bytes,2,opt,name=description,proto3" json:"description,omitempty"` + // Whether this failure should trigger an entity restart. + Restart bool `protobuf:"varint,3,opt,name=restart,proto3" json:"restart,omitempty"` } -func (m *Failure) Reset() { *m = Failure{} } -func (m *Failure) String() string { return proto.CompactTextString(m) } -func (*Failure) ProtoMessage() {} -func (*Failure) Descriptor() ([]byte, []int) { - return fileDescriptor_a4a280e6d8a8fec2, []int{6} +func (x *Failure) Reset() { + *x = Failure{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Failure) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Failure.Unmarshal(m, b) -} -func (m *Failure) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Failure.Marshal(b, m, deterministic) -} -func (m *Failure) XXX_Merge(src proto.Message) { - xxx_messageInfo_Failure.Merge(m, src) +func (x *Failure) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Failure) XXX_Size() int { - return xxx_messageInfo_Failure.Size(m) -} -func (m *Failure) XXX_DiscardUnknown() { - xxx_messageInfo_Failure.DiscardUnknown(m) + +func (*Failure) ProtoMessage() {} + +func (x *Failure) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Failure proto.InternalMessageInfo +// Deprecated: Use Failure.ProtoReflect.Descriptor instead. +func (*Failure) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{8} +} -func (m *Failure) GetCommandId() int64 { - if m != nil { - return m.CommandId +func (x *Failure) GetCommandId() int64 { + if x != nil { + return x.CommandId } return 0 } -func (m *Failure) GetDescription() string { - if m != nil { - return m.Description +func (x *Failure) GetDescription() string { + if x != nil { + return x.Description } return "" } +func (x *Failure) GetRestart() bool { + if x != nil { + return x.Restart + } + return false +} + type EntitySpec struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + // This should be the Descriptors.FileDescriptorSet in proto serialized from as generated by: // protoc --include_imports \ // --proto_path= \ @@ -479,54 +798,58 @@ type EntitySpec struct { // The entities being served. Entities []*Entity `protobuf:"bytes,2,rep,name=entities,proto3" json:"entities,omitempty"` // Optional information about the service. - ServiceInfo *ServiceInfo `protobuf:"bytes,3,opt,name=service_info,json=serviceInfo,proto3" json:"service_info,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + ServiceInfo *ServiceInfo `protobuf:"bytes,3,opt,name=service_info,json=serviceInfo,proto3" json:"service_info,omitempty"` } -func (m *EntitySpec) Reset() { *m = EntitySpec{} } -func (m *EntitySpec) String() string { return proto.CompactTextString(m) } -func (*EntitySpec) ProtoMessage() {} -func (*EntitySpec) Descriptor() ([]byte, []int) { - return fileDescriptor_a4a280e6d8a8fec2, []int{7} +func (x *EntitySpec) Reset() { + *x = EntitySpec{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *EntitySpec) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EntitySpec.Unmarshal(m, b) -} -func (m *EntitySpec) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EntitySpec.Marshal(b, m, deterministic) +func (x *EntitySpec) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *EntitySpec) XXX_Merge(src proto.Message) { - xxx_messageInfo_EntitySpec.Merge(m, src) -} -func (m *EntitySpec) XXX_Size() int { - return xxx_messageInfo_EntitySpec.Size(m) -} -func (m *EntitySpec) XXX_DiscardUnknown() { - xxx_messageInfo_EntitySpec.DiscardUnknown(m) + +func (*EntitySpec) ProtoMessage() {} + +func (x *EntitySpec) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_EntitySpec proto.InternalMessageInfo +// Deprecated: Use EntitySpec.ProtoReflect.Descriptor instead. +func (*EntitySpec) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{9} +} -func (m *EntitySpec) GetProto() []byte { - if m != nil { - return m.Proto +func (x *EntitySpec) GetProto() []byte { + if x != nil { + return x.Proto } return nil } -func (m *EntitySpec) GetEntities() []*Entity { - if m != nil { - return m.Entities +func (x *EntitySpec) GetEntities() []*Entity { + if x != nil { + return x.Entities } return nil } -func (m *EntitySpec) GetServiceInfo() *ServiceInfo { - if m != nil { - return m.ServiceInfo +func (x *EntitySpec) GetServiceInfo() *ServiceInfo { + if x != nil { + return x.ServiceInfo } return nil } @@ -534,6 +857,10 @@ func (m *EntitySpec) GetServiceInfo() *ServiceInfo { // Information about the service that proxy is proxying to. // All of the information in here is optional. It may be useful for debug purposes. type ServiceInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + // The name of the service, eg, "shopping-cart". ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` // The version of the service. @@ -545,73 +872,99 @@ type ServiceInfo struct { // If using a support library, the name of that library, eg "cloudstate" SupportLibraryName string `protobuf:"bytes,4,opt,name=support_library_name,json=supportLibraryName,proto3" json:"support_library_name,omitempty"` // The version of the support library being used. - SupportLibraryVersion string `protobuf:"bytes,5,opt,name=support_library_version,json=supportLibraryVersion,proto3" json:"support_library_version,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + SupportLibraryVersion string `protobuf:"bytes,5,opt,name=support_library_version,json=supportLibraryVersion,proto3" json:"support_library_version,omitempty"` + // Cloudstate protocol major version accepted by the support library. + ProtocolMajorVersion int32 `protobuf:"varint,6,opt,name=protocol_major_version,json=protocolMajorVersion,proto3" json:"protocol_major_version,omitempty"` + // Cloudstate protocol minor version accepted by the support library. + ProtocolMinorVersion int32 `protobuf:"varint,7,opt,name=protocol_minor_version,json=protocolMinorVersion,proto3" json:"protocol_minor_version,omitempty"` +} + +func (x *ServiceInfo) Reset() { + *x = ServiceInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ServiceInfo) Reset() { *m = ServiceInfo{} } -func (m *ServiceInfo) String() string { return proto.CompactTextString(m) } -func (*ServiceInfo) ProtoMessage() {} -func (*ServiceInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_a4a280e6d8a8fec2, []int{8} +func (x *ServiceInfo) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ServiceInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ServiceInfo.Unmarshal(m, b) -} -func (m *ServiceInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ServiceInfo.Marshal(b, m, deterministic) -} -func (m *ServiceInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_ServiceInfo.Merge(m, src) -} -func (m *ServiceInfo) XXX_Size() int { - return xxx_messageInfo_ServiceInfo.Size(m) -} -func (m *ServiceInfo) XXX_DiscardUnknown() { - xxx_messageInfo_ServiceInfo.DiscardUnknown(m) +func (*ServiceInfo) ProtoMessage() {} + +func (x *ServiceInfo) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ServiceInfo proto.InternalMessageInfo +// Deprecated: Use ServiceInfo.ProtoReflect.Descriptor instead. +func (*ServiceInfo) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{10} +} -func (m *ServiceInfo) GetServiceName() string { - if m != nil { - return m.ServiceName +func (x *ServiceInfo) GetServiceName() string { + if x != nil { + return x.ServiceName } return "" } -func (m *ServiceInfo) GetServiceVersion() string { - if m != nil { - return m.ServiceVersion +func (x *ServiceInfo) GetServiceVersion() string { + if x != nil { + return x.ServiceVersion } return "" } -func (m *ServiceInfo) GetServiceRuntime() string { - if m != nil { - return m.ServiceRuntime +func (x *ServiceInfo) GetServiceRuntime() string { + if x != nil { + return x.ServiceRuntime } return "" } -func (m *ServiceInfo) GetSupportLibraryName() string { - if m != nil { - return m.SupportLibraryName +func (x *ServiceInfo) GetSupportLibraryName() string { + if x != nil { + return x.SupportLibraryName } return "" } -func (m *ServiceInfo) GetSupportLibraryVersion() string { - if m != nil { - return m.SupportLibraryVersion +func (x *ServiceInfo) GetSupportLibraryVersion() string { + if x != nil { + return x.SupportLibraryVersion } return "" } +func (x *ServiceInfo) GetProtocolMajorVersion() int32 { + if x != nil { + return x.ProtocolMajorVersion + } + return 0 +} + +func (x *ServiceInfo) GetProtocolMinorVersion() int32 { + if x != nil { + return x.ProtocolMinorVersion + } + return 0 +} + type Entity struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + // The type of entity. By convention, this should be a fully qualified entity protocol grpc // service name, for example, cloudstate.eventsourced.EventSourced. EntityType string `protobuf:"bytes,1,opt,name=entity_type,json=entityType,proto3" json:"entity_type,omitempty"` @@ -619,246 +972,617 @@ type Entity struct { ServiceName string `protobuf:"bytes,2,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` // The ID to namespace state by. How this is used depends on the type of entity, for example, // event sourced entities will prefix this to the persistence id. - PersistenceId string `protobuf:"bytes,3,opt,name=persistence_id,json=persistenceId,proto3" json:"persistence_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + PersistenceId string `protobuf:"bytes,3,opt,name=persistence_id,json=persistenceId,proto3" json:"persistence_id,omitempty"` } -func (m *Entity) Reset() { *m = Entity{} } -func (m *Entity) String() string { return proto.CompactTextString(m) } -func (*Entity) ProtoMessage() {} -func (*Entity) Descriptor() ([]byte, []int) { - return fileDescriptor_a4a280e6d8a8fec2, []int{9} +func (x *Entity) Reset() { + *x = Entity{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *Entity) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Entity.Unmarshal(m, b) -} -func (m *Entity) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Entity.Marshal(b, m, deterministic) -} -func (m *Entity) XXX_Merge(src proto.Message) { - xxx_messageInfo_Entity.Merge(m, src) +func (x *Entity) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *Entity) XXX_Size() int { - return xxx_messageInfo_Entity.Size(m) -} -func (m *Entity) XXX_DiscardUnknown() { - xxx_messageInfo_Entity.DiscardUnknown(m) + +func (*Entity) ProtoMessage() {} + +func (x *Entity) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_Entity proto.InternalMessageInfo +// Deprecated: Use Entity.ProtoReflect.Descriptor instead. +func (*Entity) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{11} +} -func (m *Entity) GetEntityType() string { - if m != nil { - return m.EntityType +func (x *Entity) GetEntityType() string { + if x != nil { + return x.EntityType } return "" } -func (m *Entity) GetServiceName() string { - if m != nil { - return m.ServiceName +func (x *Entity) GetServiceName() string { + if x != nil { + return x.ServiceName } return "" } -func (m *Entity) GetPersistenceId() string { - if m != nil { - return m.PersistenceId +func (x *Entity) GetPersistenceId() string { + if x != nil { + return x.PersistenceId } return "" } type UserFunctionError struct { - Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -func (m *UserFunctionError) Reset() { *m = UserFunctionError{} } -func (m *UserFunctionError) String() string { return proto.CompactTextString(m) } -func (*UserFunctionError) ProtoMessage() {} -func (*UserFunctionError) Descriptor() ([]byte, []int) { - return fileDescriptor_a4a280e6d8a8fec2, []int{10} + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` } -func (m *UserFunctionError) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserFunctionError.Unmarshal(m, b) -} -func (m *UserFunctionError) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserFunctionError.Marshal(b, m, deterministic) -} -func (m *UserFunctionError) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserFunctionError.Merge(m, src) +func (x *UserFunctionError) Reset() { + *x = UserFunctionError{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *UserFunctionError) XXX_Size() int { - return xxx_messageInfo_UserFunctionError.Size(m) + +func (x *UserFunctionError) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *UserFunctionError) XXX_DiscardUnknown() { - xxx_messageInfo_UserFunctionError.DiscardUnknown(m) + +func (*UserFunctionError) ProtoMessage() {} + +func (x *UserFunctionError) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_UserFunctionError proto.InternalMessageInfo +// Deprecated: Use UserFunctionError.ProtoReflect.Descriptor instead. +func (*UserFunctionError) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{12} +} -func (m *UserFunctionError) GetMessage() string { - if m != nil { - return m.Message +func (x *UserFunctionError) GetMessage() string { + if x != nil { + return x.Message } return "" } type ProxyInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + ProtocolMajorVersion int32 `protobuf:"varint,1,opt,name=protocol_major_version,json=protocolMajorVersion,proto3" json:"protocol_major_version,omitempty"` ProtocolMinorVersion int32 `protobuf:"varint,2,opt,name=protocol_minor_version,json=protocolMinorVersion,proto3" json:"protocol_minor_version,omitempty"` ProxyName string `protobuf:"bytes,3,opt,name=proxy_name,json=proxyName,proto3" json:"proxy_name,omitempty"` ProxyVersion string `protobuf:"bytes,4,opt,name=proxy_version,json=proxyVersion,proto3" json:"proxy_version,omitempty"` SupportedEntityTypes []string `protobuf:"bytes,5,rep,name=supported_entity_types,json=supportedEntityTypes,proto3" json:"supported_entity_types,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` } -func (m *ProxyInfo) Reset() { *m = ProxyInfo{} } -func (m *ProxyInfo) String() string { return proto.CompactTextString(m) } -func (*ProxyInfo) ProtoMessage() {} -func (*ProxyInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_a4a280e6d8a8fec2, []int{11} +func (x *ProxyInfo) Reset() { + *x = ProxyInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_entity_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } } -func (m *ProxyInfo) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ProxyInfo.Unmarshal(m, b) +func (x *ProxyInfo) String() string { + return protoimpl.X.MessageStringOf(x) } -func (m *ProxyInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ProxyInfo.Marshal(b, m, deterministic) -} -func (m *ProxyInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_ProxyInfo.Merge(m, src) -} -func (m *ProxyInfo) XXX_Size() int { - return xxx_messageInfo_ProxyInfo.Size(m) -} -func (m *ProxyInfo) XXX_DiscardUnknown() { - xxx_messageInfo_ProxyInfo.DiscardUnknown(m) + +func (*ProxyInfo) ProtoMessage() {} + +func (x *ProxyInfo) ProtoReflect() protoreflect.Message { + mi := &file_entity_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -var xxx_messageInfo_ProxyInfo proto.InternalMessageInfo +// Deprecated: Use ProxyInfo.ProtoReflect.Descriptor instead. +func (*ProxyInfo) Descriptor() ([]byte, []int) { + return file_entity_proto_rawDescGZIP(), []int{13} +} -func (m *ProxyInfo) GetProtocolMajorVersion() int32 { - if m != nil { - return m.ProtocolMajorVersion +func (x *ProxyInfo) GetProtocolMajorVersion() int32 { + if x != nil { + return x.ProtocolMajorVersion } return 0 } -func (m *ProxyInfo) GetProtocolMinorVersion() int32 { - if m != nil { - return m.ProtocolMinorVersion +func (x *ProxyInfo) GetProtocolMinorVersion() int32 { + if x != nil { + return x.ProtocolMinorVersion } return 0 } -func (m *ProxyInfo) GetProxyName() string { - if m != nil { - return m.ProxyName +func (x *ProxyInfo) GetProxyName() string { + if x != nil { + return x.ProxyName } return "" } -func (m *ProxyInfo) GetProxyVersion() string { - if m != nil { - return m.ProxyVersion +func (x *ProxyInfo) GetProxyVersion() string { + if x != nil { + return x.ProxyVersion } return "" } -func (m *ProxyInfo) GetSupportedEntityTypes() []string { - if m != nil { - return m.SupportedEntityTypes +func (x *ProxyInfo) GetSupportedEntityTypes() []string { + if x != nil { + return x.SupportedEntityTypes } return nil } -func init() { - proto.RegisterType((*Reply)(nil), "cloudstate.Reply") - proto.RegisterType((*Forward)(nil), "cloudstate.Forward") - proto.RegisterType((*ClientAction)(nil), "cloudstate.ClientAction") - proto.RegisterType((*SideEffect)(nil), "cloudstate.SideEffect") - proto.RegisterType((*Command)(nil), "cloudstate.Command") - proto.RegisterType((*StreamCancelled)(nil), "cloudstate.StreamCancelled") - proto.RegisterType((*Failure)(nil), "cloudstate.Failure") - proto.RegisterType((*EntitySpec)(nil), "cloudstate.EntitySpec") - proto.RegisterType((*ServiceInfo)(nil), "cloudstate.ServiceInfo") - proto.RegisterType((*Entity)(nil), "cloudstate.Entity") - proto.RegisterType((*UserFunctionError)(nil), "cloudstate.UserFunctionError") - proto.RegisterType((*ProxyInfo)(nil), "cloudstate.ProxyInfo") -} - -func init() { proto.RegisterFile("cloudstate/entity.proto", fileDescriptor_a4a280e6d8a8fec2) } - -var fileDescriptor_a4a280e6d8a8fec2 = []byte{ - // 795 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x55, 0xcd, 0x6e, 0xf3, 0x44, - 0x14, 0x8d, 0xf3, 0xd3, 0x24, 0xd7, 0x69, 0xab, 0x4e, 0xd3, 0x34, 0xa4, 0xaa, 0x08, 0x46, 0x88, - 0xb0, 0xa8, 0x83, 0x02, 0x02, 0x09, 0x24, 0xa4, 0xb6, 0xa4, 0x6a, 0x10, 0x20, 0xe4, 0x00, 0x0b, - 0x36, 0x91, 0x6b, 0x4f, 0xca, 0x20, 0x7b, 0xc6, 0x9a, 0x71, 0x0a, 0x5e, 0xf1, 0x06, 0x2c, 0xfb, - 0x04, 0xf0, 0x76, 0x6c, 0x78, 0x03, 0xe4, 0xf9, 0x71, 0xa6, 0xc9, 0xa6, 0xdf, 0xea, 0xdb, 0x79, - 0xee, 0x39, 0x67, 0xe6, 0xdc, 0x33, 0x77, 0x12, 0x38, 0x8f, 0x12, 0xb6, 0x89, 0x45, 0x1e, 0xe6, - 0x78, 0x8a, 0x69, 0x4e, 0xf2, 0xc2, 0xcf, 0x38, 0xcb, 0x19, 0x82, 0x2d, 0x30, 0x7a, 0xe7, 0x91, - 0xb1, 0xc7, 0x04, 0x4f, 0x25, 0xf2, 0xb0, 0x59, 0x4f, 0x43, 0xaa, 0x69, 0xa3, 0x8b, 0x5d, 0x08, - 0xa7, 0x99, 0xd9, 0x63, 0x34, 0xde, 0x05, 0x63, 0x2c, 0x22, 0x4e, 0xb2, 0x9c, 0x71, 0xc5, 0xf0, - 0x3e, 0x87, 0x56, 0x80, 0xb3, 0xa4, 0x40, 0x3e, 0xb4, 0xb3, 0xb0, 0x48, 0x58, 0x18, 0x0f, 0x9d, - 0xb1, 0x33, 0x71, 0x67, 0x7d, 0x5f, 0x89, 0x7d, 0x23, 0xf6, 0xaf, 0x69, 0x11, 0x18, 0x92, 0xf7, - 0x27, 0xb4, 0xef, 0x18, 0xff, 0x3d, 0xe4, 0x31, 0x7a, 0x0f, 0x7a, 0x02, 0xf3, 0x27, 0x12, 0xe1, - 0x15, 0x0d, 0x53, 0x2c, 0xf5, 0xdd, 0xc0, 0xd5, 0xb5, 0xef, 0xc3, 0x14, 0x97, 0x94, 0x88, 0xa5, - 0x69, 0x48, 0x63, 0x45, 0xa9, 0x2b, 0x8a, 0xae, 0x49, 0x8a, 0x65, 0xa0, 0xf1, 0x1a, 0x03, 0xff, - 0x38, 0xd0, 0xbb, 0x4d, 0x08, 0xa6, 0xf9, 0x75, 0x94, 0x13, 0x46, 0xd1, 0x47, 0xd0, 0xe2, 0x65, - 0x2b, 0xda, 0xff, 0x89, 0xbf, 0x0d, 0xd0, 0x97, 0x3d, 0xde, 0xd7, 0x02, 0xc5, 0x40, 0x53, 0x68, - 0xaf, 0x95, 0x79, 0xe9, 0xc4, 0x9d, 0x9d, 0xda, 0x64, 0xdd, 0xd7, 0x7d, 0x2d, 0x30, 0x2c, 0x29, - 0x08, 0x49, 0xb2, 0xe1, 0x58, 0x9b, 0x7b, 0x29, 0x50, 0x90, 0x14, 0xa8, 0xcf, 0x9b, 0x0e, 0x1c, - 0x84, 0xd2, 0x96, 0xf7, 0xb7, 0x03, 0xb0, 0x24, 0x31, 0x9e, 0xaf, 0xd7, 0x38, 0xca, 0xdf, 0x4e, - 0x58, 0x68, 0x0c, 0xae, 0x28, 0x68, 0xf4, 0x2b, 0x67, 0x94, 0x6d, 0xc4, 0xb0, 0x39, 0x76, 0x26, - 0x9d, 0xc0, 0x2e, 0x79, 0xcf, 0x0e, 0xb4, 0x6f, 0xd5, 0x09, 0xe8, 0x02, 0xba, 0x6a, 0x14, 0x57, - 0x24, 0xd6, 0x06, 0x3b, 0xaa, 0xb0, 0x88, 0xd1, 0x11, 0xd4, 0x89, 0x8a, 0xad, 0x11, 0xd4, 0x49, - 0x8c, 0x10, 0x34, 0xa5, 0xcb, 0x86, 0xe4, 0xc9, 0x6f, 0xdb, 0x5e, 0xf3, 0x35, 0xf6, 0x46, 0xd0, - 0x11, 0x39, 0xc7, 0x61, 0x8a, 0xe3, 0x61, 0x4b, 0x7a, 0xab, 0xd6, 0xde, 0x57, 0x70, 0xbc, 0x94, - 0xdf, 0xb7, 0x21, 0x8d, 0x70, 0x92, 0xe0, 0x37, 0xf3, 0xe7, 0x7d, 0x03, 0x6d, 0x7d, 0x3f, 0xe8, - 0x12, 0xc0, 0x04, 0xab, 0x85, 0x8d, 0xa0, 0xab, 0x2b, 0x0b, 0x19, 0x92, 0x79, 0x1f, 0x84, 0x51, - 0x13, 0xbb, 0x55, 0xf2, 0xfe, 0x72, 0x00, 0xe6, 0xf2, 0xa0, 0x65, 0x86, 0x23, 0xd4, 0x87, 0x96, - 0xec, 0x47, 0x6e, 0xd5, 0x0b, 0xd4, 0x02, 0xf9, 0xa0, 0xcc, 0x10, 0x2c, 0x86, 0xf5, 0x71, 0x63, - 0xe2, 0xce, 0x90, 0x3d, 0x2c, 0x4a, 0x1f, 0x54, 0x1c, 0xf4, 0xc5, 0x76, 0x22, 0x08, 0x5d, 0x33, - 0x7d, 0xa1, 0xe7, 0xb6, 0x66, 0xa9, 0xf0, 0x05, 0x5d, 0xb3, 0x6a, 0x54, 0xca, 0x85, 0xf7, 0xaf, - 0x03, 0xae, 0x05, 0xbe, 0x66, 0xba, 0x3e, 0x84, 0x63, 0x43, 0x79, 0xc2, 0x5c, 0x6c, 0x3b, 0x3d, - 0xd2, 0xe5, 0x9f, 0x55, 0xd5, 0x26, 0xf2, 0x0d, 0xcd, 0x49, 0x75, 0xc7, 0x86, 0x18, 0xa8, 0x2a, - 0xfa, 0x18, 0xfa, 0x62, 0x93, 0x65, 0x8c, 0xe7, 0xab, 0x84, 0x3c, 0xf0, 0x90, 0x17, 0xea, 0xf0, - 0xa6, 0x64, 0x23, 0x8d, 0x7d, 0xab, 0x20, 0xe9, 0xe1, 0x33, 0x38, 0xdf, 0x55, 0x18, 0x2f, 0x2d, - 0x29, 0x3a, 0x7b, 0x29, 0xd2, 0x96, 0x3c, 0x01, 0x07, 0x2a, 0x3e, 0xf4, 0x2e, 0xb8, 0x7a, 0x04, - 0xf2, 0x22, 0x33, 0x7d, 0x82, 0x2a, 0xfd, 0x58, 0x64, 0x78, 0x2f, 0x89, 0xfa, 0x7e, 0x12, 0x1f, - 0xc0, 0x51, 0x56, 0x6e, 0x2c, 0x72, 0x4c, 0xcb, 0xf0, 0x63, 0xdd, 0xdf, 0xa1, 0x55, 0x5d, 0xc4, - 0xde, 0x15, 0x9c, 0xfc, 0x24, 0x30, 0xbf, 0xdb, 0x50, 0xf9, 0xa0, 0xe7, 0x9c, 0x33, 0x8e, 0x86, - 0xd0, 0x4e, 0xb1, 0x10, 0xe1, 0xa3, 0x39, 0xdb, 0x2c, 0xbd, 0xff, 0x1c, 0xe8, 0xfe, 0xc0, 0xd9, - 0x1f, 0x85, 0xbc, 0x90, 0x4f, 0x61, 0x20, 0xa7, 0x22, 0x62, 0xc9, 0x2a, 0x0d, 0x7f, 0x63, 0xbc, - 0x6a, 0xb4, 0x94, 0xb5, 0x82, 0xbe, 0x41, 0xbf, 0x2b, 0x41, 0x13, 0xfd, 0x0b, 0x15, 0xa1, 0x96, - 0xaa, 0xbe, 0xa3, 0x2a, 0x41, 0xa3, 0xba, 0x04, 0xc8, 0xca, 0x83, 0x57, 0xd6, 0x7b, 0xec, 0xca, - 0x8a, 0x6c, 0xf7, 0x7d, 0x38, 0x54, 0xb0, 0xd9, 0x4b, 0xdd, 0x4f, 0x4f, 0x16, 0xad, 0x93, 0x75, - 0xf4, 0x38, 0x5e, 0x59, 0x09, 0x8b, 0x61, 0x6b, 0xdc, 0x98, 0x74, 0x83, 0x7e, 0x85, 0xce, 0xab, - 0xac, 0xc5, 0xec, 0xd9, 0x81, 0x63, 0xb5, 0xfe, 0x9a, 0x88, 0x88, 0x3d, 0x61, 0x5e, 0xa0, 0x2f, - 0xa1, 0x13, 0xeb, 0x05, 0x3a, 0xb3, 0x87, 0xb9, 0x0a, 0x67, 0x34, 0xd8, 0x7f, 0x17, 0xe5, 0xbb, - 0xf2, 0x6a, 0xe8, 0x0e, 0x5c, 0x8e, 0xcb, 0x73, 0x54, 0xda, 0x97, 0x36, 0x71, 0xef, 0x32, 0x46, - 0x83, 0xbd, 0x5f, 0x97, 0x79, 0xf9, 0x27, 0xe8, 0xd5, 0x6e, 0xae, 0x60, 0x40, 0x98, 0x2d, 0x36, - 0xc1, 0xfd, 0x72, 0x6a, 0xfd, 0xef, 0x9a, 0xe2, 0xc3, 0x81, 0xfc, 0xfa, 0xe4, 0xff, 0x00, 0x00, - 0x00, 0xff, 0xff, 0xb9, 0x13, 0x29, 0x57, 0x95, 0x07, 0x00, 0x00, +var File_entity_proto protoreflect.FileDescriptor + +var file_entity_proto_rawDesc = []byte{ + 0x0a, 0x0c, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, + 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x3f, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x33, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x19, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x4d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, + 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x72, 0x0a, 0x0d, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x23, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, + 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x69, 0x0a, 0x05, 0x52, 0x65, 0x70, + 0x6c, 0x79, 0x12, 0x2e, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, + 0x61, 0x64, 0x12, 0x30, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x22, 0xb1, 0x01, 0x0a, 0x07, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, + 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, + 0x6e, 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x30, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xa5, 0x01, 0x0a, 0x0c, 0x43, 0x6c, 0x69, + 0x65, 0x6e, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x29, 0x0a, 0x05, 0x72, 0x65, 0x70, + 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x05, 0x72, + 0x65, 0x70, 0x6c, 0x79, 0x12, 0x2f, 0x0a, 0x07, 0x66, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x48, 0x00, 0x52, 0x07, 0x66, 0x6f, + 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x2f, 0x0a, 0x07, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x48, 0x00, 0x52, 0x07, 0x66, + 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0xd6, 0x01, 0x0a, 0x0a, 0x53, 0x69, 0x64, 0x65, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x12, + 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, + 0x64, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x70, 0x61, + 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, + 0x6e, 0x6f, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x73, 0x79, 0x6e, 0x63, + 0x68, 0x72, 0x6f, 0x6e, 0x6f, 0x75, 0x73, 0x12, 0x30, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, + 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xc8, 0x01, 0x0a, 0x07, 0x43, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, + 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, + 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x70, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x65, 0x64, 0x12, 0x30, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x22, 0x3e, 0x0a, 0x0f, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x43, 0x61, + 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, + 0x74, 0x79, 0x49, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x02, 0x69, 0x64, 0x22, 0x64, 0x0a, 0x07, 0x46, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x12, + 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x07, 0x72, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x22, 0x8e, 0x01, 0x0a, 0x0a, 0x45, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x70, 0x65, 0x63, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x2e, 0x0a, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x45, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, + 0x3a, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0b, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xd8, 0x02, 0x0a, 0x0b, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x21, 0x0a, 0x0c, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, + 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x5f, 0x72, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x12, 0x30, 0x0a, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x62, 0x72, + 0x61, 0x72, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, + 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x36, 0x0a, 0x17, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x5f, 0x6c, 0x69, + 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x15, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x4c, 0x69, 0x62, 0x72, + 0x61, 0x72, 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x16, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x4d, 0x61, 0x6a, 0x6f, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x12, 0x34, 0x0a, 0x16, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x6d, 0x69, 0x6e, + 0x6f, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x14, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x4d, 0x69, 0x6e, 0x6f, 0x72, 0x56, + 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x73, 0x0a, 0x06, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, + 0x12, 0x1f, 0x0a, 0x0b, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, + 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x70, 0x65, + 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, 0x2d, 0x0a, 0x11, 0x55, + 0x73, 0x65, 0x72, 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0xf1, 0x01, 0x0a, 0x09, 0x50, + 0x72, 0x6f, 0x78, 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x34, 0x0a, 0x16, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x4d, 0x61, 0x6a, 0x6f, 0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, + 0x0a, 0x16, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x5f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, + 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x4d, 0x69, 0x6e, 0x6f, 0x72, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x34, 0x0a, 0x16, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x73, 0x32, 0x96, + 0x01, 0x0a, 0x0f, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x44, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, + 0x72, 0x79, 0x12, 0x3b, 0x0a, 0x08, 0x64, 0x69, 0x73, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x15, + 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x50, 0x72, 0x6f, 0x78, + 0x79, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x16, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x2e, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x53, 0x70, 0x65, 0x63, 0x22, 0x00, 0x12, + 0x46, 0x0a, 0x0b, 0x72, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x1d, + 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x46, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x59, 0x0a, 0x16, 0x69, 0x6f, 0x2e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x5a, 0x3f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x3b, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_entity_proto_rawDescOnce sync.Once + file_entity_proto_rawDescData = file_entity_proto_rawDesc +) + +func file_entity_proto_rawDescGZIP() []byte { + file_entity_proto_rawDescOnce.Do(func() { + file_entity_proto_rawDescData = protoimpl.X.CompressGZIP(file_entity_proto_rawDescData) + }) + return file_entity_proto_rawDescData +} + +var file_entity_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_entity_proto_goTypes = []interface{}{ + (*Metadata)(nil), // 0: cloudstate.Metadata + (*MetadataEntry)(nil), // 1: cloudstate.MetadataEntry + (*Reply)(nil), // 2: cloudstate.Reply + (*Forward)(nil), // 3: cloudstate.Forward + (*ClientAction)(nil), // 4: cloudstate.ClientAction + (*SideEffect)(nil), // 5: cloudstate.SideEffect + (*Command)(nil), // 6: cloudstate.Command + (*StreamCancelled)(nil), // 7: cloudstate.StreamCancelled + (*Failure)(nil), // 8: cloudstate.Failure + (*EntitySpec)(nil), // 9: cloudstate.EntitySpec + (*ServiceInfo)(nil), // 10: cloudstate.ServiceInfo + (*Entity)(nil), // 11: cloudstate.Entity + (*UserFunctionError)(nil), // 12: cloudstate.UserFunctionError + (*ProxyInfo)(nil), // 13: cloudstate.ProxyInfo + (*any.Any)(nil), // 14: google.protobuf.Any + (*empty.Empty)(nil), // 15: google.protobuf.Empty +} +var file_entity_proto_depIdxs = []int32{ + 1, // 0: cloudstate.Metadata.entries:type_name -> cloudstate.MetadataEntry + 14, // 1: cloudstate.Reply.payload:type_name -> google.protobuf.Any + 0, // 2: cloudstate.Reply.metadata:type_name -> cloudstate.Metadata + 14, // 3: cloudstate.Forward.payload:type_name -> google.protobuf.Any + 0, // 4: cloudstate.Forward.metadata:type_name -> cloudstate.Metadata + 2, // 5: cloudstate.ClientAction.reply:type_name -> cloudstate.Reply + 3, // 6: cloudstate.ClientAction.forward:type_name -> cloudstate.Forward + 8, // 7: cloudstate.ClientAction.failure:type_name -> cloudstate.Failure + 14, // 8: cloudstate.SideEffect.payload:type_name -> google.protobuf.Any + 0, // 9: cloudstate.SideEffect.metadata:type_name -> cloudstate.Metadata + 14, // 10: cloudstate.Command.payload:type_name -> google.protobuf.Any + 0, // 11: cloudstate.Command.metadata:type_name -> cloudstate.Metadata + 11, // 12: cloudstate.EntitySpec.entities:type_name -> cloudstate.Entity + 10, // 13: cloudstate.EntitySpec.service_info:type_name -> cloudstate.ServiceInfo + 13, // 14: cloudstate.EntityDiscovery.discover:input_type -> cloudstate.ProxyInfo + 12, // 15: cloudstate.EntityDiscovery.reportError:input_type -> cloudstate.UserFunctionError + 9, // 16: cloudstate.EntityDiscovery.discover:output_type -> cloudstate.EntitySpec + 15, // 17: cloudstate.EntityDiscovery.reportError:output_type -> google.protobuf.Empty + 16, // [16:18] is the sub-list for method output_type + 14, // [14:16] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name +} + +func init() { file_entity_proto_init() } +func file_entity_proto_init() { + if File_entity_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_entity_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Metadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MetadataEntry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Reply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Forward); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ClientAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SideEffect); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Command); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StreamCancelled); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Failure); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EntitySpec); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ServiceInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Entity); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserFunctionError); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_entity_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ProxyInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_entity_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*MetadataEntry_StringValue)(nil), + (*MetadataEntry_BytesValue)(nil), + } + file_entity_proto_msgTypes[4].OneofWrappers = []interface{}{ + (*ClientAction_Reply)(nil), + (*ClientAction_Forward)(nil), + (*ClientAction_Failure)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_entity_proto_rawDesc, + NumEnums: 0, + NumMessages: 14, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_entity_proto_goTypes, + DependencyIndexes: file_entity_proto_depIdxs, + MessageInfos: file_entity_proto_msgTypes, + }.Build() + File_entity_proto = out.File + file_entity_proto_rawDesc = nil + file_entity_proto_goTypes = nil + file_entity_proto_depIdxs = nil } // Reference imports to suppress errors if they are not otherwise used. var _ context.Context -var _ grpc.ClientConn +var _ grpc.ClientConnInterface // This is a compile-time assertion to ensure that this generated file // is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 +const _ = grpc.SupportPackageIsVersion6 // EntityDiscoveryClient is the client API for EntityDiscovery service. // @@ -874,10 +1598,10 @@ type EntityDiscoveryClient interface { } type entityDiscoveryClient struct { - cc *grpc.ClientConn + cc grpc.ClientConnInterface } -func NewEntityDiscoveryClient(cc *grpc.ClientConn) EntityDiscoveryClient { +func NewEntityDiscoveryClient(cc grpc.ClientConnInterface) EntityDiscoveryClient { return &entityDiscoveryClient{cc} } @@ -914,10 +1638,10 @@ type EntityDiscoveryServer interface { type UnimplementedEntityDiscoveryServer struct { } -func (*UnimplementedEntityDiscoveryServer) Discover(ctx context.Context, req *ProxyInfo) (*EntitySpec, error) { +func (*UnimplementedEntityDiscoveryServer) Discover(context.Context, *ProxyInfo) (*EntitySpec, error) { return nil, status.Errorf(codes.Unimplemented, "method Discover not implemented") } -func (*UnimplementedEntityDiscoveryServer) ReportError(ctx context.Context, req *UserFunctionError) (*empty.Empty, error) { +func (*UnimplementedEntityDiscoveryServer) ReportError(context.Context, *UserFunctionError) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method ReportError not implemented") } @@ -975,5 +1699,5 @@ var _EntityDiscovery_serviceDesc = grpc.ServiceDesc{ }, }, Streams: []grpc.StreamDesc{}, - Metadata: "cloudstate/entity.proto", + Metadata: "entity.proto", } diff --git a/cloudstate/protocol/error.go b/cloudstate/protocol/error.go new file mode 100644 index 0000000..11a160d --- /dev/null +++ b/cloudstate/protocol/error.go @@ -0,0 +1,51 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package protocol + +type ClientError struct { + Err error +} + +func (e ClientError) Is(err error) bool { + _, ok := err.(ClientError) + return ok +} + +func (e ClientError) Error() string { + return e.Err.Error() +} + +func (e ClientError) Unwrap() error { + return e.Err +} + +type ServerError struct { + Failure *Failure + Err error +} + +func (e ServerError) Is(err error) bool { + _, ok := err.(ServerError) + return ok +} + +func (e ServerError) Error() string { + return e.Err.Error() +} + +func (e ServerError) Unwrap() error { + return e.Err +} diff --git a/cloudstate/protocol/error_test.go b/cloudstate/protocol/error_test.go new file mode 100644 index 0000000..5766b0b --- /dev/null +++ b/cloudstate/protocol/error_test.go @@ -0,0 +1,51 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package protocol + +import ( + "errors" + "fmt" + "testing" +) + +var ErrTest1 = errors.New("test1 error") + +func TestClientFailure_Error(t *testing.T) { + t.Run("test protocol error", func(t *testing.T) { + failure0 := ServerError{ + Failure: &Failure{CommandId: 0}, + Err: fmt.Errorf("its an unusual error: %w", ErrTest1), + } + + if is := errors.Is(&failure0, ErrTest1); !is { + t.Error("errors.Is(ErrTest1, failure0)") + } + + wrapped0 := fmt.Errorf("wrapped0: %w", failure0) + f := &ServerError{} + if !errors.As(wrapped0, f) { + t.Error("!errors.As(wrapped0, f)") + } + + wrapped1 := errors.Unwrap(f) + wrapped2 := errors.Unwrap(wrapped1) + wrapped3 := errors.Unwrap(wrapped2) + fmt.Printf("f: %v\n", wrapped3) + if wrapped3 != nil { + t.Error("wrapped3 != nil") + } + }) +} diff --git a/cloudstate/protocol/event_sourced.pb.go b/cloudstate/protocol/event_sourced.pb.go deleted file mode 100644 index ebd90d6..0000000 --- a/cloudstate/protocol/event_sourced.pb.go +++ /dev/null @@ -1,624 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: cloudstate/event_sourced.proto - -package protocol - -import ( - context "context" - fmt "fmt" - proto "github.com/golang/protobuf/proto" - any "github.com/golang/protobuf/ptypes/any" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -// The init message. This will always be the first message sent to the entity when -// it is loaded. -type EventSourcedInit struct { - ServiceName string `protobuf:"bytes,1,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` - // The ID of the entity. - EntityId string `protobuf:"bytes,2,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"` - // If present the entity should initialise its state using this snapshot. - Snapshot *EventSourcedSnapshot `protobuf:"bytes,3,opt,name=snapshot,proto3" json:"snapshot,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EventSourcedInit) Reset() { *m = EventSourcedInit{} } -func (m *EventSourcedInit) String() string { return proto.CompactTextString(m) } -func (*EventSourcedInit) ProtoMessage() {} -func (*EventSourcedInit) Descriptor() ([]byte, []int) { - return fileDescriptor_e62d03156a02a758, []int{0} -} - -func (m *EventSourcedInit) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EventSourcedInit.Unmarshal(m, b) -} -func (m *EventSourcedInit) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EventSourcedInit.Marshal(b, m, deterministic) -} -func (m *EventSourcedInit) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventSourcedInit.Merge(m, src) -} -func (m *EventSourcedInit) XXX_Size() int { - return xxx_messageInfo_EventSourcedInit.Size(m) -} -func (m *EventSourcedInit) XXX_DiscardUnknown() { - xxx_messageInfo_EventSourcedInit.DiscardUnknown(m) -} - -var xxx_messageInfo_EventSourcedInit proto.InternalMessageInfo - -func (m *EventSourcedInit) GetServiceName() string { - if m != nil { - return m.ServiceName - } - return "" -} - -func (m *EventSourcedInit) GetEntityId() string { - if m != nil { - return m.EntityId - } - return "" -} - -func (m *EventSourcedInit) GetSnapshot() *EventSourcedSnapshot { - if m != nil { - return m.Snapshot - } - return nil -} - -// A snapshot -type EventSourcedSnapshot struct { - // The sequence number when the snapshot was taken. - SnapshotSequence int64 `protobuf:"varint,1,opt,name=snapshot_sequence,json=snapshotSequence,proto3" json:"snapshot_sequence,omitempty"` - // The snapshot. - Snapshot *any.Any `protobuf:"bytes,2,opt,name=snapshot,proto3" json:"snapshot,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EventSourcedSnapshot) Reset() { *m = EventSourcedSnapshot{} } -func (m *EventSourcedSnapshot) String() string { return proto.CompactTextString(m) } -func (*EventSourcedSnapshot) ProtoMessage() {} -func (*EventSourcedSnapshot) Descriptor() ([]byte, []int) { - return fileDescriptor_e62d03156a02a758, []int{1} -} - -func (m *EventSourcedSnapshot) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EventSourcedSnapshot.Unmarshal(m, b) -} -func (m *EventSourcedSnapshot) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EventSourcedSnapshot.Marshal(b, m, deterministic) -} -func (m *EventSourcedSnapshot) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventSourcedSnapshot.Merge(m, src) -} -func (m *EventSourcedSnapshot) XXX_Size() int { - return xxx_messageInfo_EventSourcedSnapshot.Size(m) -} -func (m *EventSourcedSnapshot) XXX_DiscardUnknown() { - xxx_messageInfo_EventSourcedSnapshot.DiscardUnknown(m) -} - -var xxx_messageInfo_EventSourcedSnapshot proto.InternalMessageInfo - -func (m *EventSourcedSnapshot) GetSnapshotSequence() int64 { - if m != nil { - return m.SnapshotSequence - } - return 0 -} - -func (m *EventSourcedSnapshot) GetSnapshot() *any.Any { - if m != nil { - return m.Snapshot - } - return nil -} - -// An event. These will be sent to the entity when the entity starts up. -type EventSourcedEvent struct { - // The sequence number of the event. - Sequence int64 `protobuf:"varint,1,opt,name=sequence,proto3" json:"sequence,omitempty"` - // The event payload. - Payload *any.Any `protobuf:"bytes,2,opt,name=payload,proto3" json:"payload,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EventSourcedEvent) Reset() { *m = EventSourcedEvent{} } -func (m *EventSourcedEvent) String() string { return proto.CompactTextString(m) } -func (*EventSourcedEvent) ProtoMessage() {} -func (*EventSourcedEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_e62d03156a02a758, []int{2} -} - -func (m *EventSourcedEvent) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EventSourcedEvent.Unmarshal(m, b) -} -func (m *EventSourcedEvent) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EventSourcedEvent.Marshal(b, m, deterministic) -} -func (m *EventSourcedEvent) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventSourcedEvent.Merge(m, src) -} -func (m *EventSourcedEvent) XXX_Size() int { - return xxx_messageInfo_EventSourcedEvent.Size(m) -} -func (m *EventSourcedEvent) XXX_DiscardUnknown() { - xxx_messageInfo_EventSourcedEvent.DiscardUnknown(m) -} - -var xxx_messageInfo_EventSourcedEvent proto.InternalMessageInfo - -func (m *EventSourcedEvent) GetSequence() int64 { - if m != nil { - return m.Sequence - } - return 0 -} - -func (m *EventSourcedEvent) GetPayload() *any.Any { - if m != nil { - return m.Payload - } - return nil -} - -// A reply to a command. -type EventSourcedReply struct { - // The id of the command being replied to. Must match the input command. - CommandId int64 `protobuf:"varint,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"` - // The action to take - ClientAction *ClientAction `protobuf:"bytes,2,opt,name=client_action,json=clientAction,proto3" json:"client_action,omitempty"` - // Any side effects to perform - SideEffects []*SideEffect `protobuf:"bytes,3,rep,name=side_effects,json=sideEffects,proto3" json:"side_effects,omitempty"` - // A list of events to persist - these will be persisted before the reply - // is sent. - Events []*any.Any `protobuf:"bytes,4,rep,name=events,proto3" json:"events,omitempty"` - // An optional snapshot to persist. It is assumed that this snapshot will have - // the state of any events in the events field applied to it. It is illegal to - // send a snapshot without sending any events. - Snapshot *any.Any `protobuf:"bytes,5,opt,name=snapshot,proto3" json:"snapshot,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EventSourcedReply) Reset() { *m = EventSourcedReply{} } -func (m *EventSourcedReply) String() string { return proto.CompactTextString(m) } -func (*EventSourcedReply) ProtoMessage() {} -func (*EventSourcedReply) Descriptor() ([]byte, []int) { - return fileDescriptor_e62d03156a02a758, []int{3} -} - -func (m *EventSourcedReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EventSourcedReply.Unmarshal(m, b) -} -func (m *EventSourcedReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EventSourcedReply.Marshal(b, m, deterministic) -} -func (m *EventSourcedReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventSourcedReply.Merge(m, src) -} -func (m *EventSourcedReply) XXX_Size() int { - return xxx_messageInfo_EventSourcedReply.Size(m) -} -func (m *EventSourcedReply) XXX_DiscardUnknown() { - xxx_messageInfo_EventSourcedReply.DiscardUnknown(m) -} - -var xxx_messageInfo_EventSourcedReply proto.InternalMessageInfo - -func (m *EventSourcedReply) GetCommandId() int64 { - if m != nil { - return m.CommandId - } - return 0 -} - -func (m *EventSourcedReply) GetClientAction() *ClientAction { - if m != nil { - return m.ClientAction - } - return nil -} - -func (m *EventSourcedReply) GetSideEffects() []*SideEffect { - if m != nil { - return m.SideEffects - } - return nil -} - -func (m *EventSourcedReply) GetEvents() []*any.Any { - if m != nil { - return m.Events - } - return nil -} - -func (m *EventSourcedReply) GetSnapshot() *any.Any { - if m != nil { - return m.Snapshot - } - return nil -} - -// Input message type for the gRPC stream in. -type EventSourcedStreamIn struct { - // Types that are valid to be assigned to Message: - // *EventSourcedStreamIn_Init - // *EventSourcedStreamIn_Event - // *EventSourcedStreamIn_Command - Message isEventSourcedStreamIn_Message `protobuf_oneof:"message"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EventSourcedStreamIn) Reset() { *m = EventSourcedStreamIn{} } -func (m *EventSourcedStreamIn) String() string { return proto.CompactTextString(m) } -func (*EventSourcedStreamIn) ProtoMessage() {} -func (*EventSourcedStreamIn) Descriptor() ([]byte, []int) { - return fileDescriptor_e62d03156a02a758, []int{4} -} - -func (m *EventSourcedStreamIn) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EventSourcedStreamIn.Unmarshal(m, b) -} -func (m *EventSourcedStreamIn) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EventSourcedStreamIn.Marshal(b, m, deterministic) -} -func (m *EventSourcedStreamIn) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventSourcedStreamIn.Merge(m, src) -} -func (m *EventSourcedStreamIn) XXX_Size() int { - return xxx_messageInfo_EventSourcedStreamIn.Size(m) -} -func (m *EventSourcedStreamIn) XXX_DiscardUnknown() { - xxx_messageInfo_EventSourcedStreamIn.DiscardUnknown(m) -} - -var xxx_messageInfo_EventSourcedStreamIn proto.InternalMessageInfo - -type isEventSourcedStreamIn_Message interface { - isEventSourcedStreamIn_Message() -} - -type EventSourcedStreamIn_Init struct { - Init *EventSourcedInit `protobuf:"bytes,1,opt,name=init,proto3,oneof"` -} - -type EventSourcedStreamIn_Event struct { - Event *EventSourcedEvent `protobuf:"bytes,2,opt,name=event,proto3,oneof"` -} - -type EventSourcedStreamIn_Command struct { - Command *Command `protobuf:"bytes,3,opt,name=command,proto3,oneof"` -} - -func (*EventSourcedStreamIn_Init) isEventSourcedStreamIn_Message() {} - -func (*EventSourcedStreamIn_Event) isEventSourcedStreamIn_Message() {} - -func (*EventSourcedStreamIn_Command) isEventSourcedStreamIn_Message() {} - -func (m *EventSourcedStreamIn) GetMessage() isEventSourcedStreamIn_Message { - if m != nil { - return m.Message - } - return nil -} - -func (m *EventSourcedStreamIn) GetInit() *EventSourcedInit { - if x, ok := m.GetMessage().(*EventSourcedStreamIn_Init); ok { - return x.Init - } - return nil -} - -func (m *EventSourcedStreamIn) GetEvent() *EventSourcedEvent { - if x, ok := m.GetMessage().(*EventSourcedStreamIn_Event); ok { - return x.Event - } - return nil -} - -func (m *EventSourcedStreamIn) GetCommand() *Command { - if x, ok := m.GetMessage().(*EventSourcedStreamIn_Command); ok { - return x.Command - } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*EventSourcedStreamIn) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*EventSourcedStreamIn_Init)(nil), - (*EventSourcedStreamIn_Event)(nil), - (*EventSourcedStreamIn_Command)(nil), - } -} - -// Output message type for the gRPC stream out. -type EventSourcedStreamOut struct { - // Types that are valid to be assigned to Message: - // *EventSourcedStreamOut_Reply - // *EventSourcedStreamOut_Failure - Message isEventSourcedStreamOut_Message `protobuf_oneof:"message"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *EventSourcedStreamOut) Reset() { *m = EventSourcedStreamOut{} } -func (m *EventSourcedStreamOut) String() string { return proto.CompactTextString(m) } -func (*EventSourcedStreamOut) ProtoMessage() {} -func (*EventSourcedStreamOut) Descriptor() ([]byte, []int) { - return fileDescriptor_e62d03156a02a758, []int{5} -} - -func (m *EventSourcedStreamOut) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_EventSourcedStreamOut.Unmarshal(m, b) -} -func (m *EventSourcedStreamOut) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_EventSourcedStreamOut.Marshal(b, m, deterministic) -} -func (m *EventSourcedStreamOut) XXX_Merge(src proto.Message) { - xxx_messageInfo_EventSourcedStreamOut.Merge(m, src) -} -func (m *EventSourcedStreamOut) XXX_Size() int { - return xxx_messageInfo_EventSourcedStreamOut.Size(m) -} -func (m *EventSourcedStreamOut) XXX_DiscardUnknown() { - xxx_messageInfo_EventSourcedStreamOut.DiscardUnknown(m) -} - -var xxx_messageInfo_EventSourcedStreamOut proto.InternalMessageInfo - -type isEventSourcedStreamOut_Message interface { - isEventSourcedStreamOut_Message() -} - -type EventSourcedStreamOut_Reply struct { - Reply *EventSourcedReply `protobuf:"bytes,1,opt,name=reply,proto3,oneof"` -} - -type EventSourcedStreamOut_Failure struct { - Failure *Failure `protobuf:"bytes,2,opt,name=failure,proto3,oneof"` -} - -func (*EventSourcedStreamOut_Reply) isEventSourcedStreamOut_Message() {} - -func (*EventSourcedStreamOut_Failure) isEventSourcedStreamOut_Message() {} - -func (m *EventSourcedStreamOut) GetMessage() isEventSourcedStreamOut_Message { - if m != nil { - return m.Message - } - return nil -} - -func (m *EventSourcedStreamOut) GetReply() *EventSourcedReply { - if x, ok := m.GetMessage().(*EventSourcedStreamOut_Reply); ok { - return x.Reply - } - return nil -} - -func (m *EventSourcedStreamOut) GetFailure() *Failure { - if x, ok := m.GetMessage().(*EventSourcedStreamOut_Failure); ok { - return x.Failure - } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*EventSourcedStreamOut) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*EventSourcedStreamOut_Reply)(nil), - (*EventSourcedStreamOut_Failure)(nil), - } -} - -func init() { - proto.RegisterType((*EventSourcedInit)(nil), "cloudstate.eventsourced.EventSourcedInit") - proto.RegisterType((*EventSourcedSnapshot)(nil), "cloudstate.eventsourced.EventSourcedSnapshot") - proto.RegisterType((*EventSourcedEvent)(nil), "cloudstate.eventsourced.EventSourcedEvent") - proto.RegisterType((*EventSourcedReply)(nil), "cloudstate.eventsourced.EventSourcedReply") - proto.RegisterType((*EventSourcedStreamIn)(nil), "cloudstate.eventsourced.EventSourcedStreamIn") - proto.RegisterType((*EventSourcedStreamOut)(nil), "cloudstate.eventsourced.EventSourcedStreamOut") -} - -func init() { proto.RegisterFile("cloudstate/event_sourced.proto", fileDescriptor_e62d03156a02a758) } - -var fileDescriptor_e62d03156a02a758 = []byte{ - // 549 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0xcd, 0x6e, 0xd3, 0x4c, - 0x14, 0x8d, 0x9b, 0x36, 0x3f, 0x37, 0xf9, 0xa4, 0x76, 0xda, 0xaf, 0x35, 0x41, 0xa0, 0x90, 0x55, - 0xf8, 0xa9, 0x53, 0x85, 0x15, 0x0b, 0x84, 0x1a, 0x54, 0x94, 0x6c, 0xa8, 0xe4, 0xec, 0xd8, 0x58, - 0x53, 0xfb, 0x26, 0x1d, 0xc9, 0x9e, 0x09, 0x9e, 0x71, 0xa5, 0x2c, 0x78, 0x03, 0xf6, 0xac, 0x78, - 0x2e, 0x5e, 0x07, 0x79, 0x66, 0x1c, 0x26, 0xa5, 0xa0, 0xb0, 0x1b, 0xcf, 0x39, 0xe7, 0xde, 0x33, - 0xe7, 0xde, 0x04, 0x9e, 0xc6, 0xa9, 0x28, 0x12, 0xa9, 0xa8, 0xc2, 0x11, 0xde, 0x21, 0x57, 0x91, - 0x14, 0x45, 0x1e, 0x63, 0x12, 0xac, 0x72, 0xa1, 0x04, 0x39, 0xfb, 0x85, 0x07, 0x1a, 0xb7, 0x70, - 0xef, 0xd1, 0x52, 0x88, 0x65, 0x8a, 0x23, 0x4d, 0xbb, 0x29, 0x16, 0x23, 0xca, 0xd7, 0x46, 0xd3, - 0x3b, 0x73, 0x6b, 0x72, 0xc5, 0x94, 0x05, 0x06, 0xdf, 0x3d, 0x38, 0xbc, 0x2a, 0x8b, 0xcc, 0x4d, - 0x91, 0x19, 0x67, 0x8a, 0x3c, 0x83, 0xae, 0xc4, 0xfc, 0x8e, 0xc5, 0x18, 0x71, 0x9a, 0xa1, 0xef, - 0xf5, 0xbd, 0x61, 0x3b, 0xec, 0xd8, 0xbb, 0x8f, 0x34, 0x43, 0xf2, 0x18, 0xda, 0xa6, 0x4e, 0xc4, - 0x12, 0x7f, 0x4f, 0xe3, 0x2d, 0x73, 0x31, 0x4b, 0xc8, 0x0c, 0x5a, 0x92, 0xd3, 0x95, 0xbc, 0x15, - 0xca, 0xaf, 0xf7, 0xbd, 0x61, 0x67, 0x7c, 0x1e, 0xfc, 0xc1, 0x74, 0xe0, 0x36, 0x9f, 0x5b, 0x51, - 0xb8, 0x91, 0x0f, 0x0a, 0x38, 0x79, 0x88, 0x41, 0x5e, 0xc2, 0x51, 0xc5, 0x89, 0x24, 0x7e, 0x2e, - 0x90, 0xc7, 0xc6, 0x67, 0x3d, 0x3c, 0xac, 0x80, 0xb9, 0xbd, 0x27, 0x17, 0x8e, 0x9f, 0x3d, 0xed, - 0xe7, 0x24, 0x30, 0x59, 0x05, 0x55, 0x56, 0xc1, 0x25, 0x5f, 0x3b, 0x6d, 0x23, 0x38, 0x72, 0xdb, - 0xea, 0x33, 0xe9, 0x41, 0xeb, 0x5e, 0xab, 0xcd, 0x37, 0x09, 0xa0, 0xb9, 0xa2, 0xeb, 0x54, 0xd0, - 0xe4, 0xaf, 0x1d, 0x2a, 0xd2, 0xe0, 0xeb, 0xde, 0x76, 0x87, 0x10, 0x57, 0xe9, 0x9a, 0x3c, 0x01, - 0x88, 0x45, 0x96, 0x51, 0x9e, 0x94, 0xb1, 0x9a, 0x1e, 0x6d, 0x7b, 0x33, 0x4b, 0xc8, 0x5b, 0xf8, - 0x2f, 0x4e, 0x59, 0xb9, 0x11, 0x34, 0x56, 0x4c, 0x70, 0xdb, 0xca, 0x77, 0xc3, 0x7d, 0xaf, 0x09, - 0x97, 0x1a, 0x0f, 0xbb, 0xb1, 0xf3, 0x45, 0xde, 0x40, 0x57, 0xb2, 0x04, 0x23, 0x5c, 0x2c, 0x30, - 0x56, 0xd2, 0xaf, 0xf7, 0xeb, 0xc3, 0xce, 0xf8, 0xd4, 0x55, 0xcf, 0x59, 0x82, 0x57, 0x1a, 0x0e, - 0x3b, 0x72, 0x73, 0x96, 0xe4, 0x15, 0x34, 0xcc, 0xd4, 0xfc, 0x7d, 0x2d, 0x7a, 0xf8, 0x75, 0x96, - 0xb3, 0x95, 0xf7, 0xc1, 0x4e, 0x79, 0xff, 0xf0, 0xee, 0xcd, 0x59, 0xe5, 0x48, 0xb3, 0x19, 0x27, - 0xef, 0x60, 0x9f, 0x71, 0xa6, 0x74, 0x16, 0x9d, 0xf1, 0xf3, 0x9d, 0xd6, 0xa8, 0xdc, 0xe1, 0x69, - 0x2d, 0xd4, 0x42, 0x32, 0x81, 0x03, 0x4d, 0xb4, 0x59, 0xbd, 0xd8, 0xa9, 0x82, 0x3e, 0x4f, 0x6b, - 0xa1, 0x91, 0x92, 0x11, 0x34, 0xed, 0x10, 0xec, 0x3a, 0x1f, 0x6f, 0x25, 0x6e, 0xa0, 0x69, 0x2d, - 0xac, 0x58, 0x93, 0x36, 0x34, 0x33, 0x94, 0x92, 0x2e, 0x71, 0xf0, 0xcd, 0x83, 0xff, 0x7f, 0x7f, - 0xd9, 0x75, 0xa1, 0x9d, 0xe5, 0xe5, 0xd4, 0xed, 0xdb, 0x76, 0x73, 0xa6, 0xf7, 0xa4, 0x74, 0xa6, - 0xa5, 0xa5, 0xb3, 0x05, 0x65, 0x69, 0x91, 0xa3, 0x7d, 0xdf, 0x96, 0xb3, 0x0f, 0x06, 0x2a, 0x9d, - 0x59, 0x96, 0xe3, 0x6c, 0xfc, 0x05, 0xba, 0x6e, 0x65, 0x92, 0x41, 0xe3, 0x96, 0xf2, 0x24, 0x45, - 0xb2, 0xe3, 0xaf, 0xd5, 0xce, 0xa8, 0x17, 0xfc, 0x03, 0xfd, 0xba, 0x50, 0x83, 0xda, 0xd0, 0xbb, - 0xf0, 0x26, 0xe7, 0x70, 0xca, 0x84, 0xab, 0xd4, 0xab, 0x11, 0x8b, 0xf4, 0xd3, 0xb1, 0xf3, 0x67, - 0x55, 0x5d, 0xde, 0x34, 0xf4, 0xe9, 0xf5, 0xcf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x29, 0xfc, 0xf0, - 0xf2, 0x1e, 0x05, 0x00, 0x00, -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// EventSourcedClient is the client API for EventSourced service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type EventSourcedClient interface { - // The stream. One stream will be established per active entity. - // Once established, the first message sent will be Init, which contains the entity ID, and, - // if the entity has previously persisted a snapshot, it will contain that snapshot. It will - // then send zero to many event messages, one for each event previously persisted. The entity - // is expected to apply these to its state in a deterministic fashion. Once all the events - // are sent, one to many commands are sent, with new commands being sent as new requests for - // the entity come in. The entity is expected to reply to each command with exactly one reply - // message. The entity should reply in order, and any events that the entity requests to be - // persisted the entity should handle itself, applying them to its own state, as if they had - // arrived as events when the event stream was being replayed on load. - Handle(ctx context.Context, opts ...grpc.CallOption) (EventSourced_HandleClient, error) -} - -type eventSourcedClient struct { - cc *grpc.ClientConn -} - -func NewEventSourcedClient(cc *grpc.ClientConn) EventSourcedClient { - return &eventSourcedClient{cc} -} - -func (c *eventSourcedClient) Handle(ctx context.Context, opts ...grpc.CallOption) (EventSourced_HandleClient, error) { - stream, err := c.cc.NewStream(ctx, &_EventSourced_serviceDesc.Streams[0], "/cloudstate.eventsourced.EventSourced/handle", opts...) - if err != nil { - return nil, err - } - x := &eventSourcedHandleClient{stream} - return x, nil -} - -type EventSourced_HandleClient interface { - Send(*EventSourcedStreamIn) error - Recv() (*EventSourcedStreamOut, error) - grpc.ClientStream -} - -type eventSourcedHandleClient struct { - grpc.ClientStream -} - -func (x *eventSourcedHandleClient) Send(m *EventSourcedStreamIn) error { - return x.ClientStream.SendMsg(m) -} - -func (x *eventSourcedHandleClient) Recv() (*EventSourcedStreamOut, error) { - m := new(EventSourcedStreamOut) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// EventSourcedServer is the server API for EventSourced service. -type EventSourcedServer interface { - // The stream. One stream will be established per active entity. - // Once established, the first message sent will be Init, which contains the entity ID, and, - // if the entity has previously persisted a snapshot, it will contain that snapshot. It will - // then send zero to many event messages, one for each event previously persisted. The entity - // is expected to apply these to its state in a deterministic fashion. Once all the events - // are sent, one to many commands are sent, with new commands being sent as new requests for - // the entity come in. The entity is expected to reply to each command with exactly one reply - // message. The entity should reply in order, and any events that the entity requests to be - // persisted the entity should handle itself, applying them to its own state, as if they had - // arrived as events when the event stream was being replayed on load. - Handle(EventSourced_HandleServer) error -} - -// UnimplementedEventSourcedServer can be embedded to have forward compatible implementations. -type UnimplementedEventSourcedServer struct { -} - -func (*UnimplementedEventSourcedServer) Handle(srv EventSourced_HandleServer) error { - return status.Errorf(codes.Unimplemented, "method Handle not implemented") -} - -func RegisterEventSourcedServer(s *grpc.Server, srv EventSourcedServer) { - s.RegisterService(&_EventSourced_serviceDesc, srv) -} - -func _EventSourced_Handle_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(EventSourcedServer).Handle(&eventSourcedHandleServer{stream}) -} - -type EventSourced_HandleServer interface { - Send(*EventSourcedStreamOut) error - Recv() (*EventSourcedStreamIn, error) - grpc.ServerStream -} - -type eventSourcedHandleServer struct { - grpc.ServerStream -} - -func (x *eventSourcedHandleServer) Send(m *EventSourcedStreamOut) error { - return x.ServerStream.SendMsg(m) -} - -func (x *eventSourcedHandleServer) Recv() (*EventSourcedStreamIn, error) { - m := new(EventSourcedStreamIn) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -var _EventSourced_serviceDesc = grpc.ServiceDesc{ - ServiceName: "cloudstate.eventsourced.EventSourced", - HandlerType: (*EventSourcedServer)(nil), - Methods: []grpc.MethodDesc{}, - Streams: []grpc.StreamDesc{ - { - StreamName: "handle", - Handler: _EventSourced_Handle_Handler, - ServerStreams: true, - ClientStreams: true, - }, - }, - Metadata: "cloudstate/event_sourced.proto", -} diff --git a/cloudstate/protocol/function.pb.go b/cloudstate/protocol/function.pb.go deleted file mode 100644 index 02696c2..0000000 --- a/cloudstate/protocol/function.pb.go +++ /dev/null @@ -1,489 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: cloudstate/function.proto - -package protocol - -import ( - context "context" - fmt "fmt" - proto "github.com/golang/protobuf/proto" - any "github.com/golang/protobuf/ptypes/any" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -type FunctionCommand struct { - // The name of the service this function is on. - ServiceName string `protobuf:"bytes,2,opt,name=service_name,json=serviceName,proto3" json:"service_name,omitempty"` - // Command name - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - // The command payload. - Payload *any.Any `protobuf:"bytes,4,opt,name=payload,proto3" json:"payload,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FunctionCommand) Reset() { *m = FunctionCommand{} } -func (m *FunctionCommand) String() string { return proto.CompactTextString(m) } -func (*FunctionCommand) ProtoMessage() {} -func (*FunctionCommand) Descriptor() ([]byte, []int) { - return fileDescriptor_876d54e6158c20c4, []int{0} -} - -func (m *FunctionCommand) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FunctionCommand.Unmarshal(m, b) -} -func (m *FunctionCommand) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FunctionCommand.Marshal(b, m, deterministic) -} -func (m *FunctionCommand) XXX_Merge(src proto.Message) { - xxx_messageInfo_FunctionCommand.Merge(m, src) -} -func (m *FunctionCommand) XXX_Size() int { - return xxx_messageInfo_FunctionCommand.Size(m) -} -func (m *FunctionCommand) XXX_DiscardUnknown() { - xxx_messageInfo_FunctionCommand.DiscardUnknown(m) -} - -var xxx_messageInfo_FunctionCommand proto.InternalMessageInfo - -func (m *FunctionCommand) GetServiceName() string { - if m != nil { - return m.ServiceName - } - return "" -} - -func (m *FunctionCommand) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *FunctionCommand) GetPayload() *any.Any { - if m != nil { - return m.Payload - } - return nil -} - -type FunctionReply struct { - // Types that are valid to be assigned to Response: - // *FunctionReply_Reply - // *FunctionReply_Forward - Response isFunctionReply_Response `protobuf_oneof:"response"` - SideEffects []*SideEffect `protobuf:"bytes,4,rep,name=side_effects,json=sideEffects,proto3" json:"side_effects,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *FunctionReply) Reset() { *m = FunctionReply{} } -func (m *FunctionReply) String() string { return proto.CompactTextString(m) } -func (*FunctionReply) ProtoMessage() {} -func (*FunctionReply) Descriptor() ([]byte, []int) { - return fileDescriptor_876d54e6158c20c4, []int{1} -} - -func (m *FunctionReply) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_FunctionReply.Unmarshal(m, b) -} -func (m *FunctionReply) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_FunctionReply.Marshal(b, m, deterministic) -} -func (m *FunctionReply) XXX_Merge(src proto.Message) { - xxx_messageInfo_FunctionReply.Merge(m, src) -} -func (m *FunctionReply) XXX_Size() int { - return xxx_messageInfo_FunctionReply.Size(m) -} -func (m *FunctionReply) XXX_DiscardUnknown() { - xxx_messageInfo_FunctionReply.DiscardUnknown(m) -} - -var xxx_messageInfo_FunctionReply proto.InternalMessageInfo - -type isFunctionReply_Response interface { - isFunctionReply_Response() -} - -type FunctionReply_Reply struct { - Reply *Reply `protobuf:"bytes,2,opt,name=reply,proto3,oneof"` -} - -type FunctionReply_Forward struct { - Forward *Forward `protobuf:"bytes,3,opt,name=forward,proto3,oneof"` -} - -func (*FunctionReply_Reply) isFunctionReply_Response() {} - -func (*FunctionReply_Forward) isFunctionReply_Response() {} - -func (m *FunctionReply) GetResponse() isFunctionReply_Response { - if m != nil { - return m.Response - } - return nil -} - -func (m *FunctionReply) GetReply() *Reply { - if x, ok := m.GetResponse().(*FunctionReply_Reply); ok { - return x.Reply - } - return nil -} - -func (m *FunctionReply) GetForward() *Forward { - if x, ok := m.GetResponse().(*FunctionReply_Forward); ok { - return x.Forward - } - return nil -} - -func (m *FunctionReply) GetSideEffects() []*SideEffect { - if m != nil { - return m.SideEffects - } - return nil -} - -// XXX_OneofWrappers is for the internal use of the proto package. -func (*FunctionReply) XXX_OneofWrappers() []interface{} { - return []interface{}{ - (*FunctionReply_Reply)(nil), - (*FunctionReply_Forward)(nil), - } -} - -func init() { - proto.RegisterType((*FunctionCommand)(nil), "cloudstate.function.FunctionCommand") - proto.RegisterType((*FunctionReply)(nil), "cloudstate.function.FunctionReply") -} - -func init() { proto.RegisterFile("cloudstate/function.proto", fileDescriptor_876d54e6158c20c4) } - -var fileDescriptor_876d54e6158c20c4 = []byte{ - // 383 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x93, 0x4f, 0xaf, 0xd2, 0x40, - 0x14, 0xc5, 0xa9, 0xa0, 0xe8, 0x2d, 0xfe, 0x61, 0x30, 0x08, 0xac, 0xb0, 0x71, 0x51, 0x17, 0x4e, - 0x49, 0x5d, 0xb9, 0x14, 0x23, 0xc1, 0x8d, 0x26, 0x25, 0x2e, 0x74, 0x03, 0x43, 0xe7, 0x16, 0x9b, - 0xb4, 0x33, 0xcd, 0xcc, 0x54, 0xed, 0x07, 0xf1, 0x8b, 0xf8, 0x09, 0x5f, 0x98, 0xd2, 0xf7, 0xca, - 0xcb, 0xcb, 0x5b, 0xb1, 0x3b, 0x99, 0xf3, 0x9b, 0x7b, 0xce, 0xed, 0x1f, 0x98, 0xc6, 0x99, 0x2c, - 0xb9, 0x36, 0xcc, 0x60, 0x90, 0x94, 0x22, 0x36, 0xa9, 0x14, 0xb4, 0x50, 0xd2, 0x48, 0x32, 0xba, - 0xb1, 0x68, 0x63, 0xcd, 0xa6, 0x07, 0x29, 0x0f, 0x19, 0x06, 0x16, 0xd9, 0x97, 0x49, 0xc0, 0x44, - 0x55, 0xf3, 0xb3, 0x57, 0xad, 0x51, 0x28, 0x4c, 0x6a, 0x4e, 0x86, 0xf7, 0x17, 0x9e, 0xaf, 0x4e, - 0xf7, 0x3f, 0xc9, 0x3c, 0x67, 0x82, 0x93, 0xd7, 0x30, 0xd0, 0xa8, 0x7e, 0xa7, 0x31, 0x6e, 0x05, - 0xcb, 0x71, 0xf2, 0x60, 0xee, 0xf8, 0x4f, 0x22, 0xf7, 0x74, 0xf6, 0x95, 0xe5, 0x48, 0x08, 0xf4, - 0xac, 0xd5, 0xb5, 0x96, 0xd5, 0x84, 0x42, 0xbf, 0x60, 0x55, 0x26, 0x19, 0x9f, 0xf4, 0xe6, 0x8e, - 0xef, 0x86, 0x2f, 0x69, 0xdd, 0x87, 0x36, 0x7d, 0xe8, 0x47, 0x51, 0x45, 0x0d, 0xe4, 0xfd, 0x77, - 0xe0, 0x69, 0x13, 0x1d, 0x61, 0x91, 0x55, 0xe4, 0x2d, 0x3c, 0x54, 0x47, 0x61, 0x13, 0xdd, 0x70, - 0x48, 0x5b, 0x4b, 0x5a, 0x62, 0xdd, 0x89, 0x6a, 0x82, 0x04, 0xd0, 0x4f, 0xa4, 0xfa, 0xc3, 0x14, - 0xb7, 0x1d, 0xdc, 0x70, 0xd4, 0x86, 0x57, 0xb5, 0xb5, 0xee, 0x44, 0x0d, 0x45, 0x3e, 0xc0, 0x40, - 0xa7, 0x1c, 0xb7, 0x98, 0x24, 0x18, 0x1b, 0x3d, 0xe9, 0xcd, 0xbb, 0xbe, 0x1b, 0x8e, 0xdb, 0xb7, - 0x36, 0x29, 0xc7, 0xcf, 0xd6, 0x8e, 0x5c, 0x7d, 0xad, 0xf5, 0x12, 0xe0, 0xb1, 0x42, 0x5d, 0x48, - 0xa1, 0x31, 0xfc, 0xd7, 0x85, 0xe1, 0xe6, 0x48, 0x67, 0xa8, 0x75, 0xd3, 0x9e, 0xfc, 0x00, 0xf7, - 0x17, 0x13, 0x3c, 0xc3, 0xef, 0x82, 0xa9, 0x8a, 0xbc, 0xa1, 0x77, 0xbc, 0x1d, 0x7a, 0xeb, 0x31, - 0xcf, 0xbc, 0x7b, 0x29, 0xbb, 0xaf, 0xd7, 0x21, 0x3b, 0x78, 0x51, 0x8f, 0xde, 0x18, 0x85, 0x2c, - 0x47, 0xfe, 0x45, 0x5c, 0x72, 0xbe, 0xef, 0x10, 0x06, 0xc3, 0xf3, 0x84, 0x6f, 0xa5, 0xb9, 0x64, - 0xc4, 0xc2, 0x21, 0x3b, 0x78, 0x76, 0x1e, 0x71, 0xd9, 0x15, 0x16, 0xce, 0xf2, 0x1d, 0x8c, 0x53, - 0xd9, 0xa6, 0xed, 0x37, 0x17, 0xcb, 0xec, 0x67, 0xeb, 0x4f, 0x09, 0x9a, 0xc3, 0xfd, 0x23, 0xab, - 0xde, 0x5f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x25, 0xcb, 0xb1, 0x9a, 0x62, 0x03, 0x00, 0x00, -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// StatelessFunctionClient is the client API for StatelessFunction service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type StatelessFunctionClient interface { - HandleUnary(ctx context.Context, in *FunctionCommand, opts ...grpc.CallOption) (*FunctionReply, error) - HandleStreamedIn(ctx context.Context, opts ...grpc.CallOption) (StatelessFunction_HandleStreamedInClient, error) - HandleStreamedOut(ctx context.Context, in *FunctionCommand, opts ...grpc.CallOption) (StatelessFunction_HandleStreamedOutClient, error) - HandleStreamed(ctx context.Context, opts ...grpc.CallOption) (StatelessFunction_HandleStreamedClient, error) -} - -type statelessFunctionClient struct { - cc *grpc.ClientConn -} - -func NewStatelessFunctionClient(cc *grpc.ClientConn) StatelessFunctionClient { - return &statelessFunctionClient{cc} -} - -func (c *statelessFunctionClient) HandleUnary(ctx context.Context, in *FunctionCommand, opts ...grpc.CallOption) (*FunctionReply, error) { - out := new(FunctionReply) - err := c.cc.Invoke(ctx, "/cloudstate.function.StatelessFunction/handleUnary", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *statelessFunctionClient) HandleStreamedIn(ctx context.Context, opts ...grpc.CallOption) (StatelessFunction_HandleStreamedInClient, error) { - stream, err := c.cc.NewStream(ctx, &_StatelessFunction_serviceDesc.Streams[0], "/cloudstate.function.StatelessFunction/handleStreamedIn", opts...) - if err != nil { - return nil, err - } - x := &statelessFunctionHandleStreamedInClient{stream} - return x, nil -} - -type StatelessFunction_HandleStreamedInClient interface { - Send(*FunctionCommand) error - CloseAndRecv() (*FunctionReply, error) - grpc.ClientStream -} - -type statelessFunctionHandleStreamedInClient struct { - grpc.ClientStream -} - -func (x *statelessFunctionHandleStreamedInClient) Send(m *FunctionCommand) error { - return x.ClientStream.SendMsg(m) -} - -func (x *statelessFunctionHandleStreamedInClient) CloseAndRecv() (*FunctionReply, error) { - if err := x.ClientStream.CloseSend(); err != nil { - return nil, err - } - m := new(FunctionReply) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *statelessFunctionClient) HandleStreamedOut(ctx context.Context, in *FunctionCommand, opts ...grpc.CallOption) (StatelessFunction_HandleStreamedOutClient, error) { - stream, err := c.cc.NewStream(ctx, &_StatelessFunction_serviceDesc.Streams[1], "/cloudstate.function.StatelessFunction/handleStreamedOut", opts...) - if err != nil { - return nil, err - } - x := &statelessFunctionHandleStreamedOutClient{stream} - if err := x.ClientStream.SendMsg(in); err != nil { - return nil, err - } - if err := x.ClientStream.CloseSend(); err != nil { - return nil, err - } - return x, nil -} - -type StatelessFunction_HandleStreamedOutClient interface { - Recv() (*FunctionReply, error) - grpc.ClientStream -} - -type statelessFunctionHandleStreamedOutClient struct { - grpc.ClientStream -} - -func (x *statelessFunctionHandleStreamedOutClient) Recv() (*FunctionReply, error) { - m := new(FunctionReply) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func (c *statelessFunctionClient) HandleStreamed(ctx context.Context, opts ...grpc.CallOption) (StatelessFunction_HandleStreamedClient, error) { - stream, err := c.cc.NewStream(ctx, &_StatelessFunction_serviceDesc.Streams[2], "/cloudstate.function.StatelessFunction/handleStreamed", opts...) - if err != nil { - return nil, err - } - x := &statelessFunctionHandleStreamedClient{stream} - return x, nil -} - -type StatelessFunction_HandleStreamedClient interface { - Send(*FunctionCommand) error - Recv() (*FunctionReply, error) - grpc.ClientStream -} - -type statelessFunctionHandleStreamedClient struct { - grpc.ClientStream -} - -func (x *statelessFunctionHandleStreamedClient) Send(m *FunctionCommand) error { - return x.ClientStream.SendMsg(m) -} - -func (x *statelessFunctionHandleStreamedClient) Recv() (*FunctionReply, error) { - m := new(FunctionReply) - if err := x.ClientStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -// StatelessFunctionServer is the server API for StatelessFunction service. -type StatelessFunctionServer interface { - HandleUnary(context.Context, *FunctionCommand) (*FunctionReply, error) - HandleStreamedIn(StatelessFunction_HandleStreamedInServer) error - HandleStreamedOut(*FunctionCommand, StatelessFunction_HandleStreamedOutServer) error - HandleStreamed(StatelessFunction_HandleStreamedServer) error -} - -// UnimplementedStatelessFunctionServer can be embedded to have forward compatible implementations. -type UnimplementedStatelessFunctionServer struct { -} - -func (*UnimplementedStatelessFunctionServer) HandleUnary(ctx context.Context, req *FunctionCommand) (*FunctionReply, error) { - return nil, status.Errorf(codes.Unimplemented, "method HandleUnary not implemented") -} -func (*UnimplementedStatelessFunctionServer) HandleStreamedIn(srv StatelessFunction_HandleStreamedInServer) error { - return status.Errorf(codes.Unimplemented, "method HandleStreamedIn not implemented") -} -func (*UnimplementedStatelessFunctionServer) HandleStreamedOut(req *FunctionCommand, srv StatelessFunction_HandleStreamedOutServer) error { - return status.Errorf(codes.Unimplemented, "method HandleStreamedOut not implemented") -} -func (*UnimplementedStatelessFunctionServer) HandleStreamed(srv StatelessFunction_HandleStreamedServer) error { - return status.Errorf(codes.Unimplemented, "method HandleStreamed not implemented") -} - -func RegisterStatelessFunctionServer(s *grpc.Server, srv StatelessFunctionServer) { - s.RegisterService(&_StatelessFunction_serviceDesc, srv) -} - -func _StatelessFunction_HandleUnary_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(FunctionCommand) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(StatelessFunctionServer).HandleUnary(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/cloudstate.function.StatelessFunction/HandleUnary", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(StatelessFunctionServer).HandleUnary(ctx, req.(*FunctionCommand)) - } - return interceptor(ctx, in, info, handler) -} - -func _StatelessFunction_HandleStreamedIn_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(StatelessFunctionServer).HandleStreamedIn(&statelessFunctionHandleStreamedInServer{stream}) -} - -type StatelessFunction_HandleStreamedInServer interface { - SendAndClose(*FunctionReply) error - Recv() (*FunctionCommand, error) - grpc.ServerStream -} - -type statelessFunctionHandleStreamedInServer struct { - grpc.ServerStream -} - -func (x *statelessFunctionHandleStreamedInServer) SendAndClose(m *FunctionReply) error { - return x.ServerStream.SendMsg(m) -} - -func (x *statelessFunctionHandleStreamedInServer) Recv() (*FunctionCommand, error) { - m := new(FunctionCommand) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -func _StatelessFunction_HandleStreamedOut_Handler(srv interface{}, stream grpc.ServerStream) error { - m := new(FunctionCommand) - if err := stream.RecvMsg(m); err != nil { - return err - } - return srv.(StatelessFunctionServer).HandleStreamedOut(m, &statelessFunctionHandleStreamedOutServer{stream}) -} - -type StatelessFunction_HandleStreamedOutServer interface { - Send(*FunctionReply) error - grpc.ServerStream -} - -type statelessFunctionHandleStreamedOutServer struct { - grpc.ServerStream -} - -func (x *statelessFunctionHandleStreamedOutServer) Send(m *FunctionReply) error { - return x.ServerStream.SendMsg(m) -} - -func _StatelessFunction_HandleStreamed_Handler(srv interface{}, stream grpc.ServerStream) error { - return srv.(StatelessFunctionServer).HandleStreamed(&statelessFunctionHandleStreamedServer{stream}) -} - -type StatelessFunction_HandleStreamedServer interface { - Send(*FunctionReply) error - Recv() (*FunctionCommand, error) - grpc.ServerStream -} - -type statelessFunctionHandleStreamedServer struct { - grpc.ServerStream -} - -func (x *statelessFunctionHandleStreamedServer) Send(m *FunctionReply) error { - return x.ServerStream.SendMsg(m) -} - -func (x *statelessFunctionHandleStreamedServer) Recv() (*FunctionCommand, error) { - m := new(FunctionCommand) - if err := x.ServerStream.RecvMsg(m); err != nil { - return nil, err - } - return m, nil -} - -var _StatelessFunction_serviceDesc = grpc.ServiceDesc{ - ServiceName: "cloudstate.function.StatelessFunction", - HandlerType: (*StatelessFunctionServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "handleUnary", - Handler: _StatelessFunction_HandleUnary_Handler, - }, - }, - Streams: []grpc.StreamDesc{ - { - StreamName: "handleStreamedIn", - Handler: _StatelessFunction_HandleStreamedIn_Handler, - ClientStreams: true, - }, - { - StreamName: "handleStreamedOut", - Handler: _StatelessFunction_HandleStreamedOut_Handler, - ServerStreams: true, - }, - { - StreamName: "handleStreamed", - Handler: _StatelessFunction_HandleStreamed_Handler, - ServerStreams: true, - ClientStreams: true, - }, - }, - Metadata: "cloudstate/function.proto", -} diff --git a/cloudstate/protocol/types.go b/cloudstate/protocol/types.go new file mode 100644 index 0000000..200821e --- /dev/null +++ b/cloudstate/protocol/types.go @@ -0,0 +1,23 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package protocol + +const ( + EventSourced = "cloudstate.eventsourced.EventSourced" + CRDT = "cloudstate.crdt.Crdt" +) + +//_go:generate sh -c "protoc -I../../vendor/proto/api-common-protos -I ../.. internal/server/proto/server.proto --go_out=plugins=grpc:../.." diff --git a/docs/Makefile b/docs/Makefile index 676be5a..0d48d1b 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -46,12 +46,18 @@ attributes: ${cloudstate_antora} examples: # also create empty go module to ignore example sources + # https://youtrack.jetbrains.com/issue/GO-9320 + # https://github.com/golang/go/issues/30058 mkdir -p "${managed_examples}" touch "${managed_examples}/go.mod" - $(call copy_example,cloudstate/event.go) - $(call copy_example,cloudstate/eventsourced.go) - $(call copy_example,protobuf/example/shoppingcart/persistence/domain.proto) - $(call copy_example,tck/cmd/tck_shoppingcart/shoppingcart.go) + $(call copy_example,cloudstate/eventsourced/entity.go) + $(call copy_example,cloudstate/crdt/entity.go) + $(call copy_example,example/shoppingcart/entity.go) + $(call copy_example,example/shoppingcart/persistence/domain.proto) + $(call copy_example,tck/cmd/tck_eventsourced/tck_eventsourced.go) + $(call copy_example,example/crdt_shoppingcart/shoppingcart/entity.go) + $(call copy_example,example/crdt_shoppingcart/cmd/crdt_shoppingcart.go) + $(call copy_example,example/effects/shoppingcart/entity.go) ${descriptor}: ${cloudstate_antora} mkdir -p $$(dirname ${descriptor}) diff --git a/docs/src/modules/go/pages/crdt.adoc b/docs/src/modules/go/pages/crdt.adoc index 3729011..29fe094 100644 --- a/docs/src/modules/go/pages/crdt.adoc +++ b/docs/src/modules/go/pages/crdt.adoc @@ -1,6 +1,173 @@ = Conflict-free Replicated Data Types -* Explain how to use the CRDT API -* Explain how to use CrdtFactory and where it comes from -* Explain how to handle streamed calls -* Explain the APIs for each different CRDT +include::partial$include.adoc[] + +This page documents how to implement Cloudstate CRDT entities in Go. +For information on what Cloudstate CRDT entities are, please read the general xref:concepts:crdts.adoc[Conflict-free Replicated Data Type] documentation first. + +A CRDT entity can be created by implementing the {cloudstate-go-lib-api-base}/cloudstate/crdt#EntityHandler[`crdt.EntityHandler`] interface and registering an entity with a Cloudstate instance. + +[source,go] +---- +include::example$cloudstate/crdt/entity.go[tag=entity-handler] +---- + +== Accessing and creating an entity's CRDT + +Each CRDT entity manages one root CRDT. That CRDT will either be supplied to the entity by the proxy when it is started through {cloudstate-go-lib-api-base}/cloudstate/crdt#EntityHandler.Set[`crdt.EntityHandler.Set`], or, if no CRDT exists for the entity when it is started, it has to be created by the entity using the {cloudstate-go-lib-api-base}/cloudstate/crdt#EntityHandler.Default[`crdt.EntityHandler.Default`] factory method. + +[source,go] +---- +include::example$example/crdt_shoppingcart/shoppingcart/entity.go[tag=creation] +---- + +[NOTE] +==== +The state, the CRDT, supplied with `Set` by the Cloudstate instance will never be of a different type than what `Default` returns for a CRDT entity. +This is because of their symmetric use for the same entities instance and version. +In this regard, a type assertion check is not necessary. +==== + +== Handling commands + +Command handlers are implemented with the {cloudstate-go-lib-api-base}/cloudstate/crdt#EntityHandler.HandleCommand[`crdt.EntityHandler.HandleCommand`] method. +The command handler provides a `CommandContext`, a commands `name`, and the gRPCs message as a protobuf message. +The matching combination of a commands name and the messages type from the defined gRPC service can be used to handle the command. +So to handle the shopping cart service method `GetCart`: + +[source,go] +---- +rpc GetCart (GeShoppingCart) returns (Cart); +---- + +the commands name `GetCart` together with its message type `GetShoppingCart` has to be matched. +A type switch or a type assertion for the protobuf command message is useful to get the commands data, process it, and then return the appropriate return type, `Cart` in our example. + +The return type of the command handler must be the output type for the gRPC service call, this will be sent as the reply. + +The following shows the implementation of the `GetCart` command. +This command handler is a read-only command handler, it doesn't update the CRDT, it just returns some state: + +[source,go] +---- +include::example$example/crdt_shoppingcart/shoppingcart/entity.go[tag=command-handling-getcart-0] +include::example$example/crdt_shoppingcart/shoppingcart/entity.go[tag=command-handling-getcart-1] +---- + +== Updating a CRDT + +Due to Cloudstate's xref:concepts:crdts.adoc#approach-to-crdts-in-cloudstate[take in turns approach], CRDTs may only be updated in command handlers and <>. + +Here's a snipped for handling of the `AddLineItem` message that adds the item to the shopping cart. +If the gRPC service methods message identifies a service unambiguously, there is no need to dispatch the commands name. + +[source,go] +---- +include::example$example/crdt_shoppingcart/shoppingcart/entity.go[tag=add-item-0] +... +include::example$example/crdt_shoppingcart/shoppingcart/entity.go[tag=add-item-1] +include::example$example/crdt_shoppingcart/shoppingcart/entity.go[tag=add-item-2] +... +---- + +[TIP] +==== +It's good practice to dispatch commands both using their command name and messages type. +Unfortunately, the Go gRPC implementation does not provide typesafe service descriptors out of a compiled `*.proto` file as they are not exported to be user accessible. + +While the Go runtime function `runtime.FuncForPC` allows to get a function pointers pointed function name and there are ways to get the `shoppingcart.ShoppingCartServiceServer.AddItem` command name from the gRPC interface of the shopping cart service at runtime, we do not encourage doing so. +In general, the Cloudstate Go User Support library does use explicit ways to implement the gRPC service of a Cloudstate entity. +It could have been implemeted using reflection heavily, although this is non-idiomatic use of Go and would leave this library as a strange citizen in the Go ecosystem. +==== + +== Deleting a CRDT + +A CRDT can be deleted by invoking {cloudstate-go-lib-api-base}/cloudstate/crdt#Context.Delete[`crdt.Context.Delete`]. +Once a CRDT is deleted, the entity will be shut down, and all subsequent commands for the entity will be rejected. + +Caution should be taken when deleting CRDTs - the Reference Implementation of the proxy needs to maintain tombstones for each CRDT deleted, so over time, if many CRDTs are created and deleted, this will result in not just running out of memory, but increased network usage as the tombstones still need to be gossipped through the cluster for replication. + +== Streamed command handlers + +Streamed commands can be used to receive and publish updates to the state. +If a gRPC service call has a streamed result type, the handler for that call can use the {cloudstate-go-lib-api-base}/cloudstate/crdt#CommandContext[`crdt.CommandContext`], and use that to register handler functions. + +=== Responding to changes + +If the command handler wishes to publish changes to the stream it can register a handler function with {cloudstate-go-lib-api-base}/cloudstate/crdt#CommandContext.ChangeFunc[`crdt.CommandContext.ChangeFunc`], which will be invoked every time the CRDT changes. + +The handler function is then able to return a message to be sent to the client (or `empty.Empty`, if it wishes to send no message in response to that particular change). +The handler function may not modify the CRDT itself, but it may emit effects that may modify the CRDT. + +If the shopping cart service had a `WatchCart` call, like this: + +[source,protobuf] +---- +rpc WatchCart (GetShoppingCart) returns (stream Cart); +---- + +that could be implemented like this: + +[source,go] +---- +include::example$example/crdt_shoppingcart/shoppingcart/entity.go[tag=watch-cart] +---- + +=== Ending the stream + +The `ChangeFunc` handler function can end the stream by invoking {cloudstate-go-lib-api-base}/cloudstate/crdt#CommandContext.EndStream[`crdt.CommandContext.EndStream`] on the `CommandCOntext` it is passed. +If it does this, it will not receive an cancellation callback. + +=== Responding to stream cancellation + +A command handler may register an {cloudstate-go-lib-api-base}/cloudstate/crdt#CommandContext.CancelFunc[`crdt.CommandContext.CancelFunc`] handler function to be notified when the stream is cancelled. +The cancellation handler function may update the CRDT. This is useful if the CRDT is being used to track connections, for example, when using {cloudstate-go-lib-api-base}/cloudstate/crdt#Vote[`crdt.Vote`] CRDTs to track a user's online status. + +== Types of CRDTs + +The Cloudstate Go language support library offers Go types for each of the xref:concepts:crdts.adoc#crdts-available-in-cloudstate[CRDTs available in Cloudstate]. + +=== Counters and flags + +{cloudstate-go-lib-api-base}/cloudstate/crdt#GCounter[`crdt.GCounter`], {cloudstate-go-lib-api-base}/cloudstate/crdt#PNCounter[`crdt.PNCounter`] and {cloudstate-go-lib-api-base}/cloudstate/crdt#Flag[`crdt.Flag`] are available, offering operations relevant to each CRDT. + +=== Vote + +{cloudstate-go-lib-api-base}/cloudstate/crdt#Vote[`crdt.Vote`] is available for the Vote CRDT. The Vote CRDT allows updating the current node's vote using the {cloudstate-go-lib-api-base}/cloudstate/crdt#Vote.Vote[`crdt.Vote.Vote`] method, the current nodes vote can be queried using the {cloudstate-go-lib-api-base}/cloudstate/crdt#Vote.SelfVote[`crdt.Vote.SelfVote`] method. + +For determining the result of a vote, {cloudstate-go-lib-api-base}/cloudstate/crdt#Vote.Voters[`crdt.Vote.Voters`] and for determining the result of a vote, {cloudstate-go-lib-api-base}/cloudstate/crdt#Vote.VotesFor[`crdt.Vote.VotesFor`] can be used to check the total number of nodes, and the number of nodes that have voted for the condition, respectively. +In addition, convenience methods are provided for common vote decision approaches, {cloudstate-go-lib-api-base}/cloudstate/crdt#Vote.AtLeastOne[`crdt.Vote.AtLeastOne`] returns true if there is at least one voter for the condition. {cloudstate-go-lib-api-base}/cloudstate/crdt#Vote.Majority[`crdt.Vote.Majority`] returns true if the number of votes for is more than half the number of voters, and {cloudstate-go-lib-api-base}/cloudstate/crdt#Vote.All[`crdt.Vote.All`] returns `true` if the number of votes for equals the number of voters. + +=== Registers + +{cloudstate-go-lib-api-base}/cloudstate/crdt#LWWRegister[`crdt.LWWRegister`] provides the LWWRegister CRDT. It can be interacted with using the {cloudstate-go-lib-api-base}/cloudstate/crdt#LWWRegister.Set[`crdt.LWWRegister.Set`] and {cloudstate-go-lib-api-base}/cloudstate/crdt#LWWRegister.Value[`crdt.LWWRegister.Value`] methods. +If you wish to use a custom clock, you can use the {cloudstate-go-lib-api-base}/cloudstate/crdt#LWWRegister.SetWithClock[`crdt.LWWRegister.SetWithClock`] overload that allows passing a custom clock and custom clock value. + +=== Sets and Maps + +The Cloudstate Go support provides {cloudstate-go-lib-api-base}/cloudstate/crdt#GSet[`crdt.GSet`], {cloudstate-go-lib-api-base}/cloudstate/crdt#ORSet[`crdt.ORSet`] and {cloudstate-go-lib-api-base}/cloudstate/crdt#ORMap[`crdt.ORMap`]. + +[IMPORTANT] +==== +With Cloudstate maps and sets, the map keys and set values serialized form must be stable. +The Cloudstate proxy uses the serialized form of the values to track changes in the set or map. +If the same value serializes to two different sets of bytes on different occasions, they will be treated as different elements in the set or map. + +This is particularly relevant when using protocol buffers. +The ordering of map entries in a serialized protocol buffers is undefined, and very often will be different for two equal maps. +Hence, maps should never be used as keys in `ORMap` or as values in `GSet`, `ORSet`. +For the rest of the protocol buffers specification, while no guarantees are made on the stability by the specification itself, the Go protocol buffer libraries do https://pkg.go.dev/google.golang.org/protobuf/proto#MarshalOptions[produce stable orderings of fields and stable output of non-map values]. + +Care should be taken when changing the structure of protocol buffers. +Many changes that are backwards compatible from a protocol buffer standpoint do not necessarily translate into stable serializations. +==== + +== Registering the entity + +Once you've created your entity, you can register it with the {cloudstate-go-lib-api-base}/cloudstate#CloudState[`cloudstate.CloudState`] server, by invoking the {cloudstate-go-lib-api-base}/cloudstate#CloudState.RegisterCRDT[`cloudstate.CloudState.RegisterCRDT`] method. +In addition to passing your entity and service descriptor, if you use protocol buffers for serialization and any protobuf message definitions are missing from your service descriptor (they are not declared directly in the file, nor as dependencies), then you'll need to pass those protocol buffer descriptors as well. + +[source,go] +---- +include::example$example/crdt_shoppingcart/cmd/crdt_shoppingcart.go[tag=register-crdt] +---- \ No newline at end of file diff --git a/docs/src/modules/go/pages/effects.adoc b/docs/src/modules/go/pages/effects.adoc index afb58fb..9ea634a 100644 --- a/docs/src/modules/go/pages/effects.adoc +++ b/docs/src/modules/go/pages/effects.adoc @@ -1,5 +1,38 @@ = Forwarding and effects -* Explain the ServiceCallFactory interface -* Explain how to forward replies to another service. -* Explain how to emit effects. +include::partial$include.adoc[] + +This page documents how to use Cloudstate effects and forwarding in Go. +For high level information on what Cloudstate effects and forwarding is, please read the general xref:concepts:effects.adoc[forwarding and effects] documentation first. + +== Service References + +Unlike other language support libraries, the Go Support Library for Cloudstate is quite explicit and direct in the API types used. +The Forwarding and effects API being no different. + +The Go gRPC protobuf compiler plugin doesn't expose service descriptors. +As a consequence, command, forward and effect handlers require the user to provide unchecked plain strings to reference a commands gRPC service name or services method names. +The same applies for service names and command names used with effects and forwards. + +== Forwarding command + +The `Context` for each entity type provides a `Forward` method to allow forwarding a command by invoking {cloudstate-go-lib-api-base}/cloudstate/crdt#CommandContext.Forward[`crdt.CommandContext.Forward`]. +For example, if the item being processed in the `addItem` command is a "hot" item, we can make the `HotItems` entity aware of that item by forwarding a command: + +[source,go] +---- +include::example$example/effects/shoppingcart/entity.go[tag=forward] +---- + +== Emitting an effect + +The `Context` for each entity type provides a `SideEffect` method to allow forwarding a command by invoking {cloudstate-go-lib-api-base}/cloudstate/crdt#CommandContext.SideEffect[`crdt.CommandContext.SideEffect`]. +For example, upon successful completion of the `addItem` command by `ShoppingCartEntity`, if we also want to emit an effect on the `HotItems` entity, we would invoke the effectful service call as: + +[source,go] +---- +include::example$example/effects/shoppingcart/entity.go[tag=effect] +---- + +Please note that, contrary to command forwarding, the result of the effect is ignored by the current command `addItem`. +More details can be found in the common section xref:concepts:effects.adoc[Forwarding and effects]. \ No newline at end of file diff --git a/docs/src/modules/go/pages/eventsourced.adoc b/docs/src/modules/go/pages/eventsourced.adoc index 7880739..e9d8a8b 100644 --- a/docs/src/modules/go/pages/eventsourced.adoc +++ b/docs/src/modules/go/pages/eventsourced.adoc @@ -1,20 +1,22 @@ = Event sourcing +include::partial$include.adoc[] + This page documents how to implement Cloudstate event sourced entities in Go. For information on what Cloudstate event sourced entities are, please read the general xref:concepts:eventsourced.adoc[Event sourcing] documentation first. -An event sourced entity can be created by embedding the `cloudstate.EventEmitter` type and also implementing the `cloudstate.Entity` interface. +An event sourced entity can be created by implementing the {cloudstate-go-lib-api-base}/cloudstate/eventsourced#EntityHandler[`eventsourced.EntityHandler`] interface. [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=entity-type] +include::example$cloudstate/eventsourced/entity.go[tag=entity-type] ---- -Then by composing the Cloudstate entity with a `cloudstate.EventSourcedEntity` and register it with `CloudState.Register()`, your entity gets configured to be an event sourced entity and handled by the Cloudstate instance from now on. +Then register that entity with {cloudstate-go-lib-api-base}/cloudstate/cloudstate#RegisterEventSourced[`cloudstate.CloudState.RegisterEventSourced`], your entity gets configured to be an event sourced entity and handled by the Cloudstate instance from now on. [source,go] ---- -include::example$cloudstate/eventsourced.go[tag=event-sourced-entity-type] +include::example$tck/cmd/tck_eventsourced/tck_eventsourced.go[tag=event-sourced-entity-type] ---- The `ServiceName` is the fully qualified name of the gRPC service that implements this entity's interface. @@ -28,33 +30,38 @@ The `SnapshotEvery` parameter controls how often snapshots are taken, so that th If left unset, it defaults to 100. Setting it to a negative number will result in snapshots never being taken. -The `EntityFunc` is a factory method which generates a new Entity whenever Cloudstate has to initialize a new entity. +The `EntityFunc` is a factory function which generates a new entity whenever Cloudstate has to initialize one. + +[source,go] +---- +include::example$example/shoppingcart/entity.go[tag=entity-func] +---- == Persistence types and serialization Event sourced entities persist events and snapshots, and these need to be serialized when persisted. -The most straightforward way to persist events and snapshots is to use protobufs. +The most straightforward way to persist events and snapshots is to use protocol buffers (protobuf). Cloudstate will automatically detect if an emitted event is a protobuf, and serialize it as such. For other serialization options, including JSON, see xref:contribute:serialization.adoc[Serialization]. While protobufs are the recommended format for persisting events, it is recommended that you do not persist your service's protobuf messages, rather, you should create new messages, even if they are identical to the service's. -While this may introduce some overhead in needing to convert from one type to the other, the reason for doing this is that it will allow the service's public interface to evolve independently from its data storage format, which should be private. +While this may introduce some overhead in needing to convert from one type to the other, the reason for doing this is that it will allow the service's public interface to evolve independently of its data storage format, which should be private. -For our shopping cart example, we'll create a new file called `domain.proto`, the name domain is selected to indicate that these are my application's domain objects: +For our shopping cart example, we'll create a new file called `domain.proto`, the name domain is selected to indicate that these are our application's domain objects: [source,protobuf] ---- -include::example$protobuf/example/shoppingcart/persistence/domain.proto[] +include::example$example/shoppingcart/persistence/domain.proto[tag=domain] ---- == State Each entity should store its state locally in a mutable variable, either a mutable field or a multiple structure such as an array type or slice. -For our shopping cart, the state is a slice of products, so we'll create a slice of LineItems to contain that: +For our shopping cart, the state is a slice of products, so we'll create a slice of `LineItems` to contain that: [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=entity-state] +include::example$example/shoppingcart/entity.go[tag=entity-state] ---- == Constructing @@ -64,37 +71,36 @@ For this, an entity has to provide a factory function, `EntityFunc`, which is se [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=register] +include::example$tck/cmd/tck_eventsourced/tck_eventsourced.go[tag=register] ---- -The entity factory function returns a `cloudstate.Entity` which is composed of two interfaces to handle commands and events. +The entity factory function returns a {cloudstate-go-lib-api-base}/cloudstate/eventsourced#EntityHandler[`eventsourced.EntityHandler`] which handles commands and events. [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=constructing] +include::example$example/shoppingcart/entity.go[tag=entity-func] ---- == Handling commands -An event sourced entity implements the composed `cloudstate.Entity` interface. -`cloudstate.Entity` embeds the `cloudstate.EventHandler` interface and therefore entities implementing it get commands from Cloudstate through the event handler's `HandleCommand` method. - +An event sourced entity implements the {cloudstate-go-lib-api-base}/cloudstate/eventsourced#EntityHandler[`eventsourced.EntityHandler`] interface and there for command handling the {cloudstate-go-lib-api-base}/cloudstate/eventsourced#HandleCommand[`HandleCommand`] method. The command types received by an event sourced entity are declared by the gRPC Server interface which is generated from the protobuf definitions. -The Cloudstate Go Support library together with the registered `cloudstate.EventSourcedEntity` is then able to dispatch commands it gets from the Cloudstate proxy to the event sourced entity. +The Cloudstate Go Support library together with the registered `eventsourced.Entity` is then able to dispatch commands it gets from the Cloudstate proxy. [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=handle-command] +include::example$example/shoppingcart/entity.go[tag=handle-command] ---- -The return type of the command handler is by definition of the service interface, the output type for the gRPC service call, this will be sent as the reply. +The return type of the command handler is by definition of the service interface, the output type for the gRPC service call. +This will be sent as the reply. The following shows the implementation of the `GetCart` command handler. This command handler is a read-only command handler, it doesn't emit any events, it just returns some state: [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=get-cart] +include::example$example/shoppingcart/entity.go[tag=get-cart] ---- === Emitting events @@ -104,18 +110,18 @@ Commands that modify the state may do so by emitting events. WARNING: The *only* way a command handler may modify its state is by emitting an event. Any modifications made directly to the state from the command handler will not be persisted, and when the entity is passivated and next reloaded, those modifications will not be present. -A command handler may emit an event by using the embedded `cloudstate.EventEmitter` and invoking the `Emit` method on it. -Calling `Emit` will immediately invoke the associated event handler for that event - this both validates that the event can be applied to the current state, as well as updates the state so that subsequent processing in the command handler can use it. +A command handler may emit an event by using the {cloudstate-go-lib-api-base}/cloudstate/eventsourced#Context[`eventsourced.Context`] and invoking the {cloudstate-go-lib-api-base}/cloudstate/eventsourced#Emit[`Emit`] method on it. +Calling {cloudstate-go-lib-api-base}/cloudstate/eventsourced#Emit[`Emit`] will immediately invoke the associated event handler for that event - this both validates that the event can be applied to the current state, as well as updates the state so that subsequent processing in the command handler can use it. Here's an example of a command handler that emits an event: [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=add-item] +include::example$example/shoppingcart/entity.go[tag=add-item] ---- This command handler also validates the command, ensuring the quantity of items added is greater than zero. -Returning an `error` fails the command and the support library takes care of signaling that back to the requesting proxy as a `Failure` reply. +Returning an `error` fails the command and the support library takes care of signaling that back to the requesting proxy as a {cloudstate-go-lib-api-base}/cloudstate/protocol#Failure[`protocol.Failure`] reply. == Handling events @@ -123,62 +129,49 @@ Event handlers are invoked at two points, when restoring entities from the journ An event handler's responsibility is to update the state of the entity according to the event. Event handlers are the only place where it's safe to mutate the state of the entity at all. -Event handlers are declared by implementing the `cloudstate.EventHandler` interface. - -[source,go] ----- -include::example$cloudstate/event.go[tag=event-handler] ----- - +Every event sourced entity implements the {cloudstate-go-lib-api-base}/cloudstate/eventsourced#EntityHandler[`eventsourced.EntityHandler`]s interface {cloudstate-go-lib-api-base}/cloudstate/eventsourced#HandleEvent[`HandleEvent`] method. Events emitted by command handlers get dispatched to the implemented event handler which then decides how to proceed with the event. [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=handle-event] +include::example$example/shoppingcart/entity.go[tag=handle-event] ---- Here's an example of a concrete event handler for the `ItemAdded` event. [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=item-added] +include::example$example/shoppingcart/entity.go[tag=item-added] ---- == Producing and handling snapshots Snapshots are an important optimisation for event sourced entities that may contain many events, to ensure that they can be loaded quickly even when they have very long journals. -To produce a snapshot, the `cloudstate.Snapshotter` interface has to be implemented that must return a snapshot of the current state in serializable form. - -[source,go] ----- -include::example$cloudstate/event.go[tag=snapshotter] ----- - -Here is an example of the TCK shopping cart example creating snapshots for the current `domain.Cart` state of the shopping cart. +To produce a snapshot, the {cloudstate-go-lib-api-base}/cloudstate/eventsourced#Snapshooter[`eventsourced.Snapshooter`] interface has to be implemented that must return a snapshot of the current state in serializable form. [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=snapshotter] +include::example$cloudstate/eventsourced/entity.go[tag=snapshooter] ---- -When the entity is loaded again, the snapshot will first be loaded before any other events are received, and passed to a snapshot handler. -Snapshot handlers are declared by implementing the `cloudstate.SnapshotHandler` interface. +Here is an example of the shopping cart example creating snapshots for the current `domain.Cart` state of the shopping cart. [source,go] ---- -include::example$cloudstate/event.go[tag=snapshot-handler] +include::example$example/shoppingcart/entity.go[tag=snapshot] ---- -A snapshot handler then can type-switch over types the corresponding `cloudstate.Snapshotter` interface has implemented. +When the entity is loaded again, the snapshot will first be loaded before any other events are received, and passed to a snapshot handler implementing the `eventsourced.Snapshooter`s `HandleSnapshot` method. +A snapshot handler then can type-switch over types the corresponding {cloudstate-go-lib-api-base}/cloudstate/eventsourced#Snapshooter[`eventsourced.Snapshooter`] interface has implemented. [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=handle-snapshot] +include::example$example/shoppingcart/entity.go[tag=handle-snapshot] ---- == Registering the entity -Once you've created your entity, you can register it with the `cloudstate.Cloudstate` server, by invoking the `Register` method of a Cloudstate instance. +Once you've created your entity, you can register it with the {cloudstate-go-lib-api-base}/cloudstate#CloudState[`cloudstate.CloudState`] server, by invoking the `RegisterEventSourced` method of a CloudState instance. In addition to passing your entity type and service name, you also need to pass any descriptors that you use for persisting events, for example, the `domain.proto` descriptor. During registration the optional ServiceName and the ServiceVersion can be configured. @@ -186,5 +179,5 @@ During registration the optional ServiceName and the ServiceVersion can be confi [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=register] +include::example$tck/cmd/tck_eventsourced/tck_eventsourced.go[tag=register] ---- diff --git a/docs/src/modules/go/pages/gettingstarted.adoc b/docs/src/modules/go/pages/gettingstarted.adoc index 57a9b30..f1cb2b5 100644 --- a/docs/src/modules/go/pages/gettingstarted.adoc +++ b/docs/src/modules/go/pages/gettingstarted.adoc @@ -10,14 +10,13 @@ Go version:: Cloudstate Go support requires at least Go {cloudstate-go-version} Build tool:: Cloudstate does not require any particular build tool, you can select your own. protoc:: -Since Cloudstate is based on gRPC, you need a protoc compiler to compile gRPC protobuf descriptors. -This can be done manually through the https://github.com/protocolbuffers/protobuf#user-content-protocol-compiler-installation[Protocol Buffer Compiler project]. +Since Cloudstate is based on gRPC services, you need a protoc compiler to compile gRPC protobuf descriptors. +This can be done manually through the https://grpc.io/docs/languages/go/quickstart/#prerequisites[gRPC Project] where it's described how to install the protocol compiler as well as the go-protobuf and grpc compiler plugins for Go. -docker:: +docker: Cloudstate runs in Kubernetes with https://www.docker.com[Docker], hence you will need Docker to build a container that you can deploy to Kubernetes. -Most popular build tools have plugins that assist in building Docker images. -In addition to the above, you will need to install the Cloudstate Go support library by issuing `go get -u github.com/cloudstateio/go-support/cloudstate` or with Go module support let the dependency be downloaded by `go [build|run|test]`. +In addition to the above, you will need to install the Cloudstate Go language support library by issuing `go get -u github.com/cloudstateio/go-support/cloudstate` or with Go module support let the dependency be downloaded by `go [build|run|test]`. By using the Go module support your go.mod file will reference the latest version of the support library or you can define which version you like to use. @@ -55,16 +54,16 @@ The Cloudstate protocol protobuf files as well as the shopping cart example appl In addition to the `protoc` compiler, the gRPC Go plugin is needed to compile the protobuf file to `*.pb.go` files. Please follow the instructions at the https://github.com/golang/protobuf[Go support for Protocol Buffers] project page to install the protoc compiler as well as the `protoc-gen-go` plugin which also includes the Google standard protobuf types. -To build the example shopping cart application shown earlier in xref:concepts:grpc.adoc[gRPC descriptors], you could simply paste that protobuf into `protos/shoppingcart.proto`. +To build the example shopping cart application shown earlier in xref:concepts:grpc.adoc[gRPC descriptors], you could simply paste that protobuf into a file named `shoppingcart.proto`. You may wish to also define the Go package using the `go_package` proto option, to ensure the package name used conforms to Go package naming conventions. [source,protobuf] ---- -option go_package = "example/shoppingcart"; +option go_package = "example.com/shoppingcart;shoppingcart"; ---- Now if you place your protobuf files under `protobuf/` and run `protoc --go_out=. ---proto_path=protobuf ./protobuf/*.proto`, you'll find your generated protobuf files in `example/shoppingcart`. +--proto_path=protobuf ./protobuf/*.proto`, you'll find your generated protobuf files under `shoppingcart`. == Creating a main package @@ -73,24 +72,21 @@ To do this, you can use the CloudState server type, for example: [source,go] ---- -include::example$tck/cmd/tck_shoppingcart/shoppingcart.go[tag=shopping-cart-main] +include::example$tck/cmd/tck_eventsourced/tck_eventsourced.go[tag=shopping-cart-main] ---- We will see more details on registering entities in the coming pages. == Interfaces to be implemented -Cloudstate entities in Go work by implementing interfaces and composing types. - -To get support for the Cloudstate event emission the Cloudstate entity should embed the `cloudstate.EventEmitter` type. -The EventEmitter allows the entity to emit events during the handling of commands. - -Second, during registration of the entity, an entity factory function has to be provided so Cloudstate gets to know how to create and initialize an event sourced entity. +Cloudstate entities in Go work by implementing interfaces and registering those entities with a Cloudstate instance. +During the registration of the entity an entity factory function, {cloudstate-go-lib-api-base}/cloudstate/eventsourced#Entity.EntityFunc[`eventsourced.Entity.EntityFunc`], has to be provided so that Cloudstate gets to know how to create and initialize an event sourced entity. [source,go] ---- -include::example$cloudstate/eventsourced.go[tag=event-sourced-entity-func] +include::example$example/shoppingcart/entity.go[tag=entity-func] ---- -This entity factory function returns a `cloudstate.Entity` which itself is a composite interface of a `cloudstate.CommandHandler` and a `cloudstate.EventHandler`. -Every event sourced entity has to implement these two interfaces. +This entity factory function returns a type that implements the {cloudstate-go-lib-api-base}/cloudstate/eventsourced#EntityHandler[`eventsourced.EntityHandler`] interface. +An entity can implement the optional {cloudstate-go-lib-api-base}/cloudstate/eventsourced#Snapshooter[`eventsourced.Snapshooter`] interface if it likes to enable snapshot functionality. +We will see later how to handle snapshots on the following pages. diff --git a/docs/src/modules/go/pages/index.adoc b/docs/src/modules/go/pages/index.adoc index 0ed9d13..cdadc87 100644 --- a/docs/src/modules/go/pages/index.adoc +++ b/docs/src/modules/go/pages/index.adoc @@ -1,3 +1,10 @@ = Cloudstate Go Cloudstate offers an idiomatic Go support library for writing Cloudstate services. + +* xref:gettingstarted.adoc[Getting started] +* xref:eventsourced.adoc[Event sourcing] +* xref:crdt.adoc[Conflict-free Replicated Data Types] +* xref:effects.adoc[Forwarding and effects] +* xref:serialization.adoc[Serialization] +* https://pkg.go.dev/github.com/cloudstateio/go-support/cloudstate[API docs] \ No newline at end of file diff --git a/docs/src/modules/go/pages/serialization.adoc b/docs/src/modules/go/pages/serialization.adoc index a991612..970336c 100644 --- a/docs/src/modules/go/pages/serialization.adoc +++ b/docs/src/modules/go/pages/serialization.adoc @@ -14,7 +14,7 @@ Cloudstate supports a number of types and serialization options for these values Cloudstate supports serializing the following primitive types: |=== -| Protobuf type | Go type +| Protocol buffer type | Go type | string | string diff --git a/docs/src/modules/go/partials/include.adoc b/docs/src/modules/go/partials/include.adoc index 982d3cf..d44d3fa 100644 --- a/docs/src/modules/go/partials/include.adoc +++ b/docs/src/modules/go/partials/include.adoc @@ -1 +1,2 @@ :cloudstate-go-version: 1.14 +:cloudstate-go-lib-api-base: https://pkg.go.dev/github.com/cloudstateio/go-support \ No newline at end of file diff --git a/example/chat/friends/entity.go b/example/chat/friends/entity.go new file mode 100644 index 0000000..04a5d43 --- /dev/null +++ b/example/chat/friends/entity.go @@ -0,0 +1,70 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package friends + +import ( + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/crdt" + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" +) + +type Entity struct { + state *crdt.ORSet +} + +func (e *Entity) HandleCommand(ctx *crdt.CommandContext, name string, msg proto.Message) (*any.Any, error) { + switch name { + case "Add": + friend, err := encoding.MarshalAny(msg.(*FriendRequest).GetFriend()) + if err != nil { + return nil, err + } + e.state.Add(friend) + case "Remove": + friend, err := encoding.MarshalAny(msg.(*FriendRequest).GetFriend()) + if err != nil { + return nil, err + } + e.state.Remove(friend) + case "GetFriends": + var list FriendsList + for _, f := range e.state.Value() { + var friend Friend + if err := encoding.UnmarshalAny(f, &friend); err != nil { + return nil, err + } + list.Friends = append(list.Friends, &friend) + } + fmt.Printf("getFriends for user: %s, %+v\n", msg.(*FriendRequest).GetFriend().GetUser(), list) + return encoding.MarshalAny(&list) + } + return encoding.Empty, nil +} + +func (e *Entity) Default(ctx *crdt.Context) (crdt.CRDT, error) { + return crdt.NewORSet(), nil +} + +func (e *Entity) Set(ctx *crdt.Context, state crdt.CRDT) error { + switch set := state.(type) { + case *crdt.ORSet: + e.state = set + } + return fmt.Errorf("unknown type: %v", state) +} diff --git a/example/chat/friends/friends.pb.go b/example/chat/friends/friends.pb.go new file mode 100644 index 0000000..e56edae --- /dev/null +++ b/example/chat/friends/friends.pb.go @@ -0,0 +1,618 @@ +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Extension for specifying which field in a message is to be considered an +// entity key, for the purposes associating gRPC calls with entities and +// sharding. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: friends.proto + +package friends + +import ( + context "context" + _ "github.com/cloudstateio/go-support/cloudstate" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type Friend struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Avatar string `protobuf:"bytes,2,opt,name=avatar,proto3" json:"avatar,omitempty"` +} + +func (x *Friend) Reset() { + *x = Friend{} + if protoimpl.UnsafeEnabled { + mi := &file_friends_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Friend) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Friend) ProtoMessage() {} + +func (x *Friend) ProtoReflect() protoreflect.Message { + mi := &file_friends_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Friend.ProtoReflect.Descriptor instead. +func (*Friend) Descriptor() ([]byte, []int) { + return file_friends_proto_rawDescGZIP(), []int{0} +} + +func (x *Friend) GetUser() string { + if x != nil { + return x.User + } + return "" +} + +func (x *Friend) GetAvatar() string { + if x != nil { + return x.Avatar + } + return "" +} + +type FriendRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` + Friend *Friend `protobuf:"bytes,2,opt,name=friend,proto3" json:"friend,omitempty"` +} + +func (x *FriendRequest) Reset() { + *x = FriendRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_friends_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FriendRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FriendRequest) ProtoMessage() {} + +func (x *FriendRequest) ProtoReflect() protoreflect.Message { + mi := &file_friends_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FriendRequest.ProtoReflect.Descriptor instead. +func (*FriendRequest) Descriptor() ([]byte, []int) { + return file_friends_proto_rawDescGZIP(), []int{1} +} + +func (x *FriendRequest) GetUser() string { + if x != nil { + return x.User + } + return "" +} + +func (x *FriendRequest) GetFriend() *Friend { + if x != nil { + return x.Friend + } + return nil +} + +type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + User string `protobuf:"bytes,1,opt,name=user,proto3" json:"user,omitempty"` +} + +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_friends_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_friends_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_friends_proto_rawDescGZIP(), []int{2} +} + +func (x *User) GetUser() string { + if x != nil { + return x.User + } + return "" +} + +type FriendsList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Friends []*Friend `protobuf:"bytes,1,rep,name=friends,proto3" json:"friends,omitempty"` +} + +func (x *FriendsList) Reset() { + *x = FriendsList{} + if protoimpl.UnsafeEnabled { + mi := &file_friends_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FriendsList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FriendsList) ProtoMessage() {} + +func (x *FriendsList) ProtoReflect() protoreflect.Message { + mi := &file_friends_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FriendsList.ProtoReflect.Descriptor instead. +func (*FriendsList) Descriptor() ([]byte, []int) { + return file_friends_proto_rawDescGZIP(), []int{3} +} + +func (x *FriendsList) GetFriends() []*Friend { + if x != nil { + return x.Friends + } + return nil +} + +type Empty struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *Empty) Reset() { + *x = Empty{} + if protoimpl.UnsafeEnabled { + mi := &file_friends_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Empty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Empty) ProtoMessage() {} + +func (x *Empty) ProtoReflect() protoreflect.Message { + mi := &file_friends_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Empty.ProtoReflect.Descriptor instead. +func (*Empty) Descriptor() ([]byte, []int) { + return file_friends_proto_rawDescGZIP(), []int{4} +} + +var File_friends_proto protoreflect.FileDescriptor + +var file_friends_proto_rawDesc = []byte{ + 0x0a, 0x0d, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, + 0x1f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, + 0x1a, 0x1b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x34, 0x0a, + 0x06, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x61, + 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x76, 0x61, + 0x74, 0x61, 0x72, 0x22, 0x6a, 0x0a, 0x0d, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x12, 0x3f, + 0x0a, 0x06, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, + 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, + 0x2e, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x06, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x22, + 0x20, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x04, 0x75, 0x73, 0x65, + 0x72, 0x22, 0x50, 0x0a, 0x0b, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x4c, 0x69, 0x73, 0x74, + 0x12, 0x41, 0x0a, 0x07, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x27, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x66, 0x72, 0x69, 0x65, + 0x6e, 0x64, 0x73, 0x2e, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x07, 0x66, 0x72, 0x69, 0x65, + 0x6e, 0x64, 0x73, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, 0xad, 0x02, 0x0a, + 0x07, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x12, 0x5d, 0x0a, 0x03, 0x41, 0x64, 0x64, 0x12, + 0x2e, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, + 0x73, 0x2e, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x26, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, + 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x60, 0x0a, 0x06, 0x52, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x12, 0x2e, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x66, 0x72, 0x69, 0x65, + 0x6e, 0x64, 0x73, 0x2e, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x26, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x66, 0x72, 0x69, 0x65, + 0x6e, 0x64, 0x73, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x61, 0x0a, 0x0a, 0x47, 0x65, 0x74, + 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x12, 0x25, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, + 0x74, 0x2e, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x1a, 0x2c, + 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, + 0x2e, 0x46, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x41, 0x5a, 0x3f, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x2f, + 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x3b, 0x66, 0x72, 0x69, 0x65, 0x6e, 0x64, 0x73, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_friends_proto_rawDescOnce sync.Once + file_friends_proto_rawDescData = file_friends_proto_rawDesc +) + +func file_friends_proto_rawDescGZIP() []byte { + file_friends_proto_rawDescOnce.Do(func() { + file_friends_proto_rawDescData = protoimpl.X.CompressGZIP(file_friends_proto_rawDescData) + }) + return file_friends_proto_rawDescData +} + +var file_friends_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_friends_proto_goTypes = []interface{}{ + (*Friend)(nil), // 0: cloudstate.samples.chat.friends.Friend + (*FriendRequest)(nil), // 1: cloudstate.samples.chat.friends.FriendRequest + (*User)(nil), // 2: cloudstate.samples.chat.friends.User + (*FriendsList)(nil), // 3: cloudstate.samples.chat.friends.FriendsList + (*Empty)(nil), // 4: cloudstate.samples.chat.friends.Empty +} +var file_friends_proto_depIdxs = []int32{ + 0, // 0: cloudstate.samples.chat.friends.FriendRequest.friend:type_name -> cloudstate.samples.chat.friends.Friend + 0, // 1: cloudstate.samples.chat.friends.FriendsList.friends:type_name -> cloudstate.samples.chat.friends.Friend + 1, // 2: cloudstate.samples.chat.friends.Friends.Add:input_type -> cloudstate.samples.chat.friends.FriendRequest + 1, // 3: cloudstate.samples.chat.friends.Friends.Remove:input_type -> cloudstate.samples.chat.friends.FriendRequest + 2, // 4: cloudstate.samples.chat.friends.Friends.GetFriends:input_type -> cloudstate.samples.chat.friends.User + 4, // 5: cloudstate.samples.chat.friends.Friends.Add:output_type -> cloudstate.samples.chat.friends.Empty + 4, // 6: cloudstate.samples.chat.friends.Friends.Remove:output_type -> cloudstate.samples.chat.friends.Empty + 3, // 7: cloudstate.samples.chat.friends.Friends.GetFriends:output_type -> cloudstate.samples.chat.friends.FriendsList + 5, // [5:8] is the sub-list for method output_type + 2, // [2:5] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_friends_proto_init() } +func file_friends_proto_init() { + if File_friends_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_friends_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Friend); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_friends_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FriendRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_friends_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_friends_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FriendsList); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_friends_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Empty); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_friends_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_friends_proto_goTypes, + DependencyIndexes: file_friends_proto_depIdxs, + MessageInfos: file_friends_proto_msgTypes, + }.Build() + File_friends_proto = out.File + file_friends_proto_rawDesc = nil + file_friends_proto_goTypes = nil + file_friends_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// FriendsClient is the client API for Friends service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type FriendsClient interface { + Add(ctx context.Context, in *FriendRequest, opts ...grpc.CallOption) (*Empty, error) + Remove(ctx context.Context, in *FriendRequest, opts ...grpc.CallOption) (*Empty, error) + GetFriends(ctx context.Context, in *User, opts ...grpc.CallOption) (*FriendsList, error) +} + +type friendsClient struct { + cc grpc.ClientConnInterface +} + +func NewFriendsClient(cc grpc.ClientConnInterface) FriendsClient { + return &friendsClient{cc} +} + +func (c *friendsClient) Add(ctx context.Context, in *FriendRequest, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, "/cloudstate.samples.chat.friends.Friends/Add", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendsClient) Remove(ctx context.Context, in *FriendRequest, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, "/cloudstate.samples.chat.friends.Friends/Remove", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *friendsClient) GetFriends(ctx context.Context, in *User, opts ...grpc.CallOption) (*FriendsList, error) { + out := new(FriendsList) + err := c.cc.Invoke(ctx, "/cloudstate.samples.chat.friends.Friends/GetFriends", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// FriendsServer is the server API for Friends service. +type FriendsServer interface { + Add(context.Context, *FriendRequest) (*Empty, error) + Remove(context.Context, *FriendRequest) (*Empty, error) + GetFriends(context.Context, *User) (*FriendsList, error) +} + +// UnimplementedFriendsServer can be embedded to have forward compatible implementations. +type UnimplementedFriendsServer struct { +} + +func (*UnimplementedFriendsServer) Add(context.Context, *FriendRequest) (*Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Add not implemented") +} +func (*UnimplementedFriendsServer) Remove(context.Context, *FriendRequest) (*Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method Remove not implemented") +} +func (*UnimplementedFriendsServer) GetFriends(context.Context, *User) (*FriendsList, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetFriends not implemented") +} + +func RegisterFriendsServer(s *grpc.Server, srv FriendsServer) { + s.RegisterService(&_Friends_serviceDesc, srv) +} + +func _Friends_Add_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FriendRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendsServer).Add(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cloudstate.samples.chat.friends.Friends/Add", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendsServer).Add(ctx, req.(*FriendRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friends_Remove_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FriendRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendsServer).Remove(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cloudstate.samples.chat.friends.Friends/Remove", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendsServer).Remove(ctx, req.(*FriendRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Friends_GetFriends_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(User) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(FriendsServer).GetFriends(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cloudstate.samples.chat.friends.Friends/GetFriends", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(FriendsServer).GetFriends(ctx, req.(*User)) + } + return interceptor(ctx, in, info, handler) +} + +var _Friends_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cloudstate.samples.chat.friends.Friends", + HandlerType: (*FriendsServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Add", + Handler: _Friends_Add_Handler, + }, + { + MethodName: "Remove", + Handler: _Friends_Remove_Handler, + }, + { + MethodName: "GetFriends", + Handler: _Friends_GetFriends_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "friends.proto", +} diff --git a/example/chat/friends/friends.proto b/example/chat/friends/friends.proto new file mode 100644 index 0000000..856d568 --- /dev/null +++ b/example/chat/friends/friends.proto @@ -0,0 +1,52 @@ +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Extension for specifying which field in a message is to be considered an +// entity key, for the purposes associating gRPC calls with entities and +// sharding. + +syntax = "proto3"; + +import "cloudstate/entity_key.proto"; + +package cloudstate.samples.chat.friends; + +option go_package = "github.com/cloudstateio/go-support/example/chat/friends;friends"; + +message Friend { + string user = 1; + string avatar = 2; +} + +message FriendRequest { + string user = 1 [(.cloudstate.entity_key) = true]; + Friend friend = 2; +} + +message User { + string user = 1 [(.cloudstate.entity_key) = true]; +} + +message FriendsList { + repeated Friend friends = 1; +} + +message Empty { +} + +service Friends { + rpc Add (FriendRequest) returns (Empty); + rpc Remove (FriendRequest) returns (Empty); + rpc GetFriends (User) returns (FriendsList); +} \ No newline at end of file diff --git a/example/chat/presence/entity.go b/example/chat/presence/entity.go new file mode 100644 index 0000000..e01c41a --- /dev/null +++ b/example/chat/presence/entity.go @@ -0,0 +1,90 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package presence + +import ( + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/crdt" + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" + "github.com/golang/protobuf/ptypes/empty" +) + +type Entity struct { + state *crdt.Vote + users int +} + +func (p *Entity) HandleCommand(ctx *crdt.CommandContext, name string, msg proto.Message) (*any.Any, error) { + switch name { + case "Connect": + return p.Connect(ctx, msg.(*User)) + case "Monitor": + return p.Monitor(ctx, msg.(*User)) + } + return nil, nil +} + +func (p *Entity) Connect(ctx *crdt.CommandContext, user *User) (*any.Any, error) { + if ctx.Streamed() { + ctx.CancelFunc(func(c *crdt.CommandContext) error { + p.disconnect() + return nil + }) + p.connect() + } + return encoding.MarshalAny(&empty.Empty{}) +} + +func (p *Entity) Monitor(ctx *crdt.CommandContext, user *User) (*any.Any, error) { + online := p.state.AtLeastOne() + if ctx.Streamed() { + ctx.ChangeFunc(func(c *crdt.CommandContext) (*any.Any, error) { + if online != p.state.AtLeastOne() { + online = p.state.AtLeastOne() + } + fmt.Printf("onStateChange: %s return: {%v}", user.Name, online) + return encoding.MarshalAny(&OnlineStatus{Online: online}) + }) + } + fmt.Printf("onStateChange: %s return: {%v}", user.Name, online) + return encoding.MarshalAny(&OnlineStatus{Online: online}) +} + +func (p *Entity) connect() { + p.users += 1 + if p.users == 1 { + p.state.Vote(true) + } +} + +func (p *Entity) disconnect() { + p.users -= 1 + if p.users == 0 { + p.state.Vote(false) + } +} + +func (p *Entity) Default(ctx *crdt.Context) (crdt.CRDT, error) { + return crdt.NewVote(), nil +} +func (p *Entity) Set(ctx *crdt.Context, state crdt.CRDT) error { + p.state = state.(*crdt.Vote) + p.users = 0 + return nil +} diff --git a/example/chat/presence/presence.pb.go b/example/chat/presence/presence.pb.go new file mode 100644 index 0000000..e64c4f1 --- /dev/null +++ b/example/chat/presence/presence.pb.go @@ -0,0 +1,485 @@ +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Extension for specifying which field in a message is to be considered an +// entity key, for the purposes associating gRPC calls with entities and +// sharding. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: presence.proto + +package presence + +import ( + context "context" + _ "github.com/cloudstateio/go-support/cloudstate" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_presence_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_presence_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_presence_proto_rawDescGZIP(), []int{0} +} + +func (x *User) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type OnlineStatus struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Online bool `protobuf:"varint,1,opt,name=online,proto3" json:"online,omitempty"` +} + +func (x *OnlineStatus) Reset() { + *x = OnlineStatus{} + if protoimpl.UnsafeEnabled { + mi := &file_presence_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OnlineStatus) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OnlineStatus) ProtoMessage() {} + +func (x *OnlineStatus) ProtoReflect() protoreflect.Message { + mi := &file_presence_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OnlineStatus.ProtoReflect.Descriptor instead. +func (*OnlineStatus) Descriptor() ([]byte, []int) { + return file_presence_proto_rawDescGZIP(), []int{1} +} + +func (x *OnlineStatus) GetOnline() bool { + if x != nil { + return x.Online + } + return false +} + +type Empty struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *Empty) Reset() { + *x = Empty{} + if protoimpl.UnsafeEnabled { + mi := &file_presence_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Empty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Empty) ProtoMessage() {} + +func (x *Empty) ProtoReflect() protoreflect.Message { + mi := &file_presence_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Empty.ProtoReflect.Descriptor instead. +func (*Empty) Descriptor() ([]byte, []int) { + return file_presence_proto_rawDescGZIP(), []int{2} +} + +var File_presence_proto protoreflect.FileDescriptor + +var file_presence_proto_rawDesc = []byte{ + 0x0a, 0x0e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x20, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, + 0x63, 0x65, 0x1a, 0x1b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x65, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x20, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x22, 0x26, 0x0a, 0x0c, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x06, 0x6f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x32, 0xcd, 0x01, 0x0a, 0x08, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x12, + 0x5c, 0x0a, 0x07, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x12, 0x26, 0x2e, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, + 0x63, 0x68, 0x61, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x1a, 0x27, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, + 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x70, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x30, 0x01, 0x12, 0x63, 0x0a, + 0x07, 0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x12, 0x26, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, + 0x61, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x1a, 0x2e, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x73, 0x61, + 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x63, 0x65, 0x2e, 0x4f, 0x6e, 0x6c, 0x69, 0x6e, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x30, 0x01, 0x42, 0x78, 0x0a, 0x23, 0x69, 0x6f, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x68, 0x61, 0x74, + 0x2e, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x42, 0x0e, 0x50, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x5a, 0x41, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x63, 0x68, 0x61, 0x74, 0x2f, 0x70, 0x72, 0x65, 0x73, 0x65, + 0x6e, 0x63, 0x65, 0x3b, 0x70, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_presence_proto_rawDescOnce sync.Once + file_presence_proto_rawDescData = file_presence_proto_rawDesc +) + +func file_presence_proto_rawDescGZIP() []byte { + file_presence_proto_rawDescOnce.Do(func() { + file_presence_proto_rawDescData = protoimpl.X.CompressGZIP(file_presence_proto_rawDescData) + }) + return file_presence_proto_rawDescData +} + +var file_presence_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_presence_proto_goTypes = []interface{}{ + (*User)(nil), // 0: cloudstate.samples.chat.presence.User + (*OnlineStatus)(nil), // 1: cloudstate.samples.chat.presence.OnlineStatus + (*Empty)(nil), // 2: cloudstate.samples.chat.presence.Empty +} +var file_presence_proto_depIdxs = []int32{ + 0, // 0: cloudstate.samples.chat.presence.Presence.Connect:input_type -> cloudstate.samples.chat.presence.User + 0, // 1: cloudstate.samples.chat.presence.Presence.Monitor:input_type -> cloudstate.samples.chat.presence.User + 2, // 2: cloudstate.samples.chat.presence.Presence.Connect:output_type -> cloudstate.samples.chat.presence.Empty + 1, // 3: cloudstate.samples.chat.presence.Presence.Monitor:output_type -> cloudstate.samples.chat.presence.OnlineStatus + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_presence_proto_init() } +func file_presence_proto_init() { + if File_presence_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_presence_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_presence_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OnlineStatus); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_presence_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Empty); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_presence_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_presence_proto_goTypes, + DependencyIndexes: file_presence_proto_depIdxs, + MessageInfos: file_presence_proto_msgTypes, + }.Build() + File_presence_proto = out.File + file_presence_proto_rawDesc = nil + file_presence_proto_goTypes = nil + file_presence_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// PresenceClient is the client API for Presence service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type PresenceClient interface { + // Connect the given user. They will stay connected as long as the stream stays open. + Connect(ctx context.Context, in *User, opts ...grpc.CallOption) (Presence_ConnectClient, error) + // Monitor the online status of the given user. + Monitor(ctx context.Context, in *User, opts ...grpc.CallOption) (Presence_MonitorClient, error) +} + +type presenceClient struct { + cc grpc.ClientConnInterface +} + +func NewPresenceClient(cc grpc.ClientConnInterface) PresenceClient { + return &presenceClient{cc} +} + +func (c *presenceClient) Connect(ctx context.Context, in *User, opts ...grpc.CallOption) (Presence_ConnectClient, error) { + stream, err := c.cc.NewStream(ctx, &_Presence_serviceDesc.Streams[0], "/cloudstate.samples.chat.presence.Presence/Connect", opts...) + if err != nil { + return nil, err + } + x := &presenceConnectClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Presence_ConnectClient interface { + Recv() (*Empty, error) + grpc.ClientStream +} + +type presenceConnectClient struct { + grpc.ClientStream +} + +func (x *presenceConnectClient) Recv() (*Empty, error) { + m := new(Empty) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *presenceClient) Monitor(ctx context.Context, in *User, opts ...grpc.CallOption) (Presence_MonitorClient, error) { + stream, err := c.cc.NewStream(ctx, &_Presence_serviceDesc.Streams[1], "/cloudstate.samples.chat.presence.Presence/Monitor", opts...) + if err != nil { + return nil, err + } + x := &presenceMonitorClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type Presence_MonitorClient interface { + Recv() (*OnlineStatus, error) + grpc.ClientStream +} + +type presenceMonitorClient struct { + grpc.ClientStream +} + +func (x *presenceMonitorClient) Recv() (*OnlineStatus, error) { + m := new(OnlineStatus) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// PresenceServer is the server API for Presence service. +type PresenceServer interface { + // Connect the given user. They will stay connected as long as the stream stays open. + Connect(*User, Presence_ConnectServer) error + // Monitor the online status of the given user. + Monitor(*User, Presence_MonitorServer) error +} + +// UnimplementedPresenceServer can be embedded to have forward compatible implementations. +type UnimplementedPresenceServer struct { +} + +func (*UnimplementedPresenceServer) Connect(*User, Presence_ConnectServer) error { + return status.Errorf(codes.Unimplemented, "method Connect not implemented") +} +func (*UnimplementedPresenceServer) Monitor(*User, Presence_MonitorServer) error { + return status.Errorf(codes.Unimplemented, "method Monitor not implemented") +} + +func RegisterPresenceServer(s *grpc.Server, srv PresenceServer) { + s.RegisterService(&_Presence_serviceDesc, srv) +} + +func _Presence_Connect_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(User) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(PresenceServer).Connect(m, &presenceConnectServer{stream}) +} + +type Presence_ConnectServer interface { + Send(*Empty) error + grpc.ServerStream +} + +type presenceConnectServer struct { + grpc.ServerStream +} + +func (x *presenceConnectServer) Send(m *Empty) error { + return x.ServerStream.SendMsg(m) +} + +func _Presence_Monitor_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(User) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(PresenceServer).Monitor(m, &presenceMonitorServer{stream}) +} + +type Presence_MonitorServer interface { + Send(*OnlineStatus) error + grpc.ServerStream +} + +type presenceMonitorServer struct { + grpc.ServerStream +} + +func (x *presenceMonitorServer) Send(m *OnlineStatus) error { + return x.ServerStream.SendMsg(m) +} + +var _Presence_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cloudstate.samples.chat.presence.Presence", + HandlerType: (*PresenceServer)(nil), + Methods: []grpc.MethodDesc{}, + Streams: []grpc.StreamDesc{ + { + StreamName: "Connect", + Handler: _Presence_Connect_Handler, + ServerStreams: true, + }, + { + StreamName: "Monitor", + Handler: _Presence_Monitor_Handler, + ServerStreams: true, + }, + }, + Metadata: "presence.proto", +} diff --git a/example/chat/presence/presence.proto b/example/chat/presence/presence.proto new file mode 100644 index 0000000..ebd60fe --- /dev/null +++ b/example/chat/presence/presence.proto @@ -0,0 +1,46 @@ +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Extension for specifying which field in a message is to be considered an +// entity key, for the purposes associating gRPC calls with entities and +// sharding. + +syntax = "proto3"; + +import "cloudstate/entity_key.proto"; + +package cloudstate.samples.chat.presence; + +option java_package = "io.cloudstate.samples.chat.presence"; +option java_outer_classname = "PresenceProtos"; + +option go_package = "github.com/cloudstateio/go-support/example/chat/presence;presence"; + +message User { + string name = 1 [(.cloudstate.entity_key) = true]; +} + +message OnlineStatus { + bool online = 1; +} + +message Empty { +} + +service Presence { + // Connect the given user. They will stay connected as long as the stream stays open. + rpc Connect (User) returns (stream Empty); + // Monitor the online status of the given user. + rpc Monitor (User) returns (stream OnlineStatus); +} diff --git a/example/crdt_shoppingcart/cmd/crdt_shoppingcart.go b/example/crdt_shoppingcart/cmd/crdt_shoppingcart.go new file mode 100644 index 0000000..03d7b5f --- /dev/null +++ b/example/crdt_shoppingcart/cmd/crdt_shoppingcart.go @@ -0,0 +1,42 @@ +package main + +import ( + "log" + + "github.com/cloudstateio/go-support/cloudstate" + "github.com/cloudstateio/go-support/cloudstate/crdt" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/cloudstateio/go-support/example/crdt_shoppingcart/shoppingcart" +) + +// main creates a CloudState instance and registers the ShoppingCart +// as a event sourced entity. +func main() { + server, err := cloudstate.New(protocol.Config{ + ServiceName: "shopping-cart", + ServiceVersion: "0.1.0", + }) + if err != nil { + log.Fatalf("cloudstate.New failed: %v", err) + } + + // tag::register-crdt[] + err = server.RegisterCRDT(&crdt.Entity{ + ServiceName: "example.shoppingcart.ShoppingCartService", + EntityFunc: shoppingcart.NewShoppingCart, + }, protocol.DescriptorConfig{ + Service: "shoppingcart.proto", + }.AddDomainDescriptor("domain.proto", "hotitems.proto")) + // end::register-crdt[] + if err != nil { + log.Fatalf("CloudState failed to register entity: %v", err) + } + err = server.Run() + if err != nil { + log.Fatalf("CloudState failed to run: %v", err) + } +} + +func init() { + log.SetFlags(log.LstdFlags | log.Lmicroseconds) +} diff --git a/example/crdt_shoppingcart/domain/domain.pb.go b/example/crdt_shoppingcart/domain/domain.pb.go new file mode 100644 index 0000000..69e8109 --- /dev/null +++ b/example/crdt_shoppingcart/domain/domain.pb.go @@ -0,0 +1,427 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: domain.proto + +package domain + +import ( + proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type LineItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProductId string `protobuf:"bytes,1,opt,name=productId,proto3" json:"productId,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Quantity int32 `protobuf:"varint,3,opt,name=quantity,proto3" json:"quantity,omitempty"` +} + +func (x *LineItem) Reset() { + *x = LineItem{} + if protoimpl.UnsafeEnabled { + mi := &file_domain_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LineItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LineItem) ProtoMessage() {} + +func (x *LineItem) ProtoReflect() protoreflect.Message { + mi := &file_domain_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LineItem.ProtoReflect.Descriptor instead. +func (*LineItem) Descriptor() ([]byte, []int) { + return file_domain_proto_rawDescGZIP(), []int{0} +} + +func (x *LineItem) GetProductId() string { + if x != nil { + return x.ProductId + } + return "" +} + +func (x *LineItem) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *LineItem) GetQuantity() int32 { + if x != nil { + return x.Quantity + } + return 0 +} + +type ItemAdded struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item *LineItem `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *ItemAdded) Reset() { + *x = ItemAdded{} + if protoimpl.UnsafeEnabled { + mi := &file_domain_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ItemAdded) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ItemAdded) ProtoMessage() {} + +func (x *ItemAdded) ProtoReflect() protoreflect.Message { + mi := &file_domain_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ItemAdded.ProtoReflect.Descriptor instead. +func (*ItemAdded) Descriptor() ([]byte, []int) { + return file_domain_proto_rawDescGZIP(), []int{1} +} + +func (x *ItemAdded) GetItem() *LineItem { + if x != nil { + return x.Item + } + return nil +} + +type ItemRemoved struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProductId string `protobuf:"bytes,1,opt,name=productId,proto3" json:"productId,omitempty"` +} + +func (x *ItemRemoved) Reset() { + *x = ItemRemoved{} + if protoimpl.UnsafeEnabled { + mi := &file_domain_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ItemRemoved) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ItemRemoved) ProtoMessage() {} + +func (x *ItemRemoved) ProtoReflect() protoreflect.Message { + mi := &file_domain_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ItemRemoved.ProtoReflect.Descriptor instead. +func (*ItemRemoved) Descriptor() ([]byte, []int) { + return file_domain_proto_rawDescGZIP(), []int{2} +} + +func (x *ItemRemoved) GetProductId() string { + if x != nil { + return x.ProductId + } + return "" +} + +type CheckedOut struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CheckedOut) Reset() { + *x = CheckedOut{} + if protoimpl.UnsafeEnabled { + mi := &file_domain_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CheckedOut) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CheckedOut) ProtoMessage() {} + +func (x *CheckedOut) ProtoReflect() protoreflect.Message { + mi := &file_domain_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CheckedOut.ProtoReflect.Descriptor instead. +func (*CheckedOut) Descriptor() ([]byte, []int) { + return file_domain_proto_rawDescGZIP(), []int{3} +} + +type Cart struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Items []*LineItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` + Checkedout bool `protobuf:"varint,2,opt,name=checkedout,proto3" json:"checkedout,omitempty"` +} + +func (x *Cart) Reset() { + *x = Cart{} + if protoimpl.UnsafeEnabled { + mi := &file_domain_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Cart) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Cart) ProtoMessage() {} + +func (x *Cart) ProtoReflect() protoreflect.Message { + mi := &file_domain_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Cart.ProtoReflect.Descriptor instead. +func (*Cart) Descriptor() ([]byte, []int) { + return file_domain_proto_rawDescGZIP(), []int{4} +} + +func (x *Cart) GetItems() []*LineItem { + if x != nil { + return x.Items + } + return nil +} + +func (x *Cart) GetCheckedout() bool { + if x != nil { + return x.Checkedout + } + return false +} + +var File_domain_proto protoreflect.FileDescriptor + +var file_domain_proto_rawDesc = []byte{ + 0x0a, 0x0c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1b, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, + 0x63, 0x61, 0x72, 0x74, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x22, 0x58, 0x0a, 0x08, 0x4c, + 0x69, 0x6e, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, + 0x63, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x71, 0x75, 0x61, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x71, 0x75, 0x61, + 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0x46, 0x0a, 0x09, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x64, 0x64, + 0x65, 0x64, 0x12, 0x39, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x25, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, + 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x4c, + 0x69, 0x6e, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x2b, 0x0a, + 0x0b, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, + 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x22, 0x0c, 0x0a, 0x0a, 0x43, 0x68, + 0x65, 0x63, 0x6b, 0x65, 0x64, 0x4f, 0x75, 0x74, 0x22, 0x63, 0x0a, 0x04, 0x43, 0x61, 0x72, 0x74, + 0x12, 0x3b, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x25, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, + 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x4c, 0x69, + 0x6e, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x12, 0x1e, 0x0a, + 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x6f, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0a, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x65, 0x64, 0x6f, 0x75, 0x74, 0x42, 0x59, 0x0a, + 0x0b, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5a, 0x4a, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x63, 0x72, 0x64, 0x74, 0x5f, 0x73, 0x68, + 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2f, 0x64, 0x6f, 0x6d, 0x61, 0x69, + 0x6e, 0x3b, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_domain_proto_rawDescOnce sync.Once + file_domain_proto_rawDescData = file_domain_proto_rawDesc +) + +func file_domain_proto_rawDescGZIP() []byte { + file_domain_proto_rawDescOnce.Do(func() { + file_domain_proto_rawDescData = protoimpl.X.CompressGZIP(file_domain_proto_rawDescData) + }) + return file_domain_proto_rawDescData +} + +var file_domain_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_domain_proto_goTypes = []interface{}{ + (*LineItem)(nil), // 0: example.shoppingcart.domain.LineItem + (*ItemAdded)(nil), // 1: example.shoppingcart.domain.ItemAdded + (*ItemRemoved)(nil), // 2: example.shoppingcart.domain.ItemRemoved + (*CheckedOut)(nil), // 3: example.shoppingcart.domain.CheckedOut + (*Cart)(nil), // 4: example.shoppingcart.domain.Cart +} +var file_domain_proto_depIdxs = []int32{ + 0, // 0: example.shoppingcart.domain.ItemAdded.item:type_name -> example.shoppingcart.domain.LineItem + 0, // 1: example.shoppingcart.domain.Cart.items:type_name -> example.shoppingcart.domain.LineItem + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_domain_proto_init() } +func file_domain_proto_init() { + if File_domain_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_domain_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LineItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_domain_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ItemAdded); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_domain_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ItemRemoved); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_domain_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CheckedOut); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_domain_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Cart); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_domain_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_domain_proto_goTypes, + DependencyIndexes: file_domain_proto_depIdxs, + MessageInfos: file_domain_proto_msgTypes, + }.Build() + File_domain_proto = out.File + file_domain_proto_rawDesc = nil + file_domain_proto_goTypes = nil + file_domain_proto_depIdxs = nil +} diff --git a/example/crdt_shoppingcart/domain/domain.proto b/example/crdt_shoppingcart/domain/domain.proto new file mode 100644 index 0000000..3feef4d --- /dev/null +++ b/example/crdt_shoppingcart/domain/domain.proto @@ -0,0 +1,28 @@ +syntax = "proto3"; + +package example.shoppingcart.domain; + +option java_package = "com.example"; +option go_package = "github.com/cloudstateio/go-support/example/crdt_shoppingcart/domain;domain"; + +message LineItem { + string productId = 1; + string name = 2; + int32 quantity = 3; +} + +message ItemAdded { + LineItem item = 1; +} + +message ItemRemoved { + string productId = 1; +} + +message CheckedOut { +} + +message Cart { + repeated LineItem items = 1; + bool checkedout = 2; +} diff --git a/example/crdt_shoppingcart/shoppingcart/entity.go b/example/crdt_shoppingcart/shoppingcart/entity.go new file mode 100644 index 0000000..2301f63 --- /dev/null +++ b/example/crdt_shoppingcart/shoppingcart/entity.go @@ -0,0 +1,108 @@ +package shoppingcart + +import ( + "errors" + + "github.com/cloudstateio/go-support/cloudstate/crdt" + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" +) + +type ShoppingCart struct { + items *crdt.ORMap +} + +func NewShoppingCart(id crdt.EntityID) crdt.EntityHandler { + return &ShoppingCart{} +} + +func (s *ShoppingCart) getCart() (*Cart, error) { + items := &Cart{} + for _, state := range s.items.Values() { + var item LineItem + if err := encoding.DecodeStruct(state.GetLwwregister().GetValue(), &item); err != nil { + return nil, err + } + items.Items = append(items.Items, &item) + } + return items, nil +} + +// tag::command-handling-getcart-0[] +// tag::add-item-0[] +func (s *ShoppingCart) HandleCommand(ctx *crdt.CommandContext, name string, msg proto.Message) (*any.Any, error) { + // end::command-handling-getcart-0[] + // end::add-item-0[] + + // tag::watch-cart[] + switch name { + case "WatchCart": + ctx.ChangeFunc(func(c *crdt.CommandContext) (*any.Any, error) { + cart, err := s.getCart() + if err != nil { + return nil, err + } + return encoding.MarshalAny(cart) + }) + cart, err := s.getCart() + if err != nil { + return nil, err + } + return encoding.MarshalAny(cart) + } + // end::watch-cart[] + // tag::command-handling-getcart-1[] + // tag::add-item-1[] + switch m := msg.(type) { + // end::add-item-1[] + case *GetShoppingCart: + cart, err := s.getCart() + if err != nil { + return nil, err + } + return encoding.MarshalAny(cart) + // end::command-handling-getcart-1[] + // tag::add-item-2[] + case *AddLineItem: + if m.GetQuantity() <= 0 { + return nil, errors.New("cannot add a negative quantity of items") + } + + item, err := encoding.MarshalAny(&LineItem{ + ProductId: m.GetProductId(), + Name: m.GetName(), + Quantity: m.GetQuantity(), + }) + if err != nil { + return nil, err + } + key := encoding.String(m.GetProductId()) + reg, err := s.items.LWWRegister(key) + if err != nil { + return nil, err + } + if reg != nil { + reg.Set(item) + } else { + reg = crdt.NewLWWRegister(item) + } + s.items.Set(key, reg) + return encoding.Empty, nil + // end::add-item-2[] + default: + return nil, nil + } +} + +// tag::creation[] +func (s *ShoppingCart) Default(ctx *crdt.Context) (crdt.CRDT, error) { + return crdt.NewORMap(), nil +} + +func (s *ShoppingCart) Set(ctx *crdt.Context, state crdt.CRDT) error { + s.items = state.(*crdt.ORMap) + return nil +} + +// end::creation[] diff --git a/example/crdt_shoppingcart/shoppingcart/hotitems.pb.go b/example/crdt_shoppingcart/shoppingcart/hotitems.pb.go new file mode 100644 index 0000000..afc8ae8 --- /dev/null +++ b/example/crdt_shoppingcart/shoppingcart/hotitems.pb.go @@ -0,0 +1,270 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: hotitems.proto + +package shoppingcart + +import ( + context "context" + _ "github.com/cloudstateio/go-support/cloudstate" + proto "github.com/golang/protobuf/proto" + empty "github.com/golang/protobuf/ptypes/empty" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type Item struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Quantity int32 `protobuf:"varint,3,opt,name=quantity,proto3" json:"quantity,omitempty"` +} + +func (x *Item) Reset() { + *x = Item{} + if protoimpl.UnsafeEnabled { + mi := &file_hotitems_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Item) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Item) ProtoMessage() {} + +func (x *Item) ProtoReflect() protoreflect.Message { + mi := &file_hotitems_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Item.ProtoReflect.Descriptor instead. +func (*Item) Descriptor() ([]byte, []int) { + return file_hotitems_proto_rawDescGZIP(), []int{0} +} + +func (x *Item) GetProductId() string { + if x != nil { + return x.ProductId + } + return "" +} + +func (x *Item) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Item) GetQuantity() int32 { + if x != nil { + return x.Quantity + } + return 0 +} + +var File_hotitems_proto protoreflect.FileDescriptor + +var file_hotitems_proto_rawDesc = []byte{ + 0x0a, 0x0e, 0x68, 0x6f, 0x74, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x14, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, + 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x22, 0x55, 0x0a, 0x04, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x71, + 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x71, + 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x32, 0x58, 0x0a, 0x0f, 0x48, 0x6f, 0x74, 0x49, 0x74, + 0x65, 0x6d, 0x73, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x0f, 0x49, 0x74, + 0x65, 0x6d, 0x41, 0x64, 0x64, 0x65, 0x64, 0x54, 0x6f, 0x43, 0x61, 0x72, 0x74, 0x12, 0x1a, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, + 0x63, 0x61, 0x72, 0x74, 0x2e, 0x49, 0x74, 0x65, 0x6d, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x42, 0x65, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, + 0x5a, 0x56, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x73, 0x75, 0x70, + 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x63, 0x72, 0x64, + 0x74, 0x5f, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2f, 0x73, + 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x3b, 0x73, 0x68, 0x6f, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_hotitems_proto_rawDescOnce sync.Once + file_hotitems_proto_rawDescData = file_hotitems_proto_rawDesc +) + +func file_hotitems_proto_rawDescGZIP() []byte { + file_hotitems_proto_rawDescOnce.Do(func() { + file_hotitems_proto_rawDescData = protoimpl.X.CompressGZIP(file_hotitems_proto_rawDescData) + }) + return file_hotitems_proto_rawDescData +} + +var file_hotitems_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_hotitems_proto_goTypes = []interface{}{ + (*Item)(nil), // 0: example.shoppingcart.Item + (*empty.Empty)(nil), // 1: google.protobuf.Empty +} +var file_hotitems_proto_depIdxs = []int32{ + 0, // 0: example.shoppingcart.HotItemsService.ItemAddedToCart:input_type -> example.shoppingcart.Item + 1, // 1: example.shoppingcart.HotItemsService.ItemAddedToCart:output_type -> google.protobuf.Empty + 1, // [1:2] is the sub-list for method output_type + 0, // [0:1] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_hotitems_proto_init() } +func file_hotitems_proto_init() { + if File_hotitems_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_hotitems_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Item); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_hotitems_proto_rawDesc, + NumEnums: 0, + NumMessages: 1, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_hotitems_proto_goTypes, + DependencyIndexes: file_hotitems_proto_depIdxs, + MessageInfos: file_hotitems_proto_msgTypes, + }.Build() + File_hotitems_proto = out.File + file_hotitems_proto_rawDesc = nil + file_hotitems_proto_goTypes = nil + file_hotitems_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// HotItemsServiceClient is the client API for HotItemsService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type HotItemsServiceClient interface { + ItemAddedToCart(ctx context.Context, in *Item, opts ...grpc.CallOption) (*empty.Empty, error) +} + +type hotItemsServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewHotItemsServiceClient(cc grpc.ClientConnInterface) HotItemsServiceClient { + return &hotItemsServiceClient{cc} +} + +func (c *hotItemsServiceClient) ItemAddedToCart(ctx context.Context, in *Item, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/example.shoppingcart.HotItemsService/ItemAddedToCart", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// HotItemsServiceServer is the server API for HotItemsService service. +type HotItemsServiceServer interface { + ItemAddedToCart(context.Context, *Item) (*empty.Empty, error) +} + +// UnimplementedHotItemsServiceServer can be embedded to have forward compatible implementations. +type UnimplementedHotItemsServiceServer struct { +} + +func (*UnimplementedHotItemsServiceServer) ItemAddedToCart(context.Context, *Item) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method ItemAddedToCart not implemented") +} + +func RegisterHotItemsServiceServer(s *grpc.Server, srv HotItemsServiceServer) { + s.RegisterService(&_HotItemsService_serviceDesc, srv) +} + +func _HotItemsService_ItemAddedToCart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Item) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(HotItemsServiceServer).ItemAddedToCart(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/example.shoppingcart.HotItemsService/ItemAddedToCart", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(HotItemsServiceServer).ItemAddedToCart(ctx, req.(*Item)) + } + return interceptor(ctx, in, info, handler) +} + +var _HotItemsService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "example.shoppingcart.HotItemsService", + HandlerType: (*HotItemsServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ItemAddedToCart", + Handler: _HotItemsService_ItemAddedToCart_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "hotitems.proto", +} diff --git a/example/crdt_shoppingcart/shoppingcart/hotitems.proto b/example/crdt_shoppingcart/shoppingcart/hotitems.proto new file mode 100644 index 0000000..d523616 --- /dev/null +++ b/example/crdt_shoppingcart/shoppingcart/hotitems.proto @@ -0,0 +1,19 @@ +syntax = "proto3"; + +import "google/protobuf/empty.proto"; +import "cloudstate/entity_key.proto"; + +package example.shoppingcart; + +option java_package = "com.example"; +option go_package = "github.com/cloudstateio/go-support/example/crdt_shoppingcart/shoppingcart;shoppingcart"; + +service HotItemsService { + rpc ItemAddedToCart (Item) returns (google.protobuf.Empty); +} + +message Item { + string product_id = 1; + string name = 2; + int32 quantity = 3; +} diff --git a/example/crdt_shoppingcart/shoppingcart/shoppingcart.pb.go b/example/crdt_shoppingcart/shoppingcart/shoppingcart.pb.go new file mode 100644 index 0000000..5fc88e4 --- /dev/null +++ b/example/crdt_shoppingcart/shoppingcart/shoppingcart.pb.go @@ -0,0 +1,721 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: shoppingcart.proto + +package shoppingcart + +import ( + context "context" + _ "github.com/cloudstateio/go-support/cloudstate" + proto "github.com/golang/protobuf/proto" + empty "github.com/golang/protobuf/ptypes/empty" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type AddLineItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ProductId string `protobuf:"bytes,2,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Quantity int32 `protobuf:"varint,4,opt,name=quantity,proto3" json:"quantity,omitempty"` +} + +func (x *AddLineItem) Reset() { + *x = AddLineItem{} + if protoimpl.UnsafeEnabled { + mi := &file_shoppingcart_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddLineItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddLineItem) ProtoMessage() {} + +func (x *AddLineItem) ProtoReflect() protoreflect.Message { + mi := &file_shoppingcart_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddLineItem.ProtoReflect.Descriptor instead. +func (*AddLineItem) Descriptor() ([]byte, []int) { + return file_shoppingcart_proto_rawDescGZIP(), []int{0} +} + +func (x *AddLineItem) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *AddLineItem) GetProductId() string { + if x != nil { + return x.ProductId + } + return "" +} + +func (x *AddLineItem) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *AddLineItem) GetQuantity() int32 { + if x != nil { + return x.Quantity + } + return 0 +} + +type RemoveLineItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ProductId string `protobuf:"bytes,2,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` +} + +func (x *RemoveLineItem) Reset() { + *x = RemoveLineItem{} + if protoimpl.UnsafeEnabled { + mi := &file_shoppingcart_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveLineItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveLineItem) ProtoMessage() {} + +func (x *RemoveLineItem) ProtoReflect() protoreflect.Message { + mi := &file_shoppingcart_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveLineItem.ProtoReflect.Descriptor instead. +func (*RemoveLineItem) Descriptor() ([]byte, []int) { + return file_shoppingcart_proto_rawDescGZIP(), []int{1} +} + +func (x *RemoveLineItem) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *RemoveLineItem) GetProductId() string { + if x != nil { + return x.ProductId + } + return "" +} + +type GetShoppingCart struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` +} + +func (x *GetShoppingCart) Reset() { + *x = GetShoppingCart{} + if protoimpl.UnsafeEnabled { + mi := &file_shoppingcart_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetShoppingCart) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetShoppingCart) ProtoMessage() {} + +func (x *GetShoppingCart) ProtoReflect() protoreflect.Message { + mi := &file_shoppingcart_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetShoppingCart.ProtoReflect.Descriptor instead. +func (*GetShoppingCart) Descriptor() ([]byte, []int) { + return file_shoppingcart_proto_rawDescGZIP(), []int{2} +} + +func (x *GetShoppingCart) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +type LineItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Quantity int32 `protobuf:"varint,3,opt,name=quantity,proto3" json:"quantity,omitempty"` +} + +func (x *LineItem) Reset() { + *x = LineItem{} + if protoimpl.UnsafeEnabled { + mi := &file_shoppingcart_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LineItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LineItem) ProtoMessage() {} + +func (x *LineItem) ProtoReflect() protoreflect.Message { + mi := &file_shoppingcart_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LineItem.ProtoReflect.Descriptor instead. +func (*LineItem) Descriptor() ([]byte, []int) { + return file_shoppingcart_proto_rawDescGZIP(), []int{3} +} + +func (x *LineItem) GetProductId() string { + if x != nil { + return x.ProductId + } + return "" +} + +func (x *LineItem) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *LineItem) GetQuantity() int32 { + if x != nil { + return x.Quantity + } + return 0 +} + +type Cart struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Items []*LineItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` +} + +func (x *Cart) Reset() { + *x = Cart{} + if protoimpl.UnsafeEnabled { + mi := &file_shoppingcart_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Cart) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Cart) ProtoMessage() {} + +func (x *Cart) ProtoReflect() protoreflect.Message { + mi := &file_shoppingcart_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Cart.ProtoReflect.Descriptor instead. +func (*Cart) Descriptor() ([]byte, []int) { + return file_shoppingcart_proto_rawDescGZIP(), []int{4} +} + +func (x *Cart) GetItems() []*LineItem { + if x != nil { + return x.Items + } + return nil +} + +var File_shoppingcart_proto protoreflect.FileDescriptor + +var file_shoppingcart_proto_rawDesc = []byte{ + 0x0a, 0x12, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, + 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x2f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7b, 0x0a, 0x0b, 0x41, 0x64, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x49, + 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, + 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x22, 0x4e, 0x0a, 0x0e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x69, 0x6e, 0x65, 0x49, + 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, + 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, + 0x64, 0x22, 0x30, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x53, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, + 0x43, 0x61, 0x72, 0x74, 0x12, 0x1d, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x64, 0x22, 0x59, 0x0a, 0x08, 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, + 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0x3c, + 0x0a, 0x04, 0x43, 0x61, 0x72, 0x74, 0x12, 0x34, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, + 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, 0x4c, 0x69, 0x6e, + 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x32, 0xc7, 0x02, 0x0a, + 0x13, 0x53, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x61, 0x72, 0x74, 0x53, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x12, 0x44, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x49, 0x74, 0x65, 0x6d, 0x12, + 0x21, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, + 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, 0x41, 0x64, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x74, + 0x65, 0x6d, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x4a, 0x0a, 0x0a, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x24, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x1a, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x4c, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x43, 0x61, 0x72, + 0x74, 0x12, 0x25, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x68, 0x6f, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x43, 0x61, 0x72, 0x74, 0x1a, 0x1a, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, + 0x43, 0x61, 0x72, 0x74, 0x12, 0x50, 0x0a, 0x09, 0x57, 0x61, 0x74, 0x63, 0x68, 0x43, 0x61, 0x72, + 0x74, 0x12, 0x25, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x68, 0x6f, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x43, 0x61, 0x72, 0x74, 0x1a, 0x1a, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, + 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, + 0x43, 0x61, 0x72, 0x74, 0x30, 0x01, 0x42, 0x65, 0x0a, 0x0b, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, + 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x5a, 0x56, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, 0x67, + 0x6f, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2f, 0x63, 0x72, 0x64, 0x74, 0x5f, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, + 0x61, 0x72, 0x74, 0x2f, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, + 0x3b, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_shoppingcart_proto_rawDescOnce sync.Once + file_shoppingcart_proto_rawDescData = file_shoppingcart_proto_rawDesc +) + +func file_shoppingcart_proto_rawDescGZIP() []byte { + file_shoppingcart_proto_rawDescOnce.Do(func() { + file_shoppingcart_proto_rawDescData = protoimpl.X.CompressGZIP(file_shoppingcart_proto_rawDescData) + }) + return file_shoppingcart_proto_rawDescData +} + +var file_shoppingcart_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_shoppingcart_proto_goTypes = []interface{}{ + (*AddLineItem)(nil), // 0: example.shoppingcart.AddLineItem + (*RemoveLineItem)(nil), // 1: example.shoppingcart.RemoveLineItem + (*GetShoppingCart)(nil), // 2: example.shoppingcart.GetShoppingCart + (*LineItem)(nil), // 3: example.shoppingcart.LineItem + (*Cart)(nil), // 4: example.shoppingcart.Cart + (*empty.Empty)(nil), // 5: google.protobuf.Empty +} +var file_shoppingcart_proto_depIdxs = []int32{ + 3, // 0: example.shoppingcart.Cart.items:type_name -> example.shoppingcart.LineItem + 0, // 1: example.shoppingcart.ShoppingCartService.AddItem:input_type -> example.shoppingcart.AddLineItem + 1, // 2: example.shoppingcart.ShoppingCartService.RemoveItem:input_type -> example.shoppingcart.RemoveLineItem + 2, // 3: example.shoppingcart.ShoppingCartService.GetCart:input_type -> example.shoppingcart.GetShoppingCart + 2, // 4: example.shoppingcart.ShoppingCartService.WatchCart:input_type -> example.shoppingcart.GetShoppingCart + 5, // 5: example.shoppingcart.ShoppingCartService.AddItem:output_type -> google.protobuf.Empty + 5, // 6: example.shoppingcart.ShoppingCartService.RemoveItem:output_type -> google.protobuf.Empty + 4, // 7: example.shoppingcart.ShoppingCartService.GetCart:output_type -> example.shoppingcart.Cart + 4, // 8: example.shoppingcart.ShoppingCartService.WatchCart:output_type -> example.shoppingcart.Cart + 5, // [5:9] is the sub-list for method output_type + 1, // [1:5] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_shoppingcart_proto_init() } +func file_shoppingcart_proto_init() { + if File_shoppingcart_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_shoppingcart_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddLineItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_shoppingcart_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoveLineItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_shoppingcart_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetShoppingCart); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_shoppingcart_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LineItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_shoppingcart_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Cart); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_shoppingcart_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_shoppingcart_proto_goTypes, + DependencyIndexes: file_shoppingcart_proto_depIdxs, + MessageInfos: file_shoppingcart_proto_msgTypes, + }.Build() + File_shoppingcart_proto = out.File + file_shoppingcart_proto_rawDesc = nil + file_shoppingcart_proto_goTypes = nil + file_shoppingcart_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// ShoppingCartServiceClient is the client API for ShoppingCartService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type ShoppingCartServiceClient interface { + AddItem(ctx context.Context, in *AddLineItem, opts ...grpc.CallOption) (*empty.Empty, error) + RemoveItem(ctx context.Context, in *RemoveLineItem, opts ...grpc.CallOption) (*empty.Empty, error) + GetCart(ctx context.Context, in *GetShoppingCart, opts ...grpc.CallOption) (*Cart, error) + WatchCart(ctx context.Context, in *GetShoppingCart, opts ...grpc.CallOption) (ShoppingCartService_WatchCartClient, error) +} + +type shoppingCartServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewShoppingCartServiceClient(cc grpc.ClientConnInterface) ShoppingCartServiceClient { + return &shoppingCartServiceClient{cc} +} + +func (c *shoppingCartServiceClient) AddItem(ctx context.Context, in *AddLineItem, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/example.shoppingcart.ShoppingCartService/AddItem", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *shoppingCartServiceClient) RemoveItem(ctx context.Context, in *RemoveLineItem, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/example.shoppingcart.ShoppingCartService/RemoveItem", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *shoppingCartServiceClient) GetCart(ctx context.Context, in *GetShoppingCart, opts ...grpc.CallOption) (*Cart, error) { + out := new(Cart) + err := c.cc.Invoke(ctx, "/example.shoppingcart.ShoppingCartService/GetCart", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *shoppingCartServiceClient) WatchCart(ctx context.Context, in *GetShoppingCart, opts ...grpc.CallOption) (ShoppingCartService_WatchCartClient, error) { + stream, err := c.cc.NewStream(ctx, &_ShoppingCartService_serviceDesc.Streams[0], "/example.shoppingcart.ShoppingCartService/WatchCart", opts...) + if err != nil { + return nil, err + } + x := &shoppingCartServiceWatchCartClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type ShoppingCartService_WatchCartClient interface { + Recv() (*Cart, error) + grpc.ClientStream +} + +type shoppingCartServiceWatchCartClient struct { + grpc.ClientStream +} + +func (x *shoppingCartServiceWatchCartClient) Recv() (*Cart, error) { + m := new(Cart) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +// ShoppingCartServiceServer is the server API for ShoppingCartService service. +type ShoppingCartServiceServer interface { + AddItem(context.Context, *AddLineItem) (*empty.Empty, error) + RemoveItem(context.Context, *RemoveLineItem) (*empty.Empty, error) + GetCart(context.Context, *GetShoppingCart) (*Cart, error) + WatchCart(*GetShoppingCart, ShoppingCartService_WatchCartServer) error +} + +// UnimplementedShoppingCartServiceServer can be embedded to have forward compatible implementations. +type UnimplementedShoppingCartServiceServer struct { +} + +func (*UnimplementedShoppingCartServiceServer) AddItem(context.Context, *AddLineItem) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddItem not implemented") +} +func (*UnimplementedShoppingCartServiceServer) RemoveItem(context.Context, *RemoveLineItem) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoveItem not implemented") +} +func (*UnimplementedShoppingCartServiceServer) GetCart(context.Context, *GetShoppingCart) (*Cart, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetCart not implemented") +} +func (*UnimplementedShoppingCartServiceServer) WatchCart(*GetShoppingCart, ShoppingCartService_WatchCartServer) error { + return status.Errorf(codes.Unimplemented, "method WatchCart not implemented") +} + +func RegisterShoppingCartServiceServer(s *grpc.Server, srv ShoppingCartServiceServer) { + s.RegisterService(&_ShoppingCartService_serviceDesc, srv) +} + +func _ShoppingCartService_AddItem_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddLineItem) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ShoppingCartServiceServer).AddItem(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/example.shoppingcart.ShoppingCartService/AddItem", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ShoppingCartServiceServer).AddItem(ctx, req.(*AddLineItem)) + } + return interceptor(ctx, in, info, handler) +} + +func _ShoppingCartService_RemoveItem_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveLineItem) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ShoppingCartServiceServer).RemoveItem(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/example.shoppingcart.ShoppingCartService/RemoveItem", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ShoppingCartServiceServer).RemoveItem(ctx, req.(*RemoveLineItem)) + } + return interceptor(ctx, in, info, handler) +} + +func _ShoppingCartService_GetCart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetShoppingCart) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ShoppingCartServiceServer).GetCart(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/example.shoppingcart.ShoppingCartService/GetCart", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ShoppingCartServiceServer).GetCart(ctx, req.(*GetShoppingCart)) + } + return interceptor(ctx, in, info, handler) +} + +func _ShoppingCartService_WatchCart_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(GetShoppingCart) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(ShoppingCartServiceServer).WatchCart(m, &shoppingCartServiceWatchCartServer{stream}) +} + +type ShoppingCartService_WatchCartServer interface { + Send(*Cart) error + grpc.ServerStream +} + +type shoppingCartServiceWatchCartServer struct { + grpc.ServerStream +} + +func (x *shoppingCartServiceWatchCartServer) Send(m *Cart) error { + return x.ServerStream.SendMsg(m) +} + +var _ShoppingCartService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "example.shoppingcart.ShoppingCartService", + HandlerType: (*ShoppingCartServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AddItem", + Handler: _ShoppingCartService_AddItem_Handler, + }, + { + MethodName: "RemoveItem", + Handler: _ShoppingCartService_RemoveItem_Handler, + }, + { + MethodName: "GetCart", + Handler: _ShoppingCartService_GetCart_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "WatchCart", + Handler: _ShoppingCartService_WatchCart_Handler, + ServerStreams: true, + }, + }, + Metadata: "shoppingcart.proto", +} diff --git a/example/crdt_shoppingcart/shoppingcart/shoppingcart.proto b/example/crdt_shoppingcart/shoppingcart/shoppingcart.proto new file mode 100644 index 0000000..14a3ba4 --- /dev/null +++ b/example/crdt_shoppingcart/shoppingcart/shoppingcart.proto @@ -0,0 +1,42 @@ +syntax = "proto3"; + +import "google/protobuf/empty.proto"; +import "cloudstate/entity_key.proto"; + +package example.shoppingcart; + +option java_package = "com.example"; +option go_package = "github.com/cloudstateio/go-support/example/crdt_shoppingcart/shoppingcart;shoppingcart"; + +service ShoppingCartService { + rpc AddItem (AddLineItem) returns (google.protobuf.Empty); + rpc RemoveItem (RemoveLineItem) returns (google.protobuf.Empty); + rpc GetCart (GetShoppingCart) returns (Cart); + rpc WatchCart (GetShoppingCart) returns (stream Cart); +} + +message AddLineItem { + string user_id = 1 [(.cloudstate.entity_key) = true]; + string product_id = 2; + string name = 3; + int32 quantity = 4; +} + +message RemoveLineItem { + string user_id = 1 [(.cloudstate.entity_key) = true]; + string product_id = 2; +} + +message GetShoppingCart { + string user_id = 1 [(.cloudstate.entity_key) = true]; +} + +message LineItem { + string product_id = 1; + string name = 2; + int32 quantity = 3; +} + +message Cart { + repeated LineItem items = 1; +} diff --git a/example/effects/shoppingcart/entity.go b/example/effects/shoppingcart/entity.go new file mode 100644 index 0000000..fe1ee84 --- /dev/null +++ b/example/effects/shoppingcart/entity.go @@ -0,0 +1,63 @@ +package shoppingcart + +import ( + "github.com/cloudstateio/go-support/cloudstate/crdt" + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/cloudstateio/go-support/example/crdt_shoppingcart/shoppingcart" +) + +type ShoppingCart struct { +} + +func (s *ShoppingCart) HandleCommand(ctx *crdt.CommandContext, name string, cmd interface{}) (reply interface{}, err error) { + // tag::forward[] + switch cmd { + case "Forward": + switch c := cmd.(type) { + case *shoppingcart.AddLineItem: + any, err := encoding.MarshalAny(&shoppingcart.Item{ + ProductId: c.GetProductId(), + Name: c.GetName(), + Quantity: c.GetQuantity(), + }) + if err != nil { + return nil, err + } + ctx.Forward(&protocol.Forward{ + ServiceName: "example.shoppingcart.HotItemsService", + CommandName: "ItemAddedToCart", + Payload: any, + }) + } + return encoding.Empty, nil + // end::forward[] + // tag::effect[] + case "Effect": + switch c := cmd.(type) { + case *shoppingcart.AddLineItem: + any, err := encoding.MarshalAny(&shoppingcart.Item{ + ProductId: c.GetProductId(), + Name: c.GetName(), + Quantity: c.GetQuantity(), + }) + if err != nil { + return nil, err + } + ctx.SideEffect(&protocol.SideEffect{ + ServiceName: "example.shoppingcart.HotItemsService", + CommandName: "ItemAddedToCart", + Payload: any, + Synchronous: true, + }) + } + return encoding.Empty, nil + // end::effect[] + default: + return encoding.Empty, nil + } +} + +func (s *ShoppingCart) HandleEvent(ctx *interface{}, event interface{}) error { + return nil +} diff --git a/example/shoppingcart/entity.go b/example/shoppingcart/entity.go new file mode 100644 index 0000000..bd4ce14 --- /dev/null +++ b/example/shoppingcart/entity.go @@ -0,0 +1,195 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package shoppingcart + +import ( + "errors" + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/eventsourced" + domain "github.com/cloudstateio/go-support/example/shoppingcart/persistence" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/empty" +) + +// A Cloudstate event sourced entity implementing a shopping cart. +// tag::entity-type[] +// tag::entity-state[] +type ShoppingCart struct { + // our domain object + cart []*domain.LineItem +} + +// end::entity-state[] +// end::entity-type[] + +// NewShoppingCart returns a new and initialized instance of the ShoppingCart entity. +// tag::entity-func[] +func NewShoppingCart(eventsourced.EntityID) eventsourced.EntityHandler { + return &ShoppingCart{ + cart: make([]*domain.LineItem, 0), + } +} + +// end::entity-func[] + +// ItemAdded is a event handler function for the ItemAdded event. +// tag::item-added[] +func (sc *ShoppingCart) ItemAdded(added *domain.ItemAdded) error { + if added.Item.GetName() == "FAIL" { + return errors.New("boom: forced an unexpected error") + } + if item, _ := sc.find(added.Item.ProductId); item != nil { + item.Quantity += added.Item.Quantity + return nil + } + sc.cart = append(sc.cart, &domain.LineItem{ + ProductId: added.Item.ProductId, + Name: added.Item.Name, + Quantity: added.Item.Quantity, + }) + return nil +} + +// end::item-added[] + +// ItemRemoved is a event handler function for the ItemRemoved event. +func (sc *ShoppingCart) ItemRemoved(removed *domain.ItemRemoved) error { + if !sc.remove(removed.ProductId) { + return errors.New("unable to remove product") + } + return nil +} + +// HandleEvent lets us handle events by ourselves. +// tag::handle-event[] +func (sc *ShoppingCart) HandleEvent(ctx *eventsourced.Context, event interface{}) error { + switch e := event.(type) { + case *domain.ItemAdded: + return sc.ItemAdded(e) + case *domain.ItemRemoved: + return sc.ItemRemoved(e) + default: + return nil + } +} + +// end::handle-event[] + +// AddItem implements the AddItem command handling of the shopping cart service. +// tag::add-item[] +func (sc *ShoppingCart) AddItem(ctx *eventsourced.Context, li *AddLineItem) (*empty.Empty, error) { + if li.GetQuantity() <= 0 { + return nil, fmt.Errorf("cannot add negative quantity of to item %q", li.GetProductId()) + } + ctx.Emit(&domain.ItemAdded{ + Item: &domain.LineItem{ + ProductId: li.ProductId, + Name: li.Name, + Quantity: li.Quantity, + }}) + return &empty.Empty{}, nil +} + +// end::add-item[] + +// RemoveItem implements the RemoveItem command handling of the shopping cart service. +func (sc *ShoppingCart) RemoveItem(ctx *eventsourced.Context, li *RemoveLineItem) (*empty.Empty, error) { + if item, _ := sc.find(li.GetProductId()); item == nil { + return nil, fmt.Errorf("cannot remove item %s because it is not in the cart", li.GetProductId()) + } + ctx.Emit(&domain.ItemRemoved{ProductId: li.ProductId}) + return &empty.Empty{}, nil +} + +// GetCart implements the GetCart command handling of the shopping cart service. +// tag::get-cart[] +func (sc *ShoppingCart) GetCart(*eventsourced.Context, *GetShoppingCart) (*Cart, error) { + cart := &Cart{} + for _, item := range sc.cart { + cart.Items = append(cart.Items, &LineItem{ + ProductId: item.ProductId, + Name: item.Name, + Quantity: item.Quantity, + }) + } + return cart, nil +} + +// end::get-cart[] + +// HandleCommand is the entities command handler implemented by the shopping cart. +// tag::handle-command[] +func (sc *ShoppingCart) HandleCommand(ctx *eventsourced.Context, name string, cmd proto.Message) (proto.Message, error) { + switch c := cmd.(type) { + case *GetShoppingCart: + return sc.GetCart(ctx, c) + case *RemoveLineItem: + return sc.RemoveItem(ctx, c) + case *AddLineItem: + return sc.AddItem(ctx, c) + default: + return nil, nil + } +} + +// end::handle-command[] + +// Snapshot returns the current state of the shopping cart. +// tag::snapshot[] +func (sc *ShoppingCart) Snapshot(*eventsourced.Context) (snapshot interface{}, err error) { + return &domain.Cart{ + Items: append(make([]*domain.LineItem, 0, len(sc.cart)), sc.cart...), + }, nil +} + +// end::snapshot[] + +// HandleSnapshot applies given snapshot to be the current state. +// tag::handle-snapshot[] +func (sc *ShoppingCart) HandleSnapshot(ctx *eventsourced.Context, snapshot interface{}) error { + switch value := snapshot.(type) { + case *domain.Cart: + sc.cart = append(sc.cart[:0], value.Items...) + return nil + default: + return fmt.Errorf("unknown snapshot type: %v", value) + } +} + +// end::handle-snapshot[] + +// find finds a product in the shopping cart by productId and returns it as a LineItem. +func (sc *ShoppingCart) find(productID string) (item *domain.LineItem, index int) { + for i, item := range sc.cart { + if productID == item.ProductId { + return item, i + } + } + return nil, 0 +} + +// remove removes a product from the shopping cart. +// An ok flag is returned to indicate that the product was present and removed. +func (sc *ShoppingCart) remove(productID string) (ok bool) { + if item, i := sc.find(productID); item != nil { + // remove and re-slice + copy(sc.cart[i:], sc.cart[i+1:]) + sc.cart = sc.cart[:len(sc.cart)-1] + return true + } + return false +} diff --git a/example/shoppingcart/persistence/domain.pb.go b/example/shoppingcart/persistence/domain.pb.go new file mode 100644 index 0000000..cc6ef60 --- /dev/null +++ b/example/shoppingcart/persistence/domain.pb.go @@ -0,0 +1,388 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// These are the messages that get persisted - the events, plus the current state (Cart) for snapshots. +// tag::domain[] + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: domain.proto + +package persistence + +import ( + proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type LineItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProductId string `protobuf:"bytes,1,opt,name=productId,proto3" json:"productId,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Quantity int32 `protobuf:"varint,3,opt,name=quantity,proto3" json:"quantity,omitempty"` +} + +func (x *LineItem) Reset() { + *x = LineItem{} + if protoimpl.UnsafeEnabled { + mi := &file_domain_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LineItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LineItem) ProtoMessage() {} + +func (x *LineItem) ProtoReflect() protoreflect.Message { + mi := &file_domain_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LineItem.ProtoReflect.Descriptor instead. +func (*LineItem) Descriptor() ([]byte, []int) { + return file_domain_proto_rawDescGZIP(), []int{0} +} + +func (x *LineItem) GetProductId() string { + if x != nil { + return x.ProductId + } + return "" +} + +func (x *LineItem) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *LineItem) GetQuantity() int32 { + if x != nil { + return x.Quantity + } + return 0 +} + +// The item added event. +type ItemAdded struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Item *LineItem `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` +} + +func (x *ItemAdded) Reset() { + *x = ItemAdded{} + if protoimpl.UnsafeEnabled { + mi := &file_domain_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ItemAdded) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ItemAdded) ProtoMessage() {} + +func (x *ItemAdded) ProtoReflect() protoreflect.Message { + mi := &file_domain_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ItemAdded.ProtoReflect.Descriptor instead. +func (*ItemAdded) Descriptor() ([]byte, []int) { + return file_domain_proto_rawDescGZIP(), []int{1} +} + +func (x *ItemAdded) GetItem() *LineItem { + if x != nil { + return x.Item + } + return nil +} + +// The item removed event. +type ItemRemoved struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProductId string `protobuf:"bytes,1,opt,name=productId,proto3" json:"productId,omitempty"` +} + +func (x *ItemRemoved) Reset() { + *x = ItemRemoved{} + if protoimpl.UnsafeEnabled { + mi := &file_domain_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ItemRemoved) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ItemRemoved) ProtoMessage() {} + +func (x *ItemRemoved) ProtoReflect() protoreflect.Message { + mi := &file_domain_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ItemRemoved.ProtoReflect.Descriptor instead. +func (*ItemRemoved) Descriptor() ([]byte, []int) { + return file_domain_proto_rawDescGZIP(), []int{2} +} + +func (x *ItemRemoved) GetProductId() string { + if x != nil { + return x.ProductId + } + return "" +} + +// The shopping cart state. +type Cart struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Items []*LineItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` +} + +func (x *Cart) Reset() { + *x = Cart{} + if protoimpl.UnsafeEnabled { + mi := &file_domain_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Cart) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Cart) ProtoMessage() {} + +func (x *Cart) ProtoReflect() protoreflect.Message { + mi := &file_domain_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Cart.ProtoReflect.Descriptor instead. +func (*Cart) Descriptor() ([]byte, []int) { + return file_domain_proto_rawDescGZIP(), []int{3} +} + +func (x *Cart) GetItems() []*LineItem { + if x != nil { + return x.Items + } + return nil +} + +var File_domain_proto protoreflect.FileDescriptor + +var file_domain_proto_rawDesc = []byte{ + 0x0a, 0x0c, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x24, + 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, + 0x65, 0x6e, 0x63, 0x65, 0x22, 0x58, 0x0a, 0x08, 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x74, 0x65, 0x6d, + 0x12, 0x1c, 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0x4f, + 0x0a, 0x09, 0x49, 0x74, 0x65, 0x6d, 0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x42, 0x0a, 0x04, 0x69, + 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, + 0x63, 0x61, 0x72, 0x74, 0x2e, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, + 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, + 0x2b, 0x0a, 0x0b, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x12, 0x1c, + 0x0a, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x22, 0x4c, 0x0a, 0x04, + 0x43, 0x61, 0x72, 0x74, 0x12, 0x44, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, 0x70, + 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x49, + 0x74, 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x42, 0x51, 0x5a, 0x4f, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, + 0x67, 0x63, 0x61, 0x72, 0x74, 0x2f, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, + 0x65, 0x3b, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_domain_proto_rawDescOnce sync.Once + file_domain_proto_rawDescData = file_domain_proto_rawDesc +) + +func file_domain_proto_rawDescGZIP() []byte { + file_domain_proto_rawDescOnce.Do(func() { + file_domain_proto_rawDescData = protoimpl.X.CompressGZIP(file_domain_proto_rawDescData) + }) + return file_domain_proto_rawDescData +} + +var file_domain_proto_msgTypes = make([]protoimpl.MessageInfo, 4) +var file_domain_proto_goTypes = []interface{}{ + (*LineItem)(nil), // 0: com.example.shoppingcart.persistence.LineItem + (*ItemAdded)(nil), // 1: com.example.shoppingcart.persistence.ItemAdded + (*ItemRemoved)(nil), // 2: com.example.shoppingcart.persistence.ItemRemoved + (*Cart)(nil), // 3: com.example.shoppingcart.persistence.Cart +} +var file_domain_proto_depIdxs = []int32{ + 0, // 0: com.example.shoppingcart.persistence.ItemAdded.item:type_name -> com.example.shoppingcart.persistence.LineItem + 0, // 1: com.example.shoppingcart.persistence.Cart.items:type_name -> com.example.shoppingcart.persistence.LineItem + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_domain_proto_init() } +func file_domain_proto_init() { + if File_domain_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_domain_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LineItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_domain_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ItemAdded); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_domain_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ItemRemoved); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_domain_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Cart); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_domain_proto_rawDesc, + NumEnums: 0, + NumMessages: 4, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_domain_proto_goTypes, + DependencyIndexes: file_domain_proto_depIdxs, + MessageInfos: file_domain_proto_msgTypes, + }.Build() + File_domain_proto = out.File + file_domain_proto_rawDesc = nil + file_domain_proto_goTypes = nil + file_domain_proto_depIdxs = nil +} diff --git a/example/shoppingcart/persistence/domain.proto b/example/shoppingcart/persistence/domain.proto new file mode 100644 index 0000000..91f4c18 --- /dev/null +++ b/example/shoppingcart/persistence/domain.proto @@ -0,0 +1,44 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// These are the messages that get persisted - the events, plus the current state (Cart) for snapshots. +// tag::domain[] +syntax = "proto3"; + +package com.example.shoppingcart.persistence; + +option go_package = "github.com/cloudstateio/go-support/example/shoppingcart/persistence;persistence"; + +message LineItem { + string productId = 1; + string name = 2; + int32 quantity = 3; +} + +// The item added event. +message ItemAdded { + LineItem item = 1; +} + +// The item removed event. +message ItemRemoved { + string productId = 1; +} + +// The shopping cart state. +message Cart { + repeated LineItem items = 1; +} +// end::domain[] diff --git a/example/shoppingcart/shoppingcart.pb.go b/example/shoppingcart/shoppingcart.pb.go new file mode 100644 index 0000000..174e917 --- /dev/null +++ b/example/shoppingcart/shoppingcart.pb.go @@ -0,0 +1,679 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This is the public API offered by the shopping cart entity. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: shoppingcart.proto + +package shoppingcart + +import ( + context "context" + _ "github.com/cloudstateio/go-support/cloudstate" + proto "github.com/golang/protobuf/proto" + empty "github.com/golang/protobuf/ptypes/empty" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type AddLineItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ProductId string `protobuf:"bytes,2,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` + Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` + Quantity int32 `protobuf:"varint,4,opt,name=quantity,proto3" json:"quantity,omitempty"` +} + +func (x *AddLineItem) Reset() { + *x = AddLineItem{} + if protoimpl.UnsafeEnabled { + mi := &file_shoppingcart_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AddLineItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AddLineItem) ProtoMessage() {} + +func (x *AddLineItem) ProtoReflect() protoreflect.Message { + mi := &file_shoppingcart_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AddLineItem.ProtoReflect.Descriptor instead. +func (*AddLineItem) Descriptor() ([]byte, []int) { + return file_shoppingcart_proto_rawDescGZIP(), []int{0} +} + +func (x *AddLineItem) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *AddLineItem) GetProductId() string { + if x != nil { + return x.ProductId + } + return "" +} + +func (x *AddLineItem) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *AddLineItem) GetQuantity() int32 { + if x != nil { + return x.Quantity + } + return 0 +} + +type RemoveLineItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + ProductId string `protobuf:"bytes,2,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` +} + +func (x *RemoveLineItem) Reset() { + *x = RemoveLineItem{} + if protoimpl.UnsafeEnabled { + mi := &file_shoppingcart_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RemoveLineItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RemoveLineItem) ProtoMessage() {} + +func (x *RemoveLineItem) ProtoReflect() protoreflect.Message { + mi := &file_shoppingcart_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RemoveLineItem.ProtoReflect.Descriptor instead. +func (*RemoveLineItem) Descriptor() ([]byte, []int) { + return file_shoppingcart_proto_rawDescGZIP(), []int{1} +} + +func (x *RemoveLineItem) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *RemoveLineItem) GetProductId() string { + if x != nil { + return x.ProductId + } + return "" +} + +type GetShoppingCart struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` +} + +func (x *GetShoppingCart) Reset() { + *x = GetShoppingCart{} + if protoimpl.UnsafeEnabled { + mi := &file_shoppingcart_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetShoppingCart) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetShoppingCart) ProtoMessage() {} + +func (x *GetShoppingCart) ProtoReflect() protoreflect.Message { + mi := &file_shoppingcart_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetShoppingCart.ProtoReflect.Descriptor instead. +func (*GetShoppingCart) Descriptor() ([]byte, []int) { + return file_shoppingcart_proto_rawDescGZIP(), []int{2} +} + +func (x *GetShoppingCart) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +type LineItem struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Quantity int32 `protobuf:"varint,3,opt,name=quantity,proto3" json:"quantity,omitempty"` +} + +func (x *LineItem) Reset() { + *x = LineItem{} + if protoimpl.UnsafeEnabled { + mi := &file_shoppingcart_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LineItem) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LineItem) ProtoMessage() {} + +func (x *LineItem) ProtoReflect() protoreflect.Message { + mi := &file_shoppingcart_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LineItem.ProtoReflect.Descriptor instead. +func (*LineItem) Descriptor() ([]byte, []int) { + return file_shoppingcart_proto_rawDescGZIP(), []int{3} +} + +func (x *LineItem) GetProductId() string { + if x != nil { + return x.ProductId + } + return "" +} + +func (x *LineItem) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *LineItem) GetQuantity() int32 { + if x != nil { + return x.Quantity + } + return 0 +} + +type Cart struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Items []*LineItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` +} + +func (x *Cart) Reset() { + *x = Cart{} + if protoimpl.UnsafeEnabled { + mi := &file_shoppingcart_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Cart) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Cart) ProtoMessage() {} + +func (x *Cart) ProtoReflect() protoreflect.Message { + mi := &file_shoppingcart_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Cart.ProtoReflect.Descriptor instead. +func (*Cart) Descriptor() ([]byte, []int) { + return file_shoppingcart_proto_rawDescGZIP(), []int{4} +} + +func (x *Cart) GetItems() []*LineItem { + if x != nil { + return x.Items + } + return nil +} + +var File_shoppingcart_proto protoreflect.FileDescriptor + +var file_shoppingcart_proto_rawDesc = []byte{ + 0x0a, 0x12, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, + 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x1a, 0x1b, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, + 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, + 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x15, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7b, 0x0a, + 0x0b, 0x41, 0x64, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x07, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x08, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0x4e, 0x0a, 0x0e, 0x52, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x07, + 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x70, + 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x70, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x22, 0x30, 0x0a, 0x0f, 0x47, 0x65, + 0x74, 0x53, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x61, 0x72, 0x74, 0x12, 0x1d, 0x0a, + 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, + 0x90, 0xb5, 0x18, 0x01, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x59, 0x0a, 0x08, + 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x1d, 0x0a, 0x0a, 0x70, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x70, 0x72, + 0x6f, 0x64, 0x75, 0x63, 0x74, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x71, + 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x71, + 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x22, 0x40, 0x0a, 0x04, 0x43, 0x61, 0x72, 0x74, 0x12, + 0x38, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, + 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, + 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x74, + 0x65, 0x6d, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x32, 0x94, 0x03, 0x0a, 0x0c, 0x53, 0x68, + 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x43, 0x61, 0x72, 0x74, 0x12, 0x6e, 0x0a, 0x07, 0x41, 0x64, + 0x64, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x25, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, + 0x2e, 0x41, 0x64, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x1a, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x22, 0x24, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x22, 0x19, 0x2f, 0x63, + 0x61, 0x72, 0x74, 0x2f, 0x7b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x69, 0x74, + 0x65, 0x6d, 0x73, 0x2f, 0x61, 0x64, 0x64, 0x3a, 0x01, 0x2a, 0x12, 0x81, 0x01, 0x0a, 0x0a, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x49, 0x74, 0x65, 0x6d, 0x12, 0x28, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, + 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, + 0x63, 0x61, 0x72, 0x74, 0x2e, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4c, 0x69, 0x6e, 0x65, 0x49, + 0x74, 0x65, 0x6d, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x31, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x2b, 0x22, 0x29, 0x2f, 0x63, 0x61, 0x72, 0x74, 0x2f, 0x7b, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x7b, 0x70, 0x72, 0x6f, 0x64, + 0x75, 0x63, 0x74, 0x5f, 0x69, 0x64, 0x7d, 0x2f, 0x72, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x8f, + 0x01, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x43, 0x61, 0x72, 0x74, 0x12, 0x29, 0x2e, 0x63, 0x6f, 0x6d, + 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, + 0x67, 0x63, 0x61, 0x72, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, + 0x67, 0x43, 0x61, 0x72, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x6f, 0x6d, 0x2e, 0x65, 0x78, 0x61, 0x6d, + 0x70, 0x6c, 0x65, 0x2e, 0x73, 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, + 0x2e, 0x43, 0x61, 0x72, 0x74, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x33, 0x12, 0x10, 0x2f, + 0x63, 0x61, 0x72, 0x74, 0x73, 0x2f, 0x7b, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x7d, 0x5a, + 0x1f, 0x12, 0x16, 0x2f, 0x63, 0x61, 0x72, 0x74, 0x73, 0x2f, 0x7b, 0x75, 0x73, 0x65, 0x72, 0x5f, + 0x69, 0x64, 0x7d, 0x2f, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x62, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, + 0x42, 0x46, 0x5a, 0x44, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2f, 0x73, + 0x68, 0x6f, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x3b, 0x73, 0x68, 0x6f, 0x70, + 0x70, 0x69, 0x6e, 0x67, 0x63, 0x61, 0x72, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_shoppingcart_proto_rawDescOnce sync.Once + file_shoppingcart_proto_rawDescData = file_shoppingcart_proto_rawDesc +) + +func file_shoppingcart_proto_rawDescGZIP() []byte { + file_shoppingcart_proto_rawDescOnce.Do(func() { + file_shoppingcart_proto_rawDescData = protoimpl.X.CompressGZIP(file_shoppingcart_proto_rawDescData) + }) + return file_shoppingcart_proto_rawDescData +} + +var file_shoppingcart_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_shoppingcart_proto_goTypes = []interface{}{ + (*AddLineItem)(nil), // 0: com.example.shoppingcart.AddLineItem + (*RemoveLineItem)(nil), // 1: com.example.shoppingcart.RemoveLineItem + (*GetShoppingCart)(nil), // 2: com.example.shoppingcart.GetShoppingCart + (*LineItem)(nil), // 3: com.example.shoppingcart.LineItem + (*Cart)(nil), // 4: com.example.shoppingcart.Cart + (*empty.Empty)(nil), // 5: google.protobuf.Empty +} +var file_shoppingcart_proto_depIdxs = []int32{ + 3, // 0: com.example.shoppingcart.Cart.items:type_name -> com.example.shoppingcart.LineItem + 0, // 1: com.example.shoppingcart.ShoppingCart.AddItem:input_type -> com.example.shoppingcart.AddLineItem + 1, // 2: com.example.shoppingcart.ShoppingCart.RemoveItem:input_type -> com.example.shoppingcart.RemoveLineItem + 2, // 3: com.example.shoppingcart.ShoppingCart.GetCart:input_type -> com.example.shoppingcart.GetShoppingCart + 5, // 4: com.example.shoppingcart.ShoppingCart.AddItem:output_type -> google.protobuf.Empty + 5, // 5: com.example.shoppingcart.ShoppingCart.RemoveItem:output_type -> google.protobuf.Empty + 4, // 6: com.example.shoppingcart.ShoppingCart.GetCart:output_type -> com.example.shoppingcart.Cart + 4, // [4:7] is the sub-list for method output_type + 1, // [1:4] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_shoppingcart_proto_init() } +func file_shoppingcart_proto_init() { + if File_shoppingcart_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_shoppingcart_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AddLineItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_shoppingcart_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RemoveLineItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_shoppingcart_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetShoppingCart); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_shoppingcart_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LineItem); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_shoppingcart_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Cart); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_shoppingcart_proto_rawDesc, + NumEnums: 0, + NumMessages: 5, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_shoppingcart_proto_goTypes, + DependencyIndexes: file_shoppingcart_proto_depIdxs, + MessageInfos: file_shoppingcart_proto_msgTypes, + }.Build() + File_shoppingcart_proto = out.File + file_shoppingcart_proto_rawDesc = nil + file_shoppingcart_proto_goTypes = nil + file_shoppingcart_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// ShoppingCartClient is the client API for ShoppingCart service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type ShoppingCartClient interface { + AddItem(ctx context.Context, in *AddLineItem, opts ...grpc.CallOption) (*empty.Empty, error) + RemoveItem(ctx context.Context, in *RemoveLineItem, opts ...grpc.CallOption) (*empty.Empty, error) + GetCart(ctx context.Context, in *GetShoppingCart, opts ...grpc.CallOption) (*Cart, error) +} + +type shoppingCartClient struct { + cc grpc.ClientConnInterface +} + +func NewShoppingCartClient(cc grpc.ClientConnInterface) ShoppingCartClient { + return &shoppingCartClient{cc} +} + +func (c *shoppingCartClient) AddItem(ctx context.Context, in *AddLineItem, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/com.example.shoppingcart.ShoppingCart/AddItem", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *shoppingCartClient) RemoveItem(ctx context.Context, in *RemoveLineItem, opts ...grpc.CallOption) (*empty.Empty, error) { + out := new(empty.Empty) + err := c.cc.Invoke(ctx, "/com.example.shoppingcart.ShoppingCart/RemoveItem", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *shoppingCartClient) GetCart(ctx context.Context, in *GetShoppingCart, opts ...grpc.CallOption) (*Cart, error) { + out := new(Cart) + err := c.cc.Invoke(ctx, "/com.example.shoppingcart.ShoppingCart/GetCart", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ShoppingCartServer is the server API for ShoppingCart service. +type ShoppingCartServer interface { + AddItem(context.Context, *AddLineItem) (*empty.Empty, error) + RemoveItem(context.Context, *RemoveLineItem) (*empty.Empty, error) + GetCart(context.Context, *GetShoppingCart) (*Cart, error) +} + +// UnimplementedShoppingCartServer can be embedded to have forward compatible implementations. +type UnimplementedShoppingCartServer struct { +} + +func (*UnimplementedShoppingCartServer) AddItem(context.Context, *AddLineItem) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method AddItem not implemented") +} +func (*UnimplementedShoppingCartServer) RemoveItem(context.Context, *RemoveLineItem) (*empty.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method RemoveItem not implemented") +} +func (*UnimplementedShoppingCartServer) GetCart(context.Context, *GetShoppingCart) (*Cart, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetCart not implemented") +} + +func RegisterShoppingCartServer(s *grpc.Server, srv ShoppingCartServer) { + s.RegisterService(&_ShoppingCart_serviceDesc, srv) +} + +func _ShoppingCart_AddItem_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(AddLineItem) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ShoppingCartServer).AddItem(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/com.example.shoppingcart.ShoppingCart/AddItem", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ShoppingCartServer).AddItem(ctx, req.(*AddLineItem)) + } + return interceptor(ctx, in, info, handler) +} + +func _ShoppingCart_RemoveItem_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(RemoveLineItem) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ShoppingCartServer).RemoveItem(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/com.example.shoppingcart.ShoppingCart/RemoveItem", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ShoppingCartServer).RemoveItem(ctx, req.(*RemoveLineItem)) + } + return interceptor(ctx, in, info, handler) +} + +func _ShoppingCart_GetCart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetShoppingCart) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ShoppingCartServer).GetCart(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/com.example.shoppingcart.ShoppingCart/GetCart", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ShoppingCartServer).GetCart(ctx, req.(*GetShoppingCart)) + } + return interceptor(ctx, in, info, handler) +} + +var _ShoppingCart_serviceDesc = grpc.ServiceDesc{ + ServiceName: "com.example.shoppingcart.ShoppingCart", + HandlerType: (*ShoppingCartServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AddItem", + Handler: _ShoppingCart_AddItem_Handler, + }, + { + MethodName: "RemoveItem", + Handler: _ShoppingCart_RemoveItem_Handler, + }, + { + MethodName: "GetCart", + Handler: _ShoppingCart_GetCart_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "shoppingcart.proto", +} diff --git a/protobuf/example/shoppingcart/shoppingcart.proto b/example/shoppingcart/shoppingcart.proto similarity index 57% rename from protobuf/example/shoppingcart/shoppingcart.proto rename to example/shoppingcart/shoppingcart.proto index f7b3cf6..3ea4b77 100644 --- a/protobuf/example/shoppingcart/shoppingcart.proto +++ b/example/shoppingcart/shoppingcart.proto @@ -1,3 +1,18 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + // This is the public API offered by the shopping cart entity. syntax = "proto3"; @@ -8,7 +23,7 @@ import "google/api/http.proto"; package com.example.shoppingcart; -option go_package = "tck/shoppingcart"; +option go_package = "github.com/cloudstateio/go-support/example/shoppingcart;shoppingcart"; message AddLineItem { string user_id = 1 [(.cloudstate.entity_key) = true]; @@ -37,24 +52,23 @@ message Cart { } service ShoppingCart { - rpc AddItem(AddLineItem) returns (google.protobuf.Empty) { + rpc AddItem (AddLineItem) returns (google.protobuf.Empty) { option (google.api.http) = { post: "/cart/{user_id}/items/add", body: "*", }; } - rpc RemoveItem(RemoveLineItem) returns (google.protobuf.Empty) { + rpc RemoveItem (RemoveLineItem) returns (google.protobuf.Empty) { option (google.api.http).post = "/cart/{user_id}/items/{product_id}/remove"; } - rpc GetCart(GetShoppingCart) returns (Cart) { + rpc GetCart (GetShoppingCart) returns (Cart) { option (google.api.http) = { get: "/carts/{user_id}", additional_bindings: { get: "/carts/{user_id}/items", response_body: "items" - } - }; + } }; } } diff --git a/go.mod b/go.mod index 703a9aa..eecc156 100644 --- a/go.mod +++ b/go.mod @@ -1,9 +1,14 @@ module github.com/cloudstateio/go-support -go 1.13 +go 1.14 require ( - github.com/golang/protobuf v1.3.2 - google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 - google.golang.org/grpc v1.24.0 + github.com/golang/protobuf v1.4.0 + golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect + golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 // indirect + golang.org/x/text v0.3.2 // indirect + golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 + google.golang.org/genproto v0.0.0-20200413115906-b5235f65be36 + google.golang.org/grpc v1.28.1 + google.golang.org/protobuf v1.21.0 ) diff --git a/go.sum b/go.sum index 72cc347..a84e844 100644 --- a/go.sum +++ b/go.sum @@ -1,28 +1,89 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4 h1:rEvIZUSZ3fx39WIi3JkQqQBitGwpELBIYWeBVh6wn+E= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200413165638-669c56c373c4 h1:opSr2sbRXk5X5/givKrrKj9HXxFpW2sdCiP8MJSKLQY= +golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s= -google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20200413115906-b5235f65be36 h1:j7CmVRD4Kec0+f8VuBAc2Ak2MFfXm5Q2/RxuJLL+76E= +google.golang.org/genproto v0.0.0-20200413115906-b5235f65be36/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.1 h1:C1QC6KzgSiLyBabDi87BbjaGreoRgGUF5nOyvfrAZ1k= +google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0 h1:qdOKuR/EIArgaWNjetjgTzgVTAZ+S/WXVrq9HW9zimw= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc h1:/hemPrYIhOhy8zYrNj+069zDB68us2sMGsfkFJO0iZs= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/protobuf/example/shoppingcart/persistence/domain.proto b/protobuf/example/shoppingcart/persistence/domain.proto deleted file mode 100644 index c827b80..0000000 --- a/protobuf/example/shoppingcart/persistence/domain.proto +++ /dev/null @@ -1,27 +0,0 @@ -// These are the messages that get persisted - the events, plus the current state (Cart) for snapshots. -syntax = "proto3"; - -package com.example.shoppingcart.persistence; - -option go_package = "persistence"; - -message LineItem { - string productId = 1; - string name = 2; - int32 quantity = 3; -} - -// The item added event. -message ItemAdded { - LineItem item = 1; -} - -// The item removed event. -message ItemRemoved { - string productId = 1; -} - -// The shopping cart state. -message Cart { - repeated LineItem items = 1; -} diff --git a/protobuf/frontend/cloudstate/entity_key.proto b/protobuf/frontend/cloudstate/entity_key.proto index d208121..e2129a1 100644 --- a/protobuf/frontend/cloudstate/entity_key.proto +++ b/protobuf/frontend/cloudstate/entity_key.proto @@ -23,7 +23,7 @@ import "google/protobuf/descriptor.proto"; package cloudstate; option java_package = "io.cloudstate"; -option go_package = "github.com/cloudstateio/go-support/cloudstate/;cloudstate"; +option go_package = "github.com/cloudstateio/go-support/cloudstate;cloudstate"; extend google.protobuf.FieldOptions { bool entity_key = 50002; diff --git a/protobuf/protocol/cloudstate/crdt.proto b/protobuf/protocol/cloudstate/crdt.proto index 691242e..1b37803 100644 --- a/protobuf/protocol/cloudstate/crdt.proto +++ b/protobuf/protocol/cloudstate/crdt.proto @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// gRPC interface for Event Sourced Entity user functions. +// gRPC interface for CRDT Entity user functions. syntax = "proto3"; @@ -24,7 +24,7 @@ import "google/protobuf/any.proto"; import "cloudstate/entity.proto"; option java_package = "io.cloudstate.protocol"; -option go_package = "cloudstate/protocol"; +option go_package = "github.com/cloudstateio/go-support/cloudstate/entity;entity"; // CRDT Protocol // @@ -60,7 +60,7 @@ service Crdt { // // The user function must respond with one reply per command in. They do not necessarily have to be sent in the same // order that the commands were sent, the command ID is used to correlate commands to replies. - rpc handle(stream CrdtStreamIn) returns (stream CrdtStreamOut); + rpc handle (stream CrdtStreamIn) returns (stream CrdtStreamOut); } // Message for the Crdt handle stream in. diff --git a/protobuf/protocol/cloudstate/entity.proto b/protobuf/protocol/cloudstate/entity.proto index 05cd7be..a4df3a0 100644 --- a/protobuf/protocol/cloudstate/entity.proto +++ b/protobuf/protocol/cloudstate/entity.proto @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// gRPC interface for Event Sourced Entity user functions. +// gRPC interface for common messages and services for Entity user functions. syntax = "proto3"; @@ -25,12 +25,89 @@ import "google/protobuf/empty.proto"; import "google/protobuf/descriptor.proto"; option java_package = "io.cloudstate.protocol"; -option go_package = "cloudstate/protocol"; +option go_package = "github.com/cloudstateio/go-support/cloudstate/protocol;protocol"; + +// Transport-specific metadata associated with a message. +// +// The semantics of the metadata are not defined in this protocol, but rather, depend on the transport on which a +// particular instance of the metadata maps to. What keys or values are allowed or disallowed, whether duplicate values +// for the same key are allowed and how they are handled, and whether key names are case sensitive or not, are all +// undefined in the context of the Cloudstate protocol. +// +// If a metadata entry associated with a message can't be expressed in an underlying transport, for example, due to +// invalid characters in a key or value, the behavior of the proxy is undefined. This is because metadata is transport +// specific, so if the user function chooses to use metadata, it is choosing to be specific to a particular transport, +// which is beyond the scope of the Cloudstate protocol, and it's therefore the user function's responsibility to adhere +// to the semantics of that transport. The proxy MAY decide to drop metadata entries if it knows they are invalid or +// unsupported. If a metadata entry is dropped, the proxy MAY inform the user function that the entry was dropped by +// sending an error message to the EntityDiscovery.ReportError gRPC call. +// +// The metadata MAY also contain CloudEvent metadata. If a message comes from a Cloudstate event source, the Cloudstate +// proxy MUST attach CloudEvent metadata to it if the event doesn't already have CloudEvent metadata attached to it. +// This metadata SHALL be encoded according to the binary mode of the CloudEvent HTTP protocol binding, which can be +// found here: +// +// https://github.com/cloudevents/spec/blob/master/http-protocol-binding.md +// +// The Cloudstate proxy MAY synthesize appropriate values for Cloudstate metadata if no equivalent metadata exists in +// the event source, for example, if there is no type, the Cloudstate proxy MAY use the name of the gRPC message as the +// CloudEvent type, and if there is no source, the Cloudstate proxy MAY use the name of the topic as the source. +// +// If an incoming message does have CloudEvent metadata attached to it, the Cloudstate proxy MUST transcode that +// CloudEvent metadata to the HTTP protocol binding as described above. +// +// Messages sent from the user function to an event destination MAY include CloudEvent metadata. If they include any +// CloudEvent metadata, they MUST include all required CloudEvent attributes, including id, source, specversion and +// type. The behavior of the proxy is undefined if some of these attributes, but not others, are included - the proxy +// MAY ignore them all, or MAY generate values itself, but SHOULD NOT fail sending the message. If the destination for +// the message is an event destination, the Cloudstate proxy MUST transcode the supplied Cloudstate metadata to a +// binding appropriate for the underlying transport for that event destination, it MUST NOT pass the CloudEvent +// metadata as is unless the transport uses the same binding rules. +message Metadata { + // The metadata entries. + repeated MetadataEntry entries = 1; +} + +// A metadata entry. +message MetadataEntry { + + // Key for the entry. Valid keys depend on the transport from or to which this metadata is sent. + string key = 1; + + // The value. + oneof value { + + // A string value. Valid values depend on the transport from or which this metadata is sent. + // + // If the transport does not support string values, the behavior of the Cloudstate proxy is undefined from the + // point of view of this protocol. If there is a convention in the protocol for encoding string values as + // UTF-8 bytes, then the Cloudstate proxy MAY do that. + string string_value = 2; + + // A bytes value. Valid values depend on the transport from or which this metadata is sent. + // + // If the transport does not support bytes values, the behavior of the Cloudstate proxy is undefined from the + // point of view of this protocol. If there is a convention in the protocol for encoding bytes values as + // Base64 encoded strings, then the Cloudstate proxy MAY do that. + bytes bytes_value = 3; + } +} // A reply to the sender. message Reply { // The reply payload google.protobuf.Any payload = 1; + + // Metadata for the reply + // + // Not all transports support per message metadata, for example, gRPC doesn't. The Cloudstate proxy MAY ignore the + // metadata in this case, or it MAY lift the metadata into another place, for example, in gRPC, a unary call MAY + // have its reply metadata placed in the headers of the HTTP response, or the first reply to a streamed call MAY + // have its metadata placed in the headers of the HTTP response. + // + // If the metadata is ignored, the Cloudstate proxy MAY notify the user function by sending an error message to the + // EntityDiscovery.ReportError gRPC call. + Metadata metadata = 2; } // Forwards handling of this request to another entity. @@ -41,6 +118,8 @@ message Forward { string command_name = 2; // The payload. google.protobuf.Any payload = 3; + // The metadata to include with the forward + Metadata metadata = 4; } // An action for the client @@ -73,6 +152,9 @@ message SideEffect { // Whether this side effect should be performed synchronously, ie, before the reply is eventually // sent, or not. bool synchronous = 4; + + // The metadata to include with the side effect + Metadata metadata = 5; } // A command. For each command received, a reply must be sent with a matching command id. @@ -92,6 +174,14 @@ message Command { // Whether the command is streamed or not bool streamed = 5; + + // The command metadata. + // + // Not all transports support per message metadata, for example, gRPC doesn't. The Cloudstate proxy MAY include + // metadata from other locations in this case, for example, in gRPC, a unary call MAY have the HTTP request headers + // attached to the command, while a streamed call MAY have the HTTP request headers attached as the metadata for + // either the first command, or every command. This specification leaves this behavior undefined. + Metadata metadata = 6; } message StreamCancelled { @@ -112,6 +202,9 @@ message Failure { // A description of the error. string description = 2; + + // Whether this failure should trigger an entity restart. + bool restart = 3; } message EntitySpec { @@ -149,6 +242,12 @@ message ServiceInfo { // The version of the support library being used. string support_library_version = 5; + + // Cloudstate protocol major version accepted by the support library. + int32 protocol_major_version = 6; + + // Cloudstate protocol minor version accepted by the support library. + int32 protocol_minor_version = 7; } message Entity { diff --git a/protobuf/protocol/cloudstate/event_sourced.proto b/protobuf/protocol/cloudstate/event_sourced.proto index 0417f14..218a208 100644 --- a/protobuf/protocol/cloudstate/event_sourced.proto +++ b/protobuf/protocol/cloudstate/event_sourced.proto @@ -24,7 +24,7 @@ import "google/protobuf/any.proto"; import "cloudstate/entity.proto"; option java_package = "io.cloudstate.protocol"; -option go_package = "cloudstate/protocol"; +option go_package = "github.com/cloudstateio/go-support/cloudstate/entity;entity"; // The init message. This will always be the first message sent to the entity when // it is loaded. @@ -111,5 +111,6 @@ service EventSourced { // message. The entity should reply in order, and any events that the entity requests to be // persisted the entity should handle itself, applying them to its own state, as if they had // arrived as events when the event stream was being replayed on load. - rpc handle(stream EventSourcedStreamIn) returns (stream EventSourcedStreamOut) {} + rpc handle (stream EventSourcedStreamIn) returns (stream EventSourcedStreamOut) { + } } diff --git a/protobuf/protocol/cloudstate/function.proto b/protobuf/protocol/cloudstate/function.proto index 3ca581b..6c3b6d9 100644 --- a/protobuf/protocol/cloudstate/function.proto +++ b/protobuf/protocol/cloudstate/function.proto @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// gRPC interface for Event Sourced Entity user functions. +// gRPC interface for Stateless Entity user functions. syntax = "proto3"; @@ -24,8 +24,16 @@ import "google/protobuf/any.proto"; import "cloudstate/entity.proto"; option java_package = "io.cloudstate.protocol"; -option go_package = "cloudstate/protocol"; +option go_package = "github.com/cloudstateio/go-support/cloudstate/entity;entity"; +// A function command. +// +// For unary and streamed out calls, the service name, command name and payload will always be set. +// +// For streamed in and duplex streamed calls, the first command sent will just contain the service +// name and command name, but no payload. This will indicate that the function has been invoked. +// Subsequent commands on the stream will only have the payload set, the service name and command +// name will not be set. message FunctionCommand { // The name of the service this function is on. string service_name = 2; @@ -35,11 +43,15 @@ message FunctionCommand { // The command payload. google.protobuf.Any payload = 4; + + // Metadata + Metadata metadata = 5; } message FunctionReply { oneof response { + Failure failure = 1; Reply reply = 2; Forward forward = 3; } @@ -49,12 +61,76 @@ message FunctionReply { service StatelessFunction { - rpc handleUnary(FunctionCommand) returns (FunctionReply) {} + // Handle a unary command. + // + // The input command will contain the service name, command name, request metadata and the command + // payload. The reply may contain a direct reply, a forward or a failure, and it may contain many + // side effects. + rpc handleUnary (FunctionCommand) returns (FunctionReply) { + } - rpc handleStreamedIn(stream FunctionCommand) returns (FunctionReply) {} + // Handle a streamed in command. + // + // The first message in will contain the request metadata, including the service name and command + // name. It will not have an associated payload set. This will be followed by zero to many messages + // in with a payload, but no service name or command name set. + // + // If the underlying transport supports per stream metadata, rather than per message metadata, then + // that metadata will only be included in the metadata of the first message. In contrast, if the + // underlying transport supports per message metadata, there will be no metadata on the first message, + // the metadata will instead be found on each subsequent message. + // + // The semantics of stream closure in this protocol map 1:1 with the semantics of gRPC stream closure, + // that is, when the client closes the stream, the stream is considered half closed, and the server + // should eventually, but not necessarily immediately, send a response message with a status code and + // trailers. + // + // If however the server sends a response message before the client closes the stream, the stream is + // completely closed, and the client should handle this and stop sending more messages. + // + // Either the client or the server may cancel the stream at any time, cancellation is indicated + // through an HTTP2 stream RST message. + rpc handleStreamedIn (stream FunctionCommand) returns (FunctionReply) { + } - rpc handleStreamedOut(FunctionCommand) returns (stream FunctionReply) {} + // Handle a streamed out command. + // + // The input command will contain the service name, command name, request metadata and the command + // payload. Zero or more replies may be sent, each containing either a direct reply, a forward or a + // failure, and each may contain many side effects. The stream to the client will be closed when the + // this stream is closed, with the same status as this stream is closed with. + // + // Either the client or the server may cancel the stream at any time, cancellation is indicated + // through an HTTP2 stream RST message. + rpc handleStreamedOut (FunctionCommand) returns (stream FunctionReply) { + } - rpc handleStreamed(stream FunctionCommand) returns (stream FunctionReply) {} + // Handle a full duplex streamed command. + // + // The first message in will contain the request metadata, including the service name and command + // name. It will not have an associated payload set. This will be followed by zero to many messages + // in with a payload, but no service name or command name set. + // + // Zero or more replies may be sent, each containing either a direct reply, a forward or a failure, + // and each may contain many side effects. + // + // If the underlying transport supports per stream metadata, rather than per message metadata, then + // that metadata will only be included in the metadata of the first message. In contrast, if the + // underlying transport supports per message metadata, there will be no metadata on the first message, + // the metadata will instead be found on each subsequent message. + // + // The semantics of stream closure in this protocol map 1:1 with the semantics of gRPC stream closure, + // that is, when the client closes the stream, the stream is considered half closed, and the server + // should eventually, but not necessarily immediately, close the stream with a status code and + // trailers. + // + // If however the server closes the stream with a status code and trailers, the stream is immediately + // considered completely closed, and no further messages sent by the client will be handled by the + // server. + // + // Either the client or the server may cancel the stream at any time, cancellation is indicated + // through an HTTP2 stream RST message. + rpc handleStreamed (stream FunctionCommand) returns (stream FunctionReply) { + } } diff --git a/protobuf/tck/cloudstate/tck/model/eventsourced.proto b/protobuf/tck/cloudstate/tck/model/eventsourced.proto new file mode 100644 index 0000000..8f5ce15 --- /dev/null +++ b/protobuf/tck/cloudstate/tck/model/eventsourced.proto @@ -0,0 +1,124 @@ +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +// == Cloudstate TCK model test for event-sourced entities == +// + +syntax = "proto3"; + +package cloudstate.tck.model; + +import "cloudstate/entity_key.proto"; + +option java_package = "io.cloudstate.tck.model"; +option go_package = "github.com/cloudstateio/go-support/tck/eventsourced;eventsourced"; + +// +// The `EventSourcedTckModel` service should be implemented in the following ways: +// +// - The entity persistence-id must be `event-sourced-tck-model`. +// - Snapshots must be configured for every 5 events. +// - The state of the entity is simply a string. +// - Event and snapshot string values are wrapped in `Persisted` messages. +// - The snapshot handler must set the state to the value of a `Persisted` message. +// - The event handler must append the value of a `Persisted` message to the state string. +// - The `Process` method receives a `Request` message with actions to take. +// - Request actions must be processed in order, and can require emitting events, forwarding, side effects, or failing. +// - The `Process` method must reply with the state in a `Response`, after taking actions, unless forwarding or failing. +// - Forwarding and side effects must always be made to the second service `EventSourcedTwo`. +// +service EventSourcedTckModel { + rpc Process (Request) returns (Response); +} + +// +// The `EventSourcedTwo` service is only for verifying forward actions and side effects. +// The `Call` method is not required to do anything, and may simply return an empty `Response` message. +// +service EventSourcedTwo { + rpc Call (Request) returns (Response); +} + +// +// A `Request` message contains any actions that the entity should process. +// Actions must be processed in order. Any actions after a `Fail` may be ignored. +// +message Request { + string id = 1 [(.cloudstate.entity_key) = true]; + repeated RequestAction actions = 2; +} + +// +// Each `RequestAction` is one of: +// +// - Emit: emit an event, with a given value. +// - Forward: forward to another service, in place of replying with a Response. +// - Effect: add a side effect to another service to the reply. +// - Fail: fail the current `Process` command. +// +message RequestAction { + oneof action { + Emit emit = 1; + Forward forward = 2; + Effect effect = 3; + Fail fail = 4; + } +} + +// +// Emit an event, with the event value in a `Persisted` message. +// +message Emit { + string value = 1; +} + +// +// Replace the response with a forward to `cloudstate.tck.model.EventSourcedTwo/Call`. +// The payload must be a `Request` message with the given `id`. +// +message Forward { + string id = 1; +} + +// +// Add a side effect to the reply, to `cloudstate.tck.model.EventSourcedTwo/Call`. +// The payload must be a `Request` message with the given `id`. +// The side effect should be marked synchronous based on the given `synchronous` value. +// +message Effect { + string id = 1; + bool synchronous = 2; +} + +// +// Fail the current command with the given description `message`. +// +message Fail { + string message = 1; +} + +// +// The `Response` message for the `Process` must contain the current state (after processing actions). +// +message Response { + string message = 1; +} + +// +// The `Persisted` message wraps both snapshot and event values. +// +message Persisted { + string value = 1; +} \ No newline at end of file diff --git a/protobuf/tck/tck_crdt.proto b/protobuf/tck/tck_crdt.proto new file mode 100644 index 0000000..d18064e --- /dev/null +++ b/protobuf/tck/tck_crdt.proto @@ -0,0 +1,361 @@ +// Copyright 2020 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Extension for specifying which field in a message is to be considered an +// entity key, for the purposes associating gRPC calls with entities and +// sharding. + +syntax = "proto3"; + +import "google/protobuf/any.proto"; +import "cloudstate/entity_key.proto"; + +package crdt; + +option java_package = "io.cloudstate.tck.model"; +option go_package = "github.com/cloudstateio/go-support/tck/proto/crdt;crdt"; + +service TckCrdt { + rpc ProcessGCounter (GCounterRequest) returns (GCounterResponse); + rpc ProcessGCounterStreamed (GCounterRequest) returns (stream GCounterResponse); + rpc ProcessPNCounter (PNCounterRequest) returns (PNCounterResponse); + rpc ProcessGSet (GSetRequest) returns (GSetResponse); + rpc ProcessORSet (ORSetRequest) returns (ORSetResponse); + rpc ProcessFlag (FlagRequest) returns (FlagResponse); + rpc ProcessLWWRegister (LWWRegisterRequest) returns (LWWRegisterResponse); + rpc ProcessORMap (ORMapRequest) returns (ORMapResponse); + rpc ProcessVote (VoteRequest) returns (VoteResponse); +} + +message ORMapRequest { + string id = 1 [(.cloudstate.entity_key) = true]; + repeated ORMapRequestAction actions = 2; +} + +message ORMapRequestAction { + oneof action { + Get get = 1; + Delete delete = 2; + ORMapSet setKey = 3; + ORMapDelete deleteKey = 4; + ORMapActionRequest request = 5; + } +} + +message ORMapResponse { + ORMapKeys keys = 1; + ORMapEntries entries = 2; +} + +message VoteRequest { + string id = 1 [(.cloudstate.entity_key) = true]; + repeated VoteRequestAction actions = 2; +} + +message VoteRequestAction { + oneof action { + Get get = 1; + Delete delete = 2; + VoteVote vote = 3; + } +} + +message VoteResponse { + bool selfVote = 1; + uint32 voters = 2; + uint32 votesFor = 3; +} + +message GCounterRequest { + string id = 1 [(.cloudstate.entity_key) = true]; + repeated GCounterRequestAction actions = 2; +} + +message GCounterRequestAction { + oneof action { + Get get = 1; + Delete delete = 2; + GCounterIncrement increment = 3; + } +} + +message GCounterResponse { + GCounterValue value = 1; +} + +message PNCounterRequest { + string id = 1 [(.cloudstate.entity_key) = true]; + repeated PNCounterRequestAction actions = 2; +} + +message PNCounterRequestAction { + oneof action { + Get get = 1; + Delete delete = 2; + PNCounterIncrement increment = 3; + PNCounterDecrement decrement = 4; + } +} + +message PNCounterResponse { + PNCounterValue value = 1; +} + +message GSetRequest { + string id = 1 [(.cloudstate.entity_key) = true]; + repeated GSetRequestAction actions = 2; +} + +message GSetRequestAction { + oneof action { + Get get = 1; + Delete delete = 2; + GSetAdd add = 3; + } +} + +message GSetResponse { + GSetValue value = 1; +} + +message ORSetRequest { + string id = 1 [(.cloudstate.entity_key) = true]; + repeated ORSetRequestAction actions = 2; +} + +message ORSetRequestAction { + oneof action { + Get get = 1; + Delete delete = 2; + ORSetAdd add = 3; + ORSetRemove remove = 4; + } +} + +message ORSetResponse { + ORSetValue value = 1; +} + +message FlagRequest { + string id = 1 [(.cloudstate.entity_key) = true]; + repeated FlagRequestAction actions = 2; +} + +message FlagRequestAction { + oneof action { + Get get = 1; + Delete delete = 2; + FlagEnable enable = 3; + } +} + +message FlagResponse { + FlagValue value = 1; +} + +message LWWRegisterRequest { + string id = 1 [(.cloudstate.entity_key) = true]; + repeated LWWRegisterRequestAction actions = 2; +} + +message LWWRegisterRequestAction { + oneof action { + Get get = 1; + Delete delete = 2; + LWWRegisterSet set = 3; + LWWRegisterSetWithClock setWithClock = 4; + } +} + +message LWWRegisterResponse { + LWWRegisterValue value = 1; +} + +message Get { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; +} + +message Delete { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; +} + +message AnySupportType { + oneof value { + google.protobuf.Any any_value = 3; + string string_value = 4; + bytes bytes_value = 5; + int32 int32_value = 6; + int64 int64_value = 7; + float float_value = 8; + double double_value = 9; + bool bool_value = 10; + } +} + +message GCounterIncrement { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; + uint64 value = 3; +} + +message GCounterValue { + uint64 value = 2; +} + +message PNCounterIncrement { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; + int64 value = 3; +} + +message PNCounterDecrement { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; + int64 value = 3; +} + +message PNCounterValue { + int64 value = 2; +} + +message GSetAdd { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; + AnySupportType value = 3; +} + +message GSetValue { + repeated AnySupportType values = 1; +} + +message GSetValueAnySupport { + repeated AnySupportType values = 1; +} + +message ORSetAdd { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; + AnySupportType value = 3; +} + +message ORSetRemove { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; + AnySupportType value = 3; +} + +message ORSetValue { + repeated google.protobuf.Any values = 1; +} + +message FlagEnable { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; +} + +message FlagValue { + bool value = 1; +} + +message LWWRegisterSet { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; + AnySupportType value = 3; +} + +// copy from crdt.proto +enum CrdtClock { + // Use the default clock for deciding the last write, which is the system clocks + // milliseconds since epoch. + DEFAULT = 0; + // Use the reverse semantics with the default clock, to enable first write wins. + REVERSE = 1; + // Use a custom clock value, set using custom_clock_value. + CUSTOM = 2; + // Use a custom clock value, but automatically increment it by one if the clock + // value from the current value is equal to the custom_clock_value. + CUSTOM_AUTO_INCREMENT = 3; +} + +message LWWRegisterSetWithClock { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; + AnySupportType value = 3; + CrdtClock clock = 4; + int64 custom_clock_value = 5; +} + +message LWWRegisterValue { + google.protobuf.Any value = 1; +} + +message ORMapSet { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; + google.protobuf.Any entry_key = 3; + google.protobuf.Any value = 4; + oneof request { + GCounterRequest gCounterRequest = 5; + PNCounterRequest pnCounterRequest = 6; + GSetRequest gsetRequest = 7; + ORSetRequest orSetRequest = 8; + FlagRequest flagRequest = 9; + LWWRegisterRequest lwwRegisterRequest = 10; + ORMapRequest orMapRequest = 11; + VoteRequest voteRequest = 12; + }; +} + +message ORMapActionRequest { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; + google.protobuf.Any entry_key = 3; + oneof request { + GCounterRequest gCounterRequest = 4; + PNCounterRequest pnCounterRequest = 5; + GSetRequest gsetRequest = 6; + ORSetRequest orSetRequest = 7; + FlagRequest flagRequest = 8; + LWWRegisterRequest lwwRegisterRequest = 9; + ORMapRequest orMapRequest = 10; + VoteRequest voteRequest = 11; + }; +} + +message ORMapDelete { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; + google.protobuf.Any entry_key = 3; +} + +message ORMapEntry { + google.protobuf.Any entry_key = 1; + google.protobuf.Any value = 2; +} + +message ORMapEntries { + repeated ORMapEntry values = 1; +} + +message ORMapKeys { + repeated google.protobuf.Any values = 1; +} + +message VoteVote { + string key = 1 [(.cloudstate.entity_key) = true]; + string failWith = 2; + bool value = 3; +} \ No newline at end of file diff --git a/tck/cmd/tck_crdt/tck_crdt.go b/tck/cmd/tck_crdt/tck_crdt.go new file mode 100644 index 0000000..ec47ba0 --- /dev/null +++ b/tck/cmd/tck_crdt/tck_crdt.go @@ -0,0 +1,53 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "log" + + "github.com/cloudstateio/go-support/cloudstate" + "github.com/cloudstateio/go-support/cloudstate/crdt" + "github.com/cloudstateio/go-support/cloudstate/protocol" + tck "github.com/cloudstateio/go-support/tck/crdt" +) + +func main() { + server, err := cloudstate.New(protocol.Config{ + ServiceName: "io.cloudstate.tck.Crdt", // the servicename the proxy gets to know about + ServiceVersion: "0.2.0", + }) + if err != nil { + log.Fatalf("cloudstate.New failed: %v", err) + } + err = server.RegisterCRDT( + &crdt.Entity{ + ServiceName: "crdt.TckCrdt", // this is the package + service(name) from the gRPC proto file. + EntityFunc: func(id crdt.EntityID) crdt.EntityHandler { + return tck.NewEntity(id) + }, + }, + protocol.DescriptorConfig{ + Service: "tck_crdt.proto", // this is needed to find the descriptors with got for the service to be proxied. + }, + ) + if err != nil { + log.Fatalf("Cloudstate failed to register entity: %v", err) + } + err = server.Run() + if err != nil { + log.Fatalf("Cloudstate failed to run: %v", err) + } +} diff --git a/tck/cmd/tck_eventsourced/tck_eventsourced.go b/tck/cmd/tck_eventsourced/tck_eventsourced.go new file mode 100644 index 0000000..f27641e --- /dev/null +++ b/tck/cmd/tck_eventsourced/tck_eventsourced.go @@ -0,0 +1,83 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "log" + + "github.com/cloudstateio/go-support/cloudstate" + "github.com/cloudstateio/go-support/cloudstate/eventsourced" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/cloudstateio/go-support/example/shoppingcart" + tck "github.com/cloudstateio/go-support/tck/eventsourced" +) + +// tag::shopping-cart-main[] +func main() { + server, err := cloudstate.New(protocol.Config{ + ServiceName: "cloudstate.tck.model.EventSourcedTckModel", // the servicename the proxy gets to know about + ServiceVersion: "0.2.0", + }) + if err != nil { + log.Fatalf("cloudstate.New failed: %s", err) + } + err = server.RegisterEventSourced( + &eventsourced.Entity{ + ServiceName: "cloudstate.tck.model.EventSourcedTckModel", + PersistenceID: "event-sourced-tck-model", + SnapshotEvery: 5, + EntityFunc: tck.NewTestModel, + }, protocol.DescriptorConfig{ + Service: "eventsourced.proto", + }, + ) + if err != nil { + log.Fatalf("Cloudstate failed to register entity: %s", err) + } + err = server.RegisterEventSourced( + &eventsourced.Entity{ + ServiceName: "cloudstate.tck.model.EventSourcedTwo", + PersistenceID: "EventSourcedTwo", + SnapshotEvery: 5, + EntityFunc: tck.NewTestModelTwo, + }, protocol.DescriptorConfig{ + Service: "eventsourced.proto", + }, + ) + if err != nil { + log.Fatalf("Cloudstate failed to register entity: %s", err) + } + // tag::event-sourced-entity-type[] + // tag::register[] + err = server.RegisterEventSourced(&eventsourced.Entity{ + ServiceName: "com.example.shoppingcart.ShoppingCart", + PersistenceID: "ShoppingCart", + EntityFunc: shoppingcart.NewShoppingCart, + }, protocol.DescriptorConfig{ + Service: "shoppingcart.proto", + }.AddDomainDescriptor("domain.proto")) + // end::register[] + if err != nil { + log.Fatalf("CloudState failed to register entity: %s", err) + } + // end::event-sourced-entity-type[] + err = server.Run() + if err != nil { + log.Fatalf("Cloudstate failed to run: %v", err) + } +} + +// end::shopping-cart-main[] diff --git a/tck/cmd/tck_shoppingcart/shoppingcart.go b/tck/cmd/tck_shoppingcart/shoppingcart.go index 9e5122a..620fb6e 100644 --- a/tck/cmd/tck_shoppingcart/shoppingcart.go +++ b/tck/cmd/tck_shoppingcart/shoppingcart.go @@ -17,40 +17,34 @@ package main import ( - "context" - "errors" - "fmt" "log" "github.com/cloudstateio/go-support/cloudstate" - "github.com/cloudstateio/go-support/tck/shoppingcart" - domain "github.com/cloudstateio/go-support/tck/shoppingcart/persistence" - "github.com/golang/protobuf/ptypes/empty" + "github.com/cloudstateio/go-support/cloudstate/eventsourced" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/cloudstateio/go-support/example/shoppingcart" ) // main creates a CloudState instance and registers the ShoppingCart // as a event sourced entity. -// tag::shopping-cart-main[] func main() { - server, err := cloudstate.New(cloudstate.Config{ + server, err := cloudstate.New(protocol.Config{ ServiceName: "shopping-cart", - ServiceVersion: "0.1.1", + ServiceVersion: "0.1.0", }) if err != nil { - log.Fatalf("CloudState.New failed: %v", err) + log.Fatalf("cloudstate.New failed: %v", err) } - // tag::register[] - err = server.RegisterEventSourcedEntity( - &cloudstate.EventSourcedEntity{ - ServiceName: "com.example.shoppingcart.ShoppingCart", - PersistenceID: "ShoppingCart", - EntityFunc: NewShoppingCart, - }, - cloudstate.DescriptorConfig{ - Service: "shoppingcart/shoppingcart.proto", - }.AddDomainDescriptor("domain.proto"), - ) - // end::register[] + + err = server.RegisterEventSourced(&eventsourced.Entity{ + ServiceName: "com.example.shoppingcart.ShoppingCart", + PersistenceID: "ShoppingCart", + EntityFunc: shoppingcart.NewShoppingCart, + SnapshotEvery: 5, + }, protocol.DescriptorConfig{ + Service: "shoppingcart.proto", + }.AddDomainDescriptor("domain.proto")) + if err != nil { log.Fatalf("CloudState failed to register entity: %v", err) } @@ -60,185 +54,6 @@ func main() { } } -// end::shopping-cart-main[] - -// A CloudState event sourced entity. -// tag::entity-type[] -// tag::compose-entity[] -type ShoppingCart struct { - // our domain object - // tag::entity-state[] - cart []*domain.LineItem - // end::entity-state[] - // as an Emitter we can emit events - cloudstate.EventEmitter -} - -// end::compose-entity[] -// end::entity-type[] - -// NewShoppingCart returns a new and initialized instance of the ShoppingCart entity. -// tag::constructing[] -func NewShoppingCart() cloudstate.Entity { - return &ShoppingCart{ - cart: make([]*domain.LineItem, 0), - EventEmitter: cloudstate.NewEmitter(), // TODO: the EventEmitter could be provided by the event sourced handler - } -} - -// end::constructing[] - -// ItemAdded is a event handler function for the ItemAdded event. -// tag::item-added[] -func (sc *ShoppingCart) ItemAdded(added *domain.ItemAdded) error { // TODO: enable handling for values - if item, _ := sc.find(added.Item.ProductId); item != nil { - item.Quantity += added.Item.Quantity - } else { - sc.cart = append(sc.cart, &domain.LineItem{ - ProductId: added.Item.ProductId, - Name: added.Item.Name, - Quantity: added.Item.Quantity, - }) - } - return nil -} - -// end::item-added[] - -// ItemRemoved is a event handler function for the ItemRemoved event. -func (sc *ShoppingCart) ItemRemoved(removed *domain.ItemRemoved) error { - if !sc.remove(removed.ProductId) { - // this should never happen - return errors.New("unable to remove product") - } - return nil -} - -// Handle lets us handle events by ourselves. -// -// returns handle set to true if we have handled the event -// and any error that happened during the handling -// tag::handle-event[] -func (sc *ShoppingCart) HandleEvent(_ context.Context, event interface{}) (handled bool, err error) { - switch e := event.(type) { - case *domain.ItemAdded: - return true, sc.ItemAdded(e) - case *domain.ItemRemoved: - return true, sc.ItemRemoved(e) - default: - return false, nil - } -} - -// end::handle-event[] - -// AddItem implements the AddItem command handling of the shopping cart service. -// tag::add-item[] -func (sc *ShoppingCart) AddItem(_ context.Context, li *shoppingcart.AddLineItem) (*empty.Empty, error) { - if li.GetQuantity() <= 0 { - return nil, fmt.Errorf("cannot add negative quantity of to item %s", li.GetProductId()) - } - sc.Emit(&domain.ItemAdded{ - Item: &domain.LineItem{ - ProductId: li.ProductId, - Name: li.Name, - Quantity: li.Quantity, - }}) - return &empty.Empty{}, nil -} - -// end::add-item[] - -// RemoveItem implements the RemoveItem command handling of the shopping cart service. -func (sc *ShoppingCart) RemoveItem(_ context.Context, li *shoppingcart.RemoveLineItem) (*empty.Empty, error) { - if item, _ := sc.find(li.GetProductId()); item == nil { - return nil, fmt.Errorf("cannot remove item %s because it is not in the cart", li.GetProductId()) - } - sc.Emit(&domain.ItemRemoved{ProductId: li.ProductId}) - return &empty.Empty{}, nil -} - -// GetCart implements the GetCart command handling of the shopping cart service. -// tag::get-cart[] -func (sc *ShoppingCart) GetCart(_ context.Context, _ *shoppingcart.GetShoppingCart) (*shoppingcart.Cart, error) { - cart := &shoppingcart.Cart{} - for _, item := range sc.cart { - cart.Items = append(cart.Items, &shoppingcart.LineItem{ - ProductId: item.ProductId, - Name: item.Name, - Quantity: item.Quantity, - }) - } - return cart, nil -} - -// end::get-cart[] - -// tag::handle-command[] -func (sc *ShoppingCart) HandleCommand(ctx context.Context, command interface{}) (handled bool, reply interface{}, err error) { - switch cmd := command.(type) { - case *shoppingcart.GetShoppingCart: - reply, err := sc.GetCart(ctx, cmd) - return true, reply, err - case *shoppingcart.RemoveLineItem: - reply, err := sc.RemoveItem(ctx, cmd) - return true, reply, err - case *shoppingcart.AddLineItem: - reply, err := sc.AddItem(ctx, cmd) - return true, reply, err - default: - return false, reply, err - } -} - -// end::handle-command[] - -// tag::snapshotter[] -func (sc *ShoppingCart) Snapshot() (snapshot interface{}, err error) { - return domain.Cart{ - Items: append(make([]*domain.LineItem, len(sc.cart)), sc.cart...), - }, nil -} - -// end::snapshotter[] - -// tag::handle-snapshot[] -func (sc *ShoppingCart) HandleSnapshot(snapshot interface{}) (handled bool, err error) { - switch value := snapshot.(type) { - case domain.Cart: - sc.cart = append(sc.cart[:0], value.Items...) - return true, nil - default: - return false, nil - } -} - -// end::handle-snapshot[] - -// find finds a product in the shopping cart by productId and returns it as a LineItem. -func (sc *ShoppingCart) find(productId string) (item *domain.LineItem, index int) { - for i, item := range sc.cart { - if productId == item.ProductId { - return item, i - } - } - return nil, 0 -} - -// remove removes a product from the shopping cart. -// -// A ok flag is returned to indicate that the product was present and removed. -func (sc *ShoppingCart) remove(productId string) (ok bool) { - if item, i := sc.find(productId); item != nil { - // remove and re-slice - copy(sc.cart[i:], sc.cart[i+1:]) - sc.cart = sc.cart[:len(sc.cart)-1] - return true - } else { - return false - } -} - func init() { log.SetFlags(log.LstdFlags | log.Lmicroseconds) } diff --git a/tck/crdt/model.go b/tck/crdt/model.go new file mode 100644 index 0000000..785aa8a --- /dev/null +++ b/tck/crdt/model.go @@ -0,0 +1,538 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package crdt + +import ( + "errors" + "fmt" + "strings" + + "github.com/cloudstateio/go-support/cloudstate/crdt" + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" + "github.com/golang/protobuf/ptypes/empty" +) + +type TestModel struct { + id crdt.EntityID + gCounter *crdt.GCounter + pnCounter *crdt.PNCounter + gSet *crdt.GSet + orSet *crdt.ORSet + flag *crdt.Flag + lwwRegister *crdt.LWWRegister + vote *crdt.Vote + orMap *crdt.ORMap +} + +func NewEntity(id crdt.EntityID) *TestModel { + return &TestModel{id: id} +} + +func (s *TestModel) Set(_ *crdt.Context, c crdt.CRDT) error { + switch v := c.(type) { + case *crdt.GCounter: + s.gCounter = v + case *crdt.PNCounter: + s.pnCounter = v + case *crdt.GSet: + s.gSet = v + case *crdt.ORSet: + s.orSet = v + case *crdt.Flag: + s.flag = v + case *crdt.LWWRegister: + s.lwwRegister = v + case *crdt.Vote: + s.vote = v + case *crdt.ORMap: + s.orMap = v + } + return nil +} + +func (s *TestModel) Default(c *crdt.Context) (crdt.CRDT, error) { + switch strings.Split(c.EntityID.String(), "-")[0] { + case "gcounter": + return crdt.NewGCounter(), nil + case "pncounter": + return crdt.NewPNCounter(), nil + case "gset": + return crdt.NewGSet(), nil + case "orset": + return crdt.NewORSet(), nil + case "flag": + return crdt.NewFlag(), nil + case "lwwregister": + return crdt.NewLWWRegister(nil), nil + case "vote": + return crdt.NewVote(), nil + case "ormap": + return crdt.NewORMap(), nil + default: + return nil, errors.New("unknown entity type") + } +} + +func (s *TestModel) HandleCommand(cc *crdt.CommandContext, name string, cmd proto.Message) (*any.Any, error) { + switch c := cmd.(type) { + case *GCounterRequest: + for _, as := range c.GetActions() { + switch a := as.Action.(type) { + case *GCounterRequestAction_Increment: + if cc.Streamed() { + cc.ChangeFunc(func(c *crdt.CommandContext) (*any.Any, error) { + return encoding.MarshalAny(&GCounterResponse{ + Value: &GCounterValue{Value: s.gCounter.Value()}}, + ) + }) + } + s.gCounter.Increment(a.Increment.GetValue()) + if with := a.Increment.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&GCounterResponse{ + Value: &GCounterValue{Value: s.gCounter.Value()}}, + ) + case *GCounterRequestAction_Get: + if with := a.Get.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&GCounterResponse{Value: &GCounterValue{Value: s.gCounter.Value()}}) + case *GCounterRequestAction_Delete: + cc.Delete() + if with := a.Delete.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&GCounterResponse{}) + } + } + case *PNCounterRequest: + for _, as := range c.GetActions() { + switch a := as.Action.(type) { + case *PNCounterRequestAction_Increment: + s.pnCounter.Increment(a.Increment.Value) + if with := a.Increment.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&PNCounterResponse{Value: &PNCounterValue{Value: s.pnCounter.Value()}}) + case *PNCounterRequestAction_Decrement: + s.pnCounter.Decrement(a.Decrement.Value) + if with := a.Decrement.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&PNCounterResponse{Value: &PNCounterValue{Value: s.pnCounter.Value()}}) + case *PNCounterRequestAction_Get: + if with := a.Get.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&PNCounterResponse{Value: &PNCounterValue{Value: s.pnCounter.Value()}}) + case *PNCounterRequestAction_Delete: + cc.Delete() + if with := a.Delete.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&PNCounterResponse{}) + } + } + case *GSetRequest: + for _, as := range c.GetActions() { + switch a := as.Action.(type) { + case *GSetRequestAction_Get: + v := make([]*AnySupportType, 0, len(s.gSet.Value())) + for _, a := range s.gSet.Value() { + v = append(v, asAnySupportType(a)) + } + if with := a.Get.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&GSetResponse{Value: &GSetValue{Values: v}}) + case *GSetRequestAction_Delete: + cc.Delete() + if with := a.Delete.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&GSetResponse{}) + case *GSetRequestAction_Add: + anySupportAdd(s.gSet, a.Add.Value) + v := make([]*AnySupportType, 0, len(s.gSet.Value())) + for _, a := range s.gSet.Value() { + if strings.HasPrefix(a.TypeUrl, encoding.JSONTypeURLPrefix) { + v = append(v, &AnySupportType{ + Value: &AnySupportType_AnyValue{AnyValue: a}, + }) + continue + } + v = append(v, asAnySupportType(a)) + } + if with := a.Add.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&GSetResponse{Value: &GSetValue{Values: v}}) + } + } + case *ORSetRequest: + for _, as := range c.GetActions() { + switch a := as.Action.(type) { + case *ORSetRequestAction_Get: + if with := a.Get.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&ORSetResponse{Value: &ORSetValue{Values: s.orSet.Value()}}) + case *ORSetRequestAction_Delete: + cc.Delete() + if with := a.Delete.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&ORSetResponse{}) + case *ORSetRequestAction_Add: + anySupportAdd(s.orSet, a.Add.Value) + if with := a.Add.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&ORSetResponse{Value: &ORSetValue{Values: s.orSet.Value()}}) + case *ORSetRequestAction_Remove: + anySupportRemove(s.orSet, a.Remove.Value) + if with := a.Remove.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&ORSetResponse{Value: &ORSetValue{Values: s.orSet.Value()}}) + } + } + case *FlagRequest: + for _, as := range c.GetActions() { + switch a := as.Action.(type) { + case *FlagRequestAction_Get: + if with := a.Get.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&FlagResponse{Value: &FlagValue{Value: s.flag.Value()}}) + case *FlagRequestAction_Delete: + cc.Delete() + if with := a.Delete.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&FlagResponse{}) + case *FlagRequestAction_Enable: + if with := a.Enable.FailWith; with != "" { + return nil, errors.New(with) + } + s.flag.Enable() + return encoding.MarshalAny(&FlagResponse{Value: &FlagValue{Value: s.flag.Value()}}) + } + } + case *LWWRegisterRequest: + for _, as := range c.GetActions() { + switch a := as.Action.(type) { + case *LWWRegisterRequestAction_Get: + if with := a.Get.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&LWWRegisterResponse{Value: &LWWRegisterValue{Value: s.lwwRegister.Value()}}) + case *LWWRegisterRequestAction_Delete: + cc.Delete() + if with := a.Delete.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&FlagResponse{}) + case *LWWRegisterRequestAction_Set: + if with := a.Set.FailWith; with != "" { + return nil, errors.New(with) + } + anySupportAdd(&anySupportAdderSetter{s.lwwRegister}, a.Set.GetValue()) + return encoding.MarshalAny(&LWWRegisterResponse{Value: &LWWRegisterValue{Value: s.lwwRegister.Value()}}) + case *LWWRegisterRequestAction_SetWithClock: + if with := a.SetWithClock.FailWith; with != "" { + return nil, errors.New(with) + } + anySupportSetClock( + s.lwwRegister, + a.SetWithClock.GetValue(), + crdt.Clock(uint64(a.SetWithClock.GetClock().Number())), + a.SetWithClock.CustomClockValue, + ) + return encoding.MarshalAny(&LWWRegisterResponse{Value: &LWWRegisterValue{Value: s.lwwRegister.Value()}}) + } + } + case *VoteRequest: + for _, as := range c.GetActions() { + switch a := as.Action.(type) { + case *VoteRequestAction_Get: + if with := a.Get.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&VoteResponse{ + SelfVote: s.vote.SelfVote(), + Voters: s.vote.Voters(), + VotesFor: s.vote.VotesFor(), + }) + case *VoteRequestAction_Delete: + cc.Delete() + if with := a.Delete.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&empty.Empty{}) + case *VoteRequestAction_Vote: + s.vote.Vote(a.Vote.GetValue()) + if with := a.Vote.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&VoteResponse{ + SelfVote: s.vote.SelfVote(), + Voters: s.vote.Voters(), + VotesFor: s.vote.VotesFor(), + }) + } + } + case *ORMapRequest: + for _, as := range c.GetActions() { + switch a := as.Action.(type) { + case *ORMapRequestAction_Get: + if with := a.Get.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(orMapResponse(s.orMap)) + case *ORMapRequestAction_Delete: + if with := a.Delete.FailWith; with != "" { + return nil, errors.New(with) + } + cc.Delete() + return encoding.MarshalAny(orMapResponse(s.orMap)) + case *ORMapRequestAction_SetKey: + // s.orMap.Set(a.SetKey.EntryKey, a.SetKey.Value) + // TODO: how to set it? + return encoding.MarshalAny(orMapResponse(s.orMap)) + case *ORMapRequestAction_Request: + // we reuse this entities implementation to handle + // requests for CRDT values of this ORMap. + // + var entityID string + var req proto.Message + switch t := a.Request.GetRequest().(type) { + case *ORMapActionRequest_GCounterRequest: + entityID = "gcounter" + req = t.GCounterRequest + case *ORMapActionRequest_FlagRequest: + entityID = "flag" + req = t.FlagRequest + case *ORMapActionRequest_GsetRequest: + entityID = "gset" + req = t.GsetRequest + case *ORMapActionRequest_LwwRegisterRequest: + entityID = "lwwregister" + req = t.LwwRegisterRequest + case *ORMapActionRequest_OrMapRequest: // yeah, really! + entityID = "ormap" + req = t.OrMapRequest + case *ORMapActionRequest_OrSetRequest: + entityID = "orset" + req = t.OrSetRequest + case *ORMapActionRequest_VoteRequest: + entityID = "pncounter" + req = t.VoteRequest + case *ORMapActionRequest_PnCounterRequest: + entityID = "pncounter" + req = t.PnCounterRequest + } + if err := s.runRequest( + &crdt.CommandContext{Context: &crdt.Context{EntityID: crdt.EntityID(entityID)}}, + a.Request.GetEntryKey(), + req, + ); err != nil { + return nil, err + } + if with := a.Request.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(orMapResponse(s.orMap)) + case *ORMapRequestAction_DeleteKey: + s.orMap.Delete(a.DeleteKey.EntryKey) + if with := a.DeleteKey.FailWith; with != "" { + return nil, errors.New(with) + } + return encoding.MarshalAny(&ORMapResponse{}) + } + } + } + return nil, errors.New("unhandled command") +} + +func orMapResponse(orMap *crdt.ORMap) *ORMapResponse { + r := &ORMapResponse{ + Keys: &ORMapKeys{Values: orMap.Keys()}, + Entries: &ORMapEntries{ + Values: make([]*ORMapEntry, 0), + }, + } + for _, k := range orMap.Keys() { + var value *any.Any + switch s := orMap.Get(k).State().State.(type) { + case *entity.CrdtState_Gcounter: + val, err := encoding.Struct(s) + if err != nil { + panic(err) + } + value = val + } + r.Entries.Values = append(r.Entries.Values, + &ORMapEntry{ + EntryKey: k, + Value: value, + }, + ) + } + return r +} + +// runRequest runs the given action request using a temporary TestModel +// with the requests corresponding CRDT as its state. +// runRequest adds the CRDT if not already present in the map. +func (s *TestModel) runRequest(ctx *crdt.CommandContext, key *any.Any, req proto.Message) error { + m := &TestModel{} + if !s.orMap.HasKey(key) { + c, err := m.Default(ctx.Context) + if err != nil { + return err + } + s.orMap.Set(key, c) // triggers a set delta + } + if err := m.Set(ctx.Context, s.orMap.Get(key)); err != nil { + return err + } + if _, err := m.HandleCommand(ctx, "", req); err != nil { + return err + } + return nil +} + +func asAnySupportType(x *any.Any) *AnySupportType { + switch x.TypeUrl { + case encoding.PrimitiveTypeURLPrefixBool: + return &AnySupportType{ + Value: &AnySupportType_BoolValue{BoolValue: encoding.DecodeBool(x)}, + } + case encoding.PrimitiveTypeURLPrefixBytes: + return &AnySupportType{ + Value: &AnySupportType_BytesValue{BytesValue: encoding.DecodeBytes(x)}, + } + case encoding.PrimitiveTypeURLPrefixFloat: + return &AnySupportType{ + Value: &AnySupportType_FloatValue{FloatValue: encoding.DecodeFloat32(x)}, + } + case encoding.PrimitiveTypeURLPrefixDouble: + return &AnySupportType{ + Value: &AnySupportType_DoubleValue{DoubleValue: encoding.DecodeFloat64(x)}, + } + case encoding.PrimitiveTypeURLPrefixInt32: + return &AnySupportType{ + Value: &AnySupportType_Int32Value{Int32Value: encoding.DecodeInt32(x)}, + } + case encoding.PrimitiveTypeURLPrefixInt64: + return &AnySupportType{ + Value: &AnySupportType_Int64Value{Int64Value: encoding.DecodeInt64(x)}, + } + case encoding.PrimitiveTypeURLPrefixString: + return &AnySupportType{ + Value: &AnySupportType_StringValue{StringValue: encoding.DecodeString(x)}, + } + } + panic(fmt.Sprintf("no mapping found for TypeUrl: %v", x.TypeUrl)) // we're allowed to panic here :) +} + +type anySupportAdder interface { + Add(x *any.Any) +} + +type anySupportSetter interface { + Set(x *any.Any) +} + +type anySupportAdderSetter struct { + anySupportSetter +} + +func (s *anySupportAdderSetter) Add(x *any.Any) { + s.Set(x) +} + +type anySupportRemover interface { + Remove(x *any.Any) +} + +func anySupportRemove(r anySupportRemover, t *AnySupportType) { + switch v := t.Value.(type) { + case *AnySupportType_AnyValue: + r.Remove(v.AnyValue) + case *AnySupportType_StringValue: + r.Remove(encoding.String(v.StringValue)) + case *AnySupportType_BytesValue: + r.Remove(encoding.Bytes(v.BytesValue)) + case *AnySupportType_BoolValue: + r.Remove(encoding.Bool(v.BoolValue)) + case *AnySupportType_DoubleValue: + r.Remove(encoding.Float64(v.DoubleValue)) + case *AnySupportType_FloatValue: + r.Remove(encoding.Float32(v.FloatValue)) + case *AnySupportType_Int32Value: + r.Remove(encoding.Int32(v.Int32Value)) + case *AnySupportType_Int64Value: + r.Remove(encoding.Int64(v.Int64Value)) + } +} + +func anySupportAdd(a anySupportAdder, t *AnySupportType) { + switch v := t.Value.(type) { + case *AnySupportType_AnyValue: + a.Add(v.AnyValue) + case *AnySupportType_StringValue: + a.Add(encoding.String(v.StringValue)) + case *AnySupportType_BytesValue: + a.Add(encoding.Bytes(v.BytesValue)) + case *AnySupportType_BoolValue: + a.Add(encoding.Bool(v.BoolValue)) + case *AnySupportType_DoubleValue: + a.Add(encoding.Float64(v.DoubleValue)) + case *AnySupportType_FloatValue: + a.Add(encoding.Float32(v.FloatValue)) + case *AnySupportType_Int32Value: + a.Add(encoding.Int32(v.Int32Value)) + case *AnySupportType_Int64Value: + a.Add(encoding.Int64(v.Int64Value)) + } +} + +func anySupportSetClock(r *crdt.LWWRegister, t *AnySupportType, clock crdt.Clock, customValue int64) { + switch v := t.Value.(type) { + case *AnySupportType_AnyValue: + r.SetWithClock(v.AnyValue, clock, customValue) + case *AnySupportType_StringValue: + r.SetWithClock(encoding.String(v.StringValue), clock, customValue) + case *AnySupportType_BytesValue: + r.SetWithClock(encoding.Bytes(v.BytesValue), clock, customValue) + case *AnySupportType_BoolValue: + r.SetWithClock(encoding.Bool(v.BoolValue), clock, customValue) + case *AnySupportType_DoubleValue: + r.SetWithClock(encoding.Float64(v.DoubleValue), clock, customValue) + case *AnySupportType_FloatValue: + r.SetWithClock(encoding.Float32(v.FloatValue), clock, customValue) + case *AnySupportType_Int32Value: + r.SetWithClock(encoding.Int32(v.Int32Value), clock, customValue) + case *AnySupportType_Int64Value: + r.SetWithClock(encoding.Int64(v.Int64Value), clock, customValue) + } +} diff --git a/tck/crdt/tck_crdt.pb.go b/tck/crdt/tck_crdt.pb.go new file mode 100644 index 0000000..70bf4cf --- /dev/null +++ b/tck/crdt/tck_crdt.pb.go @@ -0,0 +1,5332 @@ +// Copyright 2020 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Extension for specifying which field in a message is to be considered an +// entity key, for the purposes associating gRPC calls with entities and +// sharding. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: tck_crdt.proto + +package crdt + +import ( + context "context" + _ "github.com/cloudstateio/go-support/cloudstate" + proto "github.com/golang/protobuf/proto" + any "github.com/golang/protobuf/ptypes/any" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// copy from crdt.proto +type CrdtClock int32 + +const ( + // Use the default clock for deciding the last write, which is the system clocks + // milliseconds since epoch. + CrdtClock_DEFAULT CrdtClock = 0 + // Use the reverse semantics with the default clock, to enable first write wins. + CrdtClock_REVERSE CrdtClock = 1 + // Use a custom clock value, set using custom_clock_value. + CrdtClock_CUSTOM CrdtClock = 2 + // Use a custom clock value, but automatically increment it by one if the clock + // value from the current value is equal to the custom_clock_value. + CrdtClock_CUSTOM_AUTO_INCREMENT CrdtClock = 3 +) + +// Enum value maps for CrdtClock. +var ( + CrdtClock_name = map[int32]string{ + 0: "DEFAULT", + 1: "REVERSE", + 2: "CUSTOM", + 3: "CUSTOM_AUTO_INCREMENT", + } + CrdtClock_value = map[string]int32{ + "DEFAULT": 0, + "REVERSE": 1, + "CUSTOM": 2, + "CUSTOM_AUTO_INCREMENT": 3, + } +) + +func (x CrdtClock) Enum() *CrdtClock { + p := new(CrdtClock) + *p = x + return p +} + +func (x CrdtClock) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CrdtClock) Descriptor() protoreflect.EnumDescriptor { + return file_tck_crdt_proto_enumTypes[0].Descriptor() +} + +func (CrdtClock) Type() protoreflect.EnumType { + return &file_tck_crdt_proto_enumTypes[0] +} + +func (x CrdtClock) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CrdtClock.Descriptor instead. +func (CrdtClock) EnumDescriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{0} +} + +type ORMapRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Actions []*ORMapRequestAction `protobuf:"bytes,2,rep,name=actions,proto3" json:"actions,omitempty"` +} + +func (x *ORMapRequest) Reset() { + *x = ORMapRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapRequest) ProtoMessage() {} + +func (x *ORMapRequest) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapRequest.ProtoReflect.Descriptor instead. +func (*ORMapRequest) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{0} +} + +func (x *ORMapRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ORMapRequest) GetActions() []*ORMapRequestAction { + if x != nil { + return x.Actions + } + return nil +} + +type ORMapRequestAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Action: + // *ORMapRequestAction_Get + // *ORMapRequestAction_Delete + // *ORMapRequestAction_SetKey + // *ORMapRequestAction_DeleteKey + // *ORMapRequestAction_Request + Action isORMapRequestAction_Action `protobuf_oneof:"action"` +} + +func (x *ORMapRequestAction) Reset() { + *x = ORMapRequestAction{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapRequestAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapRequestAction) ProtoMessage() {} + +func (x *ORMapRequestAction) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapRequestAction.ProtoReflect.Descriptor instead. +func (*ORMapRequestAction) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{1} +} + +func (m *ORMapRequestAction) GetAction() isORMapRequestAction_Action { + if m != nil { + return m.Action + } + return nil +} + +func (x *ORMapRequestAction) GetGet() *Get { + if x, ok := x.GetAction().(*ORMapRequestAction_Get); ok { + return x.Get + } + return nil +} + +func (x *ORMapRequestAction) GetDelete() *Delete { + if x, ok := x.GetAction().(*ORMapRequestAction_Delete); ok { + return x.Delete + } + return nil +} + +func (x *ORMapRequestAction) GetSetKey() *ORMapSet { + if x, ok := x.GetAction().(*ORMapRequestAction_SetKey); ok { + return x.SetKey + } + return nil +} + +func (x *ORMapRequestAction) GetDeleteKey() *ORMapDelete { + if x, ok := x.GetAction().(*ORMapRequestAction_DeleteKey); ok { + return x.DeleteKey + } + return nil +} + +func (x *ORMapRequestAction) GetRequest() *ORMapActionRequest { + if x, ok := x.GetAction().(*ORMapRequestAction_Request); ok { + return x.Request + } + return nil +} + +type isORMapRequestAction_Action interface { + isORMapRequestAction_Action() +} + +type ORMapRequestAction_Get struct { + Get *Get `protobuf:"bytes,1,opt,name=get,proto3,oneof"` +} + +type ORMapRequestAction_Delete struct { + Delete *Delete `protobuf:"bytes,2,opt,name=delete,proto3,oneof"` +} + +type ORMapRequestAction_SetKey struct { + SetKey *ORMapSet `protobuf:"bytes,3,opt,name=setKey,proto3,oneof"` +} + +type ORMapRequestAction_DeleteKey struct { + DeleteKey *ORMapDelete `protobuf:"bytes,4,opt,name=deleteKey,proto3,oneof"` +} + +type ORMapRequestAction_Request struct { + Request *ORMapActionRequest `protobuf:"bytes,5,opt,name=request,proto3,oneof"` +} + +func (*ORMapRequestAction_Get) isORMapRequestAction_Action() {} + +func (*ORMapRequestAction_Delete) isORMapRequestAction_Action() {} + +func (*ORMapRequestAction_SetKey) isORMapRequestAction_Action() {} + +func (*ORMapRequestAction_DeleteKey) isORMapRequestAction_Action() {} + +func (*ORMapRequestAction_Request) isORMapRequestAction_Action() {} + +type ORMapResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Keys *ORMapKeys `protobuf:"bytes,1,opt,name=keys,proto3" json:"keys,omitempty"` + Entries *ORMapEntries `protobuf:"bytes,2,opt,name=entries,proto3" json:"entries,omitempty"` +} + +func (x *ORMapResponse) Reset() { + *x = ORMapResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapResponse) ProtoMessage() {} + +func (x *ORMapResponse) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapResponse.ProtoReflect.Descriptor instead. +func (*ORMapResponse) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{2} +} + +func (x *ORMapResponse) GetKeys() *ORMapKeys { + if x != nil { + return x.Keys + } + return nil +} + +func (x *ORMapResponse) GetEntries() *ORMapEntries { + if x != nil { + return x.Entries + } + return nil +} + +type VoteRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Actions []*VoteRequestAction `protobuf:"bytes,2,rep,name=actions,proto3" json:"actions,omitempty"` +} + +func (x *VoteRequest) Reset() { + *x = VoteRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VoteRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VoteRequest) ProtoMessage() {} + +func (x *VoteRequest) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VoteRequest.ProtoReflect.Descriptor instead. +func (*VoteRequest) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{3} +} + +func (x *VoteRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *VoteRequest) GetActions() []*VoteRequestAction { + if x != nil { + return x.Actions + } + return nil +} + +type VoteRequestAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Action: + // *VoteRequestAction_Get + // *VoteRequestAction_Delete + // *VoteRequestAction_Vote + Action isVoteRequestAction_Action `protobuf_oneof:"action"` +} + +func (x *VoteRequestAction) Reset() { + *x = VoteRequestAction{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VoteRequestAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VoteRequestAction) ProtoMessage() {} + +func (x *VoteRequestAction) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VoteRequestAction.ProtoReflect.Descriptor instead. +func (*VoteRequestAction) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{4} +} + +func (m *VoteRequestAction) GetAction() isVoteRequestAction_Action { + if m != nil { + return m.Action + } + return nil +} + +func (x *VoteRequestAction) GetGet() *Get { + if x, ok := x.GetAction().(*VoteRequestAction_Get); ok { + return x.Get + } + return nil +} + +func (x *VoteRequestAction) GetDelete() *Delete { + if x, ok := x.GetAction().(*VoteRequestAction_Delete); ok { + return x.Delete + } + return nil +} + +func (x *VoteRequestAction) GetVote() *VoteVote { + if x, ok := x.GetAction().(*VoteRequestAction_Vote); ok { + return x.Vote + } + return nil +} + +type isVoteRequestAction_Action interface { + isVoteRequestAction_Action() +} + +type VoteRequestAction_Get struct { + Get *Get `protobuf:"bytes,1,opt,name=get,proto3,oneof"` +} + +type VoteRequestAction_Delete struct { + Delete *Delete `protobuf:"bytes,2,opt,name=delete,proto3,oneof"` +} + +type VoteRequestAction_Vote struct { + Vote *VoteVote `protobuf:"bytes,3,opt,name=vote,proto3,oneof"` +} + +func (*VoteRequestAction_Get) isVoteRequestAction_Action() {} + +func (*VoteRequestAction_Delete) isVoteRequestAction_Action() {} + +func (*VoteRequestAction_Vote) isVoteRequestAction_Action() {} + +type VoteResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SelfVote bool `protobuf:"varint,1,opt,name=selfVote,proto3" json:"selfVote,omitempty"` + Voters uint32 `protobuf:"varint,2,opt,name=voters,proto3" json:"voters,omitempty"` + VotesFor uint32 `protobuf:"varint,3,opt,name=votesFor,proto3" json:"votesFor,omitempty"` +} + +func (x *VoteResponse) Reset() { + *x = VoteResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VoteResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VoteResponse) ProtoMessage() {} + +func (x *VoteResponse) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VoteResponse.ProtoReflect.Descriptor instead. +func (*VoteResponse) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{5} +} + +func (x *VoteResponse) GetSelfVote() bool { + if x != nil { + return x.SelfVote + } + return false +} + +func (x *VoteResponse) GetVoters() uint32 { + if x != nil { + return x.Voters + } + return 0 +} + +func (x *VoteResponse) GetVotesFor() uint32 { + if x != nil { + return x.VotesFor + } + return 0 +} + +type GCounterRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Actions []*GCounterRequestAction `protobuf:"bytes,2,rep,name=actions,proto3" json:"actions,omitempty"` +} + +func (x *GCounterRequest) Reset() { + *x = GCounterRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GCounterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GCounterRequest) ProtoMessage() {} + +func (x *GCounterRequest) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GCounterRequest.ProtoReflect.Descriptor instead. +func (*GCounterRequest) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{6} +} + +func (x *GCounterRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *GCounterRequest) GetActions() []*GCounterRequestAction { + if x != nil { + return x.Actions + } + return nil +} + +type GCounterRequestAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Action: + // *GCounterRequestAction_Get + // *GCounterRequestAction_Delete + // *GCounterRequestAction_Increment + Action isGCounterRequestAction_Action `protobuf_oneof:"action"` +} + +func (x *GCounterRequestAction) Reset() { + *x = GCounterRequestAction{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GCounterRequestAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GCounterRequestAction) ProtoMessage() {} + +func (x *GCounterRequestAction) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GCounterRequestAction.ProtoReflect.Descriptor instead. +func (*GCounterRequestAction) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{7} +} + +func (m *GCounterRequestAction) GetAction() isGCounterRequestAction_Action { + if m != nil { + return m.Action + } + return nil +} + +func (x *GCounterRequestAction) GetGet() *Get { + if x, ok := x.GetAction().(*GCounterRequestAction_Get); ok { + return x.Get + } + return nil +} + +func (x *GCounterRequestAction) GetDelete() *Delete { + if x, ok := x.GetAction().(*GCounterRequestAction_Delete); ok { + return x.Delete + } + return nil +} + +func (x *GCounterRequestAction) GetIncrement() *GCounterIncrement { + if x, ok := x.GetAction().(*GCounterRequestAction_Increment); ok { + return x.Increment + } + return nil +} + +type isGCounterRequestAction_Action interface { + isGCounterRequestAction_Action() +} + +type GCounterRequestAction_Get struct { + Get *Get `protobuf:"bytes,1,opt,name=get,proto3,oneof"` +} + +type GCounterRequestAction_Delete struct { + Delete *Delete `protobuf:"bytes,2,opt,name=delete,proto3,oneof"` +} + +type GCounterRequestAction_Increment struct { + Increment *GCounterIncrement `protobuf:"bytes,3,opt,name=increment,proto3,oneof"` +} + +func (*GCounterRequestAction_Get) isGCounterRequestAction_Action() {} + +func (*GCounterRequestAction_Delete) isGCounterRequestAction_Action() {} + +func (*GCounterRequestAction_Increment) isGCounterRequestAction_Action() {} + +type GCounterResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value *GCounterValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *GCounterResponse) Reset() { + *x = GCounterResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GCounterResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GCounterResponse) ProtoMessage() {} + +func (x *GCounterResponse) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GCounterResponse.ProtoReflect.Descriptor instead. +func (*GCounterResponse) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{8} +} + +func (x *GCounterResponse) GetValue() *GCounterValue { + if x != nil { + return x.Value + } + return nil +} + +type PNCounterRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Actions []*PNCounterRequestAction `protobuf:"bytes,2,rep,name=actions,proto3" json:"actions,omitempty"` +} + +func (x *PNCounterRequest) Reset() { + *x = PNCounterRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PNCounterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PNCounterRequest) ProtoMessage() {} + +func (x *PNCounterRequest) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PNCounterRequest.ProtoReflect.Descriptor instead. +func (*PNCounterRequest) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{9} +} + +func (x *PNCounterRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *PNCounterRequest) GetActions() []*PNCounterRequestAction { + if x != nil { + return x.Actions + } + return nil +} + +type PNCounterRequestAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Action: + // *PNCounterRequestAction_Get + // *PNCounterRequestAction_Delete + // *PNCounterRequestAction_Increment + // *PNCounterRequestAction_Decrement + Action isPNCounterRequestAction_Action `protobuf_oneof:"action"` +} + +func (x *PNCounterRequestAction) Reset() { + *x = PNCounterRequestAction{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PNCounterRequestAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PNCounterRequestAction) ProtoMessage() {} + +func (x *PNCounterRequestAction) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PNCounterRequestAction.ProtoReflect.Descriptor instead. +func (*PNCounterRequestAction) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{10} +} + +func (m *PNCounterRequestAction) GetAction() isPNCounterRequestAction_Action { + if m != nil { + return m.Action + } + return nil +} + +func (x *PNCounterRequestAction) GetGet() *Get { + if x, ok := x.GetAction().(*PNCounterRequestAction_Get); ok { + return x.Get + } + return nil +} + +func (x *PNCounterRequestAction) GetDelete() *Delete { + if x, ok := x.GetAction().(*PNCounterRequestAction_Delete); ok { + return x.Delete + } + return nil +} + +func (x *PNCounterRequestAction) GetIncrement() *PNCounterIncrement { + if x, ok := x.GetAction().(*PNCounterRequestAction_Increment); ok { + return x.Increment + } + return nil +} + +func (x *PNCounterRequestAction) GetDecrement() *PNCounterDecrement { + if x, ok := x.GetAction().(*PNCounterRequestAction_Decrement); ok { + return x.Decrement + } + return nil +} + +type isPNCounterRequestAction_Action interface { + isPNCounterRequestAction_Action() +} + +type PNCounterRequestAction_Get struct { + Get *Get `protobuf:"bytes,1,opt,name=get,proto3,oneof"` +} + +type PNCounterRequestAction_Delete struct { + Delete *Delete `protobuf:"bytes,2,opt,name=delete,proto3,oneof"` +} + +type PNCounterRequestAction_Increment struct { + Increment *PNCounterIncrement `protobuf:"bytes,3,opt,name=increment,proto3,oneof"` +} + +type PNCounterRequestAction_Decrement struct { + Decrement *PNCounterDecrement `protobuf:"bytes,4,opt,name=decrement,proto3,oneof"` +} + +func (*PNCounterRequestAction_Get) isPNCounterRequestAction_Action() {} + +func (*PNCounterRequestAction_Delete) isPNCounterRequestAction_Action() {} + +func (*PNCounterRequestAction_Increment) isPNCounterRequestAction_Action() {} + +func (*PNCounterRequestAction_Decrement) isPNCounterRequestAction_Action() {} + +type PNCounterResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value *PNCounterValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *PNCounterResponse) Reset() { + *x = PNCounterResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PNCounterResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PNCounterResponse) ProtoMessage() {} + +func (x *PNCounterResponse) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PNCounterResponse.ProtoReflect.Descriptor instead. +func (*PNCounterResponse) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{11} +} + +func (x *PNCounterResponse) GetValue() *PNCounterValue { + if x != nil { + return x.Value + } + return nil +} + +type GSetRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Actions []*GSetRequestAction `protobuf:"bytes,2,rep,name=actions,proto3" json:"actions,omitempty"` +} + +func (x *GSetRequest) Reset() { + *x = GSetRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GSetRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GSetRequest) ProtoMessage() {} + +func (x *GSetRequest) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GSetRequest.ProtoReflect.Descriptor instead. +func (*GSetRequest) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{12} +} + +func (x *GSetRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *GSetRequest) GetActions() []*GSetRequestAction { + if x != nil { + return x.Actions + } + return nil +} + +type GSetRequestAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Action: + // *GSetRequestAction_Get + // *GSetRequestAction_Delete + // *GSetRequestAction_Add + Action isGSetRequestAction_Action `protobuf_oneof:"action"` +} + +func (x *GSetRequestAction) Reset() { + *x = GSetRequestAction{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GSetRequestAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GSetRequestAction) ProtoMessage() {} + +func (x *GSetRequestAction) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GSetRequestAction.ProtoReflect.Descriptor instead. +func (*GSetRequestAction) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{13} +} + +func (m *GSetRequestAction) GetAction() isGSetRequestAction_Action { + if m != nil { + return m.Action + } + return nil +} + +func (x *GSetRequestAction) GetGet() *Get { + if x, ok := x.GetAction().(*GSetRequestAction_Get); ok { + return x.Get + } + return nil +} + +func (x *GSetRequestAction) GetDelete() *Delete { + if x, ok := x.GetAction().(*GSetRequestAction_Delete); ok { + return x.Delete + } + return nil +} + +func (x *GSetRequestAction) GetAdd() *GSetAdd { + if x, ok := x.GetAction().(*GSetRequestAction_Add); ok { + return x.Add + } + return nil +} + +type isGSetRequestAction_Action interface { + isGSetRequestAction_Action() +} + +type GSetRequestAction_Get struct { + Get *Get `protobuf:"bytes,1,opt,name=get,proto3,oneof"` +} + +type GSetRequestAction_Delete struct { + Delete *Delete `protobuf:"bytes,2,opt,name=delete,proto3,oneof"` +} + +type GSetRequestAction_Add struct { + Add *GSetAdd `protobuf:"bytes,3,opt,name=add,proto3,oneof"` +} + +func (*GSetRequestAction_Get) isGSetRequestAction_Action() {} + +func (*GSetRequestAction_Delete) isGSetRequestAction_Action() {} + +func (*GSetRequestAction_Add) isGSetRequestAction_Action() {} + +type GSetResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value *GSetValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *GSetResponse) Reset() { + *x = GSetResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GSetResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GSetResponse) ProtoMessage() {} + +func (x *GSetResponse) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GSetResponse.ProtoReflect.Descriptor instead. +func (*GSetResponse) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{14} +} + +func (x *GSetResponse) GetValue() *GSetValue { + if x != nil { + return x.Value + } + return nil +} + +type ORSetRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Actions []*ORSetRequestAction `protobuf:"bytes,2,rep,name=actions,proto3" json:"actions,omitempty"` +} + +func (x *ORSetRequest) Reset() { + *x = ORSetRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORSetRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORSetRequest) ProtoMessage() {} + +func (x *ORSetRequest) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORSetRequest.ProtoReflect.Descriptor instead. +func (*ORSetRequest) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{15} +} + +func (x *ORSetRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *ORSetRequest) GetActions() []*ORSetRequestAction { + if x != nil { + return x.Actions + } + return nil +} + +type ORSetRequestAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Action: + // *ORSetRequestAction_Get + // *ORSetRequestAction_Delete + // *ORSetRequestAction_Add + // *ORSetRequestAction_Remove + Action isORSetRequestAction_Action `protobuf_oneof:"action"` +} + +func (x *ORSetRequestAction) Reset() { + *x = ORSetRequestAction{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORSetRequestAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORSetRequestAction) ProtoMessage() {} + +func (x *ORSetRequestAction) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORSetRequestAction.ProtoReflect.Descriptor instead. +func (*ORSetRequestAction) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{16} +} + +func (m *ORSetRequestAction) GetAction() isORSetRequestAction_Action { + if m != nil { + return m.Action + } + return nil +} + +func (x *ORSetRequestAction) GetGet() *Get { + if x, ok := x.GetAction().(*ORSetRequestAction_Get); ok { + return x.Get + } + return nil +} + +func (x *ORSetRequestAction) GetDelete() *Delete { + if x, ok := x.GetAction().(*ORSetRequestAction_Delete); ok { + return x.Delete + } + return nil +} + +func (x *ORSetRequestAction) GetAdd() *ORSetAdd { + if x, ok := x.GetAction().(*ORSetRequestAction_Add); ok { + return x.Add + } + return nil +} + +func (x *ORSetRequestAction) GetRemove() *ORSetRemove { + if x, ok := x.GetAction().(*ORSetRequestAction_Remove); ok { + return x.Remove + } + return nil +} + +type isORSetRequestAction_Action interface { + isORSetRequestAction_Action() +} + +type ORSetRequestAction_Get struct { + Get *Get `protobuf:"bytes,1,opt,name=get,proto3,oneof"` +} + +type ORSetRequestAction_Delete struct { + Delete *Delete `protobuf:"bytes,2,opt,name=delete,proto3,oneof"` +} + +type ORSetRequestAction_Add struct { + Add *ORSetAdd `protobuf:"bytes,3,opt,name=add,proto3,oneof"` +} + +type ORSetRequestAction_Remove struct { + Remove *ORSetRemove `protobuf:"bytes,4,opt,name=remove,proto3,oneof"` +} + +func (*ORSetRequestAction_Get) isORSetRequestAction_Action() {} + +func (*ORSetRequestAction_Delete) isORSetRequestAction_Action() {} + +func (*ORSetRequestAction_Add) isORSetRequestAction_Action() {} + +func (*ORSetRequestAction_Remove) isORSetRequestAction_Action() {} + +type ORSetResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value *ORSetValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *ORSetResponse) Reset() { + *x = ORSetResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORSetResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORSetResponse) ProtoMessage() {} + +func (x *ORSetResponse) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORSetResponse.ProtoReflect.Descriptor instead. +func (*ORSetResponse) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{17} +} + +func (x *ORSetResponse) GetValue() *ORSetValue { + if x != nil { + return x.Value + } + return nil +} + +type FlagRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Actions []*FlagRequestAction `protobuf:"bytes,2,rep,name=actions,proto3" json:"actions,omitempty"` +} + +func (x *FlagRequest) Reset() { + *x = FlagRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FlagRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FlagRequest) ProtoMessage() {} + +func (x *FlagRequest) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FlagRequest.ProtoReflect.Descriptor instead. +func (*FlagRequest) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{18} +} + +func (x *FlagRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *FlagRequest) GetActions() []*FlagRequestAction { + if x != nil { + return x.Actions + } + return nil +} + +type FlagRequestAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Action: + // *FlagRequestAction_Get + // *FlagRequestAction_Delete + // *FlagRequestAction_Enable + Action isFlagRequestAction_Action `protobuf_oneof:"action"` +} + +func (x *FlagRequestAction) Reset() { + *x = FlagRequestAction{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FlagRequestAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FlagRequestAction) ProtoMessage() {} + +func (x *FlagRequestAction) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FlagRequestAction.ProtoReflect.Descriptor instead. +func (*FlagRequestAction) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{19} +} + +func (m *FlagRequestAction) GetAction() isFlagRequestAction_Action { + if m != nil { + return m.Action + } + return nil +} + +func (x *FlagRequestAction) GetGet() *Get { + if x, ok := x.GetAction().(*FlagRequestAction_Get); ok { + return x.Get + } + return nil +} + +func (x *FlagRequestAction) GetDelete() *Delete { + if x, ok := x.GetAction().(*FlagRequestAction_Delete); ok { + return x.Delete + } + return nil +} + +func (x *FlagRequestAction) GetEnable() *FlagEnable { + if x, ok := x.GetAction().(*FlagRequestAction_Enable); ok { + return x.Enable + } + return nil +} + +type isFlagRequestAction_Action interface { + isFlagRequestAction_Action() +} + +type FlagRequestAction_Get struct { + Get *Get `protobuf:"bytes,1,opt,name=get,proto3,oneof"` +} + +type FlagRequestAction_Delete struct { + Delete *Delete `protobuf:"bytes,2,opt,name=delete,proto3,oneof"` +} + +type FlagRequestAction_Enable struct { + Enable *FlagEnable `protobuf:"bytes,3,opt,name=enable,proto3,oneof"` +} + +func (*FlagRequestAction_Get) isFlagRequestAction_Action() {} + +func (*FlagRequestAction_Delete) isFlagRequestAction_Action() {} + +func (*FlagRequestAction_Enable) isFlagRequestAction_Action() {} + +type FlagResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value *FlagValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *FlagResponse) Reset() { + *x = FlagResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FlagResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FlagResponse) ProtoMessage() {} + +func (x *FlagResponse) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FlagResponse.ProtoReflect.Descriptor instead. +func (*FlagResponse) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{20} +} + +func (x *FlagResponse) GetValue() *FlagValue { + if x != nil { + return x.Value + } + return nil +} + +type LWWRegisterRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Actions []*LWWRegisterRequestAction `protobuf:"bytes,2,rep,name=actions,proto3" json:"actions,omitempty"` +} + +func (x *LWWRegisterRequest) Reset() { + *x = LWWRegisterRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LWWRegisterRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LWWRegisterRequest) ProtoMessage() {} + +func (x *LWWRegisterRequest) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LWWRegisterRequest.ProtoReflect.Descriptor instead. +func (*LWWRegisterRequest) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{21} +} + +func (x *LWWRegisterRequest) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *LWWRegisterRequest) GetActions() []*LWWRegisterRequestAction { + if x != nil { + return x.Actions + } + return nil +} + +type LWWRegisterRequestAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Action: + // *LWWRegisterRequestAction_Get + // *LWWRegisterRequestAction_Delete + // *LWWRegisterRequestAction_Set + // *LWWRegisterRequestAction_SetWithClock + Action isLWWRegisterRequestAction_Action `protobuf_oneof:"action"` +} + +func (x *LWWRegisterRequestAction) Reset() { + *x = LWWRegisterRequestAction{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LWWRegisterRequestAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LWWRegisterRequestAction) ProtoMessage() {} + +func (x *LWWRegisterRequestAction) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LWWRegisterRequestAction.ProtoReflect.Descriptor instead. +func (*LWWRegisterRequestAction) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{22} +} + +func (m *LWWRegisterRequestAction) GetAction() isLWWRegisterRequestAction_Action { + if m != nil { + return m.Action + } + return nil +} + +func (x *LWWRegisterRequestAction) GetGet() *Get { + if x, ok := x.GetAction().(*LWWRegisterRequestAction_Get); ok { + return x.Get + } + return nil +} + +func (x *LWWRegisterRequestAction) GetDelete() *Delete { + if x, ok := x.GetAction().(*LWWRegisterRequestAction_Delete); ok { + return x.Delete + } + return nil +} + +func (x *LWWRegisterRequestAction) GetSet() *LWWRegisterSet { + if x, ok := x.GetAction().(*LWWRegisterRequestAction_Set); ok { + return x.Set + } + return nil +} + +func (x *LWWRegisterRequestAction) GetSetWithClock() *LWWRegisterSetWithClock { + if x, ok := x.GetAction().(*LWWRegisterRequestAction_SetWithClock); ok { + return x.SetWithClock + } + return nil +} + +type isLWWRegisterRequestAction_Action interface { + isLWWRegisterRequestAction_Action() +} + +type LWWRegisterRequestAction_Get struct { + Get *Get `protobuf:"bytes,1,opt,name=get,proto3,oneof"` +} + +type LWWRegisterRequestAction_Delete struct { + Delete *Delete `protobuf:"bytes,2,opt,name=delete,proto3,oneof"` +} + +type LWWRegisterRequestAction_Set struct { + Set *LWWRegisterSet `protobuf:"bytes,3,opt,name=set,proto3,oneof"` +} + +type LWWRegisterRequestAction_SetWithClock struct { + SetWithClock *LWWRegisterSetWithClock `protobuf:"bytes,4,opt,name=setWithClock,proto3,oneof"` +} + +func (*LWWRegisterRequestAction_Get) isLWWRegisterRequestAction_Action() {} + +func (*LWWRegisterRequestAction_Delete) isLWWRegisterRequestAction_Action() {} + +func (*LWWRegisterRequestAction_Set) isLWWRegisterRequestAction_Action() {} + +func (*LWWRegisterRequestAction_SetWithClock) isLWWRegisterRequestAction_Action() {} + +type LWWRegisterResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value *LWWRegisterValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *LWWRegisterResponse) Reset() { + *x = LWWRegisterResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LWWRegisterResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LWWRegisterResponse) ProtoMessage() {} + +func (x *LWWRegisterResponse) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LWWRegisterResponse.ProtoReflect.Descriptor instead. +func (*LWWRegisterResponse) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{23} +} + +func (x *LWWRegisterResponse) GetValue() *LWWRegisterValue { + if x != nil { + return x.Value + } + return nil +} + +type Get struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` +} + +func (x *Get) Reset() { + *x = Get{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Get) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Get) ProtoMessage() {} + +func (x *Get) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Get.ProtoReflect.Descriptor instead. +func (*Get) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{24} +} + +func (x *Get) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *Get) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +type Delete struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` +} + +func (x *Delete) Reset() { + *x = Delete{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Delete) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Delete) ProtoMessage() {} + +func (x *Delete) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Delete.ProtoReflect.Descriptor instead. +func (*Delete) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{25} +} + +func (x *Delete) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *Delete) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +type AnySupportType struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Value: + // *AnySupportType_AnyValue + // *AnySupportType_StringValue + // *AnySupportType_BytesValue + // *AnySupportType_Int32Value + // *AnySupportType_Int64Value + // *AnySupportType_FloatValue + // *AnySupportType_DoubleValue + // *AnySupportType_BoolValue + Value isAnySupportType_Value `protobuf_oneof:"value"` +} + +func (x *AnySupportType) Reset() { + *x = AnySupportType{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AnySupportType) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AnySupportType) ProtoMessage() {} + +func (x *AnySupportType) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AnySupportType.ProtoReflect.Descriptor instead. +func (*AnySupportType) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{26} +} + +func (m *AnySupportType) GetValue() isAnySupportType_Value { + if m != nil { + return m.Value + } + return nil +} + +func (x *AnySupportType) GetAnyValue() *any.Any { + if x, ok := x.GetValue().(*AnySupportType_AnyValue); ok { + return x.AnyValue + } + return nil +} + +func (x *AnySupportType) GetStringValue() string { + if x, ok := x.GetValue().(*AnySupportType_StringValue); ok { + return x.StringValue + } + return "" +} + +func (x *AnySupportType) GetBytesValue() []byte { + if x, ok := x.GetValue().(*AnySupportType_BytesValue); ok { + return x.BytesValue + } + return nil +} + +func (x *AnySupportType) GetInt32Value() int32 { + if x, ok := x.GetValue().(*AnySupportType_Int32Value); ok { + return x.Int32Value + } + return 0 +} + +func (x *AnySupportType) GetInt64Value() int64 { + if x, ok := x.GetValue().(*AnySupportType_Int64Value); ok { + return x.Int64Value + } + return 0 +} + +func (x *AnySupportType) GetFloatValue() float32 { + if x, ok := x.GetValue().(*AnySupportType_FloatValue); ok { + return x.FloatValue + } + return 0 +} + +func (x *AnySupportType) GetDoubleValue() float64 { + if x, ok := x.GetValue().(*AnySupportType_DoubleValue); ok { + return x.DoubleValue + } + return 0 +} + +func (x *AnySupportType) GetBoolValue() bool { + if x, ok := x.GetValue().(*AnySupportType_BoolValue); ok { + return x.BoolValue + } + return false +} + +type isAnySupportType_Value interface { + isAnySupportType_Value() +} + +type AnySupportType_AnyValue struct { + AnyValue *any.Any `protobuf:"bytes,3,opt,name=any_value,json=anyValue,proto3,oneof"` +} + +type AnySupportType_StringValue struct { + StringValue string `protobuf:"bytes,4,opt,name=string_value,json=stringValue,proto3,oneof"` +} + +type AnySupportType_BytesValue struct { + BytesValue []byte `protobuf:"bytes,5,opt,name=bytes_value,json=bytesValue,proto3,oneof"` +} + +type AnySupportType_Int32Value struct { + Int32Value int32 `protobuf:"varint,6,opt,name=int32_value,json=int32Value,proto3,oneof"` +} + +type AnySupportType_Int64Value struct { + Int64Value int64 `protobuf:"varint,7,opt,name=int64_value,json=int64Value,proto3,oneof"` +} + +type AnySupportType_FloatValue struct { + FloatValue float32 `protobuf:"fixed32,8,opt,name=float_value,json=floatValue,proto3,oneof"` +} + +type AnySupportType_DoubleValue struct { + DoubleValue float64 `protobuf:"fixed64,9,opt,name=double_value,json=doubleValue,proto3,oneof"` +} + +type AnySupportType_BoolValue struct { + BoolValue bool `protobuf:"varint,10,opt,name=bool_value,json=boolValue,proto3,oneof"` +} + +func (*AnySupportType_AnyValue) isAnySupportType_Value() {} + +func (*AnySupportType_StringValue) isAnySupportType_Value() {} + +func (*AnySupportType_BytesValue) isAnySupportType_Value() {} + +func (*AnySupportType_Int32Value) isAnySupportType_Value() {} + +func (*AnySupportType_Int64Value) isAnySupportType_Value() {} + +func (*AnySupportType_FloatValue) isAnySupportType_Value() {} + +func (*AnySupportType_DoubleValue) isAnySupportType_Value() {} + +func (*AnySupportType_BoolValue) isAnySupportType_Value() {} + +type GCounterIncrement struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` + Value uint64 `protobuf:"varint,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *GCounterIncrement) Reset() { + *x = GCounterIncrement{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GCounterIncrement) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GCounterIncrement) ProtoMessage() {} + +func (x *GCounterIncrement) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GCounterIncrement.ProtoReflect.Descriptor instead. +func (*GCounterIncrement) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{27} +} + +func (x *GCounterIncrement) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *GCounterIncrement) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +func (x *GCounterIncrement) GetValue() uint64 { + if x != nil { + return x.Value + } + return 0 +} + +type GCounterValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value uint64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *GCounterValue) Reset() { + *x = GCounterValue{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GCounterValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GCounterValue) ProtoMessage() {} + +func (x *GCounterValue) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GCounterValue.ProtoReflect.Descriptor instead. +func (*GCounterValue) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{28} +} + +func (x *GCounterValue) GetValue() uint64 { + if x != nil { + return x.Value + } + return 0 +} + +type PNCounterIncrement struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` + Value int64 `protobuf:"varint,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *PNCounterIncrement) Reset() { + *x = PNCounterIncrement{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PNCounterIncrement) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PNCounterIncrement) ProtoMessage() {} + +func (x *PNCounterIncrement) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PNCounterIncrement.ProtoReflect.Descriptor instead. +func (*PNCounterIncrement) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{29} +} + +func (x *PNCounterIncrement) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *PNCounterIncrement) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +func (x *PNCounterIncrement) GetValue() int64 { + if x != nil { + return x.Value + } + return 0 +} + +type PNCounterDecrement struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` + Value int64 `protobuf:"varint,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *PNCounterDecrement) Reset() { + *x = PNCounterDecrement{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PNCounterDecrement) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PNCounterDecrement) ProtoMessage() {} + +func (x *PNCounterDecrement) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PNCounterDecrement.ProtoReflect.Descriptor instead. +func (*PNCounterDecrement) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{30} +} + +func (x *PNCounterDecrement) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *PNCounterDecrement) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +func (x *PNCounterDecrement) GetValue() int64 { + if x != nil { + return x.Value + } + return 0 +} + +type PNCounterValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value int64 `protobuf:"varint,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *PNCounterValue) Reset() { + *x = PNCounterValue{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[31] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PNCounterValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PNCounterValue) ProtoMessage() {} + +func (x *PNCounterValue) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[31] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PNCounterValue.ProtoReflect.Descriptor instead. +func (*PNCounterValue) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{31} +} + +func (x *PNCounterValue) GetValue() int64 { + if x != nil { + return x.Value + } + return 0 +} + +type GSetAdd struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` + Value *AnySupportType `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *GSetAdd) Reset() { + *x = GSetAdd{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[32] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GSetAdd) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GSetAdd) ProtoMessage() {} + +func (x *GSetAdd) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[32] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GSetAdd.ProtoReflect.Descriptor instead. +func (*GSetAdd) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{32} +} + +func (x *GSetAdd) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *GSetAdd) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +func (x *GSetAdd) GetValue() *AnySupportType { + if x != nil { + return x.Value + } + return nil +} + +type GSetValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Values []*AnySupportType `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` +} + +func (x *GSetValue) Reset() { + *x = GSetValue{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[33] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GSetValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GSetValue) ProtoMessage() {} + +func (x *GSetValue) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[33] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GSetValue.ProtoReflect.Descriptor instead. +func (*GSetValue) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{33} +} + +func (x *GSetValue) GetValues() []*AnySupportType { + if x != nil { + return x.Values + } + return nil +} + +type GSetValueAnySupport struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Values []*AnySupportType `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` +} + +func (x *GSetValueAnySupport) Reset() { + *x = GSetValueAnySupport{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[34] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GSetValueAnySupport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GSetValueAnySupport) ProtoMessage() {} + +func (x *GSetValueAnySupport) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[34] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GSetValueAnySupport.ProtoReflect.Descriptor instead. +func (*GSetValueAnySupport) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{34} +} + +func (x *GSetValueAnySupport) GetValues() []*AnySupportType { + if x != nil { + return x.Values + } + return nil +} + +type ORSetAdd struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` + Value *AnySupportType `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *ORSetAdd) Reset() { + *x = ORSetAdd{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[35] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORSetAdd) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORSetAdd) ProtoMessage() {} + +func (x *ORSetAdd) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[35] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORSetAdd.ProtoReflect.Descriptor instead. +func (*ORSetAdd) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{35} +} + +func (x *ORSetAdd) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *ORSetAdd) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +func (x *ORSetAdd) GetValue() *AnySupportType { + if x != nil { + return x.Value + } + return nil +} + +type ORSetRemove struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` + Value *AnySupportType `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *ORSetRemove) Reset() { + *x = ORSetRemove{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORSetRemove) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORSetRemove) ProtoMessage() {} + +func (x *ORSetRemove) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[36] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORSetRemove.ProtoReflect.Descriptor instead. +func (*ORSetRemove) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{36} +} + +func (x *ORSetRemove) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *ORSetRemove) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +func (x *ORSetRemove) GetValue() *AnySupportType { + if x != nil { + return x.Value + } + return nil +} + +type ORSetValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Values []*any.Any `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` +} + +func (x *ORSetValue) Reset() { + *x = ORSetValue{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORSetValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORSetValue) ProtoMessage() {} + +func (x *ORSetValue) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[37] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORSetValue.ProtoReflect.Descriptor instead. +func (*ORSetValue) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{37} +} + +func (x *ORSetValue) GetValues() []*any.Any { + if x != nil { + return x.Values + } + return nil +} + +type FlagEnable struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` +} + +func (x *FlagEnable) Reset() { + *x = FlagEnable{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[38] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FlagEnable) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FlagEnable) ProtoMessage() {} + +func (x *FlagEnable) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[38] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FlagEnable.ProtoReflect.Descriptor instead. +func (*FlagEnable) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{38} +} + +func (x *FlagEnable) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *FlagEnable) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +type FlagValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value bool `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *FlagValue) Reset() { + *x = FlagValue{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[39] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FlagValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FlagValue) ProtoMessage() {} + +func (x *FlagValue) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[39] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FlagValue.ProtoReflect.Descriptor instead. +func (*FlagValue) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{39} +} + +func (x *FlagValue) GetValue() bool { + if x != nil { + return x.Value + } + return false +} + +type LWWRegisterSet struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` + Value *AnySupportType `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *LWWRegisterSet) Reset() { + *x = LWWRegisterSet{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[40] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LWWRegisterSet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LWWRegisterSet) ProtoMessage() {} + +func (x *LWWRegisterSet) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[40] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LWWRegisterSet.ProtoReflect.Descriptor instead. +func (*LWWRegisterSet) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{40} +} + +func (x *LWWRegisterSet) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *LWWRegisterSet) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +func (x *LWWRegisterSet) GetValue() *AnySupportType { + if x != nil { + return x.Value + } + return nil +} + +type LWWRegisterSetWithClock struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` + Value *AnySupportType `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` + Clock CrdtClock `protobuf:"varint,4,opt,name=clock,proto3,enum=crdt.CrdtClock" json:"clock,omitempty"` + CustomClockValue int64 `protobuf:"varint,5,opt,name=custom_clock_value,json=customClockValue,proto3" json:"custom_clock_value,omitempty"` +} + +func (x *LWWRegisterSetWithClock) Reset() { + *x = LWWRegisterSetWithClock{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[41] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LWWRegisterSetWithClock) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LWWRegisterSetWithClock) ProtoMessage() {} + +func (x *LWWRegisterSetWithClock) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[41] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LWWRegisterSetWithClock.ProtoReflect.Descriptor instead. +func (*LWWRegisterSetWithClock) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{41} +} + +func (x *LWWRegisterSetWithClock) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *LWWRegisterSetWithClock) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +func (x *LWWRegisterSetWithClock) GetValue() *AnySupportType { + if x != nil { + return x.Value + } + return nil +} + +func (x *LWWRegisterSetWithClock) GetClock() CrdtClock { + if x != nil { + return x.Clock + } + return CrdtClock_DEFAULT +} + +func (x *LWWRegisterSetWithClock) GetCustomClockValue() int64 { + if x != nil { + return x.CustomClockValue + } + return 0 +} + +type LWWRegisterValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value *any.Any `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *LWWRegisterValue) Reset() { + *x = LWWRegisterValue{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[42] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LWWRegisterValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LWWRegisterValue) ProtoMessage() {} + +func (x *LWWRegisterValue) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[42] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LWWRegisterValue.ProtoReflect.Descriptor instead. +func (*LWWRegisterValue) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{42} +} + +func (x *LWWRegisterValue) GetValue() *any.Any { + if x != nil { + return x.Value + } + return nil +} + +type ORMapSet struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` + EntryKey *any.Any `protobuf:"bytes,3,opt,name=entry_key,json=entryKey,proto3" json:"entry_key,omitempty"` + Value *any.Any `protobuf:"bytes,4,opt,name=value,proto3" json:"value,omitempty"` + // Types that are assignable to Request: + // *ORMapSet_GCounterRequest + // *ORMapSet_PnCounterRequest + // *ORMapSet_GsetRequest + // *ORMapSet_OrSetRequest + // *ORMapSet_FlagRequest + // *ORMapSet_LwwRegisterRequest + // *ORMapSet_OrMapRequest + // *ORMapSet_VoteRequest + Request isORMapSet_Request `protobuf_oneof:"request"` +} + +func (x *ORMapSet) Reset() { + *x = ORMapSet{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[43] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapSet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapSet) ProtoMessage() {} + +func (x *ORMapSet) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[43] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapSet.ProtoReflect.Descriptor instead. +func (*ORMapSet) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{43} +} + +func (x *ORMapSet) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *ORMapSet) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +func (x *ORMapSet) GetEntryKey() *any.Any { + if x != nil { + return x.EntryKey + } + return nil +} + +func (x *ORMapSet) GetValue() *any.Any { + if x != nil { + return x.Value + } + return nil +} + +func (m *ORMapSet) GetRequest() isORMapSet_Request { + if m != nil { + return m.Request + } + return nil +} + +func (x *ORMapSet) GetGCounterRequest() *GCounterRequest { + if x, ok := x.GetRequest().(*ORMapSet_GCounterRequest); ok { + return x.GCounterRequest + } + return nil +} + +func (x *ORMapSet) GetPnCounterRequest() *PNCounterRequest { + if x, ok := x.GetRequest().(*ORMapSet_PnCounterRequest); ok { + return x.PnCounterRequest + } + return nil +} + +func (x *ORMapSet) GetGsetRequest() *GSetRequest { + if x, ok := x.GetRequest().(*ORMapSet_GsetRequest); ok { + return x.GsetRequest + } + return nil +} + +func (x *ORMapSet) GetOrSetRequest() *ORSetRequest { + if x, ok := x.GetRequest().(*ORMapSet_OrSetRequest); ok { + return x.OrSetRequest + } + return nil +} + +func (x *ORMapSet) GetFlagRequest() *FlagRequest { + if x, ok := x.GetRequest().(*ORMapSet_FlagRequest); ok { + return x.FlagRequest + } + return nil +} + +func (x *ORMapSet) GetLwwRegisterRequest() *LWWRegisterRequest { + if x, ok := x.GetRequest().(*ORMapSet_LwwRegisterRequest); ok { + return x.LwwRegisterRequest + } + return nil +} + +func (x *ORMapSet) GetOrMapRequest() *ORMapRequest { + if x, ok := x.GetRequest().(*ORMapSet_OrMapRequest); ok { + return x.OrMapRequest + } + return nil +} + +func (x *ORMapSet) GetVoteRequest() *VoteRequest { + if x, ok := x.GetRequest().(*ORMapSet_VoteRequest); ok { + return x.VoteRequest + } + return nil +} + +type isORMapSet_Request interface { + isORMapSet_Request() +} + +type ORMapSet_GCounterRequest struct { + GCounterRequest *GCounterRequest `protobuf:"bytes,5,opt,name=gCounterRequest,proto3,oneof"` +} + +type ORMapSet_PnCounterRequest struct { + PnCounterRequest *PNCounterRequest `protobuf:"bytes,6,opt,name=pnCounterRequest,proto3,oneof"` +} + +type ORMapSet_GsetRequest struct { + GsetRequest *GSetRequest `protobuf:"bytes,7,opt,name=gsetRequest,proto3,oneof"` +} + +type ORMapSet_OrSetRequest struct { + OrSetRequest *ORSetRequest `protobuf:"bytes,8,opt,name=orSetRequest,proto3,oneof"` +} + +type ORMapSet_FlagRequest struct { + FlagRequest *FlagRequest `protobuf:"bytes,9,opt,name=flagRequest,proto3,oneof"` +} + +type ORMapSet_LwwRegisterRequest struct { + LwwRegisterRequest *LWWRegisterRequest `protobuf:"bytes,10,opt,name=lwwRegisterRequest,proto3,oneof"` +} + +type ORMapSet_OrMapRequest struct { + OrMapRequest *ORMapRequest `protobuf:"bytes,11,opt,name=orMapRequest,proto3,oneof"` +} + +type ORMapSet_VoteRequest struct { + VoteRequest *VoteRequest `protobuf:"bytes,12,opt,name=voteRequest,proto3,oneof"` +} + +func (*ORMapSet_GCounterRequest) isORMapSet_Request() {} + +func (*ORMapSet_PnCounterRequest) isORMapSet_Request() {} + +func (*ORMapSet_GsetRequest) isORMapSet_Request() {} + +func (*ORMapSet_OrSetRequest) isORMapSet_Request() {} + +func (*ORMapSet_FlagRequest) isORMapSet_Request() {} + +func (*ORMapSet_LwwRegisterRequest) isORMapSet_Request() {} + +func (*ORMapSet_OrMapRequest) isORMapSet_Request() {} + +func (*ORMapSet_VoteRequest) isORMapSet_Request() {} + +type ORMapActionRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` + EntryKey *any.Any `protobuf:"bytes,3,opt,name=entry_key,json=entryKey,proto3" json:"entry_key,omitempty"` + // Types that are assignable to Request: + // *ORMapActionRequest_GCounterRequest + // *ORMapActionRequest_PnCounterRequest + // *ORMapActionRequest_GsetRequest + // *ORMapActionRequest_OrSetRequest + // *ORMapActionRequest_FlagRequest + // *ORMapActionRequest_LwwRegisterRequest + // *ORMapActionRequest_OrMapRequest + // *ORMapActionRequest_VoteRequest + Request isORMapActionRequest_Request `protobuf_oneof:"request"` +} + +func (x *ORMapActionRequest) Reset() { + *x = ORMapActionRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[44] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapActionRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapActionRequest) ProtoMessage() {} + +func (x *ORMapActionRequest) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[44] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapActionRequest.ProtoReflect.Descriptor instead. +func (*ORMapActionRequest) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{44} +} + +func (x *ORMapActionRequest) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *ORMapActionRequest) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +func (x *ORMapActionRequest) GetEntryKey() *any.Any { + if x != nil { + return x.EntryKey + } + return nil +} + +func (m *ORMapActionRequest) GetRequest() isORMapActionRequest_Request { + if m != nil { + return m.Request + } + return nil +} + +func (x *ORMapActionRequest) GetGCounterRequest() *GCounterRequest { + if x, ok := x.GetRequest().(*ORMapActionRequest_GCounterRequest); ok { + return x.GCounterRequest + } + return nil +} + +func (x *ORMapActionRequest) GetPnCounterRequest() *PNCounterRequest { + if x, ok := x.GetRequest().(*ORMapActionRequest_PnCounterRequest); ok { + return x.PnCounterRequest + } + return nil +} + +func (x *ORMapActionRequest) GetGsetRequest() *GSetRequest { + if x, ok := x.GetRequest().(*ORMapActionRequest_GsetRequest); ok { + return x.GsetRequest + } + return nil +} + +func (x *ORMapActionRequest) GetOrSetRequest() *ORSetRequest { + if x, ok := x.GetRequest().(*ORMapActionRequest_OrSetRequest); ok { + return x.OrSetRequest + } + return nil +} + +func (x *ORMapActionRequest) GetFlagRequest() *FlagRequest { + if x, ok := x.GetRequest().(*ORMapActionRequest_FlagRequest); ok { + return x.FlagRequest + } + return nil +} + +func (x *ORMapActionRequest) GetLwwRegisterRequest() *LWWRegisterRequest { + if x, ok := x.GetRequest().(*ORMapActionRequest_LwwRegisterRequest); ok { + return x.LwwRegisterRequest + } + return nil +} + +func (x *ORMapActionRequest) GetOrMapRequest() *ORMapRequest { + if x, ok := x.GetRequest().(*ORMapActionRequest_OrMapRequest); ok { + return x.OrMapRequest + } + return nil +} + +func (x *ORMapActionRequest) GetVoteRequest() *VoteRequest { + if x, ok := x.GetRequest().(*ORMapActionRequest_VoteRequest); ok { + return x.VoteRequest + } + return nil +} + +type isORMapActionRequest_Request interface { + isORMapActionRequest_Request() +} + +type ORMapActionRequest_GCounterRequest struct { + GCounterRequest *GCounterRequest `protobuf:"bytes,4,opt,name=gCounterRequest,proto3,oneof"` +} + +type ORMapActionRequest_PnCounterRequest struct { + PnCounterRequest *PNCounterRequest `protobuf:"bytes,5,opt,name=pnCounterRequest,proto3,oneof"` +} + +type ORMapActionRequest_GsetRequest struct { + GsetRequest *GSetRequest `protobuf:"bytes,6,opt,name=gsetRequest,proto3,oneof"` +} + +type ORMapActionRequest_OrSetRequest struct { + OrSetRequest *ORSetRequest `protobuf:"bytes,7,opt,name=orSetRequest,proto3,oneof"` +} + +type ORMapActionRequest_FlagRequest struct { + FlagRequest *FlagRequest `protobuf:"bytes,8,opt,name=flagRequest,proto3,oneof"` +} + +type ORMapActionRequest_LwwRegisterRequest struct { + LwwRegisterRequest *LWWRegisterRequest `protobuf:"bytes,9,opt,name=lwwRegisterRequest,proto3,oneof"` +} + +type ORMapActionRequest_OrMapRequest struct { + OrMapRequest *ORMapRequest `protobuf:"bytes,10,opt,name=orMapRequest,proto3,oneof"` +} + +type ORMapActionRequest_VoteRequest struct { + VoteRequest *VoteRequest `protobuf:"bytes,11,opt,name=voteRequest,proto3,oneof"` +} + +func (*ORMapActionRequest_GCounterRequest) isORMapActionRequest_Request() {} + +func (*ORMapActionRequest_PnCounterRequest) isORMapActionRequest_Request() {} + +func (*ORMapActionRequest_GsetRequest) isORMapActionRequest_Request() {} + +func (*ORMapActionRequest_OrSetRequest) isORMapActionRequest_Request() {} + +func (*ORMapActionRequest_FlagRequest) isORMapActionRequest_Request() {} + +func (*ORMapActionRequest_LwwRegisterRequest) isORMapActionRequest_Request() {} + +func (*ORMapActionRequest_OrMapRequest) isORMapActionRequest_Request() {} + +func (*ORMapActionRequest_VoteRequest) isORMapActionRequest_Request() {} + +type ORMapDelete struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` + EntryKey *any.Any `protobuf:"bytes,3,opt,name=entry_key,json=entryKey,proto3" json:"entry_key,omitempty"` +} + +func (x *ORMapDelete) Reset() { + *x = ORMapDelete{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[45] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapDelete) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapDelete) ProtoMessage() {} + +func (x *ORMapDelete) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[45] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapDelete.ProtoReflect.Descriptor instead. +func (*ORMapDelete) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{45} +} + +func (x *ORMapDelete) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *ORMapDelete) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +func (x *ORMapDelete) GetEntryKey() *any.Any { + if x != nil { + return x.EntryKey + } + return nil +} + +type ORMapEntry struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + EntryKey *any.Any `protobuf:"bytes,1,opt,name=entry_key,json=entryKey,proto3" json:"entry_key,omitempty"` + Value *any.Any `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *ORMapEntry) Reset() { + *x = ORMapEntry{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[46] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapEntry) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapEntry) ProtoMessage() {} + +func (x *ORMapEntry) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[46] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapEntry.ProtoReflect.Descriptor instead. +func (*ORMapEntry) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{46} +} + +func (x *ORMapEntry) GetEntryKey() *any.Any { + if x != nil { + return x.EntryKey + } + return nil +} + +func (x *ORMapEntry) GetValue() *any.Any { + if x != nil { + return x.Value + } + return nil +} + +type ORMapEntries struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Values []*ORMapEntry `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` +} + +func (x *ORMapEntries) Reset() { + *x = ORMapEntries{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[47] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapEntries) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapEntries) ProtoMessage() {} + +func (x *ORMapEntries) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[47] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapEntries.ProtoReflect.Descriptor instead. +func (*ORMapEntries) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{47} +} + +func (x *ORMapEntries) GetValues() []*ORMapEntry { + if x != nil { + return x.Values + } + return nil +} + +type ORMapKeys struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Values []*any.Any `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` +} + +func (x *ORMapKeys) Reset() { + *x = ORMapKeys{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[48] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ORMapKeys) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ORMapKeys) ProtoMessage() {} + +func (x *ORMapKeys) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[48] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ORMapKeys.ProtoReflect.Descriptor instead. +func (*ORMapKeys) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{48} +} + +func (x *ORMapKeys) GetValues() []*any.Any { + if x != nil { + return x.Values + } + return nil +} + +type VoteVote struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + FailWith string `protobuf:"bytes,2,opt,name=failWith,proto3" json:"failWith,omitempty"` + Value bool `protobuf:"varint,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *VoteVote) Reset() { + *x = VoteVote{} + if protoimpl.UnsafeEnabled { + mi := &file_tck_crdt_proto_msgTypes[49] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VoteVote) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VoteVote) ProtoMessage() {} + +func (x *VoteVote) ProtoReflect() protoreflect.Message { + mi := &file_tck_crdt_proto_msgTypes[49] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VoteVote.ProtoReflect.Descriptor instead. +func (*VoteVote) Descriptor() ([]byte, []int) { + return file_tck_crdt_proto_rawDescGZIP(), []int{49} +} + +func (x *VoteVote) GetKey() string { + if x != nil { + return x.Key + } + return "" +} + +func (x *VoteVote) GetFailWith() string { + if x != nil { + return x.FailWith + } + return "" +} + +func (x *VoteVote) GetValue() bool { + if x != nil { + return x.Value + } + return false +} + +var File_tck_crdt_proto protoreflect.FileDescriptor + +var file_tck_crdt_proto_rawDesc = []byte{ + 0x0a, 0x0e, 0x74, 0x63, 0x6b, 0x5f, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x12, 0x04, 0x63, 0x72, 0x64, 0x74, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x1b, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x58, + 0x0a, 0x0c, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x32, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x4d, + 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, + 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xf8, 0x01, 0x0a, 0x12, 0x4f, 0x52, 0x4d, + 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x1d, 0x0a, 0x03, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x63, + 0x72, 0x64, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x00, 0x52, 0x03, 0x67, 0x65, 0x74, 0x12, 0x26, + 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, + 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x06, + 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x06, 0x73, 0x65, 0x74, 0x4b, 0x65, 0x79, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, + 0x4d, 0x61, 0x70, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52, 0x06, 0x73, 0x65, 0x74, 0x4b, 0x65, 0x79, + 0x12, 0x31, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4b, 0x65, 0x79, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x4d, 0x61, 0x70, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x4b, 0x65, 0x79, 0x12, 0x34, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x4d, 0x61, + 0x70, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, + 0x52, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x22, 0x62, 0x0a, 0x0d, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x23, 0x0a, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x4b, + 0x65, 0x79, 0x73, 0x52, 0x04, 0x6b, 0x65, 0x79, 0x73, 0x12, 0x2c, 0x0a, 0x07, 0x65, 0x6e, 0x74, + 0x72, 0x69, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x72, 0x64, + 0x74, 0x2e, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x07, + 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0x56, 0x0a, 0x0b, 0x56, 0x6f, 0x74, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x07, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x63, 0x72, 0x64, 0x74, 0x2e, 0x56, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, + 0x8a, 0x01, 0x0a, 0x11, 0x56, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x03, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x00, 0x52, + 0x03, 0x67, 0x65, 0x74, 0x12, 0x26, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x24, 0x0a, 0x04, + 0x76, 0x6f, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x63, 0x72, 0x64, + 0x74, 0x2e, 0x56, 0x6f, 0x74, 0x65, 0x56, 0x6f, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x76, 0x6f, + 0x74, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5e, 0x0a, 0x0c, + 0x56, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, + 0x73, 0x65, 0x6c, 0x66, 0x56, 0x6f, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x73, 0x65, 0x6c, 0x66, 0x56, 0x6f, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x76, 0x6f, 0x74, 0x65, + 0x72, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x76, 0x6f, 0x74, 0x65, 0x72, 0x73, + 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x6f, 0x74, 0x65, 0x73, 0x46, 0x6f, 0x72, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0d, 0x52, 0x08, 0x76, 0x6f, 0x74, 0x65, 0x73, 0x46, 0x6f, 0x72, 0x22, 0x5e, 0x0a, 0x0f, + 0x47, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x14, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, + 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x35, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xa1, 0x01, 0x0a, + 0x15, 0x47, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x03, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x00, + 0x52, 0x03, 0x67, 0x65, 0x74, 0x12, 0x26, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x37, 0x0a, + 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x17, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, + 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x09, 0x69, 0x6e, 0x63, + 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x22, 0x3d, 0x0a, 0x10, 0x47, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0x60, 0x0a, 0x10, 0x50, 0x4e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x36, 0x0a, 0x07, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x72, 0x64, + 0x74, 0x2e, 0x50, 0x4e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x22, 0xdd, 0x01, 0x0a, 0x16, 0x50, 0x4e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x03, + 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x63, 0x72, 0x64, 0x74, + 0x2e, 0x47, 0x65, 0x74, 0x48, 0x00, 0x52, 0x03, 0x67, 0x65, 0x74, 0x12, 0x26, 0x0a, 0x06, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x72, + 0x64, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x12, 0x38, 0x0a, 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x50, 0x4e, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, + 0x48, 0x00, 0x52, 0x09, 0x69, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x38, 0x0a, + 0x09, 0x64, 0x65, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x18, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x50, 0x4e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, + 0x72, 0x44, 0x65, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x09, 0x64, 0x65, + 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0x3f, 0x0a, 0x11, 0x50, 0x4e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x50, 0x4e, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x22, 0x56, 0x0a, 0x0b, 0x47, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x14, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, + 0x47, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x87, 0x01, 0x0a, 0x11, 0x47, + 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x1d, 0x0a, 0x03, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, + 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x00, 0x52, 0x03, 0x67, 0x65, 0x74, 0x12, + 0x26, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x0c, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, + 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x21, 0x0a, 0x03, 0x61, 0x64, 0x64, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x53, 0x65, 0x74, + 0x41, 0x64, 0x64, 0x48, 0x00, 0x52, 0x03, 0x61, 0x64, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x35, 0x0a, 0x0c, 0x47, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x25, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x53, 0x65, 0x74, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x58, 0x0a, 0x0c, 0x4f, + 0x52, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x32, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x53, 0x65, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xb6, 0x01, 0x0a, 0x12, 0x4f, 0x52, 0x53, 0x65, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x03, + 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x63, 0x72, 0x64, 0x74, + 0x2e, 0x47, 0x65, 0x74, 0x48, 0x00, 0x52, 0x03, 0x67, 0x65, 0x74, 0x12, 0x26, 0x0a, 0x06, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x72, + 0x64, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x12, 0x22, 0x0a, 0x03, 0x61, 0x64, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x0e, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x53, 0x65, 0x74, 0x41, 0x64, 0x64, + 0x48, 0x00, 0x52, 0x03, 0x61, 0x64, 0x64, 0x12, 0x2b, 0x0a, 0x06, 0x72, 0x65, 0x6d, 0x6f, 0x76, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, + 0x52, 0x53, 0x65, 0x74, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x48, 0x00, 0x52, 0x06, 0x72, 0x65, + 0x6d, 0x6f, 0x76, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x37, + 0x0a, 0x0d, 0x4f, 0x52, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x26, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x53, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x56, 0x0a, 0x0b, 0x46, 0x6c, 0x61, 0x67, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x14, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x31, 0x0a, 0x07, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, + 0x63, 0x72, 0x64, 0x74, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, + 0x90, 0x01, 0x0a, 0x11, 0x46, 0x6c, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x03, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x65, 0x74, 0x48, 0x00, 0x52, + 0x03, 0x67, 0x65, 0x74, 0x12, 0x26, 0x0a, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x2a, 0x0a, 0x06, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, + 0x72, 0x64, 0x74, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x48, 0x00, + 0x52, 0x06, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x22, 0x35, 0x0a, 0x0c, 0x46, 0x6c, 0x61, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x25, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x0f, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x64, 0x0a, 0x12, 0x4c, 0x57, 0x57, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x14, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, + 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x38, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4c, 0x57, + 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, + 0xda, 0x01, 0x0a, 0x18, 0x4c, 0x57, 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1d, 0x0a, 0x03, + 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x09, 0x2e, 0x63, 0x72, 0x64, 0x74, + 0x2e, 0x47, 0x65, 0x74, 0x48, 0x00, 0x52, 0x03, 0x67, 0x65, 0x74, 0x12, 0x26, 0x0a, 0x06, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x72, + 0x64, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x06, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x12, 0x28, 0x0a, 0x03, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x14, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4c, 0x57, 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x53, 0x65, 0x74, 0x48, 0x00, 0x52, 0x03, 0x73, 0x65, 0x74, 0x12, 0x43, 0x0a, + 0x0c, 0x73, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4c, 0x57, 0x57, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x43, 0x6c, 0x6f, + 0x63, 0x6b, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, 0x43, 0x6c, 0x6f, + 0x63, 0x6b, 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x43, 0x0a, 0x13, + 0x4c, 0x57, 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4c, 0x57, 0x57, 0x52, 0x65, 0x67, + 0x69, 0x73, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x22, 0x39, 0x0a, 0x03, 0x47, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x22, 0x3c, 0x0a, 0x06, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, + 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x22, 0xc5, 0x02, 0x0a, 0x0e, 0x41, + 0x6e, 0x79, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x12, 0x33, 0x0a, + 0x09, 0x61, 0x6e, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x48, 0x00, 0x52, 0x08, 0x61, 0x6e, 0x79, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x62, 0x79, 0x74, 0x65, 0x73, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0a, + 0x62, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, 0x0b, 0x69, 0x6e, + 0x74, 0x33, 0x32, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x48, + 0x00, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x21, 0x0a, + 0x0b, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x00, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x21, 0x0a, 0x0b, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x02, 0x48, 0x00, 0x52, 0x0a, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x23, 0x0a, 0x0c, 0x64, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x01, 0x48, 0x00, 0x52, 0x0b, 0x64, 0x6f, 0x75, + 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1f, 0x0a, 0x0a, 0x62, 0x6f, 0x6f, 0x6c, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x09, + 0x62, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x22, 0x5d, 0x0a, 0x11, 0x47, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x49, 0x6e, + 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x22, 0x25, 0x0a, 0x0d, 0x47, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x5e, 0x0a, 0x12, 0x50, 0x4e, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x65, 0x72, 0x49, 0x6e, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x16, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, + 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, + 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, + 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x5e, 0x0a, 0x12, 0x50, 0x4e, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x65, 0x72, 0x44, 0x65, 0x63, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x16, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, + 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, + 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, + 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x26, 0x0a, 0x0e, 0x50, 0x4e, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x22, 0x69, 0x0a, 0x07, 0x47, 0x53, 0x65, 0x74, 0x41, 0x64, 0x64, 0x12, 0x16, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x12, + 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x41, 0x6e, 0x79, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x39, 0x0a, 0x09, 0x47, + 0x53, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, + 0x41, 0x6e, 0x79, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x06, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x43, 0x0a, 0x13, 0x47, 0x53, 0x65, 0x74, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x41, 0x6e, 0x79, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x2c, 0x0a, + 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x63, 0x72, 0x64, 0x74, 0x2e, 0x41, 0x6e, 0x79, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x54, + 0x79, 0x70, 0x65, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x6a, 0x0a, 0x08, 0x4f, + 0x52, 0x53, 0x65, 0x74, 0x41, 0x64, 0x64, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x12, 0x2a, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x72, 0x64, + 0x74, 0x2e, 0x41, 0x6e, 0x79, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x6d, 0x0a, 0x0b, 0x4f, 0x52, 0x53, 0x65, 0x74, + 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, + 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x72, 0x64, 0x74, + 0x2e, 0x41, 0x6e, 0x79, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3a, 0x0a, 0x0a, 0x4f, 0x52, 0x53, 0x65, 0x74, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2c, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x22, 0x40, 0x0a, 0x0a, 0x46, 0x6c, 0x61, 0x67, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, + 0xb5, 0x18, 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, + 0x57, 0x69, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, + 0x57, 0x69, 0x74, 0x68, 0x22, 0x21, 0x0a, 0x09, 0x46, 0x6c, 0x61, 0x67, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x70, 0x0a, 0x0e, 0x4c, 0x57, 0x57, 0x52, 0x65, + 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x12, 0x2a, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, + 0x72, 0x64, 0x74, 0x2e, 0x41, 0x6e, 0x79, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, + 0x70, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xce, 0x01, 0x0a, 0x17, 0x4c, 0x57, + 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x74, 0x57, 0x69, 0x74, 0x68, + 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, + 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, + 0x41, 0x6e, 0x79, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x52, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x25, 0x0a, 0x05, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x43, 0x72, 0x64, 0x74, + 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x52, 0x05, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x2c, 0x0a, 0x12, + 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x63, 0x6c, 0x6f, 0x63, 0x6b, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, + 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x3e, 0x0a, 0x10, 0x4c, 0x57, + 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2a, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x96, 0x05, 0x0a, 0x08, 0x4f, + 0x52, 0x4d, 0x61, 0x70, 0x53, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, + 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x12, 0x31, 0x0a, 0x09, 0x65, + 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x4b, 0x65, 0x79, 0x12, 0x2a, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x41, 0x0a, 0x0f, 0x67, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0f, 0x67, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, + 0x10, 0x70, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x50, + 0x4e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, + 0x00, 0x52, 0x10, 0x70, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x0b, 0x67, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, + 0x47, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x67, + 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x6f, 0x72, + 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x12, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x0b, 0x66, 0x6c, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x72, 0x64, 0x74, + 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, + 0x66, 0x6c, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x4a, 0x0a, 0x12, 0x6c, + 0x77, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4c, + 0x57, 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x48, 0x00, 0x52, 0x12, 0x6c, 0x77, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x6f, 0x72, 0x4d, 0x61, 0x70, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, + 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x48, 0x00, 0x52, 0x0c, 0x6f, 0x72, 0x4d, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x35, 0x0a, 0x0b, 0x76, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x56, 0x6f, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x76, 0x6f, 0x74, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x22, 0xf4, 0x04, 0x0a, 0x12, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x03, 0x6b, + 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x12, 0x31, + 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x4b, 0x65, + 0x79, 0x12, 0x41, 0x0a, 0x0f, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x63, 0x72, 0x64, + 0x74, 0x2e, 0x47, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x48, 0x00, 0x52, 0x0f, 0x67, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x10, 0x70, 0x6e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x50, 0x4e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x10, 0x70, 0x6e, 0x43, 0x6f, 0x75, 0x6e, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x0b, 0x67, 0x73, + 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x11, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x67, 0x73, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x38, 0x0a, 0x0c, 0x6f, 0x72, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, + 0x52, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x6f, + 0x72, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x0b, 0x66, + 0x6c, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x11, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0b, 0x66, 0x6c, 0x61, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x4a, 0x0a, 0x12, 0x6c, 0x77, 0x77, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4c, 0x57, 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x12, 0x6c, 0x77, 0x77, 0x52, + 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x38, + 0x0a, 0x0c, 0x6f, 0x72, 0x4d, 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x4d, 0x61, + 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x6f, 0x72, 0x4d, 0x61, + 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x35, 0x0a, 0x0b, 0x76, 0x6f, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x63, 0x72, 0x64, 0x74, 0x2e, 0x56, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x48, 0x00, 0x52, 0x0b, 0x76, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x42, + 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x74, 0x0a, 0x0b, 0x4f, 0x52, + 0x4d, 0x61, 0x70, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, 0x01, 0x52, 0x03, 0x6b, 0x65, + 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, 0x74, 0x68, 0x12, 0x31, 0x0a, + 0x09, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x4b, 0x65, 0x79, + 0x22, 0x6b, 0x0a, 0x0a, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x31, + 0x0a, 0x09, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x08, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x4b, 0x65, + 0x79, 0x12, 0x2a, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x38, 0x0a, + 0x0c, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x28, 0x0a, + 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, + 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x22, 0x39, 0x0a, 0x09, 0x4f, 0x52, 0x4d, 0x61, 0x70, + 0x4b, 0x65, 0x79, 0x73, 0x12, 0x2c, 0x0a, 0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x06, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x22, 0x54, 0x0a, 0x08, 0x56, 0x6f, 0x74, 0x65, 0x56, 0x6f, 0x74, 0x65, 0x12, 0x16, + 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, 0x90, 0xb5, 0x18, + 0x01, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, + 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x57, 0x69, + 0x74, 0x68, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x4c, 0x0a, 0x09, 0x43, 0x72, 0x64, 0x74, + 0x43, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x46, 0x41, 0x55, 0x4c, 0x54, + 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x52, 0x45, 0x56, 0x45, 0x52, 0x53, 0x45, 0x10, 0x01, 0x12, + 0x0a, 0x0a, 0x06, 0x43, 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x43, + 0x55, 0x53, 0x54, 0x4f, 0x4d, 0x5f, 0x41, 0x55, 0x54, 0x4f, 0x5f, 0x49, 0x4e, 0x43, 0x52, 0x45, + 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x03, 0x32, 0xbb, 0x04, 0x0a, 0x07, 0x54, 0x63, 0x6b, 0x43, 0x72, + 0x64, 0x74, 0x12, 0x40, 0x0a, 0x0f, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x47, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x15, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x63, + 0x72, 0x64, 0x74, 0x2e, 0x47, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x17, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x47, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x65, 0x64, 0x12, + 0x15, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, + 0x12, 0x43, 0x0a, 0x10, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x50, 0x4e, 0x43, 0x6f, 0x75, + 0x6e, 0x74, 0x65, 0x72, 0x12, 0x16, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x50, 0x4e, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x63, + 0x72, 0x64, 0x74, 0x2e, 0x50, 0x4e, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, + 0x47, 0x53, 0x65, 0x74, 0x12, 0x11, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, 0x53, 0x65, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x47, + 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0c, 0x50, + 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4f, 0x52, 0x53, 0x65, 0x74, 0x12, 0x12, 0x2e, 0x63, 0x72, + 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x53, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x13, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x53, 0x65, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x46, + 0x6c, 0x61, 0x67, 0x12, 0x11, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x46, 0x6c, + 0x61, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x49, 0x0a, 0x12, 0x50, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x4c, 0x57, 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x12, 0x18, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4c, 0x57, 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x63, 0x72, 0x64, + 0x74, 0x2e, 0x4c, 0x57, 0x57, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, + 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x12, 0x12, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x4f, 0x52, 0x4d, + 0x61, 0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x13, 0x2e, 0x63, 0x72, 0x64, 0x74, + 0x2e, 0x4f, 0x52, 0x4d, 0x61, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, + 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x56, 0x6f, 0x74, 0x65, 0x12, 0x11, 0x2e, + 0x63, 0x72, 0x64, 0x74, 0x2e, 0x56, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x12, 0x2e, 0x63, 0x72, 0x64, 0x74, 0x2e, 0x56, 0x6f, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x51, 0x0a, 0x17, 0x69, 0x6f, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x74, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5a, + 0x36, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x73, 0x75, 0x70, 0x70, + 0x6f, 0x72, 0x74, 0x2f, 0x74, 0x63, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x63, 0x72, + 0x64, 0x74, 0x3b, 0x63, 0x72, 0x64, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_tck_crdt_proto_rawDescOnce sync.Once + file_tck_crdt_proto_rawDescData = file_tck_crdt_proto_rawDesc +) + +func file_tck_crdt_proto_rawDescGZIP() []byte { + file_tck_crdt_proto_rawDescOnce.Do(func() { + file_tck_crdt_proto_rawDescData = protoimpl.X.CompressGZIP(file_tck_crdt_proto_rawDescData) + }) + return file_tck_crdt_proto_rawDescData +} + +var file_tck_crdt_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_tck_crdt_proto_msgTypes = make([]protoimpl.MessageInfo, 50) +var file_tck_crdt_proto_goTypes = []interface{}{ + (CrdtClock)(0), // 0: crdt.CrdtClock + (*ORMapRequest)(nil), // 1: crdt.ORMapRequest + (*ORMapRequestAction)(nil), // 2: crdt.ORMapRequestAction + (*ORMapResponse)(nil), // 3: crdt.ORMapResponse + (*VoteRequest)(nil), // 4: crdt.VoteRequest + (*VoteRequestAction)(nil), // 5: crdt.VoteRequestAction + (*VoteResponse)(nil), // 6: crdt.VoteResponse + (*GCounterRequest)(nil), // 7: crdt.GCounterRequest + (*GCounterRequestAction)(nil), // 8: crdt.GCounterRequestAction + (*GCounterResponse)(nil), // 9: crdt.GCounterResponse + (*PNCounterRequest)(nil), // 10: crdt.PNCounterRequest + (*PNCounterRequestAction)(nil), // 11: crdt.PNCounterRequestAction + (*PNCounterResponse)(nil), // 12: crdt.PNCounterResponse + (*GSetRequest)(nil), // 13: crdt.GSetRequest + (*GSetRequestAction)(nil), // 14: crdt.GSetRequestAction + (*GSetResponse)(nil), // 15: crdt.GSetResponse + (*ORSetRequest)(nil), // 16: crdt.ORSetRequest + (*ORSetRequestAction)(nil), // 17: crdt.ORSetRequestAction + (*ORSetResponse)(nil), // 18: crdt.ORSetResponse + (*FlagRequest)(nil), // 19: crdt.FlagRequest + (*FlagRequestAction)(nil), // 20: crdt.FlagRequestAction + (*FlagResponse)(nil), // 21: crdt.FlagResponse + (*LWWRegisterRequest)(nil), // 22: crdt.LWWRegisterRequest + (*LWWRegisterRequestAction)(nil), // 23: crdt.LWWRegisterRequestAction + (*LWWRegisterResponse)(nil), // 24: crdt.LWWRegisterResponse + (*Get)(nil), // 25: crdt.Get + (*Delete)(nil), // 26: crdt.Delete + (*AnySupportType)(nil), // 27: crdt.AnySupportType + (*GCounterIncrement)(nil), // 28: crdt.GCounterIncrement + (*GCounterValue)(nil), // 29: crdt.GCounterValue + (*PNCounterIncrement)(nil), // 30: crdt.PNCounterIncrement + (*PNCounterDecrement)(nil), // 31: crdt.PNCounterDecrement + (*PNCounterValue)(nil), // 32: crdt.PNCounterValue + (*GSetAdd)(nil), // 33: crdt.GSetAdd + (*GSetValue)(nil), // 34: crdt.GSetValue + (*GSetValueAnySupport)(nil), // 35: crdt.GSetValueAnySupport + (*ORSetAdd)(nil), // 36: crdt.ORSetAdd + (*ORSetRemove)(nil), // 37: crdt.ORSetRemove + (*ORSetValue)(nil), // 38: crdt.ORSetValue + (*FlagEnable)(nil), // 39: crdt.FlagEnable + (*FlagValue)(nil), // 40: crdt.FlagValue + (*LWWRegisterSet)(nil), // 41: crdt.LWWRegisterSet + (*LWWRegisterSetWithClock)(nil), // 42: crdt.LWWRegisterSetWithClock + (*LWWRegisterValue)(nil), // 43: crdt.LWWRegisterValue + (*ORMapSet)(nil), // 44: crdt.ORMapSet + (*ORMapActionRequest)(nil), // 45: crdt.ORMapActionRequest + (*ORMapDelete)(nil), // 46: crdt.ORMapDelete + (*ORMapEntry)(nil), // 47: crdt.ORMapEntry + (*ORMapEntries)(nil), // 48: crdt.ORMapEntries + (*ORMapKeys)(nil), // 49: crdt.ORMapKeys + (*VoteVote)(nil), // 50: crdt.VoteVote + (*any.Any)(nil), // 51: google.protobuf.Any +} +var file_tck_crdt_proto_depIdxs = []int32{ + 2, // 0: crdt.ORMapRequest.actions:type_name -> crdt.ORMapRequestAction + 25, // 1: crdt.ORMapRequestAction.get:type_name -> crdt.Get + 26, // 2: crdt.ORMapRequestAction.delete:type_name -> crdt.Delete + 44, // 3: crdt.ORMapRequestAction.setKey:type_name -> crdt.ORMapSet + 46, // 4: crdt.ORMapRequestAction.deleteKey:type_name -> crdt.ORMapDelete + 45, // 5: crdt.ORMapRequestAction.request:type_name -> crdt.ORMapActionRequest + 49, // 6: crdt.ORMapResponse.keys:type_name -> crdt.ORMapKeys + 48, // 7: crdt.ORMapResponse.entries:type_name -> crdt.ORMapEntries + 5, // 8: crdt.VoteRequest.actions:type_name -> crdt.VoteRequestAction + 25, // 9: crdt.VoteRequestAction.get:type_name -> crdt.Get + 26, // 10: crdt.VoteRequestAction.delete:type_name -> crdt.Delete + 50, // 11: crdt.VoteRequestAction.vote:type_name -> crdt.VoteVote + 8, // 12: crdt.GCounterRequest.actions:type_name -> crdt.GCounterRequestAction + 25, // 13: crdt.GCounterRequestAction.get:type_name -> crdt.Get + 26, // 14: crdt.GCounterRequestAction.delete:type_name -> crdt.Delete + 28, // 15: crdt.GCounterRequestAction.increment:type_name -> crdt.GCounterIncrement + 29, // 16: crdt.GCounterResponse.value:type_name -> crdt.GCounterValue + 11, // 17: crdt.PNCounterRequest.actions:type_name -> crdt.PNCounterRequestAction + 25, // 18: crdt.PNCounterRequestAction.get:type_name -> crdt.Get + 26, // 19: crdt.PNCounterRequestAction.delete:type_name -> crdt.Delete + 30, // 20: crdt.PNCounterRequestAction.increment:type_name -> crdt.PNCounterIncrement + 31, // 21: crdt.PNCounterRequestAction.decrement:type_name -> crdt.PNCounterDecrement + 32, // 22: crdt.PNCounterResponse.value:type_name -> crdt.PNCounterValue + 14, // 23: crdt.GSetRequest.actions:type_name -> crdt.GSetRequestAction + 25, // 24: crdt.GSetRequestAction.get:type_name -> crdt.Get + 26, // 25: crdt.GSetRequestAction.delete:type_name -> crdt.Delete + 33, // 26: crdt.GSetRequestAction.add:type_name -> crdt.GSetAdd + 34, // 27: crdt.GSetResponse.value:type_name -> crdt.GSetValue + 17, // 28: crdt.ORSetRequest.actions:type_name -> crdt.ORSetRequestAction + 25, // 29: crdt.ORSetRequestAction.get:type_name -> crdt.Get + 26, // 30: crdt.ORSetRequestAction.delete:type_name -> crdt.Delete + 36, // 31: crdt.ORSetRequestAction.add:type_name -> crdt.ORSetAdd + 37, // 32: crdt.ORSetRequestAction.remove:type_name -> crdt.ORSetRemove + 38, // 33: crdt.ORSetResponse.value:type_name -> crdt.ORSetValue + 20, // 34: crdt.FlagRequest.actions:type_name -> crdt.FlagRequestAction + 25, // 35: crdt.FlagRequestAction.get:type_name -> crdt.Get + 26, // 36: crdt.FlagRequestAction.delete:type_name -> crdt.Delete + 39, // 37: crdt.FlagRequestAction.enable:type_name -> crdt.FlagEnable + 40, // 38: crdt.FlagResponse.value:type_name -> crdt.FlagValue + 23, // 39: crdt.LWWRegisterRequest.actions:type_name -> crdt.LWWRegisterRequestAction + 25, // 40: crdt.LWWRegisterRequestAction.get:type_name -> crdt.Get + 26, // 41: crdt.LWWRegisterRequestAction.delete:type_name -> crdt.Delete + 41, // 42: crdt.LWWRegisterRequestAction.set:type_name -> crdt.LWWRegisterSet + 42, // 43: crdt.LWWRegisterRequestAction.setWithClock:type_name -> crdt.LWWRegisterSetWithClock + 43, // 44: crdt.LWWRegisterResponse.value:type_name -> crdt.LWWRegisterValue + 51, // 45: crdt.AnySupportType.any_value:type_name -> google.protobuf.Any + 27, // 46: crdt.GSetAdd.value:type_name -> crdt.AnySupportType + 27, // 47: crdt.GSetValue.values:type_name -> crdt.AnySupportType + 27, // 48: crdt.GSetValueAnySupport.values:type_name -> crdt.AnySupportType + 27, // 49: crdt.ORSetAdd.value:type_name -> crdt.AnySupportType + 27, // 50: crdt.ORSetRemove.value:type_name -> crdt.AnySupportType + 51, // 51: crdt.ORSetValue.values:type_name -> google.protobuf.Any + 27, // 52: crdt.LWWRegisterSet.value:type_name -> crdt.AnySupportType + 27, // 53: crdt.LWWRegisterSetWithClock.value:type_name -> crdt.AnySupportType + 0, // 54: crdt.LWWRegisterSetWithClock.clock:type_name -> crdt.CrdtClock + 51, // 55: crdt.LWWRegisterValue.value:type_name -> google.protobuf.Any + 51, // 56: crdt.ORMapSet.entry_key:type_name -> google.protobuf.Any + 51, // 57: crdt.ORMapSet.value:type_name -> google.protobuf.Any + 7, // 58: crdt.ORMapSet.gCounterRequest:type_name -> crdt.GCounterRequest + 10, // 59: crdt.ORMapSet.pnCounterRequest:type_name -> crdt.PNCounterRequest + 13, // 60: crdt.ORMapSet.gsetRequest:type_name -> crdt.GSetRequest + 16, // 61: crdt.ORMapSet.orSetRequest:type_name -> crdt.ORSetRequest + 19, // 62: crdt.ORMapSet.flagRequest:type_name -> crdt.FlagRequest + 22, // 63: crdt.ORMapSet.lwwRegisterRequest:type_name -> crdt.LWWRegisterRequest + 1, // 64: crdt.ORMapSet.orMapRequest:type_name -> crdt.ORMapRequest + 4, // 65: crdt.ORMapSet.voteRequest:type_name -> crdt.VoteRequest + 51, // 66: crdt.ORMapActionRequest.entry_key:type_name -> google.protobuf.Any + 7, // 67: crdt.ORMapActionRequest.gCounterRequest:type_name -> crdt.GCounterRequest + 10, // 68: crdt.ORMapActionRequest.pnCounterRequest:type_name -> crdt.PNCounterRequest + 13, // 69: crdt.ORMapActionRequest.gsetRequest:type_name -> crdt.GSetRequest + 16, // 70: crdt.ORMapActionRequest.orSetRequest:type_name -> crdt.ORSetRequest + 19, // 71: crdt.ORMapActionRequest.flagRequest:type_name -> crdt.FlagRequest + 22, // 72: crdt.ORMapActionRequest.lwwRegisterRequest:type_name -> crdt.LWWRegisterRequest + 1, // 73: crdt.ORMapActionRequest.orMapRequest:type_name -> crdt.ORMapRequest + 4, // 74: crdt.ORMapActionRequest.voteRequest:type_name -> crdt.VoteRequest + 51, // 75: crdt.ORMapDelete.entry_key:type_name -> google.protobuf.Any + 51, // 76: crdt.ORMapEntry.entry_key:type_name -> google.protobuf.Any + 51, // 77: crdt.ORMapEntry.value:type_name -> google.protobuf.Any + 47, // 78: crdt.ORMapEntries.values:type_name -> crdt.ORMapEntry + 51, // 79: crdt.ORMapKeys.values:type_name -> google.protobuf.Any + 7, // 80: crdt.TckCrdt.ProcessGCounter:input_type -> crdt.GCounterRequest + 7, // 81: crdt.TckCrdt.ProcessGCounterStreamed:input_type -> crdt.GCounterRequest + 10, // 82: crdt.TckCrdt.ProcessPNCounter:input_type -> crdt.PNCounterRequest + 13, // 83: crdt.TckCrdt.ProcessGSet:input_type -> crdt.GSetRequest + 16, // 84: crdt.TckCrdt.ProcessORSet:input_type -> crdt.ORSetRequest + 19, // 85: crdt.TckCrdt.ProcessFlag:input_type -> crdt.FlagRequest + 22, // 86: crdt.TckCrdt.ProcessLWWRegister:input_type -> crdt.LWWRegisterRequest + 1, // 87: crdt.TckCrdt.ProcessORMap:input_type -> crdt.ORMapRequest + 4, // 88: crdt.TckCrdt.ProcessVote:input_type -> crdt.VoteRequest + 9, // 89: crdt.TckCrdt.ProcessGCounter:output_type -> crdt.GCounterResponse + 9, // 90: crdt.TckCrdt.ProcessGCounterStreamed:output_type -> crdt.GCounterResponse + 12, // 91: crdt.TckCrdt.ProcessPNCounter:output_type -> crdt.PNCounterResponse + 15, // 92: crdt.TckCrdt.ProcessGSet:output_type -> crdt.GSetResponse + 18, // 93: crdt.TckCrdt.ProcessORSet:output_type -> crdt.ORSetResponse + 21, // 94: crdt.TckCrdt.ProcessFlag:output_type -> crdt.FlagResponse + 24, // 95: crdt.TckCrdt.ProcessLWWRegister:output_type -> crdt.LWWRegisterResponse + 3, // 96: crdt.TckCrdt.ProcessORMap:output_type -> crdt.ORMapResponse + 6, // 97: crdt.TckCrdt.ProcessVote:output_type -> crdt.VoteResponse + 89, // [89:98] is the sub-list for method output_type + 80, // [80:89] is the sub-list for method input_type + 80, // [80:80] is the sub-list for extension type_name + 80, // [80:80] is the sub-list for extension extendee + 0, // [0:80] is the sub-list for field type_name +} + +func init() { file_tck_crdt_proto_init() } +func file_tck_crdt_proto_init() { + if File_tck_crdt_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_tck_crdt_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapRequestAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VoteRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VoteRequestAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VoteResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GCounterRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GCounterRequestAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GCounterResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PNCounterRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PNCounterRequestAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PNCounterResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GSetRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GSetRequestAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GSetResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORSetRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORSetRequestAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORSetResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlagRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlagRequestAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlagResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LWWRegisterRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LWWRegisterRequestAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LWWRegisterResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Get); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Delete); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AnySupportType); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GCounterIncrement); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GCounterValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PNCounterIncrement); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PNCounterDecrement); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PNCounterValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GSetAdd); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GSetValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GSetValueAnySupport); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORSetAdd); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORSetRemove); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORSetValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[38].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlagEnable); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[39].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FlagValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[40].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LWWRegisterSet); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[41].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LWWRegisterSetWithClock); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[42].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LWWRegisterValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[43].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapSet); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[44].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapActionRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[45].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapDelete); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[46].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapEntry); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[47].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapEntries); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[48].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ORMapKeys); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_tck_crdt_proto_msgTypes[49].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VoteVote); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_tck_crdt_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*ORMapRequestAction_Get)(nil), + (*ORMapRequestAction_Delete)(nil), + (*ORMapRequestAction_SetKey)(nil), + (*ORMapRequestAction_DeleteKey)(nil), + (*ORMapRequestAction_Request)(nil), + } + file_tck_crdt_proto_msgTypes[4].OneofWrappers = []interface{}{ + (*VoteRequestAction_Get)(nil), + (*VoteRequestAction_Delete)(nil), + (*VoteRequestAction_Vote)(nil), + } + file_tck_crdt_proto_msgTypes[7].OneofWrappers = []interface{}{ + (*GCounterRequestAction_Get)(nil), + (*GCounterRequestAction_Delete)(nil), + (*GCounterRequestAction_Increment)(nil), + } + file_tck_crdt_proto_msgTypes[10].OneofWrappers = []interface{}{ + (*PNCounterRequestAction_Get)(nil), + (*PNCounterRequestAction_Delete)(nil), + (*PNCounterRequestAction_Increment)(nil), + (*PNCounterRequestAction_Decrement)(nil), + } + file_tck_crdt_proto_msgTypes[13].OneofWrappers = []interface{}{ + (*GSetRequestAction_Get)(nil), + (*GSetRequestAction_Delete)(nil), + (*GSetRequestAction_Add)(nil), + } + file_tck_crdt_proto_msgTypes[16].OneofWrappers = []interface{}{ + (*ORSetRequestAction_Get)(nil), + (*ORSetRequestAction_Delete)(nil), + (*ORSetRequestAction_Add)(nil), + (*ORSetRequestAction_Remove)(nil), + } + file_tck_crdt_proto_msgTypes[19].OneofWrappers = []interface{}{ + (*FlagRequestAction_Get)(nil), + (*FlagRequestAction_Delete)(nil), + (*FlagRequestAction_Enable)(nil), + } + file_tck_crdt_proto_msgTypes[22].OneofWrappers = []interface{}{ + (*LWWRegisterRequestAction_Get)(nil), + (*LWWRegisterRequestAction_Delete)(nil), + (*LWWRegisterRequestAction_Set)(nil), + (*LWWRegisterRequestAction_SetWithClock)(nil), + } + file_tck_crdt_proto_msgTypes[26].OneofWrappers = []interface{}{ + (*AnySupportType_AnyValue)(nil), + (*AnySupportType_StringValue)(nil), + (*AnySupportType_BytesValue)(nil), + (*AnySupportType_Int32Value)(nil), + (*AnySupportType_Int64Value)(nil), + (*AnySupportType_FloatValue)(nil), + (*AnySupportType_DoubleValue)(nil), + (*AnySupportType_BoolValue)(nil), + } + file_tck_crdt_proto_msgTypes[43].OneofWrappers = []interface{}{ + (*ORMapSet_GCounterRequest)(nil), + (*ORMapSet_PnCounterRequest)(nil), + (*ORMapSet_GsetRequest)(nil), + (*ORMapSet_OrSetRequest)(nil), + (*ORMapSet_FlagRequest)(nil), + (*ORMapSet_LwwRegisterRequest)(nil), + (*ORMapSet_OrMapRequest)(nil), + (*ORMapSet_VoteRequest)(nil), + } + file_tck_crdt_proto_msgTypes[44].OneofWrappers = []interface{}{ + (*ORMapActionRequest_GCounterRequest)(nil), + (*ORMapActionRequest_PnCounterRequest)(nil), + (*ORMapActionRequest_GsetRequest)(nil), + (*ORMapActionRequest_OrSetRequest)(nil), + (*ORMapActionRequest_FlagRequest)(nil), + (*ORMapActionRequest_LwwRegisterRequest)(nil), + (*ORMapActionRequest_OrMapRequest)(nil), + (*ORMapActionRequest_VoteRequest)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_tck_crdt_proto_rawDesc, + NumEnums: 1, + NumMessages: 50, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_tck_crdt_proto_goTypes, + DependencyIndexes: file_tck_crdt_proto_depIdxs, + EnumInfos: file_tck_crdt_proto_enumTypes, + MessageInfos: file_tck_crdt_proto_msgTypes, + }.Build() + File_tck_crdt_proto = out.File + file_tck_crdt_proto_rawDesc = nil + file_tck_crdt_proto_goTypes = nil + file_tck_crdt_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// TckCrdtClient is the client API for TckCrdt service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type TckCrdtClient interface { + ProcessGCounter(ctx context.Context, in *GCounterRequest, opts ...grpc.CallOption) (*GCounterResponse, error) + ProcessGCounterStreamed(ctx context.Context, in *GCounterRequest, opts ...grpc.CallOption) (TckCrdt_ProcessGCounterStreamedClient, error) + ProcessPNCounter(ctx context.Context, in *PNCounterRequest, opts ...grpc.CallOption) (*PNCounterResponse, error) + ProcessGSet(ctx context.Context, in *GSetRequest, opts ...grpc.CallOption) (*GSetResponse, error) + ProcessORSet(ctx context.Context, in *ORSetRequest, opts ...grpc.CallOption) (*ORSetResponse, error) + ProcessFlag(ctx context.Context, in *FlagRequest, opts ...grpc.CallOption) (*FlagResponse, error) + ProcessLWWRegister(ctx context.Context, in *LWWRegisterRequest, opts ...grpc.CallOption) (*LWWRegisterResponse, error) + ProcessORMap(ctx context.Context, in *ORMapRequest, opts ...grpc.CallOption) (*ORMapResponse, error) + ProcessVote(ctx context.Context, in *VoteRequest, opts ...grpc.CallOption) (*VoteResponse, error) +} + +type tckCrdtClient struct { + cc grpc.ClientConnInterface +} + +func NewTckCrdtClient(cc grpc.ClientConnInterface) TckCrdtClient { + return &tckCrdtClient{cc} +} + +func (c *tckCrdtClient) ProcessGCounter(ctx context.Context, in *GCounterRequest, opts ...grpc.CallOption) (*GCounterResponse, error) { + out := new(GCounterResponse) + err := c.cc.Invoke(ctx, "/crdt.TckCrdt/ProcessGCounter", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tckCrdtClient) ProcessGCounterStreamed(ctx context.Context, in *GCounterRequest, opts ...grpc.CallOption) (TckCrdt_ProcessGCounterStreamedClient, error) { + stream, err := c.cc.NewStream(ctx, &_TckCrdt_serviceDesc.Streams[0], "/crdt.TckCrdt/ProcessGCounterStreamed", opts...) + if err != nil { + return nil, err + } + x := &tckCrdtProcessGCounterStreamedClient{stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil +} + +type TckCrdt_ProcessGCounterStreamedClient interface { + Recv() (*GCounterResponse, error) + grpc.ClientStream +} + +type tckCrdtProcessGCounterStreamedClient struct { + grpc.ClientStream +} + +func (x *tckCrdtProcessGCounterStreamedClient) Recv() (*GCounterResponse, error) { + m := new(GCounterResponse) + if err := x.ClientStream.RecvMsg(m); err != nil { + return nil, err + } + return m, nil +} + +func (c *tckCrdtClient) ProcessPNCounter(ctx context.Context, in *PNCounterRequest, opts ...grpc.CallOption) (*PNCounterResponse, error) { + out := new(PNCounterResponse) + err := c.cc.Invoke(ctx, "/crdt.TckCrdt/ProcessPNCounter", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tckCrdtClient) ProcessGSet(ctx context.Context, in *GSetRequest, opts ...grpc.CallOption) (*GSetResponse, error) { + out := new(GSetResponse) + err := c.cc.Invoke(ctx, "/crdt.TckCrdt/ProcessGSet", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tckCrdtClient) ProcessORSet(ctx context.Context, in *ORSetRequest, opts ...grpc.CallOption) (*ORSetResponse, error) { + out := new(ORSetResponse) + err := c.cc.Invoke(ctx, "/crdt.TckCrdt/ProcessORSet", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tckCrdtClient) ProcessFlag(ctx context.Context, in *FlagRequest, opts ...grpc.CallOption) (*FlagResponse, error) { + out := new(FlagResponse) + err := c.cc.Invoke(ctx, "/crdt.TckCrdt/ProcessFlag", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tckCrdtClient) ProcessLWWRegister(ctx context.Context, in *LWWRegisterRequest, opts ...grpc.CallOption) (*LWWRegisterResponse, error) { + out := new(LWWRegisterResponse) + err := c.cc.Invoke(ctx, "/crdt.TckCrdt/ProcessLWWRegister", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tckCrdtClient) ProcessORMap(ctx context.Context, in *ORMapRequest, opts ...grpc.CallOption) (*ORMapResponse, error) { + out := new(ORMapResponse) + err := c.cc.Invoke(ctx, "/crdt.TckCrdt/ProcessORMap", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *tckCrdtClient) ProcessVote(ctx context.Context, in *VoteRequest, opts ...grpc.CallOption) (*VoteResponse, error) { + out := new(VoteResponse) + err := c.cc.Invoke(ctx, "/crdt.TckCrdt/ProcessVote", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// TckCrdtServer is the server API for TckCrdt service. +type TckCrdtServer interface { + ProcessGCounter(context.Context, *GCounterRequest) (*GCounterResponse, error) + ProcessGCounterStreamed(*GCounterRequest, TckCrdt_ProcessGCounterStreamedServer) error + ProcessPNCounter(context.Context, *PNCounterRequest) (*PNCounterResponse, error) + ProcessGSet(context.Context, *GSetRequest) (*GSetResponse, error) + ProcessORSet(context.Context, *ORSetRequest) (*ORSetResponse, error) + ProcessFlag(context.Context, *FlagRequest) (*FlagResponse, error) + ProcessLWWRegister(context.Context, *LWWRegisterRequest) (*LWWRegisterResponse, error) + ProcessORMap(context.Context, *ORMapRequest) (*ORMapResponse, error) + ProcessVote(context.Context, *VoteRequest) (*VoteResponse, error) +} + +// UnimplementedTckCrdtServer can be embedded to have forward compatible implementations. +type UnimplementedTckCrdtServer struct { +} + +func (*UnimplementedTckCrdtServer) ProcessGCounter(context.Context, *GCounterRequest) (*GCounterResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ProcessGCounter not implemented") +} +func (*UnimplementedTckCrdtServer) ProcessGCounterStreamed(*GCounterRequest, TckCrdt_ProcessGCounterStreamedServer) error { + return status.Errorf(codes.Unimplemented, "method ProcessGCounterStreamed not implemented") +} +func (*UnimplementedTckCrdtServer) ProcessPNCounter(context.Context, *PNCounterRequest) (*PNCounterResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ProcessPNCounter not implemented") +} +func (*UnimplementedTckCrdtServer) ProcessGSet(context.Context, *GSetRequest) (*GSetResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ProcessGSet not implemented") +} +func (*UnimplementedTckCrdtServer) ProcessORSet(context.Context, *ORSetRequest) (*ORSetResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ProcessORSet not implemented") +} +func (*UnimplementedTckCrdtServer) ProcessFlag(context.Context, *FlagRequest) (*FlagResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ProcessFlag not implemented") +} +func (*UnimplementedTckCrdtServer) ProcessLWWRegister(context.Context, *LWWRegisterRequest) (*LWWRegisterResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ProcessLWWRegister not implemented") +} +func (*UnimplementedTckCrdtServer) ProcessORMap(context.Context, *ORMapRequest) (*ORMapResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ProcessORMap not implemented") +} +func (*UnimplementedTckCrdtServer) ProcessVote(context.Context, *VoteRequest) (*VoteResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method ProcessVote not implemented") +} + +func RegisterTckCrdtServer(s *grpc.Server, srv TckCrdtServer) { + s.RegisterService(&_TckCrdt_serviceDesc, srv) +} + +func _TckCrdt_ProcessGCounter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GCounterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TckCrdtServer).ProcessGCounter(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/crdt.TckCrdt/ProcessGCounter", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TckCrdtServer).ProcessGCounter(ctx, req.(*GCounterRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TckCrdt_ProcessGCounterStreamed_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(GCounterRequest) + if err := stream.RecvMsg(m); err != nil { + return err + } + return srv.(TckCrdtServer).ProcessGCounterStreamed(m, &tckCrdtProcessGCounterStreamedServer{stream}) +} + +type TckCrdt_ProcessGCounterStreamedServer interface { + Send(*GCounterResponse) error + grpc.ServerStream +} + +type tckCrdtProcessGCounterStreamedServer struct { + grpc.ServerStream +} + +func (x *tckCrdtProcessGCounterStreamedServer) Send(m *GCounterResponse) error { + return x.ServerStream.SendMsg(m) +} + +func _TckCrdt_ProcessPNCounter_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(PNCounterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TckCrdtServer).ProcessPNCounter(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/crdt.TckCrdt/ProcessPNCounter", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TckCrdtServer).ProcessPNCounter(ctx, req.(*PNCounterRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TckCrdt_ProcessGSet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GSetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TckCrdtServer).ProcessGSet(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/crdt.TckCrdt/ProcessGSet", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TckCrdtServer).ProcessGSet(ctx, req.(*GSetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TckCrdt_ProcessORSet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ORSetRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TckCrdtServer).ProcessORSet(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/crdt.TckCrdt/ProcessORSet", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TckCrdtServer).ProcessORSet(ctx, req.(*ORSetRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TckCrdt_ProcessFlag_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(FlagRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TckCrdtServer).ProcessFlag(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/crdt.TckCrdt/ProcessFlag", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TckCrdtServer).ProcessFlag(ctx, req.(*FlagRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TckCrdt_ProcessLWWRegister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LWWRegisterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TckCrdtServer).ProcessLWWRegister(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/crdt.TckCrdt/ProcessLWWRegister", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TckCrdtServer).ProcessLWWRegister(ctx, req.(*LWWRegisterRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TckCrdt_ProcessORMap_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ORMapRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TckCrdtServer).ProcessORMap(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/crdt.TckCrdt/ProcessORMap", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TckCrdtServer).ProcessORMap(ctx, req.(*ORMapRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _TckCrdt_ProcessVote_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(VoteRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TckCrdtServer).ProcessVote(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/crdt.TckCrdt/ProcessVote", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TckCrdtServer).ProcessVote(ctx, req.(*VoteRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _TckCrdt_serviceDesc = grpc.ServiceDesc{ + ServiceName: "crdt.TckCrdt", + HandlerType: (*TckCrdtServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "ProcessGCounter", + Handler: _TckCrdt_ProcessGCounter_Handler, + }, + { + MethodName: "ProcessPNCounter", + Handler: _TckCrdt_ProcessPNCounter_Handler, + }, + { + MethodName: "ProcessGSet", + Handler: _TckCrdt_ProcessGSet_Handler, + }, + { + MethodName: "ProcessORSet", + Handler: _TckCrdt_ProcessORSet_Handler, + }, + { + MethodName: "ProcessFlag", + Handler: _TckCrdt_ProcessFlag_Handler, + }, + { + MethodName: "ProcessLWWRegister", + Handler: _TckCrdt_ProcessLWWRegister_Handler, + }, + { + MethodName: "ProcessORMap", + Handler: _TckCrdt_ProcessORMap_Handler, + }, + { + MethodName: "ProcessVote", + Handler: _TckCrdt_ProcessVote_Handler, + }, + }, + Streams: []grpc.StreamDesc{ + { + StreamName: "ProcessGCounterStreamed", + Handler: _TckCrdt_ProcessGCounterStreamed_Handler, + ServerStreams: true, + }, + }, + Metadata: "tck_crdt.proto", +} diff --git a/tck/eventsourced/eventsourced.pb.go b/tck/eventsourced/eventsourced.pb.go new file mode 100644 index 0000000..9f1a2b7 --- /dev/null +++ b/tck/eventsourced/eventsourced.pb.go @@ -0,0 +1,919 @@ +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +// == Cloudstate TCK model test for event-sourced entities == +// + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.21.0 +// protoc v3.11.2 +// source: eventsourced.proto + +package eventsourced + +import ( + context "context" + _ "github.com/cloudstateio/go-support/cloudstate" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +// +// A `Request` message contains any actions that the entity should process. +// Actions must be processed in order. Any actions after a `Fail` may be ignored. +// +type Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Actions []*RequestAction `protobuf:"bytes,2,rep,name=actions,proto3" json:"actions,omitempty"` +} + +func (x *Request) Reset() { + *x = Request{} + if protoimpl.UnsafeEnabled { + mi := &file_eventsourced_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Request) ProtoMessage() {} + +func (x *Request) ProtoReflect() protoreflect.Message { + mi := &file_eventsourced_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Request.ProtoReflect.Descriptor instead. +func (*Request) Descriptor() ([]byte, []int) { + return file_eventsourced_proto_rawDescGZIP(), []int{0} +} + +func (x *Request) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Request) GetActions() []*RequestAction { + if x != nil { + return x.Actions + } + return nil +} + +// +// Each `RequestAction` is one of: +// +// - Emit: emit an event, with a given value. +// - Forward: forward to another service, in place of replying with a Response. +// - Effect: add a side effect to another service to the reply. +// - Fail: fail the current `Process` command. +// +type RequestAction struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Action: + // *RequestAction_Emit + // *RequestAction_Forward + // *RequestAction_Effect + // *RequestAction_Fail + Action isRequestAction_Action `protobuf_oneof:"action"` +} + +func (x *RequestAction) Reset() { + *x = RequestAction{} + if protoimpl.UnsafeEnabled { + mi := &file_eventsourced_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RequestAction) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RequestAction) ProtoMessage() {} + +func (x *RequestAction) ProtoReflect() protoreflect.Message { + mi := &file_eventsourced_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RequestAction.ProtoReflect.Descriptor instead. +func (*RequestAction) Descriptor() ([]byte, []int) { + return file_eventsourced_proto_rawDescGZIP(), []int{1} +} + +func (m *RequestAction) GetAction() isRequestAction_Action { + if m != nil { + return m.Action + } + return nil +} + +func (x *RequestAction) GetEmit() *Emit { + if x, ok := x.GetAction().(*RequestAction_Emit); ok { + return x.Emit + } + return nil +} + +func (x *RequestAction) GetForward() *Forward { + if x, ok := x.GetAction().(*RequestAction_Forward); ok { + return x.Forward + } + return nil +} + +func (x *RequestAction) GetEffect() *Effect { + if x, ok := x.GetAction().(*RequestAction_Effect); ok { + return x.Effect + } + return nil +} + +func (x *RequestAction) GetFail() *Fail { + if x, ok := x.GetAction().(*RequestAction_Fail); ok { + return x.Fail + } + return nil +} + +type isRequestAction_Action interface { + isRequestAction_Action() +} + +type RequestAction_Emit struct { + Emit *Emit `protobuf:"bytes,1,opt,name=emit,proto3,oneof"` +} + +type RequestAction_Forward struct { + Forward *Forward `protobuf:"bytes,2,opt,name=forward,proto3,oneof"` +} + +type RequestAction_Effect struct { + Effect *Effect `protobuf:"bytes,3,opt,name=effect,proto3,oneof"` +} + +type RequestAction_Fail struct { + Fail *Fail `protobuf:"bytes,4,opt,name=fail,proto3,oneof"` +} + +func (*RequestAction_Emit) isRequestAction_Action() {} + +func (*RequestAction_Forward) isRequestAction_Action() {} + +func (*RequestAction_Effect) isRequestAction_Action() {} + +func (*RequestAction_Fail) isRequestAction_Action() {} + +// +// Emit an event, with the event value in a `Persisted` message. +// +type Emit struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *Emit) Reset() { + *x = Emit{} + if protoimpl.UnsafeEnabled { + mi := &file_eventsourced_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Emit) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Emit) ProtoMessage() {} + +func (x *Emit) ProtoReflect() protoreflect.Message { + mi := &file_eventsourced_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Emit.ProtoReflect.Descriptor instead. +func (*Emit) Descriptor() ([]byte, []int) { + return file_eventsourced_proto_rawDescGZIP(), []int{2} +} + +func (x *Emit) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +// +// Replace the response with a forward to `cloudstate.tck.model.EventSourcedTwo/Call`. +// The payload must be a `Request` message with the given `id`. +// +type Forward struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` +} + +func (x *Forward) Reset() { + *x = Forward{} + if protoimpl.UnsafeEnabled { + mi := &file_eventsourced_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Forward) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Forward) ProtoMessage() {} + +func (x *Forward) ProtoReflect() protoreflect.Message { + mi := &file_eventsourced_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Forward.ProtoReflect.Descriptor instead. +func (*Forward) Descriptor() ([]byte, []int) { + return file_eventsourced_proto_rawDescGZIP(), []int{3} +} + +func (x *Forward) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +// +// Add a side effect to the reply, to `cloudstate.tck.model.EventSourcedTwo/Call`. +// The payload must be a `Request` message with the given `id`. +// The side effect should be marked synchronous based on the given `synchronous` value. +// +type Effect struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Synchronous bool `protobuf:"varint,2,opt,name=synchronous,proto3" json:"synchronous,omitempty"` +} + +func (x *Effect) Reset() { + *x = Effect{} + if protoimpl.UnsafeEnabled { + mi := &file_eventsourced_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Effect) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Effect) ProtoMessage() {} + +func (x *Effect) ProtoReflect() protoreflect.Message { + mi := &file_eventsourced_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Effect.ProtoReflect.Descriptor instead. +func (*Effect) Descriptor() ([]byte, []int) { + return file_eventsourced_proto_rawDescGZIP(), []int{4} +} + +func (x *Effect) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Effect) GetSynchronous() bool { + if x != nil { + return x.Synchronous + } + return false +} + +// +// Fail the current command with the given description `message`. +// +type Fail struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *Fail) Reset() { + *x = Fail{} + if protoimpl.UnsafeEnabled { + mi := &file_eventsourced_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Fail) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Fail) ProtoMessage() {} + +func (x *Fail) ProtoReflect() protoreflect.Message { + mi := &file_eventsourced_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Fail.ProtoReflect.Descriptor instead. +func (*Fail) Descriptor() ([]byte, []int) { + return file_eventsourced_proto_rawDescGZIP(), []int{5} +} + +func (x *Fail) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +// +// The `Response` message for the `Process` must contain the current state (after processing actions). +// +type Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Message string `protobuf:"bytes,1,opt,name=message,proto3" json:"message,omitempty"` +} + +func (x *Response) Reset() { + *x = Response{} + if protoimpl.UnsafeEnabled { + mi := &file_eventsourced_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Response) ProtoMessage() {} + +func (x *Response) ProtoReflect() protoreflect.Message { + mi := &file_eventsourced_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Response.ProtoReflect.Descriptor instead. +func (*Response) Descriptor() ([]byte, []int) { + return file_eventsourced_proto_rawDescGZIP(), []int{6} +} + +func (x *Response) GetMessage() string { + if x != nil { + return x.Message + } + return "" +} + +// +// The `Persisted` message wraps both snapshot and event values. +// +type Persisted struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *Persisted) Reset() { + *x = Persisted{} + if protoimpl.UnsafeEnabled { + mi := &file_eventsourced_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Persisted) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Persisted) ProtoMessage() {} + +func (x *Persisted) ProtoReflect() protoreflect.Message { + mi := &file_eventsourced_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Persisted.ProtoReflect.Descriptor instead. +func (*Persisted) Descriptor() ([]byte, []int) { + return file_eventsourced_proto_rawDescGZIP(), []int{7} +} + +func (x *Persisted) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +var File_eventsourced_proto protoreflect.FileDescriptor + +var file_eventsourced_proto_rawDesc = []byte{ + 0x0a, 0x12, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x2e, 0x74, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x1a, 0x1b, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x6b, 0x65, + 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5e, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x14, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x04, + 0x90, 0xb5, 0x18, 0x01, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3d, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x74, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, + 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x07, + 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xf0, 0x01, 0x0a, 0x0d, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x04, 0x65, 0x6d, 0x69, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x2e, 0x74, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x45, + 0x6d, 0x69, 0x74, 0x48, 0x00, 0x52, 0x04, 0x65, 0x6d, 0x69, 0x74, 0x12, 0x39, 0x0a, 0x07, 0x66, + 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x74, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x2e, 0x46, 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x48, 0x00, 0x52, 0x07, 0x66, + 0x6f, 0x72, 0x77, 0x61, 0x72, 0x64, 0x12, 0x36, 0x0a, 0x06, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x74, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x45, 0x66, + 0x66, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x06, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x12, 0x30, + 0x0a, 0x04, 0x66, 0x61, 0x69, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x74, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x48, 0x00, 0x52, 0x04, 0x66, 0x61, 0x69, 0x6c, + 0x42, 0x08, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1c, 0x0a, 0x04, 0x45, 0x6d, + 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x19, 0x0a, 0x07, 0x46, 0x6f, 0x72, 0x77, + 0x61, 0x72, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x22, 0x3a, 0x0a, 0x06, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x12, 0x0e, 0x0a, + 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x20, 0x0a, + 0x0b, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x6f, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0b, 0x73, 0x79, 0x6e, 0x63, 0x68, 0x72, 0x6f, 0x6e, 0x6f, 0x75, 0x73, 0x22, + 0x20, 0x0a, 0x04, 0x46, 0x61, 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x22, 0x24, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x21, 0x0a, 0x09, 0x50, 0x65, 0x72, 0x73, 0x69, + 0x73, 0x74, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x32, 0x60, 0x0a, 0x14, 0x45, 0x76, + 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x54, 0x63, 0x6b, 0x4d, 0x6f, 0x64, + 0x65, 0x6c, 0x12, 0x48, 0x0a, 0x07, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x12, 0x1d, 0x2e, + 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x74, 0x63, 0x6b, 0x2e, 0x6d, + 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x74, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x58, 0x0a, 0x0f, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x54, 0x77, 0x6f, 0x12, + 0x45, 0x0a, 0x04, 0x43, 0x61, 0x6c, 0x6c, 0x12, 0x1d, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x2e, 0x74, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, 0x2e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x73, 0x74, + 0x61, 0x74, 0x65, 0x2e, 0x74, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x5b, 0x0a, 0x17, 0x69, 0x6f, 0x2e, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x74, 0x63, 0x6b, 0x2e, 0x6d, 0x6f, 0x64, 0x65, + 0x6c, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x73, 0x74, 0x61, 0x74, 0x65, 0x69, 0x6f, 0x2f, 0x67, 0x6f, 0x2d, 0x73, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x2f, 0x74, 0x63, 0x6b, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x64, 0x3b, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_eventsourced_proto_rawDescOnce sync.Once + file_eventsourced_proto_rawDescData = file_eventsourced_proto_rawDesc +) + +func file_eventsourced_proto_rawDescGZIP() []byte { + file_eventsourced_proto_rawDescOnce.Do(func() { + file_eventsourced_proto_rawDescData = protoimpl.X.CompressGZIP(file_eventsourced_proto_rawDescData) + }) + return file_eventsourced_proto_rawDescData +} + +var file_eventsourced_proto_msgTypes = make([]protoimpl.MessageInfo, 8) +var file_eventsourced_proto_goTypes = []interface{}{ + (*Request)(nil), // 0: cloudstate.tck.model.Request + (*RequestAction)(nil), // 1: cloudstate.tck.model.RequestAction + (*Emit)(nil), // 2: cloudstate.tck.model.Emit + (*Forward)(nil), // 3: cloudstate.tck.model.Forward + (*Effect)(nil), // 4: cloudstate.tck.model.Effect + (*Fail)(nil), // 5: cloudstate.tck.model.Fail + (*Response)(nil), // 6: cloudstate.tck.model.Response + (*Persisted)(nil), // 7: cloudstate.tck.model.Persisted +} +var file_eventsourced_proto_depIdxs = []int32{ + 1, // 0: cloudstate.tck.model.Request.actions:type_name -> cloudstate.tck.model.RequestAction + 2, // 1: cloudstate.tck.model.RequestAction.emit:type_name -> cloudstate.tck.model.Emit + 3, // 2: cloudstate.tck.model.RequestAction.forward:type_name -> cloudstate.tck.model.Forward + 4, // 3: cloudstate.tck.model.RequestAction.effect:type_name -> cloudstate.tck.model.Effect + 5, // 4: cloudstate.tck.model.RequestAction.fail:type_name -> cloudstate.tck.model.Fail + 0, // 5: cloudstate.tck.model.EventSourcedTckModel.Process:input_type -> cloudstate.tck.model.Request + 0, // 6: cloudstate.tck.model.EventSourcedTwo.Call:input_type -> cloudstate.tck.model.Request + 6, // 7: cloudstate.tck.model.EventSourcedTckModel.Process:output_type -> cloudstate.tck.model.Response + 6, // 8: cloudstate.tck.model.EventSourcedTwo.Call:output_type -> cloudstate.tck.model.Response + 7, // [7:9] is the sub-list for method output_type + 5, // [5:7] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name +} + +func init() { file_eventsourced_proto_init() } +func file_eventsourced_proto_init() { + if File_eventsourced_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_eventsourced_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventsourced_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RequestAction); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventsourced_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Emit); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventsourced_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Forward); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventsourced_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Effect); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventsourced_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Fail); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventsourced_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Response); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_eventsourced_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Persisted); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_eventsourced_proto_msgTypes[1].OneofWrappers = []interface{}{ + (*RequestAction_Emit)(nil), + (*RequestAction_Forward)(nil), + (*RequestAction_Effect)(nil), + (*RequestAction_Fail)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_eventsourced_proto_rawDesc, + NumEnums: 0, + NumMessages: 8, + NumExtensions: 0, + NumServices: 2, + }, + GoTypes: file_eventsourced_proto_goTypes, + DependencyIndexes: file_eventsourced_proto_depIdxs, + MessageInfos: file_eventsourced_proto_msgTypes, + }.Build() + File_eventsourced_proto = out.File + file_eventsourced_proto_rawDesc = nil + file_eventsourced_proto_goTypes = nil + file_eventsourced_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// EventSourcedTckModelClient is the client API for EventSourcedTckModel service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type EventSourcedTckModelClient interface { + Process(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) +} + +type eventSourcedTckModelClient struct { + cc grpc.ClientConnInterface +} + +func NewEventSourcedTckModelClient(cc grpc.ClientConnInterface) EventSourcedTckModelClient { + return &eventSourcedTckModelClient{cc} +} + +func (c *eventSourcedTckModelClient) Process(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/cloudstate.tck.model.EventSourcedTckModel/Process", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// EventSourcedTckModelServer is the server API for EventSourcedTckModel service. +type EventSourcedTckModelServer interface { + Process(context.Context, *Request) (*Response, error) +} + +// UnimplementedEventSourcedTckModelServer can be embedded to have forward compatible implementations. +type UnimplementedEventSourcedTckModelServer struct { +} + +func (*UnimplementedEventSourcedTckModelServer) Process(context.Context, *Request) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method Process not implemented") +} + +func RegisterEventSourcedTckModelServer(s *grpc.Server, srv EventSourcedTckModelServer) { + s.RegisterService(&_EventSourcedTckModel_serviceDesc, srv) +} + +func _EventSourcedTckModel_Process_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EventSourcedTckModelServer).Process(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cloudstate.tck.model.EventSourcedTckModel/Process", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EventSourcedTckModelServer).Process(ctx, req.(*Request)) + } + return interceptor(ctx, in, info, handler) +} + +var _EventSourcedTckModel_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cloudstate.tck.model.EventSourcedTckModel", + HandlerType: (*EventSourcedTckModelServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Process", + Handler: _EventSourcedTckModel_Process_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "eventsourced.proto", +} + +// EventSourcedTwoClient is the client API for EventSourcedTwo service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type EventSourcedTwoClient interface { + Call(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) +} + +type eventSourcedTwoClient struct { + cc grpc.ClientConnInterface +} + +func NewEventSourcedTwoClient(cc grpc.ClientConnInterface) EventSourcedTwoClient { + return &eventSourcedTwoClient{cc} +} + +func (c *eventSourcedTwoClient) Call(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { + out := new(Response) + err := c.cc.Invoke(ctx, "/cloudstate.tck.model.EventSourcedTwo/Call", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// EventSourcedTwoServer is the server API for EventSourcedTwo service. +type EventSourcedTwoServer interface { + Call(context.Context, *Request) (*Response, error) +} + +// UnimplementedEventSourcedTwoServer can be embedded to have forward compatible implementations. +type UnimplementedEventSourcedTwoServer struct { +} + +func (*UnimplementedEventSourcedTwoServer) Call(context.Context, *Request) (*Response, error) { + return nil, status.Errorf(codes.Unimplemented, "method Call not implemented") +} + +func RegisterEventSourcedTwoServer(s *grpc.Server, srv EventSourcedTwoServer) { + s.RegisterService(&_EventSourcedTwo_serviceDesc, srv) +} + +func _EventSourcedTwo_Call_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Request) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(EventSourcedTwoServer).Call(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/cloudstate.tck.model.EventSourcedTwo/Call", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(EventSourcedTwoServer).Call(ctx, req.(*Request)) + } + return interceptor(ctx, in, info, handler) +} + +var _EventSourcedTwo_serviceDesc = grpc.ServiceDesc{ + ServiceName: "cloudstate.tck.model.EventSourcedTwo", + HandlerType: (*EventSourcedTwoServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "Call", + Handler: _EventSourcedTwo_Call_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "eventsourced.proto", +} diff --git a/tck/eventsourced/model.go b/tck/eventsourced/model.go new file mode 100644 index 0000000..8dc5d96 --- /dev/null +++ b/tck/eventsourced/model.go @@ -0,0 +1,111 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package eventsourced + +import ( + "errors" + "fmt" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/eventsourced" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/golang/protobuf/proto" +) + +type TestModel struct { + state string +} + +func NewTestModel(id eventsourced.EntityID) eventsourced.EntityHandler { + return &TestModel{} +} + +func (m *TestModel) HandleCommand(ctx *eventsourced.Context, name string, cmd proto.Message) (reply proto.Message, err error) { + switch c := cmd.(type) { + case *Request: + for _, action := range c.GetActions() { + switch a := action.GetAction().(type) { + case *RequestAction_Emit: + ctx.Emit(&Persisted{Value: a.Emit.GetValue()}) + case *RequestAction_Forward: + req, err := encoding.MarshalAny(&Request{Id: a.Forward.Id}) + if err != nil { + return nil, err + } + ctx.Forward(&protocol.Forward{ + ServiceName: "cloudstate.tck.model.EventSourcedTwo", + CommandName: "Call", + Payload: req, + }) + case *RequestAction_Effect: + req, err := encoding.MarshalAny(&Request{Id: a.Effect.Id}) + if err != nil { + return nil, err + } + ctx.Effect(&protocol.SideEffect{ + ServiceName: "cloudstate.tck.model.EventSourcedTwo", + CommandName: "Call", + Payload: req, + Synchronous: a.Effect.Synchronous, + }) + case *RequestAction_Fail: + return nil, errors.New(a.Fail.GetMessage()) + } + } + } + return &Response{Message: m.state}, nil +} + +func (m *TestModel) HandleEvent(ctx *eventsourced.Context, event interface{}) error { + switch c := event.(type) { + case *Persisted: + m.state += c.GetValue() + return nil + } + return errors.New("event not handled") +} + +func (m *TestModel) Snapshot(ctx *eventsourced.Context) (snapshot interface{}, err error) { + return &Persisted{Value: m.state}, nil +} + +func (m *TestModel) HandleSnapshot(ctx *eventsourced.Context, snapshot interface{}) error { + switch s := snapshot.(type) { + case *Persisted: + m.state = s.GetValue() + return nil + } + return errors.New("snapshot not handled") +} + +type TestModelTwo struct { +} + +func (m *TestModelTwo) HandleCommand(ctx *eventsourced.Context, name string, cmd proto.Message) (reply proto.Message, err error) { + switch cmd.(type) { + case *Request: + return &Response{}, nil + } + return nil, fmt.Errorf("unhandled command: %q", name) +} + +func (m *TestModelTwo) HandleEvent(ctx *eventsourced.Context, event interface{}) error { + return nil +} + +func NewTestModelTwo(id eventsourced.EntityID) eventsourced.EntityHandler { + return &TestModelTwo{} +} diff --git a/tck/run_dev_proxy.sh b/tck/run_dev_proxy.sh new file mode 100755 index 0000000..62d38e4 --- /dev/null +++ b/tck/run_dev_proxy.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -o nounset + +function rnd() { + cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w ${1:-32} | head -n 1 +} + +PROXY_IMAGE=${2:-cloudstateio/cloudstate-proxy-dev-mode:latest} +PROXY="cloudstate-proxy-$(rnd)" + +set -x +# run the proxy +docker run --rm --name "$PROXY" -p 9000:9000 -e USER_FUNCTION_HOST=host.docker.internal -e USER_FUNCTION_PORT=8090 \ + "${PROXY_IMAGE}" -Dcloudstate.proxy.passivation-timeout=30s || exit $? +tck_status=$? + +exit $tck_status diff --git a/tck/run_dev_proxy_tck.sh b/tck/run_dev_proxy_tck.sh new file mode 100755 index 0000000..aab0b0f --- /dev/null +++ b/tck/run_dev_proxy_tck.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +set -o nounset + +function rnd() { + cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w ${1:-32} | head -n 1 +} + +PROXY_IMAGE=${2:-cloudstateio/cloudstate-proxy-dev-mode:latest} +PROXY="cloudstate-proxy-$(rnd)" +TCK_IMAGE=${3:-cloudstateio/cloudstate-tck:latest} +TCK="cloudstate-tck-$(rnd)" + +finally() { + docker rm -f "$PROXY" +} +trap finally EXIT +set -x + +docker run -d --name "$PROXY" -p 9000:9000 -e USER_FUNCTION_HOST=host.docker.internal -e USER_FUNCTION_PORT=8090 "${PROXY_IMAGE}" || exit $? +docker run --rm --name cloudstate-tck -p 8090:8090 -e TCK_HOST=0.0.0.0 -e TCK_PROXY_HOST=host.docker.internal -e TCK_SERVICE_HOST=host.docker.internal "${TCK_IMAGE}" +tck_status=$? + +exit $tck_status diff --git a/tck/run_tck.sh b/tck/run_tck.sh new file mode 100755 index 0000000..273e8eb --- /dev/null +++ b/tck/run_tck.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +set -o nounset + +function rnd() { + cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w ${1:-32} | head -n 1 +} + +FUNC_IMAGE=${1:-cloudstateio/cloudstate-go-tck:latest} +FUNC="cloudstate-function-$(rnd)" +PROXY_IMAGE=${2:-cloudstateio/cloudstate-proxy-dev-mode:latest} +PROXY="cloudstate-proxy-$(rnd)" +TCK_IMAGE=${3:-cloudstateio/cloudstate-tck:latest} +TCK="cloudstate-tck-$(rnd)" + +finally() { + docker rm -f "$PROXY" + docker rm -f "$FUNC" +} +trap finally EXIT +set -x + +# run the function and the proxy +docker run -d --name "$FUNC" --net=host "${FUNC_IMAGE}" || exit $? +docker run -d --name "$PROXY" --net=host -e USER_FUNCTION_PORT=8090 "${PROXY_IMAGE}" || exit $? + +# run the tck +docker run --rm --name $TCK --net=host "${TCK_IMAGE}" +tck_status=$? +if [ "$tck_status" -ne "0" ]; then + docker logs cloudstate-function +fi +exit $tck_status diff --git a/tck/shoppingcart/persistence/domain.pb.go b/tck/shoppingcart/persistence/domain.pb.go deleted file mode 100644 index a689beb..0000000 --- a/tck/shoppingcart/persistence/domain.pb.go +++ /dev/null @@ -1,223 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: domain.proto - -package persistence - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -type LineItem struct { - ProductId string `protobuf:"bytes,1,opt,name=productId,proto3" json:"productId,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Quantity int32 `protobuf:"varint,3,opt,name=quantity,proto3" json:"quantity,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *LineItem) Reset() { *m = LineItem{} } -func (m *LineItem) String() string { return proto.CompactTextString(m) } -func (*LineItem) ProtoMessage() {} -func (*LineItem) Descriptor() ([]byte, []int) { - return fileDescriptor_73e6234e76dbdb84, []int{0} -} - -func (m *LineItem) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_LineItem.Unmarshal(m, b) -} -func (m *LineItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_LineItem.Marshal(b, m, deterministic) -} -func (m *LineItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_LineItem.Merge(m, src) -} -func (m *LineItem) XXX_Size() int { - return xxx_messageInfo_LineItem.Size(m) -} -func (m *LineItem) XXX_DiscardUnknown() { - xxx_messageInfo_LineItem.DiscardUnknown(m) -} - -var xxx_messageInfo_LineItem proto.InternalMessageInfo - -func (m *LineItem) GetProductId() string { - if m != nil { - return m.ProductId - } - return "" -} - -func (m *LineItem) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *LineItem) GetQuantity() int32 { - if m != nil { - return m.Quantity - } - return 0 -} - -// The item added event. -type ItemAdded struct { - Item *LineItem `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ItemAdded) Reset() { *m = ItemAdded{} } -func (m *ItemAdded) String() string { return proto.CompactTextString(m) } -func (*ItemAdded) ProtoMessage() {} -func (*ItemAdded) Descriptor() ([]byte, []int) { - return fileDescriptor_73e6234e76dbdb84, []int{1} -} - -func (m *ItemAdded) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ItemAdded.Unmarshal(m, b) -} -func (m *ItemAdded) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ItemAdded.Marshal(b, m, deterministic) -} -func (m *ItemAdded) XXX_Merge(src proto.Message) { - xxx_messageInfo_ItemAdded.Merge(m, src) -} -func (m *ItemAdded) XXX_Size() int { - return xxx_messageInfo_ItemAdded.Size(m) -} -func (m *ItemAdded) XXX_DiscardUnknown() { - xxx_messageInfo_ItemAdded.DiscardUnknown(m) -} - -var xxx_messageInfo_ItemAdded proto.InternalMessageInfo - -func (m *ItemAdded) GetItem() *LineItem { - if m != nil { - return m.Item - } - return nil -} - -// The item removed event. -type ItemRemoved struct { - ProductId string `protobuf:"bytes,1,opt,name=productId,proto3" json:"productId,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ItemRemoved) Reset() { *m = ItemRemoved{} } -func (m *ItemRemoved) String() string { return proto.CompactTextString(m) } -func (*ItemRemoved) ProtoMessage() {} -func (*ItemRemoved) Descriptor() ([]byte, []int) { - return fileDescriptor_73e6234e76dbdb84, []int{2} -} - -func (m *ItemRemoved) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ItemRemoved.Unmarshal(m, b) -} -func (m *ItemRemoved) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ItemRemoved.Marshal(b, m, deterministic) -} -func (m *ItemRemoved) XXX_Merge(src proto.Message) { - xxx_messageInfo_ItemRemoved.Merge(m, src) -} -func (m *ItemRemoved) XXX_Size() int { - return xxx_messageInfo_ItemRemoved.Size(m) -} -func (m *ItemRemoved) XXX_DiscardUnknown() { - xxx_messageInfo_ItemRemoved.DiscardUnknown(m) -} - -var xxx_messageInfo_ItemRemoved proto.InternalMessageInfo - -func (m *ItemRemoved) GetProductId() string { - if m != nil { - return m.ProductId - } - return "" -} - -// The shopping cart state. -type Cart struct { - Items []*LineItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Cart) Reset() { *m = Cart{} } -func (m *Cart) String() string { return proto.CompactTextString(m) } -func (*Cart) ProtoMessage() {} -func (*Cart) Descriptor() ([]byte, []int) { - return fileDescriptor_73e6234e76dbdb84, []int{3} -} - -func (m *Cart) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Cart.Unmarshal(m, b) -} -func (m *Cart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Cart.Marshal(b, m, deterministic) -} -func (m *Cart) XXX_Merge(src proto.Message) { - xxx_messageInfo_Cart.Merge(m, src) -} -func (m *Cart) XXX_Size() int { - return xxx_messageInfo_Cart.Size(m) -} -func (m *Cart) XXX_DiscardUnknown() { - xxx_messageInfo_Cart.DiscardUnknown(m) -} - -var xxx_messageInfo_Cart proto.InternalMessageInfo - -func (m *Cart) GetItems() []*LineItem { - if m != nil { - return m.Items - } - return nil -} - -func init() { - proto.RegisterType((*LineItem)(nil), "com.example.shoppingcart.persistence.LineItem") - proto.RegisterType((*ItemAdded)(nil), "com.example.shoppingcart.persistence.ItemAdded") - proto.RegisterType((*ItemRemoved)(nil), "com.example.shoppingcart.persistence.ItemRemoved") - proto.RegisterType((*Cart)(nil), "com.example.shoppingcart.persistence.Cart") -} - -func init() { proto.RegisterFile("domain.proto", fileDescriptor_73e6234e76dbdb84) } - -var fileDescriptor_73e6234e76dbdb84 = []byte{ - // 223 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x90, 0x3f, 0x4b, 0x04, 0x31, - 0x10, 0xc5, 0x89, 0xb7, 0x27, 0xb7, 0xb3, 0xda, 0xa4, 0x0a, 0x62, 0xb1, 0x04, 0x8b, 0x03, 0x21, - 0x85, 0x7e, 0x02, 0x4f, 0x9b, 0x85, 0x05, 0x61, 0x2b, 0xb1, 0x8b, 0xc9, 0xa0, 0x01, 0xf3, 0xc7, - 0x64, 0x56, 0xf4, 0xdb, 0xcb, 0x46, 0xfc, 0x53, 0x89, 0x5c, 0x37, 0x6f, 0x1e, 0xef, 0xcd, 0x8f, - 0x81, 0x23, 0x1b, 0xbd, 0x76, 0x41, 0xa5, 0x1c, 0x29, 0xf2, 0x33, 0x13, 0xbd, 0xc2, 0x37, 0xed, - 0xd3, 0x33, 0xaa, 0xf2, 0x14, 0x53, 0x72, 0xe1, 0xd1, 0xe8, 0x4c, 0x2a, 0x61, 0x2e, 0xae, 0x10, - 0x06, 0x83, 0xf2, 0x0e, 0x36, 0xa3, 0x0b, 0x38, 0x10, 0x7a, 0x7e, 0x0a, 0x6d, 0xca, 0xd1, 0xce, - 0x86, 0x06, 0x2b, 0x58, 0xcf, 0xb6, 0xed, 0xf4, 0xb3, 0xe0, 0x1c, 0x9a, 0xa0, 0x3d, 0x8a, 0x83, - 0x6a, 0xd4, 0x99, 0x9f, 0xc0, 0xe6, 0x65, 0xd6, 0x81, 0x1c, 0xbd, 0x8b, 0x55, 0xcf, 0xb6, 0xeb, - 0xe9, 0x5b, 0xcb, 0x5b, 0x68, 0x97, 0xd6, 0x2b, 0x6b, 0xd1, 0xf2, 0x1d, 0x34, 0x8e, 0xd0, 0xd7, - 0xd6, 0xee, 0x42, 0xa9, 0xff, 0xb0, 0xa9, 0x2f, 0xb0, 0xa9, 0x66, 0xe5, 0x39, 0x74, 0x55, 0xa1, - 0x8f, 0xaf, 0x68, 0xff, 0xa6, 0x95, 0x23, 0x34, 0xd7, 0x3a, 0x13, 0xbf, 0x81, 0xf5, 0x12, 0x2e, - 0x82, 0xf5, 0xab, 0x3d, 0x2e, 0x7f, 0x86, 0x77, 0xc7, 0xf7, 0xdd, 0x2f, 0xfb, 0xe1, 0xb0, 0x7e, - 0xf8, 0xf2, 0x23, 0x00, 0x00, 0xff, 0xff, 0xc7, 0xe9, 0xbb, 0x2b, 0x71, 0x01, 0x00, 0x00, -} diff --git a/tck/shoppingcart/shoppingcart.pb.go b/tck/shoppingcart/shoppingcart.pb.go deleted file mode 100644 index 1e4037d..0000000 --- a/tck/shoppingcart/shoppingcart.pb.go +++ /dev/null @@ -1,466 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: shoppingcart/shoppingcart.proto - -package shoppingcart - -import ( - context "context" - fmt "fmt" - _ "github.com/cloudstateio/go-support/cloudstate/protocol" - proto "github.com/golang/protobuf/proto" - empty "github.com/golang/protobuf/ptypes/empty" - _ "google.golang.org/genproto/googleapis/api/annotations" - grpc "google.golang.org/grpc" - codes "google.golang.org/grpc/codes" - status "google.golang.org/grpc/status" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -type AddLineItem struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - ProductId string `protobuf:"bytes,2,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` - Name string `protobuf:"bytes,3,opt,name=name,proto3" json:"name,omitempty"` - Quantity int32 `protobuf:"varint,4,opt,name=quantity,proto3" json:"quantity,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *AddLineItem) Reset() { *m = AddLineItem{} } -func (m *AddLineItem) String() string { return proto.CompactTextString(m) } -func (*AddLineItem) ProtoMessage() {} -func (*AddLineItem) Descriptor() ([]byte, []int) { - return fileDescriptor_230c614558c2d7f8, []int{0} -} - -func (m *AddLineItem) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_AddLineItem.Unmarshal(m, b) -} -func (m *AddLineItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_AddLineItem.Marshal(b, m, deterministic) -} -func (m *AddLineItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_AddLineItem.Merge(m, src) -} -func (m *AddLineItem) XXX_Size() int { - return xxx_messageInfo_AddLineItem.Size(m) -} -func (m *AddLineItem) XXX_DiscardUnknown() { - xxx_messageInfo_AddLineItem.DiscardUnknown(m) -} - -var xxx_messageInfo_AddLineItem proto.InternalMessageInfo - -func (m *AddLineItem) GetUserId() string { - if m != nil { - return m.UserId - } - return "" -} - -func (m *AddLineItem) GetProductId() string { - if m != nil { - return m.ProductId - } - return "" -} - -func (m *AddLineItem) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *AddLineItem) GetQuantity() int32 { - if m != nil { - return m.Quantity - } - return 0 -} - -type RemoveLineItem struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - ProductId string `protobuf:"bytes,2,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *RemoveLineItem) Reset() { *m = RemoveLineItem{} } -func (m *RemoveLineItem) String() string { return proto.CompactTextString(m) } -func (*RemoveLineItem) ProtoMessage() {} -func (*RemoveLineItem) Descriptor() ([]byte, []int) { - return fileDescriptor_230c614558c2d7f8, []int{1} -} - -func (m *RemoveLineItem) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_RemoveLineItem.Unmarshal(m, b) -} -func (m *RemoveLineItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_RemoveLineItem.Marshal(b, m, deterministic) -} -func (m *RemoveLineItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_RemoveLineItem.Merge(m, src) -} -func (m *RemoveLineItem) XXX_Size() int { - return xxx_messageInfo_RemoveLineItem.Size(m) -} -func (m *RemoveLineItem) XXX_DiscardUnknown() { - xxx_messageInfo_RemoveLineItem.DiscardUnknown(m) -} - -var xxx_messageInfo_RemoveLineItem proto.InternalMessageInfo - -func (m *RemoveLineItem) GetUserId() string { - if m != nil { - return m.UserId - } - return "" -} - -func (m *RemoveLineItem) GetProductId() string { - if m != nil { - return m.ProductId - } - return "" -} - -type GetShoppingCart struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetShoppingCart) Reset() { *m = GetShoppingCart{} } -func (m *GetShoppingCart) String() string { return proto.CompactTextString(m) } -func (*GetShoppingCart) ProtoMessage() {} -func (*GetShoppingCart) Descriptor() ([]byte, []int) { - return fileDescriptor_230c614558c2d7f8, []int{2} -} - -func (m *GetShoppingCart) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetShoppingCart.Unmarshal(m, b) -} -func (m *GetShoppingCart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetShoppingCart.Marshal(b, m, deterministic) -} -func (m *GetShoppingCart) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetShoppingCart.Merge(m, src) -} -func (m *GetShoppingCart) XXX_Size() int { - return xxx_messageInfo_GetShoppingCart.Size(m) -} -func (m *GetShoppingCart) XXX_DiscardUnknown() { - xxx_messageInfo_GetShoppingCart.DiscardUnknown(m) -} - -var xxx_messageInfo_GetShoppingCart proto.InternalMessageInfo - -func (m *GetShoppingCart) GetUserId() string { - if m != nil { - return m.UserId - } - return "" -} - -type LineItem struct { - ProductId string `protobuf:"bytes,1,opt,name=product_id,json=productId,proto3" json:"product_id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - Quantity int32 `protobuf:"varint,3,opt,name=quantity,proto3" json:"quantity,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *LineItem) Reset() { *m = LineItem{} } -func (m *LineItem) String() string { return proto.CompactTextString(m) } -func (*LineItem) ProtoMessage() {} -func (*LineItem) Descriptor() ([]byte, []int) { - return fileDescriptor_230c614558c2d7f8, []int{3} -} - -func (m *LineItem) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_LineItem.Unmarshal(m, b) -} -func (m *LineItem) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_LineItem.Marshal(b, m, deterministic) -} -func (m *LineItem) XXX_Merge(src proto.Message) { - xxx_messageInfo_LineItem.Merge(m, src) -} -func (m *LineItem) XXX_Size() int { - return xxx_messageInfo_LineItem.Size(m) -} -func (m *LineItem) XXX_DiscardUnknown() { - xxx_messageInfo_LineItem.DiscardUnknown(m) -} - -var xxx_messageInfo_LineItem proto.InternalMessageInfo - -func (m *LineItem) GetProductId() string { - if m != nil { - return m.ProductId - } - return "" -} - -func (m *LineItem) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *LineItem) GetQuantity() int32 { - if m != nil { - return m.Quantity - } - return 0 -} - -type Cart struct { - Items []*LineItem `protobuf:"bytes,1,rep,name=items,proto3" json:"items,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Cart) Reset() { *m = Cart{} } -func (m *Cart) String() string { return proto.CompactTextString(m) } -func (*Cart) ProtoMessage() {} -func (*Cart) Descriptor() ([]byte, []int) { - return fileDescriptor_230c614558c2d7f8, []int{4} -} - -func (m *Cart) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Cart.Unmarshal(m, b) -} -func (m *Cart) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Cart.Marshal(b, m, deterministic) -} -func (m *Cart) XXX_Merge(src proto.Message) { - xxx_messageInfo_Cart.Merge(m, src) -} -func (m *Cart) XXX_Size() int { - return xxx_messageInfo_Cart.Size(m) -} -func (m *Cart) XXX_DiscardUnknown() { - xxx_messageInfo_Cart.DiscardUnknown(m) -} - -var xxx_messageInfo_Cart proto.InternalMessageInfo - -func (m *Cart) GetItems() []*LineItem { - if m != nil { - return m.Items - } - return nil -} - -func init() { - proto.RegisterType((*AddLineItem)(nil), "com.example.shoppingcart.AddLineItem") - proto.RegisterType((*RemoveLineItem)(nil), "com.example.shoppingcart.RemoveLineItem") - proto.RegisterType((*GetShoppingCart)(nil), "com.example.shoppingcart.GetShoppingCart") - proto.RegisterType((*LineItem)(nil), "com.example.shoppingcart.LineItem") - proto.RegisterType((*Cart)(nil), "com.example.shoppingcart.Cart") -} - -func init() { proto.RegisterFile("shoppingcart/shoppingcart.proto", fileDescriptor_230c614558c2d7f8) } - -var fileDescriptor_230c614558c2d7f8 = []byte{ - // 461 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0xc1, 0x6e, 0xd3, 0x40, - 0x10, 0xd5, 0x26, 0x69, 0xd3, 0x4e, 0x11, 0x54, 0x2b, 0x51, 0x19, 0x97, 0xb6, 0xd1, 0x0a, 0xa4, - 0x14, 0x24, 0x2f, 0xb4, 0x17, 0xe0, 0x44, 0x8b, 0x50, 0x15, 0x09, 0x71, 0x30, 0x27, 0x7a, 0xa9, - 0x36, 0xde, 0x21, 0xb5, 0x1a, 0x7b, 0x8d, 0x3d, 0x46, 0x54, 0x51, 0x0f, 0xf0, 0x03, 0x20, 0xc1, - 0xaf, 0xf0, 0x25, 0xfc, 0x02, 0x1f, 0x82, 0xbc, 0x76, 0xa8, 0x13, 0xb1, 0xe2, 0xc2, 0xcd, 0x3b, - 0x6f, 0x76, 0xde, 0x7b, 0xfb, 0xc6, 0xb0, 0x57, 0x9c, 0x9b, 0x2c, 0x8b, 0xd3, 0x49, 0xa4, 0x72, - 0x92, 0xed, 0x43, 0x90, 0xe5, 0x86, 0x0c, 0xf7, 0x22, 0x93, 0x04, 0xf8, 0x51, 0x25, 0xd9, 0x14, - 0x83, 0x36, 0xee, 0x6f, 0x4f, 0x8c, 0x99, 0x4c, 0x51, 0xda, 0xbe, 0x71, 0xf9, 0x4e, 0x62, 0x92, - 0xd1, 0x65, 0x7d, 0xcd, 0xdf, 0x8e, 0xa6, 0xa6, 0xd4, 0x05, 0x29, 0x42, 0x89, 0x29, 0xc5, 0x74, - 0x79, 0x76, 0x81, 0x73, 0xf0, 0x6e, 0x73, 0x53, 0x65, 0xb1, 0x54, 0x69, 0x6a, 0x48, 0x51, 0x6c, - 0xd2, 0xa2, 0x41, 0x6f, 0xb7, 0xd0, 0x73, 0xa2, 0xac, 0x2e, 0x8b, 0x19, 0x6c, 0x1c, 0x69, 0xfd, - 0x2a, 0x4e, 0x71, 0x44, 0x98, 0xf0, 0x1d, 0xe8, 0x97, 0x05, 0xe6, 0x67, 0xb1, 0xf6, 0xd8, 0x80, - 0x0d, 0xd7, 0x8f, 0x7b, 0x5f, 0x7f, 0x78, 0x2c, 0x5c, 0xad, 0x8a, 0x23, 0xcd, 0x77, 0x00, 0xb2, - 0xdc, 0xe8, 0x32, 0xa2, 0xaa, 0xa3, 0x53, 0x75, 0x84, 0xeb, 0x4d, 0x65, 0xa4, 0x39, 0x87, 0x5e, - 0xaa, 0x12, 0xf4, 0xba, 0x16, 0xb0, 0xdf, 0xdc, 0x87, 0xb5, 0xf7, 0xa5, 0xb2, 0x5a, 0xbd, 0xde, - 0x80, 0x0d, 0x57, 0xc2, 0x3f, 0x67, 0xf1, 0x1a, 0x6e, 0x86, 0x98, 0x98, 0x0f, 0xf8, 0x7f, 0xf8, - 0xc5, 0x23, 0xb8, 0x75, 0x82, 0xf4, 0xa6, 0x79, 0xce, 0x17, 0x2a, 0xa7, 0x7f, 0x0c, 0x14, 0x6f, - 0x61, 0xad, 0xc5, 0xdd, 0x1e, 0xce, 0x5c, 0xe6, 0x3a, 0x0e, 0x73, 0xdd, 0x25, 0x73, 0xcf, 0xa1, - 0x67, 0x15, 0x3c, 0x81, 0x95, 0x98, 0x30, 0x29, 0x3c, 0x36, 0xe8, 0x0e, 0x37, 0x0e, 0x44, 0xe0, - 0x8a, 0x3e, 0x98, 0x2b, 0x09, 0xeb, 0x0b, 0x07, 0xdf, 0xbb, 0x70, 0x63, 0xc1, 0x4c, 0x0a, 0xfd, - 0x23, 0xad, 0xad, 0xd8, 0xfb, 0xee, 0x31, 0xad, 0x3c, 0xfd, 0xad, 0xa0, 0x8e, 0x3d, 0x98, 0xaf, - 0x53, 0xf0, 0xb2, 0x5a, 0x27, 0x71, 0xef, 0xf3, 0xcf, 0x5f, 0xdf, 0x3a, 0xbb, 0xe2, 0x8e, 0xb4, - 0x1b, 0x3a, 0x6b, 0xde, 0xe8, 0x4a, 0x5a, 0x66, 0xa9, 0xb4, 0x7e, 0xc6, 0x1e, 0xf0, 0x4f, 0x0c, - 0xa0, 0x0e, 0xc8, 0x72, 0x0e, 0xdd, 0x9c, 0x8b, 0x31, 0x3a, 0x69, 0x1f, 0x5b, 0xda, 0x87, 0x62, - 0xff, 0xef, 0xb4, 0xb3, 0xeb, 0xf7, 0xbf, 0x92, 0xb9, 0x1d, 0xc9, 0xbf, 0x30, 0xe8, 0x9f, 0x20, - 0x59, 0xff, 0xfb, 0x6e, 0x01, 0x4b, 0xb9, 0xfb, 0xbb, 0xee, 0xd6, 0x0a, 0x17, 0x4f, 0xad, 0x92, - 0x43, 0xbe, 0x69, 0x95, 0x14, 0xd7, 0x52, 0x4e, 0xf7, 0xf8, 0xd6, 0x72, 0xad, 0x96, 0x37, 0xae, - 0x63, 0x39, 0xe6, 0xa7, 0x9b, 0x14, 0x5d, 0x2c, 0xfc, 0xd5, 0xe3, 0x55, 0x6b, 0xf4, 0xf0, 0x77, - 0x00, 0x00, 0x00, 0xff, 0xff, 0xee, 0x63, 0x38, 0x32, 0xf9, 0x03, 0x00, 0x00, -} - -// Reference imports to suppress errors if they are not otherwise used. -var _ context.Context -var _ grpc.ClientConn - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the grpc package it is being compiled against. -const _ = grpc.SupportPackageIsVersion4 - -// ShoppingCartClient is the client API for ShoppingCart service. -// -// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. -type ShoppingCartClient interface { - AddItem(ctx context.Context, in *AddLineItem, opts ...grpc.CallOption) (*empty.Empty, error) - RemoveItem(ctx context.Context, in *RemoveLineItem, opts ...grpc.CallOption) (*empty.Empty, error) - GetCart(ctx context.Context, in *GetShoppingCart, opts ...grpc.CallOption) (*Cart, error) -} - -type shoppingCartClient struct { - cc *grpc.ClientConn -} - -func NewShoppingCartClient(cc *grpc.ClientConn) ShoppingCartClient { - return &shoppingCartClient{cc} -} - -func (c *shoppingCartClient) AddItem(ctx context.Context, in *AddLineItem, opts ...grpc.CallOption) (*empty.Empty, error) { - out := new(empty.Empty) - err := c.cc.Invoke(ctx, "/com.example.shoppingcart.ShoppingCart/AddItem", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *shoppingCartClient) RemoveItem(ctx context.Context, in *RemoveLineItem, opts ...grpc.CallOption) (*empty.Empty, error) { - out := new(empty.Empty) - err := c.cc.Invoke(ctx, "/com.example.shoppingcart.ShoppingCart/RemoveItem", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *shoppingCartClient) GetCart(ctx context.Context, in *GetShoppingCart, opts ...grpc.CallOption) (*Cart, error) { - out := new(Cart) - err := c.cc.Invoke(ctx, "/com.example.shoppingcart.ShoppingCart/GetCart", in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// ShoppingCartServer is the server API for ShoppingCart service. -type ShoppingCartServer interface { - AddItem(context.Context, *AddLineItem) (*empty.Empty, error) - RemoveItem(context.Context, *RemoveLineItem) (*empty.Empty, error) - GetCart(context.Context, *GetShoppingCart) (*Cart, error) -} - -// UnimplementedShoppingCartServer can be embedded to have forward compatible implementations. -type UnimplementedShoppingCartServer struct { -} - -func (*UnimplementedShoppingCartServer) AddItem(ctx context.Context, req *AddLineItem) (*empty.Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method AddItem not implemented") -} -func (*UnimplementedShoppingCartServer) RemoveItem(ctx context.Context, req *RemoveLineItem) (*empty.Empty, error) { - return nil, status.Errorf(codes.Unimplemented, "method RemoveItem not implemented") -} -func (*UnimplementedShoppingCartServer) GetCart(ctx context.Context, req *GetShoppingCart) (*Cart, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetCart not implemented") -} - -func RegisterShoppingCartServer(s *grpc.Server, srv ShoppingCartServer) { - s.RegisterService(&_ShoppingCart_serviceDesc, srv) -} - -func _ShoppingCart_AddItem_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(AddLineItem) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ShoppingCartServer).AddItem(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/com.example.shoppingcart.ShoppingCart/AddItem", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ShoppingCartServer).AddItem(ctx, req.(*AddLineItem)) - } - return interceptor(ctx, in, info, handler) -} - -func _ShoppingCart_RemoveItem_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(RemoveLineItem) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ShoppingCartServer).RemoveItem(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/com.example.shoppingcart.ShoppingCart/RemoveItem", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ShoppingCartServer).RemoveItem(ctx, req.(*RemoveLineItem)) - } - return interceptor(ctx, in, info, handler) -} - -func _ShoppingCart_GetCart_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(GetShoppingCart) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ShoppingCartServer).GetCart(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/com.example.shoppingcart.ShoppingCart/GetCart", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ShoppingCartServer).GetCart(ctx, req.(*GetShoppingCart)) - } - return interceptor(ctx, in, info, handler) -} - -var _ShoppingCart_serviceDesc = grpc.ServiceDesc{ - ServiceName: "com.example.shoppingcart.ShoppingCart", - HandlerType: (*ShoppingCartServer)(nil), - Methods: []grpc.MethodDesc{ - { - MethodName: "AddItem", - Handler: _ShoppingCart_AddItem_Handler, - }, - { - MethodName: "RemoveItem", - Handler: _ShoppingCart_RemoveItem_Handler, - }, - { - MethodName: "GetCart", - Handler: _ShoppingCart_GetCart_Handler, - }, - }, - Streams: []grpc.StreamDesc{}, - Metadata: "shoppingcart/shoppingcart.proto", -} diff --git a/tck/test/crdt/synth/crdt_test.go b/tck/test/crdt/synth/crdt_test.go new file mode 100644 index 0000000..ab610b9 --- /dev/null +++ b/tck/test/crdt/synth/crdt_test.go @@ -0,0 +1,69 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "context" + "fmt" + "reflect" + "runtime" + "testing" + "time" + + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/cloudstateio/go-support/example/crdt_shoppingcart/shoppingcart" +) + +// TestCRDT runs the TCK for the CRDT state model. +// As defined by the Cloudstate specification, each CRDT state model type +// has three state actions CRDTs can emit on state changes. +// - create +// - update +// - delete + +func Command(i interface{}) string { + // github.com/cloudstateio/go-support/example/crdt_shoppingcart/shoppingcart.ShoppingCartServiceServer.AddItem + return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() +} + +func TestCRDT(t *testing.T) { + s := newServer(t) + s.newClientConn() + defer s.teardown() + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + t.Run("huh", func(t *testing.T) { + fmt.Println(Command(shoppingcart.ShoppingCartServiceServer.AddItem)) + }) + + t.Run("entity discovery should find the service", func(t *testing.T) { + edc := protocol.NewEntityDiscoveryClient(s.conn) + discover, err := edc.Discover(ctx, &protocol.ProxyInfo{ + ProtocolMajorVersion: 0, + ProtocolMinorVersion: 1, + ProxyName: "a-proxy", + ProxyVersion: "0.0.0", + SupportedEntityTypes: []string{protocol.EventSourced, protocol.CRDT}, + }) + if err != nil { + t.Fatal(err) + } + tr := tester{t} + tr.expectedInt(len(discover.GetEntities()), 1) + tr.expectedString(discover.GetEntities()[0].GetServiceName(), serviceName) + }) +} diff --git a/tck/test/crdt/synth/flag_model.go b/tck/test/crdt/synth/flag_model.go new file mode 100644 index 0000000..10c9589 --- /dev/null +++ b/tck/test/crdt/synth/flag_model.go @@ -0,0 +1,43 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "github.com/cloudstateio/go-support/tck/crdt" + "github.com/golang/protobuf/proto" +) + +func flagRequest(messages ...proto.Message) *crdt.FlagRequest { + r := &crdt.FlagRequest{ + Actions: make([]*crdt.FlagRequestAction, 0), + } + for _, i := range messages { + switch t := i.(type) { + case *crdt.Get: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.FlagRequestAction{Action: &crdt.FlagRequestAction_Get{Get: t}}) + case *crdt.Delete: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.FlagRequestAction{Action: &crdt.FlagRequestAction_Delete{Delete: t}}) + case *crdt.FlagEnable: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.FlagRequestAction{Action: &crdt.FlagRequestAction_Enable{Enable: t}}) + default: + panic("no type matched") + } + } + return r +} diff --git a/tck/test/crdt/synth/flag_test.go b/tck/test/crdt/synth/flag_test.go new file mode 100644 index 0000000..001612e --- /dev/null +++ b/tck/test/crdt/synth/flag_test.go @@ -0,0 +1,152 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "context" + "testing" + "time" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/tck/crdt" +) + +func TestCRDTFlag(t *testing.T) { + s := newServer(t) + defer s.teardown() + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + t.Run("Flag", func(t *testing.T) { + entityID := "flag-1" + command := "ProcessFlag" + p := newProxy(ctx, s) + defer p.teardown() + + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + t.Run("Get emits client action", func(t *testing.T) { + tr := tester{t} + switch m := p.command(entityID, command, + flagRequest(&crdt.Get{}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + tr.expectedNotNil(m.Reply.GetClientAction()) + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetStateAction()) + // action reply + tr.expectedNotNil(m.Reply.GetClientAction().GetReply()) + var f crdt.FlagValue + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &f) + tr.expectedFalse(f.GetValue()) + default: + tr.unexpected(m) + } + }) + t.Run("FlagEnable emits client action and create state action", func(t *testing.T) { + tr := tester{t} + switch m := p.command(entityID, command, + flagRequest(&crdt.FlagEnable{}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetClientAction().GetFailure()) + var f crdt.FlagResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &f) + tr.expectedTrue(f.GetValue().GetValue()) + // state action + tr.expectedNil(m.Reply.GetStateAction().GetUpdate()) + tr.expectedNil(m.Reply.GetStateAction().GetDelete()) + tr.expectedNotNil(m.Reply.GetStateAction().GetCreate()) + tr.expectedTrue(m.Reply.GetStateAction().GetCreate().GetFlag().GetValue()) + default: + tr.unexpected(m) + } + }) + t.Run("Delete emits client action and delete state action", func(t *testing.T) { + tr := tester{t} + switch m := p.command(entityID, command, + flagRequest(&crdt.Delete{}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetClientAction().GetFailure()) + var f crdt.FlagResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &f) + // state action + tr.expectedNil(m.Reply.GetStateAction().GetCreate()) + tr.expectedNil(m.Reply.GetStateAction().GetUpdate()) + tr.expectedNotNil(m.Reply.GetStateAction().GetDelete()) + default: + tr.unexpected(m) + } + }) + t.Run("FlagState should reflect state", func(t *testing.T) { + tr := tester{t} + p := newProxy(ctx, s) + defer p.teardown() + + entityID = "flag-2" + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + p.state(&entity.FlagState{Value: true}) + switch m := p.command(entityID, command, + flagRequest(&crdt.Get{}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetClientAction().GetFailure()) + tr.expectedNil(m.Reply.GetStateAction().GetCreate()) + var f crdt.FlagResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &f) + tr.expectedTrue(f.GetValue().GetValue()) + // state action + tr.expectedNil(m.Reply.GetStateAction().GetCreate()) + tr.expectedNil(m.Reply.GetStateAction().GetUpdate()) + tr.expectedNil(m.Reply.GetStateAction().GetDelete()) + default: + tr.unexpected(m) + } + }) + t.Run("FlagDelta should reflect state", func(t *testing.T) { + tr := tester{t} + p := newProxy(ctx, s) + defer p.teardown() + + entityID = "flag-3" + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + p.delta(&entity.FlagDelta{Value: true}) + switch m := p.command(entityID, command, + flagRequest(&crdt.Get{}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetClientAction().GetFailure()) + var f crdt.FlagResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &f) + tr.expectedTrue(f.GetValue().GetValue()) + // state action + tr.expectedNil(m.Reply.GetStateAction().GetCreate()) + tr.expectedNil(m.Reply.GetStateAction().GetUpdate()) + tr.expectedNil(m.Reply.GetStateAction().GetDelete()) + default: + tr.unexpected(m) + } + }) + }) +} diff --git a/tck/test/crdt/synth/gcounter_model.go b/tck/test/crdt/synth/gcounter_model.go new file mode 100644 index 0000000..c6722cc --- /dev/null +++ b/tck/test/crdt/synth/gcounter_model.go @@ -0,0 +1,43 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "github.com/cloudstateio/go-support/tck/crdt" + "github.com/golang/protobuf/proto" +) + +func gcounterRequest(messages ...proto.Message) *crdt.GCounterRequest { + r := &crdt.GCounterRequest{ + Actions: make([]*crdt.GCounterRequestAction, 0), + } + for _, i := range messages { + switch t := i.(type) { + case *crdt.Get: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.GCounterRequestAction{Action: &crdt.GCounterRequestAction_Get{Get: t}}) + case *crdt.Delete: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.GCounterRequestAction{Action: &crdt.GCounterRequestAction_Delete{Delete: t}}) + case *crdt.GCounterIncrement: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.GCounterRequestAction{Action: &crdt.GCounterRequestAction_Increment{Increment: t}}) + default: + panic("no type matched") + } + } + return r +} diff --git a/tck/test/crdt/synth/gcounter_test.go b/tck/test/crdt/synth/gcounter_test.go new file mode 100644 index 0000000..2db4589 --- /dev/null +++ b/tck/test/crdt/synth/gcounter_test.go @@ -0,0 +1,374 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "context" + "testing" + "time" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/tck/crdt" +) + +func TestCRDTGCounter(t *testing.T) { + s := newServer(t) + defer s.teardown() + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + t.Run("CrdtInit", func(t *testing.T) { + p := newProxy(ctx, s) + s.t = t + defer p.teardown() + t.Run("sending CrdtInit fo an unknown service should fail", func(t *testing.T) { + tr := tester{t} + p.init(&entity.CrdtInit{ServiceName: "unknown", EntityId: "unknown"}) + resp, err := p.Recv() + tr.expectedNil(err) + tr.expectedNotNil(resp) + tr.expectedBool(len(resp.GetFailure().GetDescription()) > 0, true) + }) + }) + + command := "ProcessGCounter" + t.Run("GCounter", func(t *testing.T) { + entityID := "gcounter-0" + p := newProxy(ctx, s) + defer p.teardown() + t.Run("sending CrdtInit should not fail", func(t *testing.T) { + tr := tester{t} + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + resp, err := p.Recv() + tr.expectedNil(err) + tr.expectedNil(resp) + }) + t.Run("incrementing a GCounter should emit a client action and create state action", func(t *testing.T) { + tr := tester{t} + switch m := p.command( + entityID, command, gcounterRequest(&crdt.GCounterIncrement{Key: entityID, Value: 8}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + r := crdt.GCounterResponse{} + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedUInt64(r.GetValue().GetValue(), 8) + tr.expectedUInt64(m.Reply.GetStateAction().GetCreate().GetGcounter().GetValue(), 8) + default: + tr.unexpected(m) + } + }) + t.Run("a second increment should emit a client action and an update state action", func(t *testing.T) { + tr := tester{t} + switch m := p.command( + entityID, command, gcounterRequest(&crdt.GCounterIncrement{Key: entityID, Value: 8}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + r := crdt.GCounterResponse{} + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedUInt64(r.GetValue().GetValue(), 16) + tr.expectedUInt64(m.Reply.GetStateAction().GetUpdate().GetGcounter().GetIncrement(), 8) + default: + tr.unexpected(m) + } + }) + t.Run("get should return the counters value", func(t *testing.T) { + tr := tester{t} + switch m := p.command(entityID, command, gcounterRequest(&crdt.Get{Key: entityID})).Message.(type) { + case *entity.CrdtStreamOut_Reply: + r := crdt.GCounterResponse{} + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedUInt64(r.GetValue().GetValue(), 16) + default: + tr.unexpected(m) + } + }) + t.Run("the counter should apply new state and return its value", func(t *testing.T) { + tr := tester{t} + p.state(&entity.GCounterState{Value: 24}) + switch m := p.command( + entityID, command, gcounterRequest(&crdt.Get{Key: entityID}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + r := crdt.GCounterResponse{} + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedUInt64(r.GetValue().GetValue(), 24) + default: + tr.unexpected(m) + } + }) + t.Run("the counter should apply a delta and return its value", func(t *testing.T) { + tr := tester{t} + p.delta(&entity.GCounterDelta{Increment: 8}) + switch m := p.command( + entityID, command, gcounterRequest(&crdt.Get{Key: entityID}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + r := crdt.GCounterResponse{} + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedUInt64(r.GetValue().GetValue(), 32) + default: + tr.unexpected(m) + } + }) + t.Run("deleting an entity should emit a delete state action", func(t *testing.T) { + tr := tester{t} + switch m := p.command( + entityID, command, gcounterRequest(&crdt.Delete{Key: entityID}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + tr.expectedNotNil(m.Reply.GetClientAction().GetReply()) + tr.expectedNotNil(m.Reply.GetStateAction().GetDelete()) + default: + tr.unexpected(m) + } + }) + t.Run("after an entity was deleted, we could initialise an another entity", func(t *testing.T) { + // this is not explicit specified by the spec, but it says, that the user function should + // clear its state and the proxy could close the stream anytime, but also does not say + // the user function can close the stream. So our implementation would be prepared for a + // new entity re-using the same stream (why not). + p.init(&entity.CrdtInit{ + ServiceName: serviceName, + EntityId: "gcounter-xyz", + }) + // nothing should be returned here + resp, err := p.Recv() + if err != nil { + t.Fatal(err) + } + if resp != nil { + t.Fatal("no response expected") + } + }) + }) + + t.Run("GCounter Streamed", func(t *testing.T) { + command := "ProcessGCounterStreamed" + entityID := "gcounter-x-0" + p := newProxy(ctx, s) + defer p.teardown() + t.Run("sending CrdtInit should not fail", func(t *testing.T) { + tr := tester{t} + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + resp, err := p.Recv() + tr.expectedNil(err) + tr.expectedNil(resp) + }) + t.Run("incrementing a GCounter should emit a client action and create state action", func(t *testing.T) { + tr := tester{t} + switch m := p.commandStreamed( + entityID, command, gcounterRequest(&crdt.GCounterIncrement{Key: entityID, Value: 8}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + r := crdt.GCounterResponse{} + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedUInt64(r.GetValue().GetValue(), 8) + tr.expectedUInt64(m.Reply.GetStateAction().GetCreate().GetGcounter().GetValue(), 8) + default: + tr.unexpected(m) + } + }) + t.Run("incrementing a GCounter should emit a client action and create state action", func(t *testing.T) { + tr := tester{t} + prevCmdID := p.seq - 1 + switch m := p.command( + entityID, command, gcounterRequest(&crdt.GCounterIncrement{Key: entityID, Value: 8}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + r := crdt.GCounterResponse{} + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedUInt64(r.GetValue().GetValue(), 16) + tr.expectedUInt64(m.Reply.GetStateAction().GetUpdate().GetGcounter().GetIncrement(), 8) + default: + tr.unexpected(m) + } + // validate streaming + recv, err := p.Recv() + if err != nil { + t.Fatal(err) + } + // there must be a response with the command id from the first command sent. + tr.expectedNotNil(recv) + tr.expectedInt64(recv.GetStreamedMessage().GetCommandId(), prevCmdID) + r := crdt.GCounterResponse{} + tr.toProto(recv.GetStreamedMessage().GetClientAction().GetReply().GetPayload(), &r) + tr.expectedUInt64(r.GetValue().GetValue(), 16) + }) + }) + + t.Run("GCounter – CrdtDelete", func(t *testing.T) { + entityID := "gcounter-0" + tr := tester{t} + p := newProxy(ctx, s) + defer p.teardown() + + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + switch m := p.command( + entityID, command, gcounterRequest(&crdt.GCounterIncrement{Key: entityID, Value: 8}), + ).Message.(type) { + case *entity.CrdtStreamOut_Failure: + tr.unexpected(m) + } + p.sendDelete(delete{&entity.CrdtDelete{}}) + // nothing should be returned here + resp, err := p.Recv() + if err != nil { + t.Fatal(err) + } + if resp != nil { + t.Fatal("no response expected") + } + entityID = "gcounter-0.1" + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + switch m := p.command( + entityID, command, gcounterRequest(&crdt.GCounterIncrement{Key: entityID, Value: 16}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + tr.expectedUInt64(m.Reply.GetStateAction().GetCreate().GetGcounter().GetValue(), 16) + default: + tr.unexpected(m) + } + }) + + t.Run("GCounter – unknown entity id used", func(t *testing.T) { + entityID := "gcounter-1" + tr := tester{t} + p := newProxy(ctx, s) + defer p.teardown() + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + switch m := p.command( + entityID, command, gcounterRequest(&crdt.GCounterIncrement{Key: entityID, Value: 8}), + ).Message.(type) { + case *entity.CrdtStreamOut_Failure: + tr.unexpected(m) + } + t.Run("calling GetGCounter for a non existing entity id should fail", func(t *testing.T) { + tr := tester{t} + entityID := "gcounter-1-xxx" + switch m := p.command( + entityID, command, gcounterRequest(&crdt.Get{Key: entityID}), + ).Message.(type) { + case *entity.CrdtStreamOut_Failure: + default: + tr.unexpected(m) + } + }) + }) + + t.Run("GCounter – incompatible CRDT delta sequence", func(t *testing.T) { + entityID := "gcounter-2" + p := newProxy(ctx, s) + defer p.teardown() + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + t.Run("setting a delta without ever sending state should fail", func(t *testing.T) { + t.Skip("we can't test this one for now") + p.delta(&entity.GCounterDelta{Increment: 7}) + resp, err := p.Recv() + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("response expected") + } + switch m := resp.Message.(type) { + case *entity.CrdtStreamOut_Failure: + // the expected failure + default: + t.Fatalf("got unexpected message: %+v", m) + } + }) + }) + + t.Run("GCounter – incompatible CRDT delta used", func(t *testing.T) { + entityID := "gcounter-3" + tr := tester{t} + p := newProxy(ctx, s) + defer p.teardown() + + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + switch m := p.command( + entityID, command, gcounterRequest(&crdt.GCounterIncrement{Key: entityID, Value: 8}), + ).Message.(type) { + case *entity.CrdtStreamOut_Failure: + tr.unexpected(m) + } + t.Run("setting a delta for a different CRDT type should fail", func(t *testing.T) { + tr := tester{t} + p.delta(&entity.PNCounterDelta{Change: 7}) + // nothing should be returned here + resp, err := p.Recv() + if err != nil { + t.Fatal(err) + } + if resp == nil { + t.Fatal("response expected") + } + switch m := resp.Message.(type) { + case *entity.CrdtStreamOut_Failure: + default: + tr.unexpected(m) + } + }) + }) + + // TODO: check if that is enough + t.Run("GCounter – inconsistent local state", func(t *testing.T) { + entityID := "gcounter-4" + tr := tester{t} + p := newProxy(ctx, s) + defer p.teardown() + + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + p.command(entityID, command, gcounterRequest(&crdt.GCounterIncrement{Key: entityID, Value: 7})) + switch m := p.command( + entityID, command, gcounterRequest(&crdt.GCounterIncrement{Key: entityID, Value: 7, FailWith: "error"}), + ).Message.(type) { + case *entity.CrdtStreamOut_Failure: + tr.expectedString(m.Failure.Description, "error") + default: + tr.unexpected(m) + } + + // TODO: revise this tests as we should have a stream still up after a client failure + // _, err := + // if err == nil { + // t.Fatal("expected err") + // } + // if err != io.EOF { + // t.Fatal("expected io.EOF") + // } + // + // switch m := p.sendCmdRecvReply(command{ + // &entity.Command{EntityID: entityID, Name: "IncrementGCounter"}, + // &crdt.GCounterIncrement{Key: entityID, Value: 9}, + // }).Message.(type) { + // case *entity.CrdtStreamOut_Reply: + // value := crdt.GCounterValue{} + // err := encoding.UnmarshalAny(m.Reply.GetClientAction().GetReply().GetPayload(), &value) + // if err != nil { + // t.Fatal(err) + // } + // if got, want := value.GetValue(), uint64(8+9); got != want { + // t.Fatalf("got = %v; wanted: %d, for value:%+v", got, want, value) + // } + // if got, want := m.Reply.GetStateAction().GetUpdate().GetGcounter().GetIncrement(), uint64(9); got != want { + // t.Fatalf("got = %v; wanted: %d, for value:%+v", got, want, m.Reply) + // } + // default: + // t.Fatalf("got unexpected message: %+v", m) + // } + }) +} diff --git a/tck/test/crdt/synth/gset_model.go b/tck/test/crdt/synth/gset_model.go new file mode 100644 index 0000000..63e98a4 --- /dev/null +++ b/tck/test/crdt/synth/gset_model.go @@ -0,0 +1,43 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "github.com/cloudstateio/go-support/tck/crdt" + "github.com/golang/protobuf/proto" +) + +func gsetRequest(messages ...proto.Message) *crdt.GSetRequest { + r := &crdt.GSetRequest{ + Actions: make([]*crdt.GSetRequestAction, 0), + } + for _, i := range messages { + switch t := i.(type) { + case *crdt.Get: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.GSetRequestAction{Action: &crdt.GSetRequestAction_Get{Get: t}}) + case *crdt.Delete: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.GSetRequestAction{Action: &crdt.GSetRequestAction_Delete{Delete: t}}) + case *crdt.GSetAdd: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.GSetRequestAction{Action: &crdt.GSetRequestAction_Add{Add: t}}) + default: + panic("no type matched") + } + } + return r +} diff --git a/tck/test/crdt/synth/gset_test.go b/tck/test/crdt/synth/gset_test.go new file mode 100644 index 0000000..9ecc5e3 --- /dev/null +++ b/tck/test/crdt/synth/gset_test.go @@ -0,0 +1,149 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "context" + "reflect" + "strings" + "testing" + "time" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/tck/crdt" +) + +func TestCRDTGSet(t *testing.T) { + s := newServer(t) + s.newClientConn() + defer s.teardown() + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + t.Run("GSet", func(t *testing.T) { + entityID := "gset-1" + command := "ProcessGSet" + p := newProxy(ctx, s) + defer p.teardown() + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + + type pair struct { + Left string + Right int64 + } + t.Run("calling AddGSet should emit client action and create state action", func(t *testing.T) { + tr := tester{t} + one, err := encoding.Struct(pair{"one", 1}) + if err != nil { + t.Fatal(err) + } + switch m := p.command( + entityID, command, gsetRequest(&crdt.GSetAdd{ + Key: entityID, + Value: &crdt.AnySupportType{Value: &crdt.AnySupportType_AnyValue{AnyValue: one}}, + }), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + tr.expectedNil(m.Reply.GetStateAction().GetUpdate()) + tr.expectedNil(m.Reply.GetStateAction().GetDelete()) + // action reply + var r crdt.GSetResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedInt(len(r.GetValue().GetValues()), 1) + var p pair + tr.toStruct(r.GetValue().GetValues()[0].GetAnyValue(), &p) + tr.expectedString(p.Left, "one") + tr.expectedInt64(p.Right, 1) + // create state action + tr.expectedInt(len(m.Reply.GetStateAction().GetCreate().GetGset().GetItems()), 1) + i := m.Reply.GetStateAction().GetCreate().GetGset().GetItems()[0] + tr.expectedBool(strings.HasPrefix(i.TypeUrl, encoding.JSONTypeURLPrefix), true) + var state pair + tr.toStruct(i, &state) + tr.expectedString(state.Left, "one") + tr.expectedInt64(state.Right, 1) + default: + tr.unexpected(m) + } + }) + t.Run("further calls of AddGSet should emit client action and delta state action", func(t *testing.T) { + tr := tester{t} + two, err := encoding.Struct(pair{"two", 2}) + if err != nil { + t.Fatal(err) + } + switch m := p.command( + entityID, command, gsetRequest(&crdt.GSetAdd{ + Key: entityID, + Value: &crdt.AnySupportType{Value: &crdt.AnySupportType_AnyValue{AnyValue: two}}, + }), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + tr.expectedNil(m.Reply.GetStateAction().GetCreate()) + tr.expectedNil(m.Reply.GetStateAction().GetDelete()) + // action reply + var r crdt.GSetResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedInt(len(r.GetValue().GetValues()), 2) + found := 0 + for _, v := range r.GetValue().GetValues() { + var p pair + tr.toStruct(v.GetAnyValue(), &p) + if reflect.DeepEqual(p, pair{Left: "one", Right: 1}) { + found++ + } + if reflect.DeepEqual(p, pair{Left: "two", Right: 2}) { + found++ + } + } + tr.expectedInt(found, 2) + // update state action + tr.expectedInt(len(m.Reply.GetStateAction().GetUpdate().GetGset().GetAdded()), 1) + i := m.Reply.GetStateAction().GetUpdate().GetGset().GetAdded()[0] + tr.expectedBool(strings.HasPrefix(i.TypeUrl, encoding.JSONTypeURLPrefix), true) + var state pair + tr.toStruct(i, &state) + tr.expectedString(state.Left, "two") + tr.expectedInt64(state.Right, 2) + default: + tr.unexpected(m) + } + }) + }) + + t.Run("GSet AnySupportTypes", func(t *testing.T) { + entityID := "gset-2" + command := "ProcessGSet" + p := newProxy(ctx, s) + defer p.teardown() + p.init(&entity.CrdtInit{ + ServiceName: serviceName, + EntityId: entityID, + }) + + var values = []*crdt.AnySupportType{ + {Value: &crdt.AnySupportType_BoolValue{BoolValue: true}}, + {Value: &crdt.AnySupportType_FloatValue{FloatValue: float32(1)}}, + {Value: &crdt.AnySupportType_Int32Value{Int32Value: int32(2)}}, + {Value: &crdt.AnySupportType_Int64Value{Int64Value: int64(3)}}, + {Value: &crdt.AnySupportType_DoubleValue{DoubleValue: 4.4}}, + {Value: &crdt.AnySupportType_StringValue{StringValue: "five"}}, + {Value: &crdt.AnySupportType_BytesValue{BytesValue: []byte{'a', 'b', 3, 4, 5, 6}}}, + } + p.command(entityID, command, gsetRequest(&crdt.GSetAdd{Key: entityID, Value: values[0]})) + }) +} diff --git a/tck/test/crdt/synth/lwwregister_model.go b/tck/test/crdt/synth/lwwregister_model.go new file mode 100644 index 0000000..a4053b4 --- /dev/null +++ b/tck/test/crdt/synth/lwwregister_model.go @@ -0,0 +1,46 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "github.com/cloudstateio/go-support/tck/crdt" + "github.com/golang/protobuf/proto" +) + +func lwwRegisterRequest(messages ...proto.Message) *crdt.LWWRegisterRequest { + r := &crdt.LWWRegisterRequest{ + Actions: make([]*crdt.LWWRegisterRequestAction, 0), + } + for _, i := range messages { + switch t := i.(type) { + case *crdt.Get: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.LWWRegisterRequestAction{Action: &crdt.LWWRegisterRequestAction_Get{Get: t}}) + case *crdt.Delete: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.LWWRegisterRequestAction{Action: &crdt.LWWRegisterRequestAction_Delete{Delete: t}}) + case *crdt.LWWRegisterSet: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.LWWRegisterRequestAction{Action: &crdt.LWWRegisterRequestAction_Set{Set: t}}) + case *crdt.LWWRegisterSetWithClock: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.LWWRegisterRequestAction{Action: &crdt.LWWRegisterRequestAction_SetWithClock{SetWithClock: t}}) + default: + panic("no type matched") + } + } + return r +} diff --git a/tck/test/crdt/synth/lwwregister_test.go b/tck/test/crdt/synth/lwwregister_test.go new file mode 100644 index 0000000..94d0f2c --- /dev/null +++ b/tck/test/crdt/synth/lwwregister_test.go @@ -0,0 +1,138 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "context" + "reflect" + "testing" + "time" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/tck/crdt" + "github.com/golang/protobuf/ptypes/any" +) + +func TestCRDTLWWRegister(t *testing.T) { + s := newServer(t) + defer s.teardown() + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + type pair struct { + Left string + Right int64 + } + t.Run("LWWRegister", func(t *testing.T) { + entityID := "lwwregister-1" + command := "ProcessORSet" + p := newProxy(ctx, s) + defer p.teardown() + + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + t.Run("LWWRegisterSet emits client action and create state action", func(t *testing.T) { + tr := tester{t} + one, err := encoding.Struct(pair{"one", 1}) + if err != nil { + t.Fatal(err) + } + switch m := p.command(entityID, command, lwwRegisterRequest(&crdt.LWWRegisterSet{ + Value: &crdt.AnySupportType{ + Value: &crdt.AnySupportType_AnyValue{AnyValue: one}, + }, + }), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetClientAction().GetFailure()) + var r crdt.LWWRegisterResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + one, err := encoding.Struct(pair{"one", 1}) + if err != nil { + t.Fatal(err) + } + tr.expectedOneIn([]*any.Any{r.GetValue().GetValue()}, one) + // state action + tr.expectedNotNil(m.Reply.GetStateAction().GetCreate()) + tr.expectedNil(m.Reply.GetStateAction().GetUpdate()) + tr.expectedNil(m.Reply.GetStateAction().GetDelete()) + var p pair + tr.expectedTrue(m.Reply.GetStateAction().GetCreate().GetLwwregister().GetClock() == entity.CrdtClock_DEFAULT) + tr.toStruct(m.Reply.GetStateAction().GetCreate().GetLwwregister().GetValue(), &p) + tr.expectedTrue(reflect.DeepEqual(p, pair{"one", 1})) + default: + tr.unexpected(m) + } + }) + t.Run("LWWRegisterSetWithClock emits client action and update state action", func(t *testing.T) { + tr := tester{t} + two, err := encoding.Struct(pair{"two", 2}) + if err != nil { + t.Fatal(err) + } + switch m := p.command(entityID, command, lwwRegisterRequest(&crdt.LWWRegisterSetWithClock{ + Value: &crdt.AnySupportType{ + Value: &crdt.AnySupportType_AnyValue{AnyValue: two}, + }, + Clock: crdt.CrdtClock_CUSTOM, + CustomClockValue: 7, + }), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetClientAction().GetFailure()) + var r crdt.LWWRegisterResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + two, err := encoding.Struct(pair{"two", 2}) + if err != nil { + t.Fatal(err) + } + tr.expectedOneIn([]*any.Any{r.GetValue().GetValue()}, two) + // state action + tr.expectedNil(m.Reply.GetStateAction().GetCreate()) + tr.expectedNotNil(m.Reply.GetStateAction().GetUpdate()) + tr.expectedNil(m.Reply.GetStateAction().GetDelete()) + var p pair + tr.toStruct(m.Reply.GetStateAction().GetUpdate().GetLwwregister().GetValue(), &p) + tr.expectedTrue(reflect.DeepEqual(p, pair{"two", 2})) + tr.expectedTrue(m.Reply.GetStateAction().GetUpdate().GetLwwregister().GetClock() == entity.CrdtClock_CUSTOM) + tr.expectedTrue(m.Reply.GetStateAction().GetUpdate().GetLwwregister().GetCustomClockValue() == 7) + default: + tr.unexpected(m) + } + }) + t.Run("Delete emits client action and create state action", func(t *testing.T) { + tr := tester{t} + switch m := p.command(entityID, command, lwwRegisterRequest(&crdt.Delete{})).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetClientAction().GetFailure()) + var r crdt.LWWRegisterResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + // state action + tr.expectedNil(m.Reply.GetStateAction().GetCreate()) + tr.expectedNil(m.Reply.GetStateAction().GetUpdate()) + tr.expectedNotNil(m.Reply.GetStateAction().GetDelete()) + default: + tr.unexpected(m) + } + }) + }) +} diff --git a/tck/test/crdt/synth/ormap_bench_test.go b/tck/test/crdt/synth/ormap_bench_test.go new file mode 100644 index 0000000..3913360 --- /dev/null +++ b/tck/test/crdt/synth/ormap_bench_test.go @@ -0,0 +1,50 @@ +package synth + +import ( + "context" + "testing" + "time" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/tck/crdt" +) + +func BenchmarkCRDTORMap(b *testing.B) { + s := newServer(&testing.T{}) + defer s.teardown() + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + entityID := "ormap-1" + command := "ProcessORMap" + p := newProxy(ctx, s) + defer p.teardown() + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + + tr := tester{s.t} + b.Run("ORMap", func(b *testing.B) { + b.ReportAllocs() + inc0 := uint64(1) + for i := 0; i < b.N; i++ { + switch m := p.command(entityID, command, + ormapRequest(&crdt.ORMapActionRequest{ + EntryKey: encoding.String("niner"), + Request: &crdt.ORMapActionRequest_GCounterRequest{ + GCounterRequest: gcounterRequest(&crdt.GCounterIncrement{Value: inc0}), + }, + }), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + var r crdt.ORMapResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + var state entity.CrdtState_Gcounter + err := encoding.DecodeStruct(r.GetEntries().Values[0].GetValue(), &state) + if err != nil { + tr.t.Fatal(err) + } + default: + tr.unexpected(m) + } + } + }) +} diff --git a/tck/test/crdt/synth/ormap_model.go b/tck/test/crdt/synth/ormap_model.go new file mode 100644 index 0000000..ccd037f --- /dev/null +++ b/tck/test/crdt/synth/ormap_model.go @@ -0,0 +1,49 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "github.com/cloudstateio/go-support/tck/crdt" + "github.com/golang/protobuf/proto" +) + +func ormapRequest(messages ...proto.Message) *crdt.ORMapRequest { + r := &crdt.ORMapRequest{ + Actions: make([]*crdt.ORMapRequestAction, 0), + } + for _, i := range messages { + switch t := i.(type) { + case *crdt.Get: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.ORMapRequestAction{Action: &crdt.ORMapRequestAction_Get{Get: t}}) + case *crdt.Delete: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.ORMapRequestAction{Action: &crdt.ORMapRequestAction_Delete{Delete: t}}) + case *crdt.ORMapSet: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.ORMapRequestAction{Action: &crdt.ORMapRequestAction_SetKey{SetKey: t}}) + case *crdt.ORMapDelete: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.ORMapRequestAction{Action: &crdt.ORMapRequestAction_DeleteKey{DeleteKey: t}}) + case *crdt.ORMapActionRequest: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.ORMapRequestAction{Action: &crdt.ORMapRequestAction_Request{Request: t}}) + default: + panic("no type matched") + } + } + return r +} diff --git a/tck/test/crdt/synth/ormap_test.go b/tck/test/crdt/synth/ormap_test.go new file mode 100644 index 0000000..0a6b3a9 --- /dev/null +++ b/tck/test/crdt/synth/ormap_test.go @@ -0,0 +1,138 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "context" + "testing" + "time" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/tck/crdt" +) + +func TestCRDTORMap(t *testing.T) { + s := newServer(t) + defer s.teardown() + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + t.Run("ORMap", func(t *testing.T) { + entityID := "ormap-1" + command := "ProcessORMap" + p := newProxy(ctx, s) + defer p.teardown() + + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + t.Run("Get", func(t *testing.T) { + tr := tester{t} + switch m := p.command(entityID, command, + ormapRequest(&crdt.Get{}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + tr.expectedNil(m.Reply.GetStateAction()) + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNotNil(m.Reply.GetClientAction()) + default: + tr.unexpected(m) + } + }) + t.Run("Set – GCounter", func(t *testing.T) { + tr := tester{t} + switch m := p.command(entityID, command, + ormapRequest(&crdt.ORMapActionRequest{ + EntryKey: encoding.String("niner"), + Request: &crdt.ORMapActionRequest_GCounterRequest{ + GCounterRequest: gcounterRequest(&crdt.GCounterIncrement{Value: 9}), + }, + }), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + tr.expectedNotNil(m.Reply.GetStateAction().GetCreate()) + tr.expectedNotNil(m.Reply.GetClientAction()) + default: + tr.unexpected(m) + } + switch m := p.command(entityID, command, + ormapRequest(&crdt.ORMapActionRequest{ + EntryKey: encoding.String("niner"), + Request: &crdt.ORMapActionRequest_GCounterRequest{ + GCounterRequest: gcounterRequest(&crdt.GCounterIncrement{Value: 18}), + }, + }), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + tr.expectedNotNil(m.Reply.GetClientAction()) + + var r crdt.ORMapResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedInt(len(r.GetKeys().GetValues()), 1) + tr.expectedOneIn(r.GetKeys().GetValues(), encoding.String("niner")) + tr.expectedInt(len(r.GetEntries().GetValues()), 1) + + tr.expectedNotNil(m.Reply.GetStateAction().GetUpdate()) + tr.expectedInt(len(m.Reply.GetStateAction().GetUpdate().GetOrmap().GetUpdated()), 1) + tr.expectedUInt64( + m.Reply.GetStateAction().GetUpdate().GetOrmap().GetUpdated()[0].Delta.GetGcounter().Increment, + 18, + ) + default: + tr.unexpected(m) + } + }) + t.Run("Delete", func(t *testing.T) { + tr := tester{t} + switch m := p.command(entityID, command, + ormapRequest(&crdt.Delete{}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + tr.expectedNotNil(m.Reply.GetStateAction().GetDelete()) + default: + tr.unexpected(m) + } + }) + }) + t.Run("ORMap – State", func(t *testing.T) { + tr := tester{t} + entityID := "ormap-2" + command := "ProcessORMap" + p := newProxy(ctx, s) + defer p.teardown() + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + p.state(&entity.ORMapState{ + Entries: []*entity.ORMapEntry{ + { + Key: encoding.String("one"), + Value: &entity.CrdtState{State: &entity.CrdtState_Flag{Flag: &entity.FlagState{Value: false}}}, + }, + }, + }) + switch m := p.command(entityID, command, + ormapRequest(&crdt.ORMapActionRequest{ + EntryKey: encoding.String("one"), + Request: &crdt.ORMapActionRequest_FlagRequest{ + FlagRequest: flagRequest(&crdt.FlagEnable{}), + }, + }), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + tr.expectedNotNil(m.Reply.GetStateAction().GetCreate()) + default: + tr.unexpected(m) + } + }) +} diff --git a/tck/test/crdt/synth/orset_model.go b/tck/test/crdt/synth/orset_model.go new file mode 100644 index 0000000..b6e7b7b --- /dev/null +++ b/tck/test/crdt/synth/orset_model.go @@ -0,0 +1,46 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "github.com/cloudstateio/go-support/tck/crdt" + "github.com/golang/protobuf/proto" +) + +func orsetRequest(messages ...proto.Message) *crdt.ORSetRequest { + r := &crdt.ORSetRequest{ + Actions: make([]*crdt.ORSetRequestAction, 0), + } + for _, i := range messages { + switch t := i.(type) { + case *crdt.Get: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.ORSetRequestAction{Action: &crdt.ORSetRequestAction_Get{Get: t}}) + case *crdt.Delete: + r.Actions = append(r.Actions, &crdt.ORSetRequestAction{Action: &crdt.ORSetRequestAction_Delete{Delete: t}}) + r.Id = t.Key + case *crdt.ORSetAdd: + r.Actions = append(r.Actions, &crdt.ORSetRequestAction{Action: &crdt.ORSetRequestAction_Add{Add: t}}) + r.Id = t.Key + case *crdt.ORSetRemove: + r.Actions = append(r.Actions, &crdt.ORSetRequestAction{Action: &crdt.ORSetRequestAction_Remove{Remove: t}}) + r.Id = t.Key + default: + panic("no type matched") + } + } + return r +} diff --git a/tck/test/crdt/synth/orset_test.go b/tck/test/crdt/synth/orset_test.go new file mode 100644 index 0000000..d5605ab --- /dev/null +++ b/tck/test/crdt/synth/orset_test.go @@ -0,0 +1,137 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "context" + "testing" + "time" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/tck/crdt" +) + +func TestCRDTORSet(t *testing.T) { + s := newServer(t) + s.newClientConn() + defer s.teardown() + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + type pair struct { + Left string + Right int64 + } + t.Run("ORSet", func(t *testing.T) { + entityID := "orset-1" + command := "ProcessORSet" + p := newProxy(ctx, s) + defer p.teardown() + + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + t.Run("ORSetAdd emits client action and create state action", func(t *testing.T) { + tr := tester{t} + one, err := encoding.Struct(pair{"one", 1}) + if err != nil { + t.Fatal(err) + } + switch m := p.command(entityID, command, orsetRequest(&crdt.ORSetAdd{Value: &crdt.AnySupportType{ + Value: &crdt.AnySupportType_AnyValue{AnyValue: one}}, + }), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetClientAction().GetFailure()) + var r crdt.ORSetResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + one, err := encoding.Struct(pair{"one", 1}) + if err != nil { + t.Fatal(err) + } + tr.expectedOneIn(r.GetValue().GetValues(), one) + // state + tr.expectedNotNil(m.Reply.GetStateAction().GetCreate()) + tr.expectedOneIn(m.Reply.GetStateAction().GetCreate().GetOrset().GetItems(), one) + default: + tr.unexpected(m) + } + }) + t.Run("ORSetRemove emits client action and update state action", func(t *testing.T) { + tr := tester{t} + two, err := encoding.Struct(pair{"two", 2}) + if err != nil { + t.Fatal(err) + } + p.command(entityID, command, orsetRequest(&crdt.ORSetAdd{Value: &crdt.AnySupportType{ + Value: &crdt.AnySupportType_AnyValue{AnyValue: two}}, + })) + one, err := encoding.Struct(pair{"one", 1}) + if err != nil { + t.Fatal(err) + } + switch m := p.command(entityID, command, orsetRequest(&crdt.ORSetRemove{Value: &crdt.AnySupportType{ + Value: &crdt.AnySupportType_AnyValue{AnyValue: one}}, + }), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetClientAction().GetFailure()) + tr.expectedNil(m.Reply.GetClientAction().GetForward()) + var r crdt.ORSetResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + two, err := encoding.Struct(pair{"two", 2}) + if err != nil { + t.Fatal(err) + } + tr.expectedOneIn(r.GetValue().GetValues(), two) + tr.expectedInt(len(r.GetValue().GetValues()), 1) + // state + tr.expectedNotNil(m.Reply.GetStateAction().GetUpdate()) + one, err := encoding.Struct(pair{"one", 1}) + if err != nil { + t.Fatal(err) + } + tr.expectedOneIn(m.Reply.GetStateAction().GetUpdate().GetOrset().GetRemoved(), one) + default: + tr.unexpected(m) + } + }) + t.Run("Delete emits client action and delete state action", func(t *testing.T) { + tr := tester{t} + two, err := encoding.Struct(pair{"two", 2}) + if err != nil { + t.Fatal(err) + } + p.command(entityID, command, orsetRequest(&crdt.ORSetAdd{Value: &crdt.AnySupportType{ + Value: &crdt.AnySupportType_AnyValue{AnyValue: two}}, + })) + switch m := p.command( + entityID, command, orsetRequest(&crdt.Delete{}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + tr.expectedNil(m.Reply.GetSideEffects()) + var r crdt.ORSetResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedNotNil(m.Reply.GetStateAction().GetDelete()) + default: + tr.unexpected(m) + } + }) + }) +} diff --git a/tck/test/crdt/synth/pncounter_model.go b/tck/test/crdt/synth/pncounter_model.go new file mode 100644 index 0000000..d136e25 --- /dev/null +++ b/tck/test/crdt/synth/pncounter_model.go @@ -0,0 +1,46 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "github.com/cloudstateio/go-support/tck/crdt" + "github.com/golang/protobuf/proto" +) + +func pncounterRequest(messages ...proto.Message) *crdt.PNCounterRequest { + r := &crdt.PNCounterRequest{ + Actions: make([]*crdt.PNCounterRequestAction, 0, len(messages)), + } + for _, i := range messages { + switch t := i.(type) { + case *crdt.PNCounterIncrement: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.PNCounterRequestAction{Action: &crdt.PNCounterRequestAction_Increment{Increment: t}}) + case *crdt.PNCounterDecrement: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.PNCounterRequestAction{Action: &crdt.PNCounterRequestAction_Decrement{Decrement: t}}) + case *crdt.Get: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.PNCounterRequestAction{Action: &crdt.PNCounterRequestAction_Get{Get: t}}) + case *crdt.Delete: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.PNCounterRequestAction{Action: &crdt.PNCounterRequestAction_Delete{Delete: t}}) + default: + panic("no type matched") + } + } + return r +} diff --git a/tck/test/crdt/synth/pncounter_test.go b/tck/test/crdt/synth/pncounter_test.go new file mode 100644 index 0000000..16a97f4 --- /dev/null +++ b/tck/test/crdt/synth/pncounter_test.go @@ -0,0 +1,113 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "context" + "testing" + "time" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/tck/crdt" +) + +func TestCRDTPNCounter(t *testing.T) { + s := newServer(t) + s.newClientConn() + defer s.teardown() + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + t.Run("PNCounter", func(t *testing.T) { + entityID := "pncounter-1" + command := "ProcessPNCounter" + p := newProxy(ctx, s) + defer p.teardown() + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + + t.Run("incrementing a PNCounter should emit client action and create-state action", func(t *testing.T) { + tr := tester{t} + switch m := p.command( + entityID, command, pncounterRequest(&crdt.PNCounterIncrement{Key: entityID, Value: 7}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + var r crdt.PNCounterResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedInt64(r.GetValue().GetValue(), 7) + tr.expectedInt64(m.Reply.GetStateAction().GetCreate().GetPncounter().GetValue(), 7) + default: + tr.unexpected(m) + } + }) + t.Run("a second increment should emit a client action and an update-state action", func(t *testing.T) { + tr := tester{t} + switch m := p.command( + entityID, command, pncounterRequest(&crdt.PNCounterIncrement{Key: entityID, Value: 7}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + var r crdt.PNCounterResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedInt64(r.GetValue().GetValue(), 14) + tr.expectedInt64(m.Reply.GetStateAction().GetUpdate().GetPncounter().GetChange(), 7) + default: + tr.unexpected(m) + } + }) + t.Run("a decrement should emit a client action and an update state action", func(t *testing.T) { + tr := tester{t} + switch m := p.command( + entityID, command, pncounterRequest(&crdt.PNCounterDecrement{Key: entityID, Value: 28}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + var r crdt.PNCounterResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedInt64(r.GetValue().GetValue(), -14) + tr.expectedInt64(m.Reply.GetStateAction().GetUpdate().GetPncounter().GetChange(), -28) + default: + tr.unexpected(m) + } + }) + t.Run("the counter should apply new state and return its value", func(t *testing.T) { + tr := tester{t} + p.state(&entity.PNCounterState{Value: 49}) + switch m := p.command( + entityID, command, pncounterRequest(&crdt.Get{Key: entityID}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + var r crdt.PNCounterResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedInt64(r.GetValue().GetValue(), 49) + tr.expectedNil(m.Reply.GetClientAction().GetFailure()) + default: + tr.unexpected(m) + } + }) + t.Run("the counter should apply a delta and return its value", func(t *testing.T) { + tr := tester{t} + p.delta(&entity.PNCounterDelta{Change: -56}) + switch m := p.command( + entityID, command, pncounterRequest(&crdt.Get{Key: entityID}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + var r crdt.PNCounterResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedInt64(r.GetValue().GetValue(), -7) + default: + tr.unexpected(m) + } + }) + }) +} diff --git a/tck/test/crdt/synth/proxy.go b/tck/test/crdt/synth/proxy.go new file mode 100644 index 0000000..39e30c5 --- /dev/null +++ b/tck/test/crdt/synth/proxy.go @@ -0,0 +1,352 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "context" + "testing" + "time" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/golang/protobuf/proto" +) + +const recvTimeout = 1 + +type proxy struct { + h entity.Crdt_HandleClient + t *testing.T + seq int64 + recvC chan resp + cancelC chan bool +} + +func newProxy(ctx context.Context, s *server) *proxy { + s.t.Helper() + h, err := entity.NewCrdtClient(s.conn).Handle(ctx) + if err != nil { + s.t.Fatal(err) + } + p := &proxy{ + t: s.t, + h: h, + seq: 1, + recvC: make(chan resp), + cancelC: make(chan bool), + } + go func() { + for { + recv, err := p.h.Recv() + select { + case p.recvC <- resp{recv, err}: + case <-p.cancelC: + return + } + } + }() + return p +} + +func (p *proxy) Send(in *entity.CrdtStreamIn) error { + return p.h.Send(in) +} + +func (p *proxy) teardown() { + close(p.cancelC) +} + +type command struct { + c *protocol.Command + m proto.Message +} + +type state struct { + s *entity.CrdtState +} + +type delta struct { + d *entity.CrdtDelta +} + +type delete struct { + d *entity.CrdtDelete +} + +type resp struct { + out *entity.CrdtStreamOut + err error +} + +func (p *proxy) Recv() (*entity.CrdtStreamOut, error) { + select { + case m := <-p.recvC: + return m.out, m.err + case <-time.After(recvTimeout * time.Second): + p.t.Log("no response") + return nil, nil + } +} + +func (p *proxy) init(i *entity.CrdtInit) { + err := p.h.Send(&entity.CrdtStreamIn{ + Message: &entity.CrdtStreamIn_Init{Init: i}, + }) + if err != nil { + p.t.Fatal(err) + } +} + +func (p *proxy) state(m proto.Message) { + switch s := m.(type) { + case *entity.PNCounterState: + p.sendState(state{ + &entity.CrdtState{State: &entity.CrdtState_Pncounter{ + Pncounter: s, + }}, + }) + case *entity.GCounterState: + p.sendState(state{ + &entity.CrdtState{State: &entity.CrdtState_Gcounter{ + Gcounter: s, + }}, + }) + case *entity.FlagState: + p.sendState(state{ + &entity.CrdtState{State: &entity.CrdtState_Flag{ + Flag: s, + }}, + }) + case *entity.VoteState: + p.sendState(state{ + &entity.CrdtState{State: &entity.CrdtState_Vote{ + Vote: s, + }}, + }) + case *entity.ORMapState: + p.sendState(state{ + &entity.CrdtState{State: &entity.CrdtState_Ormap{ + Ormap: s, + }}, + }) + default: + p.t.Fatal("state type not found") + } +} + +func (p *proxy) sendState(st state) { + if err := p.h.Send(stateMsg(st.s)); err != nil { + p.t.Fatal(err) + } +} + +func (p *proxy) sendRecvState(st state) (*entity.CrdtStreamOut, error) { + if err := p.h.Send(stateMsg(st.s)); err != nil { + return nil, err + } + return p.Recv() +} + +func (p *proxy) delta(m proto.Message) { + switch d := m.(type) { + case *entity.PNCounterDelta: + p.sendDelta(delta{ + &entity.CrdtDelta{Delta: &entity.CrdtDelta_Pncounter{ + Pncounter: d, + }}}, + ) + case *entity.GCounterDelta: + p.sendDelta(delta{ + d: &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Gcounter{ + Gcounter: d, + }}}, + ) + case *entity.FlagDelta: + p.sendDelta(delta{ + d: &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Flag{ + Flag: d, + }}}, + ) + case *entity.VoteDelta: + p.sendDelta(delta{ + d: &entity.CrdtDelta{ + Delta: &entity.CrdtDelta_Vote{ + Vote: d, + }}}, + ) + default: + p.t.Fatal("state type not found") + } +} + +func (p *proxy) sendDelta(d delta) { + p.t.Helper() + if err := p.h.Send(deltaMsg(d.d)); err != nil { + p.t.Fatal(err) + } +} + +func (p *proxy) sendDelete(d delete) { + p.t.Helper() + if err := p.h.Send(deleteMsg(d.d)); err != nil { + p.t.Fatal(err) + } +} + +func (p *proxy) sendRecvDelta(d delta) (*entity.CrdtStreamOut, error) { + if err := p.h.Send(deltaMsg(d.d)); err != nil { + return nil, err + } + return p.Recv() +} + +func (p *proxy) command(entityID string, name string, m proto.Message) *entity.CrdtStreamOut { + return p.sendCmdRecvReply(command{ + &protocol.Command{EntityId: entityID, Name: name}, + m, + }) +} + +func (p *proxy) commandStreamed(entityID string, name string, m proto.Message) *entity.CrdtStreamOut { + return p.sendCmdRecvReply(command{ + &protocol.Command{EntityId: entityID, Name: name, Streamed: true}, + m, + }) +} + +func (p *proxy) sendCmdRecvReply(cmd command) *entity.CrdtStreamOut { + p.t.Helper() + if cmd.c.Id == 0 { + cmd.c.Id = p.seq + defer func() { p.seq++ }() + } + any, err := encoding.MarshalAny(cmd.m) + if err != nil { + p.t.Fatal(err) + } + cmd.c.Payload = any + err = p.h.Send(commandMsg(cmd.c)) + if err != nil { + p.t.Fatal(err) + } + msg, err := p.Recv() + if err != nil { + p.t.Fatal(err) + } + if msg == nil { + p.t.Fatal("nothing received") + } + switch msg.Message.(type) { + case *entity.CrdtStreamOut_Failure: + default: + p.checkCommandID(msg) + } + return msg +} + +func (p *proxy) sendCmdRecvErr(cmd command) (*entity.CrdtStreamOut, error) { + p.t.Helper() + if cmd.c.Id == 0 { + cmd.c.Id = p.seq + defer func() { p.seq++ }() + } + any, err := encoding.MarshalAny(cmd.m) + if err != nil { + return nil, err + } + cmd.c.Payload = any + err = p.h.Send(commandMsg(cmd.c)) + if err != nil { + return nil, err + } + recv, err := p.Recv() + if err != nil { + return nil, err + } + if recv == nil { + p.t.Fatal("nothing received") + } + switch recv.Message.(type) { + case *entity.CrdtStreamOut_Failure: + default: + p.checkCommandID(recv) + } + return recv, nil +} + +func commandMsg(c *protocol.Command) *entity.CrdtStreamIn { + return &entity.CrdtStreamIn{ + Message: &entity.CrdtStreamIn_Command{ + Command: c, + }, + } +} + +func stateMsg(s *entity.CrdtState) *entity.CrdtStreamIn { + return &entity.CrdtStreamIn{ + Message: &entity.CrdtStreamIn_State{ + State: s, + }, + } +} + +func deltaMsg(d *entity.CrdtDelta) *entity.CrdtStreamIn { + return &entity.CrdtStreamIn{ + Message: &entity.CrdtStreamIn_Changed{ + Changed: d, + }, + } +} + +func deleteMsg(d *entity.CrdtDelete) *entity.CrdtStreamIn { + return &entity.CrdtStreamIn{ + Message: &entity.CrdtStreamIn_Deleted{ + Deleted: d, + }, + } +} + +func (p *proxy) checkCommandID(msg interface{}) { + p.t.Helper() + switch m := msg.(type) { + case *entity.CrdtStreamOut: + switch out := m.Message.(type) { + case *entity.CrdtStreamOut_Reply: + if got, want := out.Reply.CommandId, p.seq; got != want { + p.t.Fatalf("command = %v; wanted: %d, for message:%+v", got, want, out) + } + case *entity.CrdtStreamOut_Failure: + if got, want := out.Failure.CommandId, p.seq; got != want { + p.t.Fatalf("command = %v; wanted: %d, for message:%+v", got, want, out) + } + case *entity.CrdtStreamOut_StreamedMessage: + if got, want := out.StreamedMessage.CommandId, p.seq; got != want { + p.t.Fatalf("command = %v; wanted: %d, for message:%+v", got, want, out) + } + case *entity.CrdtStreamOut_StreamCancelledResponse: + if got, want := out.StreamCancelledResponse.CommandId, p.seq; got != want { + p.t.Fatalf("command = %v; wanted: %d, for message:%+v", got, want, out) + } + default: + p.t.Fatalf("unexpected message: %+v", m) + } + default: + p.t.Fatalf("unexpected message: %+v", m) + } +} diff --git a/tck/test/crdt/synth/server.go b/tck/test/crdt/synth/server.go new file mode 100644 index 0000000..7b24c10 --- /dev/null +++ b/tck/test/crdt/synth/server.go @@ -0,0 +1,105 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "context" + "log" + "net" + "testing" + + "github.com/cloudstateio/go-support/cloudstate" + "github.com/cloudstateio/go-support/cloudstate/crdt" + "github.com/cloudstateio/go-support/cloudstate/protocol" + crdt2 "github.com/cloudstateio/go-support/tck/crdt" + "google.golang.org/grpc" + "google.golang.org/grpc/test/bufconn" +) + +const serviceName = "crdt.TckCrdt" + +type server struct { + t *testing.T + server *cloudstate.CloudState + conn *grpc.ClientConn + lis *bufconn.Listener + teardownServer func() + teardownClient func() +} + +func newServer(t *testing.T) *server { + t.Helper() + s := server{t: t} + if s.t == nil { + panic("not test context defined") + } + server, err := cloudstate.New(protocol.Config{ + ServiceName: "io.cloudstate.tck.Crdt", // the service name the proxy gets to know about + ServiceVersion: "0.2.0", + }) + if err != nil { + s.t.Fatal(err) + } + s.server = server + err = server.RegisterCRDT( + &crdt.Entity{ + ServiceName: serviceName, // this is the package + service(name) from the gRPC proto file. + EntityFunc: func(id crdt.EntityID) crdt.EntityHandler { + return crdt2.NewEntity(id) + }, + }, + protocol.DescriptorConfig{ + Service: "tck_crdt.proto", // this is needed to find the descriptors with got for the service to be proxied. + }, + ) + if err != nil { + s.t.Fatal(err) + } + s.lis = bufconn.Listen(1024 * 1024) + s.teardownServer = func() { + s.server.Stop() + } + go func() { + if err := server.RunWithListener(s.lis); err != nil { + log.Fatalf("Server exited with error: %v", err) + } + }() + s.newClientConn() + return &s +} + +func (s *server) newClientConn() { + if s.conn != nil && s.teardownClient != nil { + s.teardownClient() + } + // client + ctx := context.Background() + conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { + return s.lis.Dial() + }), grpc.WithInsecure()) + s.conn = conn + if err != nil { + s.t.Fatalf("Failed to dial bufnet: %v", err) + } + s.teardownClient = func() { + s.conn.Close() + } +} + +func (s *server) teardown() { + s.teardownClient() + s.teardownServer() +} diff --git a/tck/test/crdt/synth/tester.go b/tck/test/crdt/synth/tester.go new file mode 100644 index 0000000..40eae78 --- /dev/null +++ b/tck/test/crdt/synth/tester.go @@ -0,0 +1,155 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "reflect" + "testing" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/ptypes/any" +) + +type tester struct { + t *testing.T +} + +func (t *tester) toStruct(x *any.Any, i interface{}) { + t.t.Helper() + if err := encoding.DecodeStruct(x, i); err != nil { + t.t.Fatal(err) + } +} + +func (t *tester) toProto(x *any.Any, p proto.Message) { + t.t.Helper() + if err := encoding.UnmarshalAny(x, p); err != nil { + t.t.Fatal(err) + } +} + +func (t *tester) unexpected(i ...interface{}) { + t.t.Helper() + t.t.Fatalf("got unexpected: %+v", i...) +} + +func (t *tester) expectedInt(got int, want int) { + t.t.Helper() + if got != want { + t.t.Fatalf("got = %v; wanted: %d", got, want) + } +} + +func (t *tester) expectedInt64(got int64, want int64) { + t.t.Helper() + if got != want { + t.t.Fatalf("got = %v; wanted: %d", got, want) + } +} + +func (t *tester) expectedUInt64(got uint64, want uint64) { + t.t.Helper() + if got != want { + t.t.Fatalf("got = %v; wanted: %d", got, want) + } +} + +func (t *tester) expectedUInt32(got uint32, want uint32) { + t.t.Helper() + if got != want { + t.t.Fatalf("got = %v; wanted: %d", got, want) + } +} + +func (t *tester) expectedString(got string, want string) { + t.t.Helper() + if got != want { + t.t.Fatalf("got = %v; wanted: %s", got, want) + } +} + +func (t *tester) expectedNoError(got error) { + t.t.Helper() + if got != nil { + t.t.Fatalf("got = %v; wanted: nil", got) + } +} + +func (t *tester) expectedNil(got interface{}) { + t.t.Helper() + if got == nil { + return + } + if reflect.ValueOf(got).IsNil() { + return + } + t.t.Fatalf("got = %v; wanted: nil", got) +} + +func (t *tester) expectedNotNil(got interface{}) { + t.t.Helper() + if got == nil { + t.t.Fatalf("got = %v; wanted: not nil", got) + } + if reflect.ValueOf(got).IsNil() { + t.t.Fatalf("got = %v; wanted: not nil", got) + } +} + +func (t *tester) expectedBool(got bool, want bool) { + t.t.Helper() + if got != want { + t.t.Fatalf("got = %v; wanted: %v", got, want) + } +} + +func (t *tester) expectedTrue(got bool) { + t.t.Helper() + if !got { + t.t.Fatalf("got = %v; wanted: true", got) + } +} + +func (t *tester) expectedFalse(got bool) { + t.t.Helper() + if got { + t.t.Fatalf("got = %v; wanted: false", got) + } +} + +func (t *tester) expectedSame(x *any.Any, i interface{}) { + t.t.Helper() + if !oneEquals([]*any.Any{x}, i) { + t.t.Fatalf("none of %+v found in %+v", i, x) + } +} + +func (t *tester) expectedOneIn(x []*any.Any, i interface{}) { + t.t.Helper() + if !oneEquals(x, i) { + t.t.Fatalf("none of %+v found in %+v", i, x) + } +} + +func oneEquals(x []*any.Any, i interface{}) bool { + for _, a := range x { + if reflect.DeepEqual(a, i) { + return true + } + } + return false +} diff --git a/tck/test/crdt/synth/vote_model.go b/tck/test/crdt/synth/vote_model.go new file mode 100644 index 0000000..12c3250 --- /dev/null +++ b/tck/test/crdt/synth/vote_model.go @@ -0,0 +1,43 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "github.com/cloudstateio/go-support/tck/crdt" + "github.com/golang/protobuf/proto" +) + +func voteRequest(messages ...proto.Message) *crdt.VoteRequest { + r := &crdt.VoteRequest{ + Actions: make([]*crdt.VoteRequestAction, 0), + } + for _, i := range messages { + switch t := i.(type) { + case *crdt.Get: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.VoteRequestAction{Action: &crdt.VoteRequestAction_Get{Get: t}}) + case *crdt.Delete: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.VoteRequestAction{Action: &crdt.VoteRequestAction_Delete{Delete: t}}) + case *crdt.VoteVote: + r.Id = t.Key + r.Actions = append(r.Actions, &crdt.VoteRequestAction{Action: &crdt.VoteRequestAction_Vote{Vote: t}}) + default: + panic("no type matched") + } + } + return r +} diff --git a/tck/test/crdt/synth/vote_test.go b/tck/test/crdt/synth/vote_test.go new file mode 100644 index 0000000..20f9a21 --- /dev/null +++ b/tck/test/crdt/synth/vote_test.go @@ -0,0 +1,158 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package synth + +import ( + "context" + "testing" + "time" + + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/tck/crdt" +) + +func TestCRDTVote(t *testing.T) { + s := newServer(t) + defer s.teardown() + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + t.Run("Vote", func(t *testing.T) { + entityID := "vote-1" + command := "ProcessVote" + p := newProxy(ctx, s) + defer p.teardown() + + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + t.Run("Get emits client action", func(t *testing.T) { + tr := tester{t} + switch m := p.command(entityID, command, + voteRequest(&crdt.Get{}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetClientAction().GetFailure()) + tr.expectedNil(m.Reply.GetStateAction().GetCreate()) + var r crdt.VoteResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedFalse(r.SelfVote) + default: + tr.unexpected(m) + } + }) + t.Run("Vote emits client and state action", func(t *testing.T) { + tr := tester{t} + switch m := p.command(entityID, command, + voteRequest(&crdt.VoteVote{Value: true}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetClientAction().GetFailure()) + var r crdt.VoteResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedTrue(r.SelfVote) + tr.expectedUInt32(r.VotesFor, 1) + tr.expectedUInt32(r.Voters, 1) + // state + tr.expectedNotNil(m.Reply.GetStateAction().GetCreate()) + tr.expectedTrue(m.Reply.GetStateAction().GetCreate().GetVote().GetSelfVote()) + tr.expectedUInt32(m.Reply.GetStateAction().GetCreate().GetVote().GetVotesFor(), 1) + tr.expectedUInt32(m.Reply.GetStateAction().GetCreate().GetVote().GetTotalVoters(), 1) + default: + tr.unexpected(m) + } + + switch m := p.command(entityID, command, + voteRequest(&crdt.VoteVote{Value: false}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + var r crdt.VoteResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedFalse(r.SelfVote) + tr.expectedUInt32(r.VotesFor, 0) + tr.expectedUInt32(r.Voters, 1) + // state + tr.expectedNotNil(m.Reply.GetStateAction().GetUpdate()) + tr.expectedFalse(m.Reply.GetStateAction().GetUpdate().GetVote().GetSelfVote()) + tr.expectedUInt32(uint32(m.Reply.GetStateAction().GetUpdate().GetVote().GetVotesFor()), 0) + tr.expectedUInt32(uint32(m.Reply.GetStateAction().GetUpdate().GetVote().GetTotalVoters()), 1) + default: + tr.unexpected(m) + } + }) + t.Run("VoteState", func(t *testing.T) { + tr := tester{t} + p.state(&entity.VoteState{ + TotalVoters: 6, + VotesFor: 3, + SelfVote: true, + }) + switch m := p.command(entityID, command, + voteRequest(&crdt.Get{}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetStateAction()) + tr.expectedNotNil(m.Reply.GetClientAction().GetReply()) + var r crdt.VoteResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedTrue(r.SelfVote) + tr.expectedUInt32(r.Voters, 6) + tr.expectedUInt32(r.VotesFor, 3) + default: + tr.unexpected(m) + } + }) + }) + t.Run("VoteState", func(t *testing.T) { + entityID := "vote-1" + command := "ProcessVote" + p := newProxy(ctx, s) + defer p.teardown() + tr := tester{t} + + p.init(&entity.CrdtInit{ServiceName: serviceName, EntityId: entityID}) + p.command(entityID, command, + voteRequest(&crdt.VoteVote{Value: true}), + ) + p.delta(&entity.VoteDelta{ + TotalVoters: 7, + VotesFor: 3, + SelfVote: false, + }) + switch m := p.command(entityID, command, + voteRequest(&crdt.Get{}), + ).Message.(type) { + case *entity.CrdtStreamOut_Reply: + // action reply + tr.expectedNil(m.Reply.GetSideEffects()) + tr.expectedNil(m.Reply.GetStateAction()) + tr.expectedNotNil(m.Reply.GetClientAction().GetReply()) + var r crdt.VoteResponse + tr.toProto(m.Reply.GetClientAction().GetReply().GetPayload(), &r) + tr.expectedTrue(r.SelfVote) // Delta does not affect self vote! + tr.expectedUInt32(r.Voters, 7) + tr.expectedUInt32(r.VotesFor, 3) + default: + tr.unexpected(m) + } + }) +} diff --git a/tck/test/eventsourced/eventsourced_test.go b/tck/test/eventsourced/eventsourced_test.go new file mode 100644 index 0000000..248206e --- /dev/null +++ b/tck/test/eventsourced/eventsourced_test.go @@ -0,0 +1,611 @@ +// +// Copyright 2019 Lightbend Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package eventsourced + +import ( + "context" + "errors" + "io" + "testing" + "time" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/cloudstateio/go-support/example/shoppingcart" + domain "github.com/cloudstateio/go-support/example/shoppingcart/persistence" +) + +const serviceName = "com.example.shoppingcart.ShoppingCart" + +func TestEventsourcingShoppingCart(t *testing.T) { + s := newServer(t) + s.newClientConn() + defer s.teardown() + + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + edc := protocol.NewEntityDiscoveryClient(s.conn) + discover, err := edc.Discover(ctx, &protocol.ProxyInfo{ + ProtocolMajorVersion: 0, + ProtocolMinorVersion: 0, + ProxyName: "a-cs-proxy", + ProxyVersion: "0.0.0", + SupportedEntityTypes: []string{protocol.EventSourced, protocol.CRDT}, + }) + if err != nil { + t.Fatal(err) + } + // discovery + if l := len(discover.GetEntities()); l != 1 { + t.Fatalf("discover.Entities is:%d, should be: 1", l) + } + s.serviceName = discover.GetEntities()[0].GetServiceName() + t.Run("entity discovery should find the shopping cart service", func(t *testing.T) { + if s.serviceName != serviceName { + t.Fatalf("discover.Entities[0].ServiceName is:%v, should be: %s", s.serviceName, serviceName) + } + }) + + t.Run("calling GetShoppingCart should fail without an init message", func(t *testing.T) { + p := newProxy(ctx, s) + r := p.sendRecvCmd(command{ + c: &protocol.Command{EntityId: "e1", Name: "GetShoppingCart"}, + m: &shoppingcart.GetShoppingCart{UserId: "user1"}, + }) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Failure: + case *entity.EventSourcedStreamOut_Reply: + t.Fatal("a message should not be allowed to be received without a init message sent before") + default: + t.Fatalf("unexpected message: %+v", m) + } + }) + + t.Run("calling GetShoppingCart with an init message should succeed", func(t *testing.T) { + p := newProxy(ctx, s) + p.sendInit(&entity.EventSourcedInit{ + ServiceName: s.serviceName, + EntityId: "e2", + }) + r := p.sendRecvCmd(command{ + c: &protocol.Command{EntityId: "e2", Name: "GetShoppingCart"}, + m: &shoppingcart.GetShoppingCart{UserId: "user2"}, + }) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + case *entity.EventSourcedStreamOut_Failure: + t.Fatalf("expected reply but got: %+v", m.Failure) + default: + t.Fatalf("unexpected message: %+v", m) + } + }) + + t.Run("after added line items, the cart should return the same lines added", func(t *testing.T) { + p := newProxy(ctx, s) + p.sendInit(&entity.EventSourcedInit{ + ServiceName: s.serviceName, + EntityId: "e3", + }) + // add line item + addLineItem := &shoppingcart.AddLineItem{ + UserId: "user1", ProductId: "e-bike-1", Name: "e-Bike", Quantity: 2, + } + r := p.sendRecvCmd(command{ + c: &protocol.Command{EntityId: "e3", Name: "AddLineItem"}, + m: addLineItem, + }) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + t.Run("the reply should have events", func(t *testing.T) { + events := m.Reply.GetEvents() + if got, want := len(events), 1; got != want { + t.Fatalf("len(events) = %d; want %d", got, want) + } + itemAdded := &domain.ItemAdded{} + err := encoding.UnmarshalAny(events[0], itemAdded) + if err != nil { + t.Fatal(err) + } + if got, want := itemAdded.Item.ProductId, addLineItem.ProductId; got != want { + t.Fatalf("itemAdded.Item.ProductId = %s; want; %s", got, want) + } + if got, want := itemAdded.Item.Name, addLineItem.Name; got != want { + t.Fatalf("itemAdded.Item.Name = %s; want; %s", got, want) + } + if got, want := itemAdded.Item.Quantity, addLineItem.Quantity; got != want { + t.Fatalf("itemAdded.Item.Quantity = %d; want; %d", got, want) + } + }) + t.Run("the reply should have a snapshot", func(t *testing.T) { + snapshot := m.Reply.GetSnapshot() + if snapshot == nil { + t.Fatalf("snapshot was nil but should not") + } + cart := &domain.Cart{} + err := encoding.UnmarshalAny(snapshot, cart) + if err != nil { + t.Fatal(err) + } + if got, want := len(cart.Items), 1; got != want { + t.Fatalf("len(cart.Items) = %d; want: %d", got, want) + } + item := cart.Items[0] + if got, want := item.ProductId, addLineItem.ProductId; got != want { + t.Fatalf("itemAdded.Item.ProductId = %s; want; %s", got, want) + } + if got, want := item.Name, addLineItem.Name; got != want { + t.Fatalf("itemAdded.Item.Name = %s; want; %s", got, want) + } + if got, want := item.Quantity, addLineItem.Quantity; got != want { + t.Fatalf("itemAdded.Item.Quantity = %d; want; %d", got, want) + } + }) + case *entity.EventSourcedStreamOut_Failure: + p.checkCommandID(m) + t.Fatalf("expected reply but got: %+v", m.Failure) + default: + t.Fatalf("unexpected message: %+v", m) + } + // get the shopping cart + r = p.sendRecvCmd(command{ + c: &protocol.Command{EntityId: "e3", Name: "GetShoppingCart"}, + m: &shoppingcart.GetShoppingCart{UserId: "user1"}, + }) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + payload := m.Reply.GetClientAction().GetReply().GetPayload() + cart := &shoppingcart.Cart{} + if err := encoding.UnmarshalAny(payload, cart); err != nil { + t.Fatal(err) + } + if l := len(cart.Items); l != 1 { + t.Fatalf("len(cart.Items) is: %d, but should be 1", l) + } + li, ai := cart.Items[0], addLineItem + if got, want := li.Quantity, ai.Quantity; got != want { + t.Fatalf("Quantity = %d; want: %d", got, want) + } + if got, want := li.Name, ai.Name; got != want { + t.Fatalf("Name = %s; want: %s", got, want) + } + if got, want := li.ProductId, ai.ProductId; got != want { + t.Fatalf("ProductId = %s; want: %s", got, want) + } + case *entity.EventSourcedStreamOut_Failure: + t.Fatalf("expected reply but got: %+v", m.Failure) + default: + t.Fatalf("unexpected message: %+v", m) + } + }) + + t.Run("the entity should have consistent state after a context failure", func(t *testing.T) { + p := newProxy(ctx, s) + p.sendInit(&entity.EventSourcedInit{ + ServiceName: s.serviceName, + EntityId: "e3", + }) + // add line item + addLineItem := &shoppingcart.AddLineItem{UserId: "user1", ProductId: "e-bike-1", Name: "e-Bike", Quantity: 2} + r := p.sendRecvCmd(command{ + c: &protocol.Command{EntityId: "e3", Name: "AddLineItem"}, + m: addLineItem, + }) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + case *entity.EventSourcedStreamOut_Failure: + p.checkCommandID(m) + t.Fatalf("expected reply but got: %+v", m.Failure) + default: + t.Fatalf("unexpected message: %+v", m) + } + + // add BOOM line item + r = p.sendRecvCmd(command{ + c: &protocol.Command{EntityId: "e3", Name: "AddLineItem"}, + m: &shoppingcart.AddLineItem{UserId: "user1", ProductId: "e-bike-1", Name: "FAIL", Quantity: 4}, + }) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + t.Fatalf("expected failure but got: %+v", m.Reply) + case *entity.EventSourcedStreamOut_Failure: + p.checkCommandID(m) + default: + t.Fatalf("unexpected message: %+v", m) + } + // get the shopping cart + _, err = p.sendRecvCmdErr(command{ + c: &protocol.Command{ + EntityId: "e2", + Name: "GetShoppingCart", + }, + m: &shoppingcart.GetShoppingCart{UserId: "user1"}, + }) + if err == nil { + t.Fatal(errors.New("expected error")) + } + if err != io.EOF { + t.Fatal(errors.New("expected io.EOF error")) + } + }) + + t.Run("an init message with an initial snapshot should initialise an entity", func(t *testing.T) { + p := newProxy(ctx, s) + cart := &domain.Cart{Items: make([]*domain.LineItem, 0)} + cart.Items = append(cart.Items, &domain.LineItem{ + ProductId: "e-bike-2", Name: "Cross", Quantity: 3, + }) + cart.Items = append(cart.Items, &domain.LineItem{ + ProductId: "e-bike-3", Name: "Cross TWO", Quantity: 1, + }) + cart.Items = append(cart.Items, &domain.LineItem{ + ProductId: "e-bike-4", Name: "City", Quantity: 5, + }) + any, err := encoding.MarshalAny(cart) + if err != nil { + t.Fatal(err) + } + p.sendInit(&entity.EventSourcedInit{ + ServiceName: s.serviceName, + EntityId: "e9", + Snapshot: &entity.EventSourcedSnapshot{ + SnapshotSequence: 0, + Snapshot: any, + }, + }) + r := p.sendRecvCmd(command{ + c: &protocol.Command{ + EntityId: "e9", + Name: "GetShoppingCart", + }, + m: &shoppingcart.GetShoppingCart{UserId: "user1"}, + }) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Failure: + t.Fatalf("expected reply but got: %+v", m.Failure) + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + reply := &domain.Cart{} + err := encoding.UnmarshalAny(m.Reply.GetClientAction().GetReply().GetPayload(), reply) + if err != nil { + t.Fatal(err) + } + if l := len(reply.Items); l != 3 { + t.Fatalf("len(cart.Items) is: %d, but should be 1", l) + } + for i := 0; i < len(reply.Items); i++ { + li := reply.Items[i] + ci := cart.Items[i] + if got, want := li.Quantity, ci.Quantity; got != want { + t.Fatalf("Quantity = %d; want: %d", got, want) + } + if got, want := li.Name, ci.Name; got != want { + t.Fatalf("Name = %s; want: %s", got, want) + } + if got, want := li.ProductId, ci.ProductId; got != want { + t.Fatalf("ProductId = %s; want: %s", got, want) + } + } + default: + t.Fatalf("unexpected message: %+v", m) + } + }) + + t.Run("an initialised entity with an event sent should return its applied state", func(t *testing.T) { + p := newProxy(ctx, s) + // init + p.sendInit(&entity.EventSourcedInit{ + ServiceName: s.serviceName, + EntityId: "e20", + }) + // send an event + lineItem := &domain.LineItem{ProductId: "e-bike-100", Name: "AMP 100", Quantity: 1} + event, err := encoding.MarshalAny(&domain.ItemAdded{Item: lineItem}) + if err != nil { + t.Fatal(err) + } + p.sendEvent(&entity.EventSourcedEvent{Sequence: 0, Payload: event}) + r := p.sendRecvCmd(command{ + &protocol.Command{EntityId: "e20", Name: "GetShoppingCart"}, + &shoppingcart.GetShoppingCart{UserId: "user1"}, + }) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + cart := &shoppingcart.Cart{} + if err := encoding.UnmarshalAny(m.Reply.GetClientAction().GetReply().GetPayload(), cart); err != nil { + t.Fatal(err) + } + if l := len(cart.Items); l != 1 { + t.Fatalf("len(cart.Items) is: %d, but should be 1", l) + } + li := cart.Items[0] + if got, want := li.Quantity, lineItem.Quantity; got != want { + t.Fatalf("Quantity = %d; want: %d", got, want) + } + if got, want := li.Name, lineItem.Name; got != want { + t.Fatalf("Name = %s; want: %s", got, want) + } + if got, want := li.ProductId, lineItem.ProductId; got != want { + t.Fatalf("ProductId = %s; want: %s", got, want) + } + case *entity.EventSourcedStreamOut_Failure: + t.Fatalf("expected reply but got: %+v", m.Failure) + default: + t.Fatalf("unexpected message: %+v", m) + } + }) + + t.Run("adding negative quantity should fail, and leave the entity in a conistent state", func(t *testing.T) { + p := newProxy(ctx, s) + entityID := "e23" + userID := "user1" + p.sendInit(&entity.EventSourcedInit{ + ServiceName: s.serviceName, + EntityId: entityID, + }) + // add line item + add := []command{ + { + &protocol.Command{EntityId: entityID, Name: "AddLineItem"}, + &shoppingcart.AddLineItem{UserId: userID, ProductId: "e-bike-1", Name: "e-Bike", Quantity: 1}, + }, + { + &protocol.Command{EntityId: entityID, Name: "AddLineItem"}, + &shoppingcart.AddLineItem{UserId: userID, ProductId: "e-bike-2", Name: "e-Bike 2", Quantity: 2}, + }, + { + &protocol.Command{EntityId: entityID, Name: "AddLineItem"}, + &shoppingcart.AddLineItem{UserId: userID, ProductId: "e-bike-2", Name: "e-Bike 2", Quantity: -1}, + }, + } + for i, cmd := range add { + r := p.sendRecvCmd(cmd) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + if i < 2 && m.Reply.ClientAction.GetFailure() != nil { + t.Fatalf("unexpected ClientAction failure: %+v", m) + } + if i == 2 && m.Reply.ClientAction.GetFailure() == nil { + t.Fatalf("expected ClientAction failure: %+v", m) + } + case *entity.EventSourcedStreamOut_Failure: + p.checkCommandID(m) + t.Fatalf("expected reply but got: %+v", m.Failure) + default: + t.Fatalf("unexpected message: %+v", m) + } + } + // get the shopping chart + r := p.sendRecvCmd(command{ + &protocol.Command{EntityId: entityID, Name: "GetShoppingCart"}, + &shoppingcart.GetShoppingCart{UserId: userID}, + }) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + cart := &shoppingcart.Cart{} + if err := encoding.UnmarshalAny(m.Reply.GetClientAction().GetReply().GetPayload(), cart); err != nil { + t.Fatal(err) + } + if got, want := len(cart.Items), 2; got != want { + t.Fatalf("len(cart.Items) is: %d; want: %d", got, want) + } + for _, i := range cart.Items { + if i.ProductId == "e-bike-2" && i.Quantity != 2 { + t.Fatal("cart is in an inconsistent state after an emit-fail sequence") + } + } + // li := cart.Items[0] + // if got, want := li.Quantity, lineItem.Quantity; got != want { + // t.Fatalf("Quantity = %d; want: %d", got, want) + // } + // if got, want := li.Name, lineItem.Name; got != want { + // t.Fatalf("Name = %s; want: %s", got, want) + // } + // if got, want := li.ProductId, lineItem.ProductId; got != want { + // t.Fatalf("ProductId = %s; want: %s", got, want) + // } + case *entity.EventSourcedStreamOut_Failure: + t.Fatalf("expected reply but got: %+v", m.Failure) + default: + t.Fatalf("unexpected message: %+v", m) + } + }) + + t.Run("removing a non existent item should fail", func(t *testing.T) { + p := newProxy(ctx, s) + entityID := "e24" + p.sendInit(&entity.EventSourcedInit{ServiceName: s.serviceName, EntityId: entityID}) + // add line item + add := []command{ + { + &protocol.Command{EntityId: entityID, Name: "AddLineItem"}, + &shoppingcart.AddLineItem{UserId: "user1", ProductId: "e-bike-1", Name: "e-Bike", Quantity: 1}, + }, + { + &protocol.Command{EntityId: entityID, Name: "AddLineItem"}, + &shoppingcart.AddLineItem{UserId: "user1", ProductId: "e-bike-2", Name: "e-Bike 2", Quantity: 2}, + }, + { + &protocol.Command{EntityId: entityID, Name: "RemoveLineItem"}, + &shoppingcart.RemoveLineItem{UserId: "user1", ProductId: "e-bike-1"}, + }, + { + &protocol.Command{EntityId: entityID, Name: "RemoveLineItem"}, + &shoppingcart.RemoveLineItem{UserId: "user1", ProductId: "e-bike-1"}, + }, + } + for i, cmd := range add { + r := p.sendRecvCmd(cmd) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + if i <= 2 && m.Reply.ClientAction.GetFailure() != nil { + t.Fatalf("unexpected ClientAction failure: %+v", m) + } + if i == 3 && m.Reply.ClientAction.GetFailure() == nil { + t.Fatalf("expected ClientAction failure: %+v", m) + } + case *entity.EventSourcedStreamOut_Failure: + p.checkCommandID(m) + t.Fatalf("expected reply but got: %+v", m.Failure) + default: + t.Fatalf("unexpected message: %+v", m) + } + } + }) + + t.Run("adding and removing line items should result in a consistent state", func(t *testing.T) { + p := newProxy(ctx, s) + entityID := "e22" + p.sendInit(&entity.EventSourcedInit{ServiceName: s.serviceName, EntityId: entityID}) + // add line item + add := []command{ + { + &protocol.Command{EntityId: entityID, Name: "AddLineItem"}, + &shoppingcart.AddLineItem{UserId: "user1", ProductId: "e-bike-1", Name: "e-Bike", Quantity: 1}, + }, + { + &protocol.Command{EntityId: entityID, Name: "AddLineItem"}, + &shoppingcart.AddLineItem{UserId: "user1", ProductId: "e-bike-2", Name: "e-Bike 2", Quantity: 2}, + }, + { + &protocol.Command{EntityId: entityID, Name: "AddLineItem"}, + &shoppingcart.AddLineItem{UserId: "user1", ProductId: "e-bike-3", Name: "e-Bike 3", Quantity: 3}, + }, + { + &protocol.Command{EntityId: entityID, Name: "AddLineItem"}, + &shoppingcart.AddLineItem{UserId: "user1", ProductId: "e-bike-3", Name: "e-Bike 3", Quantity: 4}, + }, + } + for _, cmd := range add { + r := p.sendRecvCmd(cmd) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + if m.Reply.ClientAction.GetFailure() != nil { + t.Fatalf("unexpected ClientAction failure: %+v", m) + } + case *entity.EventSourcedStreamOut_Failure: + p.checkCommandID(m) + t.Fatalf("expected reply but got: %+v", m.Failure) + default: + t.Fatalf("unexpected message: %+v", m) + } + } + // get the shopping cart + r := p.sendRecvCmd(command{ + &protocol.Command{ + EntityId: entityID, + Name: "GetShoppingCart", + }, + &shoppingcart.GetShoppingCart{UserId: "user1"}, + }) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + payload := m.Reply.GetClientAction().GetReply().GetPayload() + cart := &shoppingcart.Cart{} + if err := encoding.UnmarshalAny(payload, cart); err != nil { + t.Fatal(err) + } + if got, want := len(cart.Items), 3; got != want { + t.Fatalf("len(cart.Items) = %d; want: %d ", got, want) + } + eBike3Count := int32(0) + for _, c := range cart.Items { + if c.ProductId == "e-bike-3" { + eBike3Count += c.Quantity + } + } + if got, want := eBike3Count, int32(7); got != want { + t.Fatalf("eBike3Count = %d; want: %d ", got, want) + } + case *entity.EventSourcedStreamOut_Failure: + t.Fatalf("expected reply but got: %+v", m.Failure) + default: + t.Fatalf("unexpected message: %+v", m) + } + // remove item + remove := []command{ + { + &protocol.Command{EntityId: entityID, Name: "RemoveLineItem"}, + &shoppingcart.RemoveLineItem{UserId: "user1", ProductId: "e-bike-1"}, + }, + { + &protocol.Command{EntityId: entityID, Name: "RemoveLineItem"}, + &shoppingcart.RemoveLineItem{UserId: "user1", ProductId: "e-bike-2"}, + }, + { + &protocol.Command{EntityId: entityID, Name: "RemoveLineItem"}, + &shoppingcart.RemoveLineItem{UserId: "user1", ProductId: "e-bike-3"}, + }, + } + for _, cmd := range remove { + r := p.sendRecvCmd(cmd) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + if m.Reply.ClientAction.GetFailure() != nil { + t.Fatalf("unexpected ClientAction failure: %+v", m) + } + case *entity.EventSourcedStreamOut_Failure: + p.checkCommandID(m) + t.Fatalf("expected reply but got: %+v", m.Failure) + default: + t.Fatalf("unexpected message: %+v", m) + } + } + // get the shopping cart + r = p.sendRecvCmd(command{ + &protocol.Command{EntityId: entityID, Name: "GetShoppingCart"}, + &shoppingcart.GetShoppingCart{UserId: "user1"}, + }) + switch m := r.Message.(type) { + case *entity.EventSourcedStreamOut_Reply: + p.checkCommandID(m) + payload := m.Reply.GetClientAction().GetReply().GetPayload() + cart := &shoppingcart.Cart{} + if err := encoding.UnmarshalAny(payload, cart); err != nil { + t.Fatal(err) + } + if got, want := len(cart.Items), 0; got != want { + t.Fatalf("len(cart.Items) = %d; want: %d ", got, want) + } + case *entity.EventSourcedStreamOut_Failure: + t.Fatalf("expected reply but got: %+v", m.Failure) + default: + t.Fatalf("unexpected message: %+v", m) + } + }) + + t.Run("send the User Function an error message", func(t *testing.T) { + reportError, err := edc.ReportError(ctx, &protocol.UserFunctionError{Message: "an error occured"}) + if err != nil { + t.Fatal(err) + } + if reportError == nil { + t.Fatalf("reportError was nil") + } + }) +} diff --git a/tck/test/eventsourced/proxy.go b/tck/test/eventsourced/proxy.go new file mode 100644 index 0000000..93aea6d --- /dev/null +++ b/tck/test/eventsourced/proxy.go @@ -0,0 +1,125 @@ +package eventsourced + +import ( + "context" + "testing" + + "github.com/cloudstateio/go-support/cloudstate/encoding" + "github.com/cloudstateio/go-support/cloudstate/entity" + "github.com/cloudstateio/go-support/cloudstate/protocol" + "github.com/golang/protobuf/proto" +) + +type command struct { + c *protocol.Command + m proto.Message +} + +type proxy struct { + h entity.EventSourced_HandleClient + t *testing.T + seq int64 +} + +func newProxy(ctx context.Context, s *server) *proxy { + s.t.Helper() + h, err := entity.NewEventSourcedClient(s.conn).Handle(ctx) + if err != nil { + s.t.Fatal(err) + } + return &proxy{t: s.t, h: h, seq: 1} +} + +func (p *proxy) checkCommandID(m interface{}) { + p.t.Helper() + switch m := m.(type) { + case *entity.EventSourcedStreamOut_Reply: + if got, want := m.Reply.CommandId, p.seq; got != want { + p.t.Fatalf("got command id: %d; want: %d", got, want) + } + case *entity.EventSourcedStreamOut_Failure: + if got, want := m.Failure.CommandId, p.seq; got != want { + p.t.Fatalf("got command id: %d; want: %d", got, want) + } + default: + p.t.Fatalf("unexpected message: %+v", m) + } +} + +func (p *proxy) sendRecvCmd(cmd command) *entity.EventSourcedStreamOut { + p.t.Helper() + if cmd.c.Id == 0 { + p.seq++ + cmd.c.Id = p.seq + } + any, err := encoding.MarshalAny(cmd.m) + if err != nil { + p.t.Fatal(err) + } + cmd.c.Payload = any + err = p.h.Send(commandMsg(cmd.c)) + if err != nil { + p.t.Fatal(err) + } + recv, err := p.h.Recv() + if err != nil { + p.t.Fatal(err) + } + return recv +} + +func (p *proxy) sendRecvCmdErr(cmd command) (*entity.EventSourcedStreamOut, error) { + p.t.Helper() + if cmd.c.Id == 0 { + p.seq++ + cmd.c.Id = p.seq + } + any, err := encoding.MarshalAny(cmd.m) + if err != nil { + return nil, err + } + cmd.c.Payload = any + err = p.h.Send(commandMsg(cmd.c)) + if err != nil { + return nil, err + } + return p.h.Recv() +} + +func (p *proxy) sendInit(init *entity.EventSourcedInit) { + p.t.Helper() + if err := p.h.Send(initMsg(init)); err != nil { + p.t.Fatal(err) + } +} + +func (p *proxy) sendEvent(e *entity.EventSourcedEvent) { + err := p.h.Send(eventMsg(e)) + if err != nil { + p.t.Fatal(err) + } +} + +func eventMsg(e *entity.EventSourcedEvent) *entity.EventSourcedStreamIn { + return &entity.EventSourcedStreamIn{ + Message: &entity.EventSourcedStreamIn_Event{ + Event: e, + }, + } +} + +func initMsg(i *entity.EventSourcedInit) *entity.EventSourcedStreamIn { + return &entity.EventSourcedStreamIn{ + Message: &entity.EventSourcedStreamIn_Init{ + Init: i, + }, + } +} + +func commandMsg(c *protocol.Command) *entity.EventSourcedStreamIn { + return &entity.EventSourcedStreamIn{ + Message: &entity.EventSourcedStreamIn_Command{ + Command: c, + }, + } +} diff --git a/tck/test/eventsourced/server.go b/tck/test/eventsourced/server.go new file mode 100644 index 0000000..867cdfa --- /dev/null +++ b/tck/test/eventsourced/server.go @@ -0,0 +1,86 @@ +package eventsourced + +import ( + "context" + "log" + "net" + "testing" + + "github.com/cloudstateio/go-support/cloudstate" + "github.com/cloudstateio/go-support/cloudstate/eventsourced" + "github.com/cloudstateio/go-support/cloudstate/protocol" + shoppingcart2 "github.com/cloudstateio/go-support/example/shoppingcart" + "google.golang.org/grpc" + "google.golang.org/grpc/test/bufconn" +) + +type server struct { + t *testing.T + server *cloudstate.CloudState + conn *grpc.ClientConn + lis *bufconn.Listener + teardownServer func() + teardownClient func() + serviceName string +} + +func newServer(t *testing.T) *server { + t.Helper() + s := server{t: t} + if s.t == nil { + panic("not test context defined") + } + s.t.Helper() + server, err := cloudstate.New(protocol.Config{ + ServiceName: "shopping-cart", + ServiceVersion: "9.9.8", + }) + if err != nil { + s.t.Fatal(err) + } + s.server = server + err = server.RegisterEventSourced(&eventsourced.Entity{ + ServiceName: "com.example.shoppingcart.ShoppingCart", + PersistenceID: "ShoppingCart", + EntityFunc: shoppingcart2.NewShoppingCart, + SnapshotEvery: 1, + }, protocol.DescriptorConfig{ + Service: "shoppingcart.proto", + }.AddDomainDescriptor("domain.proto")) + if err != nil { + s.t.Fatal(err) + } + s.lis = bufconn.Listen(1024 * 1024) + s.teardownServer = func() { + s.server.Stop() + } + go func() { + if err := server.RunWithListener(s.lis); err != nil { + log.Fatalf("Server exited with error: %v", err) + } + }() + return &s +} + +func (s *server) newClientConn() { + if s.conn != nil && s.teardownClient != nil { + s.teardownClient() + } + // client + ctx := context.Background() + conn, err := grpc.DialContext(ctx, "bufnet", grpc.WithContextDialer(func(context.Context, string) (net.Conn, error) { + return s.lis.Dial() + }), grpc.WithInsecure()) + s.conn = conn + if err != nil { + s.t.Fatalf("Failed to dial bufnet: %v", err) + } + s.teardownClient = func() { + s.conn.Close() + } +} + +func (s *server) teardown() { + s.teardownClient() + s.teardownServer() +}