├── go.work ├── go.mod ├── examples ├── go.mod ├── go.sum ├── protos │ └── user_example.proto ├── main.go ├── logic │ └── user.go └── actors │ └── user_example.pb.go ├── spawn ├── protos │ ├── eigr │ │ └── functions │ │ │ └── protocol │ │ │ └── actors │ │ │ ├── extensions.proto │ │ │ ├── state.proto │ │ │ ├── actor.proto │ │ │ └── protocol.proto │ ├── google │ │ ├── api │ │ │ ├── annotations.proto │ │ │ └── http.proto │ │ └── protobuf │ │ │ ├── source_context.proto │ │ │ ├── empty.proto │ │ │ ├── struct.proto │ │ │ ├── wrappers.proto │ │ │ ├── duration.proto │ │ │ ├── any.proto │ │ │ ├── timestamp.proto │ │ │ ├── type.proto │ │ │ ├── api.proto │ │ │ └── field_mask.proto │ └── grpc │ │ └── reflection │ │ └── v1alpha │ │ └── reflection.proto ├── go.mod ├── go.sum ├── actors │ ├── types.go │ └── actor.go ├── eigr │ └── functions │ │ └── protocol │ │ └── actors │ │ ├── extensions.pb.go │ │ └── state.pb.go └── system │ └── system.go ├── .gitignore ├── .github └── workflows │ └── go.yml ├── go.work.sum ├── Dockerfile ├── documentation └── actors.md ├── Makefile ├── CODE_OF_CONDUCT.md ├── README.md └── LICENSE /go.work: -------------------------------------------------------------------------------- 1 | go 1.23 2 | 3 | use ( 4 | ./spawn 5 | ./examples 6 | ) 7 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/eigr/spawn-go-sdk 2 | 3 | go 1.23 4 | 5 | replace github.com/eigr/spawn-go-sdk/spawn => ./spawn 6 | 7 | replace spawn/eigr/functions/protocol/actors => ./spawn/eigr/functions/protocol/actors 8 | -------------------------------------------------------------------------------- /examples/go.mod: -------------------------------------------------------------------------------- 1 | module examples 2 | 3 | go 1.23 4 | 5 | toolchain go1.23.0 6 | 7 | require ( 8 | github.com/eigr/spawn-go-sdk/spawn v0.1.0 9 | google.golang.org/protobuf v1.35.2 10 | ) 11 | 12 | replace github.com/eigr/spawn-go-sdk/spawn => ../spawn 13 | -------------------------------------------------------------------------------- /spawn/protos/eigr/functions/protocol/actors/extensions.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package eigr.functions.protocol.actors; 4 | 5 | import "google/protobuf/descriptor.proto"; 6 | 7 | option go_package = "spawn/eigr/functions/protocol/actors"; 8 | 9 | extend google.protobuf.FieldOptions { 10 | bool actor_id = 9999; 11 | } 12 | -------------------------------------------------------------------------------- /spawn/go.mod: -------------------------------------------------------------------------------- 1 | module "github.com/eigr/spawn-go-sdk" 2 | 3 | go 1.23 4 | 5 | toolchain go1.23.0 6 | 7 | require ( 8 | google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 9 | google.golang.org/protobuf v1.35.2 10 | ) 11 | 12 | replace spawn/eigr/functions/protocol/actors => ./eigr/functions/protocol/actors 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | # Ignore all the binaries 18 | bin/* 19 | -------------------------------------------------------------------------------- /.github/workflows/go.yml: -------------------------------------------------------------------------------- 1 | name: Go Build 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | jobs: 10 | 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Set up Go 17 | uses: actions/setup-go@v4 18 | with: 19 | go-version: '1.23' 20 | 21 | - name: Build 22 | run: make build 23 | -------------------------------------------------------------------------------- /go.work.sum: -------------------------------------------------------------------------------- 1 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 2 | golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= 3 | golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 4 | golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 5 | google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= 6 | google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= 7 | -------------------------------------------------------------------------------- /examples/go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 2 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 3 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 4 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 5 | google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= 6 | google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 7 | -------------------------------------------------------------------------------- /examples/protos/user_example.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package examples.actors; 4 | 5 | option go_package = "examples/actors"; 6 | 7 | message UserState { 8 | string name = 1; 9 | } 10 | 11 | message ChangeUserNamePayload { 12 | string new_name = 1; 13 | } 14 | 15 | message ChangeUserNameResponse { 16 | // this is a bad example, but it's just an example 17 | enum ResponseStatus { 18 | OK = 0; 19 | ERROR = 1; 20 | } 21 | ResponseStatus response_status = 1; 22 | } 23 | 24 | service UserActor { 25 | rpc ChangeUserName(ChangeUserNamePayload) returns (ChangeUserNameResponse) {} 26 | } -------------------------------------------------------------------------------- /spawn/go.sum: -------------------------------------------------------------------------------- 1 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 2 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 3 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 4 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 5 | google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576 h1:CkkIfIt50+lT6NHAVoRYEyAvQGFM7xEwXUUywFvEb3Q= 6 | google.golang.org/genproto/googleapis/api v0.0.0-20241209162323-e6fa225c2576/go.mod h1:1R3kvZ1dtP3+4p4d3G8uJ8rFk/fWlScl38vanWACI08= 7 | google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io= 8 | google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= 9 | -------------------------------------------------------------------------------- /examples/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "time" 6 | 7 | domain "examples/actors" 8 | logic "examples/logic" 9 | 10 | actorSystem "github.com/eigr/spawn-go-sdk/spawn/system" 11 | ) 12 | 13 | func main() { 14 | userActor := logic.BuilUserActor() 15 | 16 | // Initializes the Spawn system 17 | system := actorSystem.NewSystem("spawn-system"). 18 | UseProxyPort(9001). 19 | ExposePort(8090). 20 | RegisterActor(userActor) 21 | 22 | // Start the system 23 | if err := system.Start(); err != nil { 24 | log.Fatalf("Failed to start Actor System: %v", err) 25 | } 26 | 27 | time.Sleep(5 * time.Second) 28 | 29 | resp, _ := system.Invoke( 30 | "spawn-system", 31 | "UserActor", 32 | "ChangeUserName", 33 | &domain.ChangeUserNamePayload{NewName: "John Doe"}, 34 | actorSystem.Options{}) 35 | 36 | log.Printf("Response: %v", resp) 37 | 38 | system.Await() 39 | } 40 | -------------------------------------------------------------------------------- /spawn/protos/google/api/annotations.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | import "google/api/http.proto"; 20 | import "google/protobuf/descriptor.proto"; 21 | 22 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 23 | option java_multiple_files = true; 24 | option java_outer_classname = "AnnotationsProto"; 25 | option java_package = "com.google.api"; 26 | option objc_class_prefix = "GAPI"; 27 | 28 | extend google.protobuf.MethodOptions { 29 | // See `HttpRule`. 30 | HttpRule http = 72295728; 31 | } 32 | -------------------------------------------------------------------------------- /spawn/protos/eigr/functions/protocol/actors/state.proto: -------------------------------------------------------------------------------- 1 | // The Spawn State Extension Protocol 2 | // 3 | // 4 | syntax = "proto3"; 5 | 6 | package eigr.functions.protocol.state; 7 | 8 | import "eigr/functions/protocol/actors/actor.proto"; 9 | 10 | option java_package = "io.eigr.functions.protocol.state"; 11 | option go_package = "spawn/eigr/functions/protocol/actors"; 12 | 13 | // A revision is just a version number for a record in the snapshot table that stores the actors' state. 14 | // When an actor has its snaphost timeout, it increments its internal revision number and saves it along with its internal data. 15 | // Some of the persistence adapters can use this revision number to find the state of an Actor at a given point in time. 16 | // As Actors in Spawn persist their internal data as snapshots from time to time a revision number may not indicate the state of a given change 17 | // but will most likely point to the exact time that a given actor's internal state was persisted into the database. 18 | message Revision { 19 | int64 value = 1; 20 | } 21 | 22 | // A checkpoint encapsulates a revision and the state it represents. 23 | message Checkpoint { 24 | 25 | Revision revision = 1; 26 | 27 | eigr.functions.protocol.actors.ActorState state = 2; 28 | } 29 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Step 1: Build the Go binary 2 | FROM golang:1.23-alpine as builder 3 | 4 | # Installs dependencies for compilation and UPX 5 | RUN apk update && apk add --no-cache \ 6 | build-base \ 7 | upx \ 8 | git \ 9 | && rm -rf /var/cache/apk/* 10 | 11 | # Working directory where the Go code will be copied 12 | WORKDIR /app 13 | 14 | # Copies go.mod and go.sum to resolve dependencies 15 | COPY examples/go.mod examples/go.sum ./ 16 | 17 | RUN go mod tidy 18 | 19 | COPY examples/ . 20 | 21 | # Compiles the Go binary in production-optimized mode 22 | RUN GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o /bin/examples/app . 23 | 24 | # Step 2: Apply UPX to the binary in a separate intermediate step 25 | FROM alpine:latest as compress-step 26 | 27 | # Install UPX 28 | RUN apk add --no-cache upx 29 | 30 | # Copy the Go binary from the builder step and apply UPX 31 | COPY --from=builder /bin/examples/app /app/app 32 | RUN upx --best --ultra-brute /app/app 33 | 34 | # Step 3: Creating the final image using scratch 35 | FROM scratch 36 | 37 | # Create a non-root user and group with meaningful names 38 | USER nobody:nogroup 39 | 40 | # Copy the optimized binary from the UPX step 41 | COPY --from=compress-step /app/app /app/app 42 | 43 | # Sets the default command to run the binary 44 | CMD ["/app/app"] 45 | -------------------------------------------------------------------------------- /spawn/actors/types.go: -------------------------------------------------------------------------------- 1 | package actors 2 | 3 | import ( 4 | "google.golang.org/protobuf/proto" 5 | ) 6 | 7 | // Kind defines the type of the actor (e.g., UNNAMED, NAMED). 8 | type Kind string 9 | 10 | const ( 11 | Unnamed Kind = "UNNAMED" 12 | Named Kind = "NAMED" 13 | Pooled Kind = "Pooled" 14 | Task Kind = "Task" 15 | Projection Kind = "Projection" 16 | ) 17 | 18 | type Workflow struct{} 19 | 20 | // Value represents the return on a stock. 21 | type Value struct { 22 | State proto.Message 23 | Response proto.Message 24 | Workflow interface{} 25 | } 26 | 27 | // ValueBuilder is the builder to create an instance of Value. 28 | type ValueBuilder struct { 29 | value Value 30 | } 31 | 32 | // Of creates a new ValueBuilder with the initial response. 33 | func Of(response proto.Message) *ValueBuilder { 34 | return &ValueBuilder{ 35 | value: Value{Response: response}, 36 | } 37 | } 38 | 39 | // State defines the state. 40 | func (b *ValueBuilder) State(state proto.Message) *ValueBuilder { 41 | b.value.State = state 42 | return b 43 | } 44 | 45 | // Workflow creates a new flow. 46 | func (b *ValueBuilder) Workflow(workflow interface{}) *ValueBuilder { 47 | b.value.Workflow = workflow 48 | return b 49 | } 50 | 51 | // Materialize finalizes the builder and returns the constructed Value. 52 | func (b *ValueBuilder) Materialize() Value { 53 | return b.value 54 | } 55 | 56 | // ActorContext provides context for an actor's handler. 57 | type ActorContext struct { 58 | CurrentState proto.Message 59 | } 60 | -------------------------------------------------------------------------------- /documentation/actors.md: -------------------------------------------------------------------------------- 1 | # Actors 2 | 3 | his is an example of what kind of Actors you can create with Spawn 4 | 5 | ## Named Actor 6 | 7 | In this example we are creating an actor in a Named way, that is, it is a known actor at compile time. Or a 'global' actor with only one name. 8 | 9 | ```go 10 | actorConfig := spawn.ActorConfig{ 11 | Name: "UserActor", // Actor name 12 | StateType: &actors.UserState{}, // State type 13 | Kind: spawn.Named, // Actor Type (Named) 14 | Stateful: true, // Stateful actor 15 | SnapshotTimeout: 60, // Snapshot timeout 16 | DeactivatedTimeout: 120, // Deactivation timeout 17 | } 18 | ``` 19 | 20 | ```go 21 | // Creates an actor with the given configuration 22 | actor := system.BuildActor(actorConfig) 23 | 24 | // Define a simple action for the actor 25 | actor.AddAction("ChangeUserName", func(ctx spawn.ActorContext, payload proto.Message) (spawn.Value, error) { 26 | // Convert payload to expected type 27 | input, ok := payload.(*actors.ChangeUserNamePayload) 28 | if !ok { 29 | return spawn.Value{}, fmt.Errorf("invalid payload type") 30 | } 31 | 32 | // Updates the status and prepares the response 33 | state := &actors.UserState{Name: input.NewName} 34 | response := &actors.ChangeUserNameResponse{Status: actors.ChangeUserNameResponse_OK} 35 | 36 | // Returns status and response 37 | return spawn.Of(state, response), nil 38 | }) 39 | ``` -------------------------------------------------------------------------------- /examples/logic/user.go: -------------------------------------------------------------------------------- 1 | package logic 2 | 3 | import ( 4 | "fmt" 5 | "log" 6 | 7 | domain "examples/actors" 8 | 9 | spawn "github.com/eigr/spawn-go-sdk/spawn/actors" 10 | 11 | "google.golang.org/protobuf/proto" 12 | ) 13 | 14 | func BuilUserActor() *spawn.Actor { 15 | // Defines the actor configuration 16 | actorConfig := spawn.ActorConfig{ 17 | Name: "UserActor", // Name of ator 18 | StateType: &domain.UserState{}, // State type 19 | Kind: spawn.Named, // Actor Type (Named) 20 | Stateful: true, // Stateful actor 21 | SnapshotTimeout: 60, // Snapshot timeout 22 | DeactivatedTimeout: 120, // Deactivation timeout 23 | } 24 | 25 | // Creates an actor directly 26 | userActor := spawn.ActorOf(actorConfig) 27 | 28 | // Define a simple action for the actor 29 | userActor.AddAction("ChangeUserName", func(ctx *spawn.ActorContext, payload proto.Message) (spawn.Value, error) { 30 | // Convert payload to expected type 31 | log.Printf("Received invoke on Action ChangeUserName. Payload: %v", payload) 32 | input, ok := payload.(*domain.ChangeUserNamePayload) 33 | if !ok { 34 | return spawn.Value{}, fmt.Errorf("invalid payload type") 35 | } 36 | 37 | // Updates the status and prepares the response 38 | newState := &domain.UserState{Name: input.NewName} 39 | response := &domain.ChangeUserNameResponse{ResponseStatus: domain.ChangeUserNameResponse_OK} 40 | 41 | // Returns response to caller and persist new state 42 | return spawn.Of(response). 43 | State(newState). 44 | Materialize(), nil 45 | }) 46 | 47 | return userActor 48 | } 49 | -------------------------------------------------------------------------------- /spawn/actors/actor.go: -------------------------------------------------------------------------------- 1 | package actors 2 | 3 | import ( 4 | "sync" 5 | 6 | "google.golang.org/protobuf/proto" 7 | ) 8 | 9 | // ActionHandler defines the function of a Protobuf-supported action. 10 | type ActionHandler func(ctx *ActorContext, payload proto.Message) (Value, error) 11 | 12 | // Actor represents an actor in Spawn. 13 | type Actor struct { 14 | Name string 15 | StateType proto.Message 16 | Kind Kind 17 | Stateful bool 18 | SnapshotTimeout int64 19 | DeactivatedTimeout int64 20 | MinPoolSize int32 21 | MaxPoolSize int32 22 | Actions map[string]ActionHandler 23 | mu sync.Mutex 24 | } 25 | 26 | // ActorConfig configures an actor. 27 | type ActorConfig struct { 28 | Name string 29 | StateType proto.Message 30 | Kind Kind 31 | Stateful bool 32 | SnapshotTimeout int64 33 | DeactivatedTimeout int64 34 | MinPoolSize int32 35 | MaxPoolSize int32 36 | } 37 | 38 | // ActorOf creates a new actor instance (preferred method for API consistency). 39 | func ActorOf(config ActorConfig) *Actor { 40 | return newActor(config) // Delegates to the existing constructor for simplicity. 41 | } 42 | 43 | // AddAction adds a new action to the actor. 44 | func (a *Actor) AddAction(name string, handler ActionHandler) { 45 | a.mu.Lock() 46 | defer a.mu.Unlock() 47 | a.Actions[name] = handler 48 | } 49 | 50 | // NewActor creates a new actor instance (legacy method, can be deprecated if needed). 51 | func newActor(config ActorConfig) *Actor { 52 | return &Actor{ 53 | Name: config.Name, 54 | StateType: config.StateType, 55 | Kind: config.Kind, 56 | Stateful: config.Stateful, 57 | SnapshotTimeout: config.SnapshotTimeout, 58 | DeactivatedTimeout: config.DeactivatedTimeout, 59 | Actions: make(map[string]ActionHandler), 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /spawn/protos/google/protobuf/source_context.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option java_package = "com.google.protobuf"; 36 | option java_outer_classname = "SourceContextProto"; 37 | option java_multiple_files = true; 38 | option objc_class_prefix = "GPB"; 39 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 40 | option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; 41 | 42 | // `SourceContext` represents information about the source of a 43 | // protobuf element, like the file in which it is defined. 44 | message SourceContext { 45 | // The path-qualified name of the .proto file that contained the associated 46 | // protobuf element. For example: `"google/protobuf/source_context.proto"`. 47 | string file_name = 1; 48 | } -------------------------------------------------------------------------------- /spawn/protos/google/protobuf/empty.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option go_package = "google.golang.org/protobuf/types/known/emptypb"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "EmptyProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | option cc_enable_arenas = true; 42 | 43 | // A generic empty message that you can re-use to avoid defining duplicated 44 | // empty messages in your APIs. A typical example is to use it as the request 45 | // or the response type of an API method. For instance: 46 | // 47 | // service Foo { 48 | // rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty); 49 | // } 50 | // 51 | message Empty {} 52 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ROOT_DIR=$(shell pwd) 2 | SPAWN_DIR=$(ROOT_DIR)/spawn 3 | SPAWN_PROTO_DIR=$(SPAWN_DIR)/protos 4 | SPAWN_PROTO_EXT_DIR=$(SPAWN_PROTO_DIR)/eigr/functions/protocol/actors 5 | GOOGLE_API_DIR=$(SPAWN_PROTO_DIR)/google/api 6 | GOOGLE_PROTOBUF_DIR=$(SPAWN_PROTO_DIR)/google/protobuf 7 | GRPC_DIR=$(SPAWN_PROTO_DIR)/grpc/reflection/v1alpha 8 | EXAMPLES_PROTO_DIR=$(ROOT_DIR)/examples/protos 9 | SPAWN_PROTO_OUT_DIR=$(SPAWN_DIR) 10 | EXAMPLES_PROTO_OUT_DIR=$(ROOT_DIR)/examples 11 | 12 | IMAGE_NAME = eigr/spawn-example:latest 13 | DOCKERFILE = Dockerfile 14 | 15 | GO_CMD=go 16 | GO_FLAGS=-v 17 | GO_BUILD_FLAGS_DEBUG=-gcflags="all=-N -l" 18 | 19 | # Diretório de saída para binários 20 | BIN_DIR=./bin 21 | EXAMPLES_BIN=$(BIN_DIR)/examples/app 22 | EXAMPLES_DIR=./examples 23 | 24 | PROTOC=protoc 25 | PROTOC_GEN_GO=$(shell go env GOPATH)/bin/protoc-gen-go 26 | 27 | # Auxiliary variables 28 | SPAWN_PROTO_FILES=$(wildcard $(SPAWN_PROTO_EXT_DIR)/*.proto) 29 | EXAMPLES_PROTO_FILES=$(wildcard $(EXAMPLES_PROTO_DIR)/*.proto) 30 | 31 | # Check if the Protobuf plugin is installed 32 | $(PROTOC_GEN_GO): 33 | @echo "Instalando protoc-gen-go..." 34 | @go install google.golang.org/protobuf/cmd/protoc-gen-go@latest 35 | 36 | # Protobuf code generation for spawn 37 | .PHONY: proto-spawn 38 | proto-spawn: $(PROTOC_GEN_GO) 39 | @echo "Generating Go code from spawn Protobuf files..." 40 | @$(PROTOC) \ 41 | --proto_path=$(SPAWN_PROTO_DIR) \ 42 | --proto_path=$(GOOGLE_API_DIR) \ 43 | --proto_path=$(GOOGLE_PROTOBUF_DIR) \ 44 | --proto_path=$(GRPC_DIR) \ 45 | --go_out=$(SPAWN_PROTO_OUT_DIR) \ 46 | --go_opt=paths=source_relative \ 47 | $(SPAWN_PROTO_FILES) 48 | 49 | # Protobuf code generation for examples 50 | .PHONY: proto-examples 51 | proto-examples: $(PROTOC_GEN_GO) 52 | @echo "Generating Go code from the examples' Protobuf files..." 53 | @$(PROTOC) \ 54 | --proto_path=$(EXAMPLES_PROTO_DIR) \ 55 | --proto_path=$(GOOGLE_API_DIR) \ 56 | --proto_path=$(GOOGLE_PROTOBUF_DIR) \ 57 | --go_out=$(EXAMPLES_PROTO_OUT_DIR) \ 58 | --go_opt=paths=source_relative \ 59 | $(EXAMPLES_PROTO_FILES) 60 | 61 | # Protobuf code generation for the entire project 62 | .PHONY: proto 63 | proto: proto-spawn proto-examples 64 | 65 | # Spawn directory setup 66 | .PHONY: setup-spawn 67 | setup-spawn: 68 | @echo "Setting dependencies for the spawn directory..." 69 | @cd spawn && go mod tidy 70 | 71 | # Examples directory setup 72 | .PHONY: setup-examples 73 | setup-examples: 74 | @echo "Setting dependencies for the examples directory..." 75 | @cd examples && go mod tidy 76 | 77 | # Complete project setup 78 | .PHONY: setup 79 | setup: setup-spawn setup-examples 80 | 81 | # Cleaning up files generated at spawn 82 | .PHONY: clean-spawn 83 | clean-spawn: 84 | @echo "Removing files generated by Protobuf on spawn..." 85 | @rm -f $(SPAWN_PROTO_OUT_DIR)/*.pb.go 86 | 87 | # Cleaning up files generated in the examples 88 | .PHONY: clean-examples 89 | clean-examples: 90 | @echo "Removing Protobuf generated files in the examples..." 91 | @rm -f $(EXAMPLES_PROTO_OUT_DIR)/*.pb.go 92 | 93 | # Cleaning the entire project 94 | .PHONY: clean 95 | clean: clean-spawn clean-examples 96 | 97 | # Bbuild for the examples directory in development mode (debug) 98 | build-debug: 99 | @echo "Compiling the examples directory in debug mode..." 100 | $(GO_CMD) build $(GO_FLAGS) $(GO_BUILD_FLAGS_DEBUG) -o $(EXAMPLES_BIN) $(EXAMPLES_DIR) 101 | @echo "Build de debug finalizado em $(EXAMPLES_BIN)" 102 | 103 | # Standard task to compile the examples 104 | build: build-debug 105 | 106 | # Task to run the generated binary 107 | run: 108 | @echo "Running the example binary..." 109 | $(EXAMPLES_BIN) 110 | 111 | # Task to compile the Dockerfile and generate the final image 112 | docker-build: 113 | docker build -t $(IMAGE_NAME) -f $(DOCKERFILE) . 114 | 115 | # Task to run the binary inside the container 116 | docker-run: 117 | docker run --rm $(IMAGE_NAME) -------------------------------------------------------------------------------- /spawn/protos/google/protobuf/struct.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option cc_enable_arenas = true; 36 | option go_package = "google.golang.org/protobuf/types/known/structpb"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "StructProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 42 | 43 | // `Struct` represents a structured data value, consisting of fields 44 | // which map to dynamically typed values. In some languages, `Struct` 45 | // might be supported by a native representation. For example, in 46 | // scripting languages like JS a struct is represented as an 47 | // object. The details of that representation are described together 48 | // with the proto support for the language. 49 | // 50 | // The JSON representation for `Struct` is JSON object. 51 | message Struct { 52 | // Unordered map of dynamically typed values. 53 | map fields = 1; 54 | } 55 | 56 | // `Value` represents a dynamically typed value which can be either 57 | // null, a number, a string, a boolean, a recursive struct value, or a 58 | // list of values. A producer of value is expected to set one of these 59 | // variants. Absence of any variant indicates an error. 60 | // 61 | // The JSON representation for `Value` is JSON value. 62 | message Value { 63 | // The kind of value. 64 | oneof kind { 65 | // Represents a null value. 66 | NullValue null_value = 1; 67 | // Represents a double value. 68 | double number_value = 2; 69 | // Represents a string value. 70 | string string_value = 3; 71 | // Represents a boolean value. 72 | bool bool_value = 4; 73 | // Represents a structured value. 74 | Struct struct_value = 5; 75 | // Represents a repeated `Value`. 76 | ListValue list_value = 6; 77 | } 78 | } 79 | 80 | // `NullValue` is a singleton enumeration to represent the null value for the 81 | // `Value` type union. 82 | // 83 | // The JSON representation for `NullValue` is JSON `null`. 84 | enum NullValue { 85 | // Null value. 86 | NULL_VALUE = 0; 87 | } 88 | 89 | // `ListValue` is a wrapper around a repeated field of values. 90 | // 91 | // The JSON representation for `ListValue` is JSON array. 92 | message ListValue { 93 | // Repeated field of dynamically typed values. 94 | repeated Value values = 1; 95 | } -------------------------------------------------------------------------------- /spawn/protos/google/protobuf/wrappers.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | // 31 | // Wrappers for primitive (non-message) types. These types are useful 32 | // for embedding primitives in the `google.protobuf.Any` type and for places 33 | // where we need to distinguish between the absence of a primitive 34 | // typed field and its default value. 35 | // 36 | // These wrappers have no meaningful use within repeated fields as they lack 37 | // the ability to detect presence on individual elements. 38 | // These wrappers have no meaningful use within a map or a oneof since 39 | // individual entries of a map or fields of a oneof can already detect presence. 40 | 41 | syntax = "proto3"; 42 | 43 | package google.protobuf; 44 | 45 | option cc_enable_arenas = true; 46 | option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; 47 | option java_package = "com.google.protobuf"; 48 | option java_outer_classname = "WrappersProto"; 49 | option java_multiple_files = true; 50 | option objc_class_prefix = "GPB"; 51 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 52 | 53 | // Wrapper message for `double`. 54 | // 55 | // The JSON representation for `DoubleValue` is JSON number. 56 | message DoubleValue { 57 | // The double value. 58 | double value = 1; 59 | } 60 | 61 | // Wrapper message for `float`. 62 | // 63 | // The JSON representation for `FloatValue` is JSON number. 64 | message FloatValue { 65 | // The float value. 66 | float value = 1; 67 | } 68 | 69 | // Wrapper message for `int64`. 70 | // 71 | // The JSON representation for `Int64Value` is JSON string. 72 | message Int64Value { 73 | // The int64 value. 74 | int64 value = 1; 75 | } 76 | 77 | // Wrapper message for `uint64`. 78 | // 79 | // The JSON representation for `UInt64Value` is JSON string. 80 | message UInt64Value { 81 | // The uint64 value. 82 | uint64 value = 1; 83 | } 84 | 85 | // Wrapper message for `int32`. 86 | // 87 | // The JSON representation for `Int32Value` is JSON number. 88 | message Int32Value { 89 | // The int32 value. 90 | int32 value = 1; 91 | } 92 | 93 | // Wrapper message for `uint32`. 94 | // 95 | // The JSON representation for `UInt32Value` is JSON number. 96 | message UInt32Value { 97 | // The uint32 value. 98 | uint32 value = 1; 99 | } 100 | 101 | // Wrapper message for `bool`. 102 | // 103 | // The JSON representation for `BoolValue` is JSON `true` and `false`. 104 | message BoolValue { 105 | // The bool value. 106 | bool value = 1; 107 | } 108 | 109 | // Wrapper message for `string`. 110 | // 111 | // The JSON representation for `StringValue` is JSON string. 112 | message StringValue { 113 | // The string value. 114 | string value = 1; 115 | } 116 | 117 | // Wrapper message for `bytes`. 118 | // 119 | // The JSON representation for `BytesValue` is JSON string. 120 | message BytesValue { 121 | // The bytes value. 122 | bytes value = 1; 123 | } -------------------------------------------------------------------------------- /spawn/eigr/functions/protocol/actors/extensions.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.35.2 4 | // protoc v3.12.4 5 | // source: eigr/functions/protocol/actors/extensions.proto 6 | 7 | package actors 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | descriptorpb "google.golang.org/protobuf/types/descriptorpb" 13 | reflect "reflect" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | var file_eigr_functions_protocol_actors_extensions_proto_extTypes = []protoimpl.ExtensionInfo{ 24 | { 25 | ExtendedType: (*descriptorpb.FieldOptions)(nil), 26 | ExtensionType: (*bool)(nil), 27 | Field: 9999, 28 | Name: "eigr.functions.protocol.actors.actor_id", 29 | Tag: "varint,9999,opt,name=actor_id", 30 | Filename: "eigr/functions/protocol/actors/extensions.proto", 31 | }, 32 | } 33 | 34 | // Extension fields to descriptorpb.FieldOptions. 35 | var ( 36 | // optional bool actor_id = 9999; 37 | E_ActorId = &file_eigr_functions_protocol_actors_extensions_proto_extTypes[0] 38 | ) 39 | 40 | var File_eigr_functions_protocol_actors_extensions_proto protoreflect.FileDescriptor 41 | 42 | var file_eigr_functions_protocol_actors_extensions_proto_rawDesc = []byte{ 43 | 0x0a, 0x2f, 0x65, 0x69, 0x67, 0x72, 0x2f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 44 | 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 45 | 0x2f, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 46 | 0x6f, 0x12, 0x1e, 0x65, 0x69, 0x67, 0x72, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 47 | 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x61, 0x63, 0x74, 0x6f, 0x72, 48 | 0x73, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 49 | 0x75, 0x66, 0x2f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x6f, 0x72, 0x2e, 0x70, 0x72, 50 | 0x6f, 0x74, 0x6f, 0x3a, 0x39, 0x0a, 0x08, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x12, 51 | 0x1d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 52 | 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x8f, 53 | 0x4e, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x49, 0x64, 0x42, 0x26, 54 | 0x5a, 0x24, 0x73, 0x70, 0x61, 0x77, 0x6e, 0x2f, 0x65, 0x69, 0x67, 0x72, 0x2f, 0x66, 0x75, 0x6e, 55 | 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 56 | 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 57 | } 58 | 59 | var file_eigr_functions_protocol_actors_extensions_proto_goTypes = []any{ 60 | (*descriptorpb.FieldOptions)(nil), // 0: google.protobuf.FieldOptions 61 | } 62 | var file_eigr_functions_protocol_actors_extensions_proto_depIdxs = []int32{ 63 | 0, // 0: eigr.functions.protocol.actors.actor_id:extendee -> google.protobuf.FieldOptions 64 | 1, // [1:1] is the sub-list for method output_type 65 | 1, // [1:1] is the sub-list for method input_type 66 | 1, // [1:1] is the sub-list for extension type_name 67 | 0, // [0:1] is the sub-list for extension extendee 68 | 0, // [0:0] is the sub-list for field type_name 69 | } 70 | 71 | func init() { file_eigr_functions_protocol_actors_extensions_proto_init() } 72 | func file_eigr_functions_protocol_actors_extensions_proto_init() { 73 | if File_eigr_functions_protocol_actors_extensions_proto != nil { 74 | return 75 | } 76 | type x struct{} 77 | out := protoimpl.TypeBuilder{ 78 | File: protoimpl.DescBuilder{ 79 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 80 | RawDescriptor: file_eigr_functions_protocol_actors_extensions_proto_rawDesc, 81 | NumEnums: 0, 82 | NumMessages: 0, 83 | NumExtensions: 1, 84 | NumServices: 0, 85 | }, 86 | GoTypes: file_eigr_functions_protocol_actors_extensions_proto_goTypes, 87 | DependencyIndexes: file_eigr_functions_protocol_actors_extensions_proto_depIdxs, 88 | ExtensionInfos: file_eigr_functions_protocol_actors_extensions_proto_extTypes, 89 | }.Build() 90 | File_eigr_functions_protocol_actors_extensions_proto = out.File 91 | file_eigr_functions_protocol_actors_extensions_proto_rawDesc = nil 92 | file_eigr_functions_protocol_actors_extensions_proto_goTypes = nil 93 | file_eigr_functions_protocol_actors_extensions_proto_depIdxs = nil 94 | } 95 | -------------------------------------------------------------------------------- /spawn/protos/google/protobuf/duration.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option cc_enable_arenas = true; 37 | option go_package = "google.golang.org/protobuf/types/known/durationpb"; 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "DurationProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | 43 | // A Duration represents a signed, fixed-length span of time represented 44 | // as a count of seconds and fractions of seconds at nanosecond 45 | // resolution. It is independent of any calendar and concepts like "day" 46 | // or "month". It is related to Timestamp in that the difference between 47 | // two Timestamp values is a Duration and it can be added or subtracted 48 | // from a Timestamp. Range is approximately +-10,000 years. 49 | // 50 | // # Examples 51 | // 52 | // Example 1: Compute Duration from two Timestamps in pseudo code. 53 | // 54 | // Timestamp start = ...; 55 | // Timestamp end = ...; 56 | // Duration duration = ...; 57 | // 58 | // duration.seconds = end.seconds - start.seconds; 59 | // duration.nanos = end.nanos - start.nanos; 60 | // 61 | // if (duration.seconds < 0 && duration.nanos > 0) { 62 | // duration.seconds += 1; 63 | // duration.nanos -= 1000000000; 64 | // } else if (duration.seconds > 0 && duration.nanos < 0) { 65 | // duration.seconds -= 1; 66 | // duration.nanos += 1000000000; 67 | // } 68 | // 69 | // Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. 70 | // 71 | // Timestamp start = ...; 72 | // Duration duration = ...; 73 | // Timestamp end = ...; 74 | // 75 | // end.seconds = start.seconds + duration.seconds; 76 | // end.nanos = start.nanos + duration.nanos; 77 | // 78 | // if (end.nanos < 0) { 79 | // end.seconds -= 1; 80 | // end.nanos += 1000000000; 81 | // } else if (end.nanos >= 1000000000) { 82 | // end.seconds += 1; 83 | // end.nanos -= 1000000000; 84 | // } 85 | // 86 | // Example 3: Compute Duration from datetime.timedelta in Python. 87 | // 88 | // td = datetime.timedelta(days=3, minutes=10) 89 | // duration = Duration() 90 | // duration.FromTimedelta(td) 91 | // 92 | // # JSON Mapping 93 | // 94 | // In JSON format, the Duration type is encoded as a string rather than an 95 | // object, where the string ends in the suffix "s" (indicating seconds) and 96 | // is preceded by the number of seconds, with nanoseconds expressed as 97 | // fractional seconds. For example, 3 seconds with 0 nanoseconds should be 98 | // encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should 99 | // be expressed in JSON format as "3.000000001s", and 3 seconds and 1 100 | // microsecond should be expressed in JSON format as "3.000001s". 101 | // 102 | message Duration { 103 | // Signed seconds of the span of time. Must be from -315,576,000,000 104 | // to +315,576,000,000 inclusive. Note: these bounds are computed from: 105 | // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years 106 | int64 seconds = 1; 107 | 108 | // Signed fractions of a second at nanosecond resolution of the span 109 | // of time. Durations less than one second are represented with a 0 110 | // `seconds` field and a positive or negative `nanos` field. For durations 111 | // of one second or more, a non-zero value for the `nanos` field must be 112 | // of the same sign as the `seconds` field. Must be from -999,999,999 113 | // to +999,999,999 inclusive. 114 | int32 nanos = 2; 115 | } 116 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | e-mail. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /spawn/protos/grpc/reflection/v1alpha/reflection.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2016 gRPC authors. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Service exported by server reflection 16 | 17 | syntax = "proto3"; 18 | 19 | package grpc.reflection.v1alpha; 20 | 21 | service ServerReflection { 22 | // The reflection service is structured as a bidirectional stream, ensuring 23 | // all related requests go to a single server. 24 | rpc ServerReflectionInfo(stream ServerReflectionRequest) 25 | returns (stream ServerReflectionResponse); 26 | } 27 | 28 | // The message sent by the client when calling ServerReflectionInfo method. 29 | message ServerReflectionRequest { 30 | string host = 1; 31 | // To use reflection service, the client should set one of the following 32 | // fields in message_request. The server distinguishes requests by their 33 | // defined field and then handles them using corresponding methods. 34 | oneof message_request { 35 | // Find a proto file by the file name. 36 | string file_by_filename = 3; 37 | 38 | // Find the proto file that declares the given fully-qualified symbol name. 39 | // This field should be a fully-qualified symbol name 40 | // (e.g. .[.] or .). 41 | string file_containing_symbol = 4; 42 | 43 | // Find the proto file which defines an extension extending the given 44 | // message type with the given field number. 45 | ExtensionRequest file_containing_extension = 5; 46 | 47 | // Finds the tag numbers used by all known extensions of the given message 48 | // type, and appends them to ExtensionNumberResponse in an undefined order. 49 | // Its corresponding method is best-effort: it's not guaranteed that the 50 | // reflection service will implement this method, and it's not guaranteed 51 | // that this method will provide all extensions. Returns 52 | // StatusCode::UNIMPLEMENTED if it's not implemented. 53 | // This field should be a fully-qualified type name. The format is 54 | // . 55 | string all_extension_numbers_of_type = 6; 56 | 57 | // List the full names of registered services. The content will not be 58 | // checked. 59 | string list_services = 7; 60 | } 61 | } 62 | 63 | // The type name and extension number sent by the client when requesting 64 | // file_containing_extension. 65 | message ExtensionRequest { 66 | // Fully-qualified type name. The format should be . 67 | string containing_type = 1; 68 | int32 extension_number = 2; 69 | } 70 | 71 | // The message sent by the server to answer ServerReflectionInfo method. 72 | message ServerReflectionResponse { 73 | string valid_host = 1; 74 | ServerReflectionRequest original_request = 2; 75 | // The server set one of the following fields accroding to the message_request 76 | // in the request. 77 | oneof message_response { 78 | // This message is used to answer file_by_filename, file_containing_symbol, 79 | // file_containing_extension requests with transitive dependencies. As 80 | // the repeated label is not allowed in oneof fields, we use a 81 | // FileDescriptorResponse message to encapsulate the repeated fields. 82 | // The reflection service is allowed to avoid sending FileDescriptorProtos 83 | // that were previously sent in response to earlier requests in the stream. 84 | FileDescriptorResponse file_descriptor_response = 4; 85 | 86 | // This message is used to answer all_extension_numbers_of_type requst. 87 | ExtensionNumberResponse all_extension_numbers_response = 5; 88 | 89 | // This message is used to answer list_services request. 90 | ListServiceResponse list_services_response = 6; 91 | 92 | // This message is used when an error occurs. 93 | ErrorResponse error_response = 7; 94 | } 95 | } 96 | 97 | // Serialized FileDescriptorProto messages sent by the server answering 98 | // a file_by_filename, file_containing_symbol, or file_containing_extension 99 | // request. 100 | message FileDescriptorResponse { 101 | // Serialized FileDescriptorProto messages. We avoid taking a dependency on 102 | // descriptor.proto, which uses proto2 only features, by making them opaque 103 | // bytes instead. 104 | repeated bytes file_descriptor_proto = 1; 105 | } 106 | 107 | // A list of extension numbers sent by the server answering 108 | // all_extension_numbers_of_type request. 109 | message ExtensionNumberResponse { 110 | // Full name of the base type, including the package name. The format 111 | // is . 112 | string base_type_name = 1; 113 | repeated int32 extension_number = 2; 114 | } 115 | 116 | // A list of ServiceResponse sent by the server answering list_services request. 117 | message ListServiceResponse { 118 | // The information of each service may be expanded in the future, so we use 119 | // ServiceResponse message to encapsulate it. 120 | repeated ServiceResponse service = 1; 121 | } 122 | 123 | // The information of a single service used by ListServiceResponse to answer 124 | // list_services request. 125 | message ServiceResponse { 126 | // Full name of a registered service, including its package name. The format 127 | // is . 128 | string name = 1; 129 | } 130 | 131 | // The error code and error message sent by the server when an error occurs. 132 | message ErrorResponse { 133 | // This field uses the error codes defined in grpc::StatusCode. 134 | int32 error_code = 1; 135 | string error_message = 2; 136 | } -------------------------------------------------------------------------------- /spawn/protos/google/protobuf/any.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option go_package = "google.golang.org/protobuf/types/known/anypb"; 37 | option java_package = "com.google.protobuf"; 38 | option java_outer_classname = "AnyProto"; 39 | option java_multiple_files = true; 40 | option objc_class_prefix = "GPB"; 41 | 42 | // `Any` contains an arbitrary serialized protocol buffer message along with a 43 | // URL that describes the type of the serialized message. 44 | // 45 | // Protobuf library provides support to pack/unpack Any values in the form 46 | // of utility functions or additional generated methods of the Any type. 47 | // 48 | // Example 1: Pack and unpack a message in C++. 49 | // 50 | // Foo foo = ...; 51 | // Any any; 52 | // any.PackFrom(foo); 53 | // ... 54 | // if (any.UnpackTo(&foo)) { 55 | // ... 56 | // } 57 | // 58 | // Example 2: Pack and unpack a message in Java. 59 | // 60 | // Foo foo = ...; 61 | // Any any = Any.pack(foo); 62 | // ... 63 | // if (any.is(Foo.class)) { 64 | // foo = any.unpack(Foo.class); 65 | // } 66 | // 67 | // Example 3: Pack and unpack a message in Python. 68 | // 69 | // foo = Foo(...) 70 | // any = Any() 71 | // any.Pack(foo) 72 | // ... 73 | // if any.Is(Foo.DESCRIPTOR): 74 | // any.Unpack(foo) 75 | // ... 76 | // 77 | // Example 4: Pack and unpack a message in Go 78 | // 79 | // foo := &pb.Foo{...} 80 | // any, err := anypb.New(foo) 81 | // if err != nil { 82 | // ... 83 | // } 84 | // ... 85 | // foo := &pb.Foo{} 86 | // if err := any.UnmarshalTo(foo); err != nil { 87 | // ... 88 | // } 89 | // 90 | // The pack methods provided by protobuf library will by default use 91 | // 'type.googleapis.com/full.type.name' as the type URL and the unpack 92 | // methods only use the fully qualified type name after the last '/' 93 | // in the type URL, for example "foo.bar.com/x/y.z" will yield type 94 | // name "y.z". 95 | // 96 | // 97 | // JSON 98 | // 99 | // The JSON representation of an `Any` value uses the regular 100 | // representation of the deserialized, embedded message, with an 101 | // additional field `@type` which contains the type URL. Example: 102 | // 103 | // package google.profile; 104 | // message Person { 105 | // string first_name = 1; 106 | // string last_name = 2; 107 | // } 108 | // 109 | // { 110 | // "@type": "type.googleapis.com/google.profile.Person", 111 | // "firstName": , 112 | // "lastName": 113 | // } 114 | // 115 | // If the embedded message type is well-known and has a custom JSON 116 | // representation, that representation will be embedded adding a field 117 | // `value` which holds the custom JSON in addition to the `@type` 118 | // field. Example (for message [google.protobuf.Duration][]): 119 | // 120 | // { 121 | // "@type": "type.googleapis.com/google.protobuf.Duration", 122 | // "value": "1.212s" 123 | // } 124 | // 125 | message Any { 126 | // A URL/resource name that uniquely identifies the type of the serialized 127 | // protocol buffer message. This string must contain at least 128 | // one "/" character. The last segment of the URL's path must represent 129 | // the fully qualified name of the type (as in 130 | // `path/google.protobuf.Duration`). The name should be in a canonical form 131 | // (e.g., leading "." is not accepted). 132 | // 133 | // In practice, teams usually precompile into the binary all types that they 134 | // expect it to use in the context of Any. However, for URLs which use the 135 | // scheme `http`, `https`, or no scheme, one can optionally set up a type 136 | // server that maps type URLs to message definitions as follows: 137 | // 138 | // * If no scheme is provided, `https` is assumed. 139 | // * An HTTP GET on the URL must yield a [google.protobuf.Type][] 140 | // value in binary format, or produce an error. 141 | // * Applications are allowed to cache lookup results based on the 142 | // URL, or have them precompiled into a binary to avoid any 143 | // lookup. Therefore, binary compatibility needs to be preserved 144 | // on changes to types. (Use versioned type names to manage 145 | // breaking changes.) 146 | // 147 | // Note: this functionality is not currently available in the official 148 | // protobuf release, and it is not used for type URLs beginning with 149 | // type.googleapis.com. 150 | // 151 | // Schemes other than `http`, `https` (or the empty scheme) might be 152 | // used with implementation specific semantics. 153 | // 154 | string type_url = 1; 155 | 156 | // Must be a valid serialized protocol buffer of the above specified type. 157 | bytes value = 2; 158 | } -------------------------------------------------------------------------------- /spawn/protos/google/protobuf/timestamp.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 36 | option cc_enable_arenas = true; 37 | option go_package = "google.golang.org/protobuf/types/known/timestamppb"; 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "TimestampProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | 43 | // A Timestamp represents a point in time independent of any time zone or local 44 | // calendar, encoded as a count of seconds and fractions of seconds at 45 | // nanosecond resolution. The count is relative to an epoch at UTC midnight on 46 | // January 1, 1970, in the proleptic Gregorian calendar which extends the 47 | // Gregorian calendar backwards to year one. 48 | // 49 | // All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap 50 | // second table is needed for interpretation, using a [24-hour linear 51 | // smear](https://developers.google.com/time/smear). 52 | // 53 | // The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By 54 | // restricting to that range, we ensure that we can convert to and from [RFC 55 | // 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. 56 | // 57 | // # Examples 58 | // 59 | // Example 1: Compute Timestamp from POSIX `time()`. 60 | // 61 | // Timestamp timestamp; 62 | // timestamp.set_seconds(time(NULL)); 63 | // timestamp.set_nanos(0); 64 | // 65 | // Example 2: Compute Timestamp from POSIX `gettimeofday()`. 66 | // 67 | // struct timeval tv; 68 | // gettimeofday(&tv, NULL); 69 | // 70 | // Timestamp timestamp; 71 | // timestamp.set_seconds(tv.tv_sec); 72 | // timestamp.set_nanos(tv.tv_usec * 1000); 73 | // 74 | // Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. 75 | // 76 | // FILETIME ft; 77 | // GetSystemTimeAsFileTime(&ft); 78 | // UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; 79 | // 80 | // // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z 81 | // // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. 82 | // Timestamp timestamp; 83 | // timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); 84 | // timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); 85 | // 86 | // Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. 87 | // 88 | // long millis = System.currentTimeMillis(); 89 | // 90 | // Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) 91 | // .setNanos((int) ((millis % 1000) * 1000000)).build(); 92 | // 93 | // Example 5: Compute Timestamp from Java `Instant.now()`. 94 | // 95 | // Instant now = Instant.now(); 96 | // 97 | // Timestamp timestamp = 98 | // Timestamp.newBuilder().setSeconds(now.getEpochSecond()) 99 | // .setNanos(now.getNano()).build(); 100 | // 101 | // Example 6: Compute Timestamp from current time in Python. 102 | // 103 | // timestamp = Timestamp() 104 | // timestamp.GetCurrentTime() 105 | // 106 | // # JSON Mapping 107 | // 108 | // In JSON format, the Timestamp type is encoded as a string in the 109 | // [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the 110 | // format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" 111 | // where {year} is always expressed using four digits while {month}, {day}, 112 | // {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional 113 | // seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), 114 | // are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone 115 | // is required. A proto3 JSON serializer should always use UTC (as indicated by 116 | // "Z") when printing the Timestamp type and a proto3 JSON parser should be 117 | // able to accept both UTC and other timezones (as indicated by an offset). 118 | // 119 | // For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 120 | // 01:30 UTC on January 15, 2017. 121 | // 122 | // In JavaScript, one can convert a Date object to this format using the 123 | // standard 124 | // [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) 125 | // method. In Python, a standard `datetime.datetime` object can be converted 126 | // to this format using 127 | // [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with 128 | // the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use 129 | // the Joda Time's [`ISODateTimeFormat.dateTime()`]( 130 | // http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D 131 | // ) to obtain a formatter capable of generating timestamps in this format. 132 | // 133 | message Timestamp { 134 | // Represents seconds of UTC time since Unix epoch 135 | // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 136 | // 9999-12-31T23:59:59Z inclusive. 137 | int64 seconds = 1; 138 | 139 | // Non-negative fractions of a second at nanosecond resolution. Negative 140 | // second values with fractions must still have non-negative nanos values 141 | // that count forward in time. Must be from 0 to 999,999,999 142 | // inclusive. 143 | int32 nanos = 2; 144 | } 145 | -------------------------------------------------------------------------------- /spawn/protos/eigr/functions/protocol/actors/actor.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package eigr.functions.protocol.actors; 4 | 5 | import "google/protobuf/any.proto"; 6 | import "google/protobuf/timestamp.proto"; 7 | 8 | option java_package = "io.eigr.functions.protocol.actors"; 9 | option go_package = "spawn/eigr/functions/protocol/actors"; 10 | 11 | message Registry { map actors = 1; } 12 | 13 | message ActorSystem { 14 | string name = 1; 15 | Registry registry = 2; 16 | } 17 | 18 | // A strategy for save state. 19 | message ActorSnapshotStrategy { 20 | oneof strategy { 21 | // the timeout strategy. 22 | TimeoutStrategy timeout = 1; 23 | } 24 | } 25 | 26 | // A strategy which a user function's entity is passivated. 27 | message ActorDeactivationStrategy { 28 | oneof strategy { 29 | // the timeout strategy. 30 | TimeoutStrategy timeout = 1; 31 | } 32 | } 33 | 34 | // A strategy based on a timeout. 35 | message TimeoutStrategy { 36 | // The timeout in millis 37 | int64 timeout = 1; 38 | } 39 | 40 | // A action represents an action that the user can perform on an Actor. 41 | // Actions in supporting languages are represented by functions or methods. 42 | // An Actor action has nothing to do with the semantics of Actions in a 43 | // CQRS/EventSourced system. It just represents an action that supporting 44 | // languages can invoke. 45 | message Action { 46 | 47 | // The name of the function or method in the supporting language that has been 48 | // registered in Ator. 49 | string name = 1; 50 | } 51 | 52 | // A FixedTimerAction is similar to a regular Action, its main differences are 53 | // that it is scheduled to run at regular intervals and only takes the actor's 54 | // state as an argument. Timer Actions are good for executing loops that 55 | // manipulate the actor's own state. In Elixir or other languages in BEAM it 56 | // would be similar to invoking Process.send_after(self(), atom, msg, timeout) 57 | message FixedTimerAction { 58 | 59 | // The time to wait until the action is triggered 60 | int32 seconds = 1; 61 | 62 | // See Action description Above 63 | Action action = 2; 64 | } 65 | 66 | message ActorState { 67 | map tags = 1; 68 | google.protobuf.Any state = 2; 69 | } 70 | 71 | // Metadata represents a set of key-value pairs that can be used to 72 | // provide additional information about an Actor. 73 | message Metadata { 74 | // A channel group represents a way to send actions to various actors 75 | // that belong to a certain semantic group. Following the Pub-Sub pattern. 76 | repeated Channel channel_group = 1; 77 | 78 | map tags = 2; 79 | } 80 | 81 | // Represents a Pub-Sub binding, where a actor can be subscribed to a channel 82 | // and map a specific action to a specific topic if necessary 83 | // if the action is not informed, the default action will be "receive". 84 | message Channel { 85 | string topic = 1; 86 | string action = 2; 87 | } 88 | 89 | // The type that defines the runtime characteristics of the Actor. 90 | // Regardless of the type of actor it is important that 91 | // all actors are registered during the proxy and host initialization phase. 92 | enum Kind { 93 | // When no type is informed, the default to be assumed will be the Named 94 | // pattern. 95 | UNKNOW_KIND = 0; 96 | 97 | // NAMED actors as the name suggests have only one real instance of themselves 98 | // running during their entire lifecycle. That is, they are the opposite of 99 | // the UNNAMED type Actors. 100 | NAMED = 1; 101 | 102 | // UNNAMED actors are used to create children of this based actor at runtime 103 | UNNAMED = 2; 104 | 105 | // Pooled Actors are similar to Unnamed actors, but unlike them, 106 | // their identifying name will always be the one registered at the system 107 | // initialization stage. The great advantage of Pooled actors is that they 108 | // have multiple instances of themselves acting as a request service pool. 109 | // Pooled actors are also stateless actors, that is, they will not have their 110 | // in-memory state persisted via Statesstore. This is done to avoid problems 111 | // with the correctness of the stored state. 112 | // Pooled Actors are generally used for tasks where the Actor Model would 113 | // perform worse than other concurrency models and for tasks that do not 114 | // require state concerns. Integration flows, data caching, proxies are good 115 | // examples of use cases for this type of Actor. 116 | POOLED = 3; 117 | 118 | // Reserved for future use 119 | PROXY = 4; 120 | 121 | TASK = 5; 122 | 123 | // Projection actors are used to project data from different actor streams. 124 | PROJECTION = 6; 125 | } 126 | 127 | message ProjectionSubject { 128 | string actor = 1; 129 | string action = 2; 130 | google.protobuf.Timestamp start_time = 3; 131 | } 132 | 133 | message EventsRetentionTime { 134 | int64 time = 1; 135 | } 136 | 137 | message EventsRetentionStrategy { 138 | oneof strategy { 139 | EventsRetentionTime time_in_ms = 1; 140 | bool infinite = 2; 141 | } 142 | } 143 | 144 | message ProjectionSettings { 145 | // Define this for projections that need to listen to events 146 | repeated ProjectionSubject subjects = 1; 147 | 148 | // Define this for actors that can emit events 149 | bool sourceable = 2; 150 | 151 | // The strategy for event store retention 152 | EventsRetentionStrategy events_retention_strategy = 3; 153 | 154 | // Define how we consume events from subjects 155 | bool strict_events_ordering = 4; 156 | } 157 | 158 | message ActorSettings { 159 | 160 | // Indicates the type of Actor to be configured. 161 | Kind kind = 1; 162 | 163 | // Indicates whether an actor's state should be persisted in a definitive 164 | // store. 165 | bool stateful = 2; 166 | 167 | // Snapshot strategy 168 | ActorSnapshotStrategy snapshot_strategy = 3; 169 | 170 | // Deactivate strategy 171 | ActorDeactivationStrategy deactivation_strategy = 4; 172 | 173 | // When kind is POOLED this is used to define minimun actor instances 174 | int32 min_pool_size = 5; 175 | 176 | // When kind is POOLED this is used to define maximum actor instances 177 | int32 max_pool_size = 6; 178 | 179 | // Event source settings 180 | ProjectionSettings projection_settings = 7; 181 | } 182 | 183 | message ActorId { 184 | // The name of a Actor Entity. 185 | string name = 1; 186 | 187 | // Name of a ActorSystem 188 | string system = 2; 189 | 190 | // When the Actor is of the Unnamed type, 191 | // the name of the parent Actor must be informed here. 192 | string parent = 3; 193 | } 194 | 195 | message Actor { 196 | // Actor Identification 197 | ActorId id = 1; 198 | 199 | // A Actor state. 200 | ActorState state = 2; 201 | 202 | // Actor metadata 203 | Metadata metadata = 6; 204 | 205 | // Actor settings. 206 | ActorSettings settings = 3; 207 | 208 | // The actions registered for an actor 209 | repeated Action actions = 4; 210 | 211 | // The registered timer actions for an actor. 212 | repeated FixedTimerAction timer_actions = 5; 213 | } 214 | -------------------------------------------------------------------------------- /spawn/protos/google/protobuf/type.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | import "google/protobuf/any.proto"; 36 | import "google/protobuf/source_context.proto"; 37 | 38 | option cc_enable_arenas = true; 39 | option java_package = "com.google.protobuf"; 40 | option java_outer_classname = "TypeProto"; 41 | option java_multiple_files = true; 42 | option objc_class_prefix = "GPB"; 43 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 44 | option go_package = "google.golang.org/protobuf/types/known/typepb"; 45 | 46 | // A protocol buffer message type. 47 | message Type { 48 | // The fully qualified message name. 49 | string name = 1; 50 | // The list of fields. 51 | repeated Field fields = 2; 52 | // The list of types appearing in `oneof` definitions in this type. 53 | repeated string oneofs = 3; 54 | // The protocol buffer options. 55 | repeated Option options = 4; 56 | // The source context. 57 | SourceContext source_context = 5; 58 | // The source syntax. 59 | Syntax syntax = 6; 60 | // The source edition string, only valid when syntax is SYNTAX_EDITIONS. 61 | string edition = 7; 62 | } 63 | 64 | // A single field of a message type. 65 | message Field { 66 | // Basic field types. 67 | enum Kind { 68 | // Field type unknown. 69 | TYPE_UNKNOWN = 0; 70 | // Field type double. 71 | TYPE_DOUBLE = 1; 72 | // Field type float. 73 | TYPE_FLOAT = 2; 74 | // Field type int64. 75 | TYPE_INT64 = 3; 76 | // Field type uint64. 77 | TYPE_UINT64 = 4; 78 | // Field type int32. 79 | TYPE_INT32 = 5; 80 | // Field type fixed64. 81 | TYPE_FIXED64 = 6; 82 | // Field type fixed32. 83 | TYPE_FIXED32 = 7; 84 | // Field type bool. 85 | TYPE_BOOL = 8; 86 | // Field type string. 87 | TYPE_STRING = 9; 88 | // Field type group. Proto2 syntax only, and deprecated. 89 | TYPE_GROUP = 10; 90 | // Field type message. 91 | TYPE_MESSAGE = 11; 92 | // Field type bytes. 93 | TYPE_BYTES = 12; 94 | // Field type uint32. 95 | TYPE_UINT32 = 13; 96 | // Field type enum. 97 | TYPE_ENUM = 14; 98 | // Field type sfixed32. 99 | TYPE_SFIXED32 = 15; 100 | // Field type sfixed64. 101 | TYPE_SFIXED64 = 16; 102 | // Field type sint32. 103 | TYPE_SINT32 = 17; 104 | // Field type sint64. 105 | TYPE_SINT64 = 18; 106 | } 107 | 108 | // Whether a field is optional, required, or repeated. 109 | enum Cardinality { 110 | // For fields with unknown cardinality. 111 | CARDINALITY_UNKNOWN = 0; 112 | // For optional fields. 113 | CARDINALITY_OPTIONAL = 1; 114 | // For required fields. Proto2 syntax only. 115 | CARDINALITY_REQUIRED = 2; 116 | // For repeated fields. 117 | CARDINALITY_REPEATED = 3; 118 | } 119 | 120 | // The field type. 121 | Kind kind = 1; 122 | // The field cardinality. 123 | Cardinality cardinality = 2; 124 | // The field number. 125 | int32 number = 3; 126 | // The field name. 127 | string name = 4; 128 | // The field type URL, without the scheme, for message or enumeration 129 | // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. 130 | string type_url = 6; 131 | // The index of the field type in `Type.oneofs`, for message or enumeration 132 | // types. The first type has index 1; zero means the type is not in the list. 133 | int32 oneof_index = 7; 134 | // Whether to use alternative packed wire representation. 135 | bool packed = 8; 136 | // The protocol buffer options. 137 | repeated Option options = 9; 138 | // The field JSON name. 139 | string json_name = 10; 140 | // The string value of the default value of this field. Proto2 syntax only. 141 | string default_value = 11; 142 | } 143 | 144 | // Enum type definition. 145 | message Enum { 146 | // Enum type name. 147 | string name = 1; 148 | // Enum value definitions. 149 | repeated EnumValue enumvalue = 2; 150 | // Protocol buffer options. 151 | repeated Option options = 3; 152 | // The source context. 153 | SourceContext source_context = 4; 154 | // The source syntax. 155 | Syntax syntax = 5; 156 | // The source edition string, only valid when syntax is SYNTAX_EDITIONS. 157 | string edition = 6; 158 | } 159 | 160 | // Enum value definition. 161 | message EnumValue { 162 | // Enum value name. 163 | string name = 1; 164 | // Enum value number. 165 | int32 number = 2; 166 | // Protocol buffer options. 167 | repeated Option options = 3; 168 | } 169 | 170 | // A protocol buffer option, which can be attached to a message, field, 171 | // enumeration, etc. 172 | message Option { 173 | // The option's name. For protobuf built-in options (options defined in 174 | // descriptor.proto), this is the short name. For example, `"map_entry"`. 175 | // For custom options, it should be the fully-qualified name. For example, 176 | // `"google.api.http"`. 177 | string name = 1; 178 | // The option's value packed in an Any message. If the value is a primitive, 179 | // the corresponding wrapper type defined in google/protobuf/wrappers.proto 180 | // should be used. If the value is an enum, it should be stored as an int32 181 | // value using the google.protobuf.Int32Value type. 182 | Any value = 2; 183 | } 184 | 185 | // The syntax in which a protocol buffer element is defined. 186 | enum Syntax { 187 | // Syntax `proto2`. 188 | SYNTAX_PROTO2 = 0; 189 | // Syntax `proto3`. 190 | SYNTAX_PROTO3 = 1; 191 | // Syntax `editions`. 192 | SYNTAX_EDITIONS = 2; 193 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Spawn Go SDK](https://github.com/eigr/spawn) 2 | 3 | **Seamless Actor Mesh Runtime for Go Developers** 4 | 5 | --- 6 | 7 | ## 🚀 **Why Choose Spawn?** 8 | 9 | - **Developer Friendly**: Simplify building distributed, stateful applications. 10 | - **Scalable**: Designed for cloud-native environments with polyglot support. 11 | - **Effortless Integration**: Build robust systems with minimal boilerplate. 12 | 13 | --- 14 | 15 | ## **🌟 Features** 16 | 17 | - Fully managed actor lifecycle. 18 | - State persistence and snapshots. 19 | - Polyglot SDKs for ultimate flexibility. In this case GO SDK \0/. 20 | - Optimized for high performance and low latency. 21 | 22 | --- 23 | 24 | ## **📦 Installation** 25 | 26 | Set up your environment in seconds. Install the Spawn CLI: 27 | 28 | ```bash 29 | curl -sSL https://github.com/eigr/spawn/releases/download/v1.4.3/install.sh | sh 30 | ``` 31 | 32 | ## 🔥 Getting Started 33 | 34 | ### 1️⃣ Create a New Project 35 | 36 | ```bash 37 | spawn new go hello_world 38 | ``` 39 | 40 | ### 2️⃣ Define Your Protocol 41 | 42 | Leverage the power of Protobuf to define your actor's schema: 43 | 44 | ```proto 45 | syntax = "proto3"; 46 | 47 | package examples.actors; 48 | 49 | option go_package = "examples/actors"; 50 | 51 | message UserState { 52 | string name = 1; 53 | } 54 | 55 | message ChangeUserNamePayload { 56 | string new_name = 1; 57 | } 58 | 59 | message ChangeUserNameResponse { 60 | // this is a bad example, but it's just an example 61 | enum ResponseStatus { 62 | OK = 0; 63 | ERROR = 1; 64 | } 65 | ResponseStatus response_status = 1; 66 | } 67 | 68 | service UserActor { 69 | rpc ChangeUserName(ChangeUserNamePayload) returns (ChangeUserNameResponse) {} 70 | } 71 | ``` 72 | 73 | ### 3️⃣ Compile Your Protobuf 74 | 75 | Follow the example in our [Makefile](./Makefile). 76 | 77 | ### 4️⃣ Implement Your Business Logic 78 | 79 | Start writing actors with ease: 80 | 81 | ```go 82 | package main 83 | 84 | import ( 85 | "fmt" 86 | "log" 87 | "time" 88 | 89 | domain "examples/actors" 90 | 91 | spawn "github.com/eigr/spawn-go-sdk/spawn/actors" 92 | actorSystem "github.com/eigr/spawn-go-sdk/spawn/system" 93 | "google.golang.org/protobuf/proto" 94 | ) 95 | 96 | func main() { 97 | // Defines the actor configuration 98 | actorConfig := spawn.ActorConfig{ 99 | Name: "UserActor", // Name of ator 100 | StateType: &domain.UserState{}, // State type 101 | Kind: spawn.Named, // Actor Type (Named) 102 | Stateful: true, // Stateful actor 103 | SnapshotTimeout: 60, // Snapshot timeout 104 | DeactivatedTimeout: 120, // Deactivation timeout 105 | } 106 | 107 | // Creates an actor directly 108 | userActor := spawn.ActorOf(actorConfig) 109 | 110 | // Define a simple action for the actor 111 | userActor.AddAction("ChangeUserName", func(ctx *spawn.ActorContext, payload proto.Message) (spawn.Value, error) { 112 | // Convert payload to expected type 113 | log.Printf("Received invoke on Action ChangeUserName. Payload: %v", payload) 114 | input, ok := payload.(*domain.ChangeUserNamePayload) 115 | if !ok { 116 | return spawn.Value{}, fmt.Errorf("invalid payload type") 117 | } 118 | 119 | // Updates the status and prepares the response 120 | newState := &domain.UserState{Name: input.NewName} 121 | response := &domain.ChangeUserNameResponse{ResponseStatus: domain.ChangeUserNameResponse_OK} 122 | 123 | // Returns response to caller and persist new state 124 | return spawn.Of(response). 125 | State(newState). 126 | Materialize(), nil 127 | }) 128 | 129 | // Initializes the Spawn system 130 | system := actorSystem.NewSystem("spawn-system"). 131 | UseProxyPort(9001). 132 | ExposePort(8090). 133 | RegisterActor(userActor) 134 | 135 | // Start the system 136 | if err := system.Start(); err != nil { 137 | log.Fatalf("Failed to start Actor System: %v", err) 138 | } 139 | 140 | resp, _ := system.Invoke( 141 | "spawn-system", 142 | "UserActor", 143 | "ChangeUserName", 144 | &domain.ChangeUserNamePayload{NewName: "Joe"}, 145 | actorSystem.Options{}) 146 | 147 | log.Printf("Response: %v", resp) 148 | 149 | system.Await() 150 | } 151 | ``` 152 | 153 | ### 5️⃣ Build and generate application in dev mode 154 | 155 | ```bash 156 | go build -v -gcflags="all=-N -l" -o ./bin/examples/app ./examples 157 | ``` 158 | 159 | ### 6️⃣ Start Spawn CLI in dev mode 160 | 161 | ```bash 162 | spawn dev run 163 | ``` 164 | 165 | Expected output similar to this: 166 | 167 | ```bash 168 | 🏃 Starting Spawn Proxy in dev mode... 169 | ❕ Spawn Proxy uses the following mapped ports: [ 170 | Proxy HTTP: nil:9001, 171 | Proxy gRPC: nil:9980 172 | ] 173 | 🚀 Spawn Proxy started successfully in dev mode. Container Id: 7961ed391e06b36c6d73290a6d6a0cbb60cf910fd4e4ff3fc5b7bd49ed677976 174 | ``` 175 | 176 | ### 7️⃣ Start application in dev mode 177 | 178 | ```bash 179 | ./bin/examples/app 180 | ``` 181 | 182 | Outputs need to be similar with this: 183 | 184 | ```bash 185 | 2024/12/10 20:09:37 HTTP server started on port 8090 186 | 2024/12/10 20:09:37 Actors successfully registered and system started 187 | ``` 188 | 189 | ### 8️⃣ Validate Spawn CLI docker logs 190 | 191 | Use `Id` for previous `spawn dev run` command to see docker logs. 192 | 193 | ```bash 194 | docker logs -f 7961ed391e06b36c6d73290a6d6a0cbb60cf910fd4e4ff3fc5b7bd49ed677976 195 | ``` 196 | 197 | Expected output similar to (ommited some logs for brevity): 198 | 199 | ```bash 200 | 2024-12-10 21:21:32.028 [proxy@GF-595]:[pid=<0.2770.0> ]:[info]:[Proxy.Config] Loading configs 201 | 2024-12-10 21:21:32.029 [proxy@GF-595]:[pid=<0.2770.0> ]:[info]:Loading config: [actor_system_name]:[my-system] 202 | 2024-12-10 21:21:32.044 [proxy@GF-595]:[pid=<0.2775.0> ]:[info]:[SUPERVISOR] Sidecar.Supervisor is up 203 | 2024-12-10 21:21:32.044 [proxy@GF-595]:[pid=<0.2777.0> ]:[info]:[SUPERVISOR] Sidecar.ProcessSupervisor is up 204 | 2024-12-10 21:21:32.045 [proxy@GF-595]:[pid=<0.2779.0> ]:[info]:[SUPERVISOR] Sidecar.MetricsSupervisor is up 205 | 2024-12-10 21:21:32.046 [proxy@GF-595]:[pid=<0.2783.0> ]:[info]:[SUPERVISOR] Spawn.Supervisor is up 206 | 2024-12-10 21:21:32.048 [proxy@GF-595]:[pid=<0.2791.0> ]:[info]:[SUPERVISOR] Spawn.Cluster.StateHandoff.ManagerSupervisor is up 207 | 2024-12-10 21:21:32.053 [proxy@GF-595]:[pid=<0.2809.0> ]:[info]:[mnesiac:proxy@GF-595] mnesiac starting, with [] 208 | 2024-12-10 21:21:32.078 [proxy@GF-595]:[pid=<0.2809.0> ]:[info]:Elixir.Statestores.Adapters.Native.SnapshotStore Initialized with result {:aborted, {:already_exists, Statestores.Adapters.Native.SnapshotStore}} 209 | 2024-12-10 21:21:32.079 [proxy@GF-595]:[pid=<0.2809.0> ]:[info]:[mnesiac:proxy@GF-595] mnesiac started 210 | 2024-12-10 21:21:32.083 [proxy@GF-595]:[pid=<0.2855.0> ]:[info]:[SUPERVISOR] Actors.Supervisors.ActorSupervisor is up 211 | 2024-12-10 21:21:32.123 [proxy@GF-595]:[pid=<0.2772.0> ]:[info]:Running Proxy.Router with Bandit 1.5.2 at 0.0.0.0:9001 (http) 212 | 2024-12-10 21:21:32.124 [proxy@GF-595]:[pid=<0.2770.0> ]:[info]:Proxy Application started successfully in 0.095587ms. Running with 8 schedulers. 213 | 2024-12-10 21:21:56.518 [proxy@GF-595]:[pid=<0.3419.0> ]:[info]:POST /api/v1/system 214 | 2024-12-10 21:21:56.523 [proxy@GF-595]:[pid=<0.3419.0> ]:[info]:Sent 200 in 4ms 215 | 2024-12-10 21:21:56.526 [proxy@GF-595]:[pid=<0.3433.0> ]:[notice]:Activating Actor "UserActor" with Parent "" in Node :"proxy@GF-595". Persistence true. 216 | 2024-12-10 21:21:56.528 [proxy@GF-595]:[pid=<0.3424.0> ]:[info]:Actor UserActor Activated on Node :"proxy@GF-595" in 3402ms 217 | ``` 218 | 219 | ## 📚 Explore More 220 | 221 | Check out our examples folder for additional use cases and inspiration. 222 | 223 | ## 💡 Why Spawn Matters 224 | 225 | CTOs, Tech Leads, and Developers love Spawn for its simplicity, scalability, and flexibility. Build reliable, distributed systems faster than ever. 226 | 227 | Unleash the power of polyglot distributed systems with Spawn today! -------------------------------------------------------------------------------- /spawn/protos/google/protobuf/api.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | import "google/protobuf/source_context.proto"; 36 | import "google/protobuf/type.proto"; 37 | 38 | option java_package = "com.google.protobuf"; 39 | option java_outer_classname = "ApiProto"; 40 | option java_multiple_files = true; 41 | option objc_class_prefix = "GPB"; 42 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 43 | option go_package = "google.golang.org/protobuf/types/known/apipb"; 44 | 45 | // Api is a light-weight descriptor for an API Interface. 46 | // 47 | // Interfaces are also described as "protocol buffer services" in some contexts, 48 | // such as by the "service" keyword in a .proto file, but they are different 49 | // from API Services, which represent a concrete implementation of an interface 50 | // as opposed to simply a description of methods and bindings. They are also 51 | // sometimes simply referred to as "APIs" in other contexts, such as the name of 52 | // this message itself. See https://cloud.google.com/apis/design/glossary for 53 | // detailed terminology. 54 | message Api { 55 | // The fully qualified name of this interface, including package name 56 | // followed by the interface's simple name. 57 | string name = 1; 58 | 59 | // The methods of this interface, in unspecified order. 60 | repeated Method methods = 2; 61 | 62 | // Any metadata attached to the interface. 63 | repeated Option options = 3; 64 | 65 | // A version string for this interface. If specified, must have the form 66 | // `major-version.minor-version`, as in `1.10`. If the minor version is 67 | // omitted, it defaults to zero. If the entire version field is empty, the 68 | // major version is derived from the package name, as outlined below. If the 69 | // field is not empty, the version in the package name will be verified to be 70 | // consistent with what is provided here. 71 | // 72 | // The versioning schema uses [semantic 73 | // versioning](http://semver.org) where the major version number 74 | // indicates a breaking change and the minor version an additive, 75 | // non-breaking change. Both version numbers are signals to users 76 | // what to expect from different versions, and should be carefully 77 | // chosen based on the product plan. 78 | // 79 | // The major version is also reflected in the package name of the 80 | // interface, which must end in `v`, as in 81 | // `google.feature.v1`. For major versions 0 and 1, the suffix can 82 | // be omitted. Zero major versions must only be used for 83 | // experimental, non-GA interfaces. 84 | // 85 | string version = 4; 86 | 87 | // Source context for the protocol buffer service represented by this 88 | // message. 89 | SourceContext source_context = 5; 90 | 91 | // Included interfaces. See [Mixin][]. 92 | repeated Mixin mixins = 6; 93 | 94 | // The source syntax of the service. 95 | Syntax syntax = 7; 96 | } 97 | 98 | // Method represents a method of an API interface. 99 | message Method { 100 | // The simple name of this method. 101 | string name = 1; 102 | 103 | // A URL of the input message type. 104 | string request_type_url = 2; 105 | 106 | // If true, the request is streamed. 107 | bool request_streaming = 3; 108 | 109 | // The URL of the output message type. 110 | string response_type_url = 4; 111 | 112 | // If true, the response is streamed. 113 | bool response_streaming = 5; 114 | 115 | // Any metadata attached to the method. 116 | repeated Option options = 6; 117 | 118 | // The source syntax of this method. 119 | Syntax syntax = 7; 120 | } 121 | 122 | // Declares an API Interface to be included in this interface. The including 123 | // interface must redeclare all the methods from the included interface, but 124 | // documentation and options are inherited as follows: 125 | // 126 | // - If after comment and whitespace stripping, the documentation 127 | // string of the redeclared method is empty, it will be inherited 128 | // from the original method. 129 | // 130 | // - Each annotation belonging to the service config (http, 131 | // visibility) which is not set in the redeclared method will be 132 | // inherited. 133 | // 134 | // - If an http annotation is inherited, the path pattern will be 135 | // modified as follows. Any version prefix will be replaced by the 136 | // version of the including interface plus the [root][] path if 137 | // specified. 138 | // 139 | // Example of a simple mixin: 140 | // 141 | // package google.acl.v1; 142 | // service AccessControl { 143 | // // Get the underlying ACL object. 144 | // rpc GetAcl(GetAclRequest) returns (Acl) { 145 | // option (google.api.http).get = "/v1/{resource=**}:getAcl"; 146 | // } 147 | // } 148 | // 149 | // package google.storage.v2; 150 | // service Storage { 151 | // rpc GetAcl(GetAclRequest) returns (Acl); 152 | // 153 | // // Get a data record. 154 | // rpc GetData(GetDataRequest) returns (Data) { 155 | // option (google.api.http).get = "/v2/{resource=**}"; 156 | // } 157 | // } 158 | // 159 | // Example of a mixin configuration: 160 | // 161 | // apis: 162 | // - name: google.storage.v2.Storage 163 | // mixins: 164 | // - name: google.acl.v1.AccessControl 165 | // 166 | // The mixin construct implies that all methods in `AccessControl` are 167 | // also declared with same name and request/response types in 168 | // `Storage`. A documentation generator or annotation processor will 169 | // see the effective `Storage.GetAcl` method after inherting 170 | // documentation and annotations as follows: 171 | // 172 | // service Storage { 173 | // // Get the underlying ACL object. 174 | // rpc GetAcl(GetAclRequest) returns (Acl) { 175 | // option (google.api.http).get = "/v2/{resource=**}:getAcl"; 176 | // } 177 | // ... 178 | // } 179 | // 180 | // Note how the version in the path pattern changed from `v1` to `v2`. 181 | // 182 | // If the `root` field in the mixin is specified, it should be a 183 | // relative path under which inherited HTTP paths are placed. Example: 184 | // 185 | // apis: 186 | // - name: google.storage.v2.Storage 187 | // mixins: 188 | // - name: google.acl.v1.AccessControl 189 | // root: acls 190 | // 191 | // This implies the following inherited HTTP annotation: 192 | // 193 | // service Storage { 194 | // // Get the underlying ACL object. 195 | // rpc GetAcl(GetAclRequest) returns (Acl) { 196 | // option (google.api.http).get = "/v2/acls/{resource=**}:getAcl"; 197 | // } 198 | // ... 199 | // } 200 | message Mixin { 201 | // The fully qualified name of the interface which is included. 202 | string name = 1; 203 | 204 | // If non-empty specifies a path under which inherited HTTP paths 205 | // are rooted. 206 | string root = 2; 207 | } -------------------------------------------------------------------------------- /spawn/protos/google/protobuf/field_mask.proto: -------------------------------------------------------------------------------- 1 | // Protocol Buffers - Google's data interchange format 2 | // Copyright 2008 Google Inc. All rights reserved. 3 | // https://developers.google.com/protocol-buffers/ 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | 31 | syntax = "proto3"; 32 | 33 | package google.protobuf; 34 | 35 | option java_package = "com.google.protobuf"; 36 | option java_outer_classname = "FieldMaskProto"; 37 | option java_multiple_files = true; 38 | option objc_class_prefix = "GPB"; 39 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 40 | option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; 41 | option cc_enable_arenas = true; 42 | 43 | // `FieldMask` represents a set of symbolic field paths, for example: 44 | // 45 | // paths: "f.a" 46 | // paths: "f.b.d" 47 | // 48 | // Here `f` represents a field in some root message, `a` and `b` 49 | // fields in the message found in `f`, and `d` a field found in the 50 | // message in `f.b`. 51 | // 52 | // Field masks are used to specify a subset of fields that should be 53 | // returned by a get operation or modified by an update operation. 54 | // Field masks also have a custom JSON encoding (see below). 55 | // 56 | // # Field Masks in Projections 57 | // 58 | // When used in the context of a projection, a response message or 59 | // sub-message is filtered by the API to only contain those fields as 60 | // specified in the mask. For example, if the mask in the previous 61 | // example is applied to a response message as follows: 62 | // 63 | // f { 64 | // a : 22 65 | // b { 66 | // d : 1 67 | // x : 2 68 | // } 69 | // y : 13 70 | // } 71 | // z: 8 72 | // 73 | // The result will not contain specific values for fields x,y and z 74 | // (their value will be set to the default, and omitted in proto text 75 | // output): 76 | // 77 | // 78 | // f { 79 | // a : 22 80 | // b { 81 | // d : 1 82 | // } 83 | // } 84 | // 85 | // A repeated field is not allowed except at the last position of a 86 | // paths string. 87 | // 88 | // If a FieldMask object is not present in a get operation, the 89 | // operation applies to all fields (as if a FieldMask of all fields 90 | // had been specified). 91 | // 92 | // Note that a field mask does not necessarily apply to the 93 | // top-level response message. In case of a REST get operation, the 94 | // field mask applies directly to the response, but in case of a REST 95 | // list operation, the mask instead applies to each individual message 96 | // in the returned resource list. In case of a REST custom method, 97 | // other definitions may be used. Where the mask applies will be 98 | // clearly documented together with its declaration in the API. In 99 | // any case, the effect on the returned resource/resources is required 100 | // behavior for APIs. 101 | // 102 | // # Field Masks in Update Operations 103 | // 104 | // A field mask in update operations specifies which fields of the 105 | // targeted resource are going to be updated. The API is required 106 | // to only change the values of the fields as specified in the mask 107 | // and leave the others untouched. If a resource is passed in to 108 | // describe the updated values, the API ignores the values of all 109 | // fields not covered by the mask. 110 | // 111 | // If a repeated field is specified for an update operation, new values will 112 | // be appended to the existing repeated field in the target resource. Note that 113 | // a repeated field is only allowed in the last position of a `paths` string. 114 | // 115 | // If a sub-message is specified in the last position of the field mask for an 116 | // update operation, then new value will be merged into the existing sub-message 117 | // in the target resource. 118 | // 119 | // For example, given the target message: 120 | // 121 | // f { 122 | // b { 123 | // d: 1 124 | // x: 2 125 | // } 126 | // c: [1] 127 | // } 128 | // 129 | // And an update message: 130 | // 131 | // f { 132 | // b { 133 | // d: 10 134 | // } 135 | // c: [2] 136 | // } 137 | // 138 | // then if the field mask is: 139 | // 140 | // paths: ["f.b", "f.c"] 141 | // 142 | // then the result will be: 143 | // 144 | // f { 145 | // b { 146 | // d: 10 147 | // x: 2 148 | // } 149 | // c: [1, 2] 150 | // } 151 | // 152 | // An implementation may provide options to override this default behavior for 153 | // repeated and message fields. 154 | // 155 | // In order to reset a field's value to the default, the field must 156 | // be in the mask and set to the default value in the provided resource. 157 | // Hence, in order to reset all fields of a resource, provide a default 158 | // instance of the resource and set all fields in the mask, or do 159 | // not provide a mask as described below. 160 | // 161 | // If a field mask is not present on update, the operation applies to 162 | // all fields (as if a field mask of all fields has been specified). 163 | // Note that in the presence of schema evolution, this may mean that 164 | // fields the client does not know and has therefore not filled into 165 | // the request will be reset to their default. If this is unwanted 166 | // behavior, a specific service may require a client to always specify 167 | // a field mask, producing an error if not. 168 | // 169 | // As with get operations, the location of the resource which 170 | // describes the updated values in the request message depends on the 171 | // operation kind. In any case, the effect of the field mask is 172 | // required to be honored by the API. 173 | // 174 | // ## Considerations for HTTP REST 175 | // 176 | // The HTTP kind of an update operation which uses a field mask must 177 | // be set to PATCH instead of PUT in order to satisfy HTTP semantics 178 | // (PUT must only be used for full updates). 179 | // 180 | // # JSON Encoding of Field Masks 181 | // 182 | // In JSON, a field mask is encoded as a single string where paths are 183 | // separated by a comma. Fields name in each path are converted 184 | // to/from lower-camel naming conventions. 185 | // 186 | // As an example, consider the following message declarations: 187 | // 188 | // message Profile { 189 | // User user = 1; 190 | // Photo photo = 2; 191 | // } 192 | // message User { 193 | // string display_name = 1; 194 | // string address = 2; 195 | // } 196 | // 197 | // In proto a field mask for `Profile` may look as such: 198 | // 199 | // mask { 200 | // paths: "user.display_name" 201 | // paths: "photo" 202 | // } 203 | // 204 | // In JSON, the same mask is represented as below: 205 | // 206 | // { 207 | // mask: "user.displayName,photo" 208 | // } 209 | // 210 | // # Field Masks and Oneof Fields 211 | // 212 | // Field masks treat fields in oneofs just as regular fields. Consider the 213 | // following message: 214 | // 215 | // message SampleMessage { 216 | // oneof test_oneof { 217 | // string name = 4; 218 | // SubMessage sub_message = 9; 219 | // } 220 | // } 221 | // 222 | // The field mask can be: 223 | // 224 | // mask { 225 | // paths: "name" 226 | // } 227 | // 228 | // Or: 229 | // 230 | // mask { 231 | // paths: "sub_message" 232 | // } 233 | // 234 | // Note that oneof type names ("test_oneof" in this case) cannot be used in 235 | // paths. 236 | // 237 | // ## Field Mask Verification 238 | // 239 | // The implementation of any API method which has a FieldMask type field in the 240 | // request should verify the included field paths, and return an 241 | // `INVALID_ARGUMENT` error if any path is unmappable. 242 | message FieldMask { 243 | // The set of field mask paths. 244 | repeated string paths = 1; 245 | } -------------------------------------------------------------------------------- /spawn/eigr/functions/protocol/actors/state.pb.go: -------------------------------------------------------------------------------- 1 | // The Spawn State Extension Protocol 2 | // 3 | // 4 | 5 | // Code generated by protoc-gen-go. DO NOT EDIT. 6 | // versions: 7 | // protoc-gen-go v1.35.2 8 | // protoc v3.12.4 9 | // source: eigr/functions/protocol/actors/state.proto 10 | 11 | package actors 12 | 13 | import ( 14 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 15 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 16 | reflect "reflect" 17 | sync "sync" 18 | ) 19 | 20 | const ( 21 | // Verify that this generated code is sufficiently up-to-date. 22 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 23 | // Verify that runtime/protoimpl is sufficiently up-to-date. 24 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 25 | ) 26 | 27 | // A revision is just a version number for a record in the snapshot table that stores the actors' state. 28 | // When an actor has its snaphost timeout, it increments its internal revision number and saves it along with its internal data. 29 | // Some of the persistence adapters can use this revision number to find the state of an Actor at a given point in time. 30 | // As Actors in Spawn persist their internal data as snapshots from time to time a revision number may not indicate the state of a given change 31 | // but will most likely point to the exact time that a given actor's internal state was persisted into the database. 32 | type Revision struct { 33 | state protoimpl.MessageState 34 | sizeCache protoimpl.SizeCache 35 | unknownFields protoimpl.UnknownFields 36 | 37 | Value int64 `protobuf:"varint,1,opt,name=value,proto3" json:"value,omitempty"` 38 | } 39 | 40 | func (x *Revision) Reset() { 41 | *x = Revision{} 42 | mi := &file_eigr_functions_protocol_actors_state_proto_msgTypes[0] 43 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 44 | ms.StoreMessageInfo(mi) 45 | } 46 | 47 | func (x *Revision) String() string { 48 | return protoimpl.X.MessageStringOf(x) 49 | } 50 | 51 | func (*Revision) ProtoMessage() {} 52 | 53 | func (x *Revision) ProtoReflect() protoreflect.Message { 54 | mi := &file_eigr_functions_protocol_actors_state_proto_msgTypes[0] 55 | if x != nil { 56 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 57 | if ms.LoadMessageInfo() == nil { 58 | ms.StoreMessageInfo(mi) 59 | } 60 | return ms 61 | } 62 | return mi.MessageOf(x) 63 | } 64 | 65 | // Deprecated: Use Revision.ProtoReflect.Descriptor instead. 66 | func (*Revision) Descriptor() ([]byte, []int) { 67 | return file_eigr_functions_protocol_actors_state_proto_rawDescGZIP(), []int{0} 68 | } 69 | 70 | func (x *Revision) GetValue() int64 { 71 | if x != nil { 72 | return x.Value 73 | } 74 | return 0 75 | } 76 | 77 | // A checkpoint encapsulates a revision and the state it represents. 78 | type Checkpoint struct { 79 | state protoimpl.MessageState 80 | sizeCache protoimpl.SizeCache 81 | unknownFields protoimpl.UnknownFields 82 | 83 | Revision *Revision `protobuf:"bytes,1,opt,name=revision,proto3" json:"revision,omitempty"` 84 | State *ActorState `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` 85 | } 86 | 87 | func (x *Checkpoint) Reset() { 88 | *x = Checkpoint{} 89 | mi := &file_eigr_functions_protocol_actors_state_proto_msgTypes[1] 90 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 91 | ms.StoreMessageInfo(mi) 92 | } 93 | 94 | func (x *Checkpoint) String() string { 95 | return protoimpl.X.MessageStringOf(x) 96 | } 97 | 98 | func (*Checkpoint) ProtoMessage() {} 99 | 100 | func (x *Checkpoint) ProtoReflect() protoreflect.Message { 101 | mi := &file_eigr_functions_protocol_actors_state_proto_msgTypes[1] 102 | if x != nil { 103 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 104 | if ms.LoadMessageInfo() == nil { 105 | ms.StoreMessageInfo(mi) 106 | } 107 | return ms 108 | } 109 | return mi.MessageOf(x) 110 | } 111 | 112 | // Deprecated: Use Checkpoint.ProtoReflect.Descriptor instead. 113 | func (*Checkpoint) Descriptor() ([]byte, []int) { 114 | return file_eigr_functions_protocol_actors_state_proto_rawDescGZIP(), []int{1} 115 | } 116 | 117 | func (x *Checkpoint) GetRevision() *Revision { 118 | if x != nil { 119 | return x.Revision 120 | } 121 | return nil 122 | } 123 | 124 | func (x *Checkpoint) GetState() *ActorState { 125 | if x != nil { 126 | return x.State 127 | } 128 | return nil 129 | } 130 | 131 | var File_eigr_functions_protocol_actors_state_proto protoreflect.FileDescriptor 132 | 133 | var file_eigr_functions_protocol_actors_state_proto_rawDesc = []byte{ 134 | 0x0a, 0x2a, 0x65, 0x69, 0x67, 0x72, 0x2f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 135 | 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 136 | 0x2f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1d, 0x65, 0x69, 137 | 0x67, 0x72, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 138 | 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x2a, 0x65, 0x69, 0x67, 139 | 0x72, 0x2f, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 140 | 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x2f, 0x61, 0x63, 0x74, 0x6f, 141 | 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x20, 0x0a, 0x08, 0x52, 0x65, 0x76, 0x69, 0x73, 142 | 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 143 | 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x0a, 0x43, 0x68, 144 | 0x65, 0x63, 0x6b, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x12, 0x43, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 145 | 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x65, 0x69, 0x67, 146 | 0x72, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 147 | 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x52, 0x65, 0x76, 0x69, 0x73, 148 | 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 149 | 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x65, 150 | 0x69, 0x67, 0x72, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 151 | 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x2e, 0x41, 0x63, 152 | 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x42, 153 | 0x48, 0x0a, 0x20, 0x69, 0x6f, 0x2e, 0x65, 0x69, 0x67, 0x72, 0x2e, 0x66, 0x75, 0x6e, 0x63, 0x74, 154 | 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x73, 0x74, 155 | 0x61, 0x74, 0x65, 0x5a, 0x24, 0x73, 0x70, 0x61, 0x77, 0x6e, 0x2f, 0x65, 0x69, 0x67, 0x72, 0x2f, 156 | 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 157 | 0x6f, 0x6c, 0x2f, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 158 | 0x33, 159 | } 160 | 161 | var ( 162 | file_eigr_functions_protocol_actors_state_proto_rawDescOnce sync.Once 163 | file_eigr_functions_protocol_actors_state_proto_rawDescData = file_eigr_functions_protocol_actors_state_proto_rawDesc 164 | ) 165 | 166 | func file_eigr_functions_protocol_actors_state_proto_rawDescGZIP() []byte { 167 | file_eigr_functions_protocol_actors_state_proto_rawDescOnce.Do(func() { 168 | file_eigr_functions_protocol_actors_state_proto_rawDescData = protoimpl.X.CompressGZIP(file_eigr_functions_protocol_actors_state_proto_rawDescData) 169 | }) 170 | return file_eigr_functions_protocol_actors_state_proto_rawDescData 171 | } 172 | 173 | var file_eigr_functions_protocol_actors_state_proto_msgTypes = make([]protoimpl.MessageInfo, 2) 174 | var file_eigr_functions_protocol_actors_state_proto_goTypes = []any{ 175 | (*Revision)(nil), // 0: eigr.functions.protocol.state.Revision 176 | (*Checkpoint)(nil), // 1: eigr.functions.protocol.state.Checkpoint 177 | (*ActorState)(nil), // 2: eigr.functions.protocol.actors.ActorState 178 | } 179 | var file_eigr_functions_protocol_actors_state_proto_depIdxs = []int32{ 180 | 0, // 0: eigr.functions.protocol.state.Checkpoint.revision:type_name -> eigr.functions.protocol.state.Revision 181 | 2, // 1: eigr.functions.protocol.state.Checkpoint.state:type_name -> eigr.functions.protocol.actors.ActorState 182 | 2, // [2:2] is the sub-list for method output_type 183 | 2, // [2:2] is the sub-list for method input_type 184 | 2, // [2:2] is the sub-list for extension type_name 185 | 2, // [2:2] is the sub-list for extension extendee 186 | 0, // [0:2] is the sub-list for field type_name 187 | } 188 | 189 | func init() { file_eigr_functions_protocol_actors_state_proto_init() } 190 | func file_eigr_functions_protocol_actors_state_proto_init() { 191 | if File_eigr_functions_protocol_actors_state_proto != nil { 192 | return 193 | } 194 | file_eigr_functions_protocol_actors_actor_proto_init() 195 | type x struct{} 196 | out := protoimpl.TypeBuilder{ 197 | File: protoimpl.DescBuilder{ 198 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 199 | RawDescriptor: file_eigr_functions_protocol_actors_state_proto_rawDesc, 200 | NumEnums: 0, 201 | NumMessages: 2, 202 | NumExtensions: 0, 203 | NumServices: 0, 204 | }, 205 | GoTypes: file_eigr_functions_protocol_actors_state_proto_goTypes, 206 | DependencyIndexes: file_eigr_functions_protocol_actors_state_proto_depIdxs, 207 | MessageInfos: file_eigr_functions_protocol_actors_state_proto_msgTypes, 208 | }.Build() 209 | File_eigr_functions_protocol_actors_state_proto = out.File 210 | file_eigr_functions_protocol_actors_state_proto_rawDesc = nil 211 | file_eigr_functions_protocol_actors_state_proto_goTypes = nil 212 | file_eigr_functions_protocol_actors_state_proto_depIdxs = nil 213 | } 214 | -------------------------------------------------------------------------------- /examples/actors/user_example.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.35.2 4 | // protoc v3.12.4 5 | // source: user_example.proto 6 | 7 | package actors 8 | 9 | import ( 10 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 11 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 12 | reflect "reflect" 13 | sync "sync" 14 | ) 15 | 16 | const ( 17 | // Verify that this generated code is sufficiently up-to-date. 18 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 19 | // Verify that runtime/protoimpl is sufficiently up-to-date. 20 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 21 | ) 22 | 23 | // this is a bad example, but it's just an example 24 | type ChangeUserNameResponse_ResponseStatus int32 25 | 26 | const ( 27 | ChangeUserNameResponse_OK ChangeUserNameResponse_ResponseStatus = 0 28 | ChangeUserNameResponse_ERROR ChangeUserNameResponse_ResponseStatus = 1 29 | ) 30 | 31 | // Enum value maps for ChangeUserNameResponse_ResponseStatus. 32 | var ( 33 | ChangeUserNameResponse_ResponseStatus_name = map[int32]string{ 34 | 0: "OK", 35 | 1: "ERROR", 36 | } 37 | ChangeUserNameResponse_ResponseStatus_value = map[string]int32{ 38 | "OK": 0, 39 | "ERROR": 1, 40 | } 41 | ) 42 | 43 | func (x ChangeUserNameResponse_ResponseStatus) Enum() *ChangeUserNameResponse_ResponseStatus { 44 | p := new(ChangeUserNameResponse_ResponseStatus) 45 | *p = x 46 | return p 47 | } 48 | 49 | func (x ChangeUserNameResponse_ResponseStatus) String() string { 50 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 51 | } 52 | 53 | func (ChangeUserNameResponse_ResponseStatus) Descriptor() protoreflect.EnumDescriptor { 54 | return file_user_example_proto_enumTypes[0].Descriptor() 55 | } 56 | 57 | func (ChangeUserNameResponse_ResponseStatus) Type() protoreflect.EnumType { 58 | return &file_user_example_proto_enumTypes[0] 59 | } 60 | 61 | func (x ChangeUserNameResponse_ResponseStatus) Number() protoreflect.EnumNumber { 62 | return protoreflect.EnumNumber(x) 63 | } 64 | 65 | // Deprecated: Use ChangeUserNameResponse_ResponseStatus.Descriptor instead. 66 | func (ChangeUserNameResponse_ResponseStatus) EnumDescriptor() ([]byte, []int) { 67 | return file_user_example_proto_rawDescGZIP(), []int{2, 0} 68 | } 69 | 70 | type UserState struct { 71 | state protoimpl.MessageState 72 | sizeCache protoimpl.SizeCache 73 | unknownFields protoimpl.UnknownFields 74 | 75 | Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` 76 | } 77 | 78 | func (x *UserState) Reset() { 79 | *x = UserState{} 80 | mi := &file_user_example_proto_msgTypes[0] 81 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 82 | ms.StoreMessageInfo(mi) 83 | } 84 | 85 | func (x *UserState) String() string { 86 | return protoimpl.X.MessageStringOf(x) 87 | } 88 | 89 | func (*UserState) ProtoMessage() {} 90 | 91 | func (x *UserState) ProtoReflect() protoreflect.Message { 92 | mi := &file_user_example_proto_msgTypes[0] 93 | if x != nil { 94 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 95 | if ms.LoadMessageInfo() == nil { 96 | ms.StoreMessageInfo(mi) 97 | } 98 | return ms 99 | } 100 | return mi.MessageOf(x) 101 | } 102 | 103 | // Deprecated: Use UserState.ProtoReflect.Descriptor instead. 104 | func (*UserState) Descriptor() ([]byte, []int) { 105 | return file_user_example_proto_rawDescGZIP(), []int{0} 106 | } 107 | 108 | func (x *UserState) GetName() string { 109 | if x != nil { 110 | return x.Name 111 | } 112 | return "" 113 | } 114 | 115 | type ChangeUserNamePayload struct { 116 | state protoimpl.MessageState 117 | sizeCache protoimpl.SizeCache 118 | unknownFields protoimpl.UnknownFields 119 | 120 | NewName string `protobuf:"bytes,1,opt,name=new_name,json=newName,proto3" json:"new_name,omitempty"` 121 | } 122 | 123 | func (x *ChangeUserNamePayload) Reset() { 124 | *x = ChangeUserNamePayload{} 125 | mi := &file_user_example_proto_msgTypes[1] 126 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 127 | ms.StoreMessageInfo(mi) 128 | } 129 | 130 | func (x *ChangeUserNamePayload) String() string { 131 | return protoimpl.X.MessageStringOf(x) 132 | } 133 | 134 | func (*ChangeUserNamePayload) ProtoMessage() {} 135 | 136 | func (x *ChangeUserNamePayload) ProtoReflect() protoreflect.Message { 137 | mi := &file_user_example_proto_msgTypes[1] 138 | if x != nil { 139 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 140 | if ms.LoadMessageInfo() == nil { 141 | ms.StoreMessageInfo(mi) 142 | } 143 | return ms 144 | } 145 | return mi.MessageOf(x) 146 | } 147 | 148 | // Deprecated: Use ChangeUserNamePayload.ProtoReflect.Descriptor instead. 149 | func (*ChangeUserNamePayload) Descriptor() ([]byte, []int) { 150 | return file_user_example_proto_rawDescGZIP(), []int{1} 151 | } 152 | 153 | func (x *ChangeUserNamePayload) GetNewName() string { 154 | if x != nil { 155 | return x.NewName 156 | } 157 | return "" 158 | } 159 | 160 | type ChangeUserNameResponse struct { 161 | state protoimpl.MessageState 162 | sizeCache protoimpl.SizeCache 163 | unknownFields protoimpl.UnknownFields 164 | 165 | ResponseStatus ChangeUserNameResponse_ResponseStatus `protobuf:"varint,1,opt,name=response_status,json=responseStatus,proto3,enum=examples.actors.ChangeUserNameResponse_ResponseStatus" json:"response_status,omitempty"` 166 | } 167 | 168 | func (x *ChangeUserNameResponse) Reset() { 169 | *x = ChangeUserNameResponse{} 170 | mi := &file_user_example_proto_msgTypes[2] 171 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 172 | ms.StoreMessageInfo(mi) 173 | } 174 | 175 | func (x *ChangeUserNameResponse) String() string { 176 | return protoimpl.X.MessageStringOf(x) 177 | } 178 | 179 | func (*ChangeUserNameResponse) ProtoMessage() {} 180 | 181 | func (x *ChangeUserNameResponse) ProtoReflect() protoreflect.Message { 182 | mi := &file_user_example_proto_msgTypes[2] 183 | if x != nil { 184 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 185 | if ms.LoadMessageInfo() == nil { 186 | ms.StoreMessageInfo(mi) 187 | } 188 | return ms 189 | } 190 | return mi.MessageOf(x) 191 | } 192 | 193 | // Deprecated: Use ChangeUserNameResponse.ProtoReflect.Descriptor instead. 194 | func (*ChangeUserNameResponse) Descriptor() ([]byte, []int) { 195 | return file_user_example_proto_rawDescGZIP(), []int{2} 196 | } 197 | 198 | func (x *ChangeUserNameResponse) GetResponseStatus() ChangeUserNameResponse_ResponseStatus { 199 | if x != nil { 200 | return x.ResponseStatus 201 | } 202 | return ChangeUserNameResponse_OK 203 | } 204 | 205 | var File_user_example_proto protoreflect.FileDescriptor 206 | 207 | var file_user_example_proto_rawDesc = []byte{ 208 | 0x0a, 0x12, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x70, 209 | 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x61, 210 | 0x63, 0x74, 0x6f, 0x72, 0x73, 0x22, 0x1f, 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 211 | 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 212 | 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x32, 0x0a, 0x15, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 213 | 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 214 | 0x19, 0x0a, 0x08, 0x6e, 0x65, 0x77, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 215 | 0x09, 0x52, 0x07, 0x6e, 0x65, 0x77, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x9e, 0x01, 0x0a, 0x16, 0x43, 216 | 0x68, 0x61, 0x6e, 0x67, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 217 | 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x5f, 0x0a, 0x0f, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 218 | 0x65, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 219 | 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 220 | 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x52, 221 | 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 222 | 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x0e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 223 | 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x23, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 224 | 0x73, 0x65, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x06, 0x0a, 0x02, 0x4f, 0x4b, 0x10, 0x00, 225 | 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01, 0x32, 0x70, 0x0a, 0x09, 0x55, 226 | 0x73, 0x65, 0x72, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x63, 0x0a, 0x0e, 0x43, 0x68, 0x61, 0x6e, 227 | 0x67, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x26, 0x2e, 0x65, 0x78, 0x61, 228 | 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x2e, 0x43, 0x68, 0x61, 229 | 0x6e, 0x67, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x50, 0x61, 0x79, 0x6c, 0x6f, 230 | 0x61, 0x64, 0x1a, 0x27, 0x2e, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2e, 0x61, 0x63, 231 | 0x74, 0x6f, 0x72, 0x73, 0x2e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x55, 0x73, 0x65, 0x72, 0x4e, 232 | 0x61, 0x6d, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x11, 0x5a, 233 | 0x0f, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x73, 0x2f, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 234 | 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 235 | } 236 | 237 | var ( 238 | file_user_example_proto_rawDescOnce sync.Once 239 | file_user_example_proto_rawDescData = file_user_example_proto_rawDesc 240 | ) 241 | 242 | func file_user_example_proto_rawDescGZIP() []byte { 243 | file_user_example_proto_rawDescOnce.Do(func() { 244 | file_user_example_proto_rawDescData = protoimpl.X.CompressGZIP(file_user_example_proto_rawDescData) 245 | }) 246 | return file_user_example_proto_rawDescData 247 | } 248 | 249 | var file_user_example_proto_enumTypes = make([]protoimpl.EnumInfo, 1) 250 | var file_user_example_proto_msgTypes = make([]protoimpl.MessageInfo, 3) 251 | var file_user_example_proto_goTypes = []any{ 252 | (ChangeUserNameResponse_ResponseStatus)(0), // 0: examples.actors.ChangeUserNameResponse.ResponseStatus 253 | (*UserState)(nil), // 1: examples.actors.UserState 254 | (*ChangeUserNamePayload)(nil), // 2: examples.actors.ChangeUserNamePayload 255 | (*ChangeUserNameResponse)(nil), // 3: examples.actors.ChangeUserNameResponse 256 | } 257 | var file_user_example_proto_depIdxs = []int32{ 258 | 0, // 0: examples.actors.ChangeUserNameResponse.response_status:type_name -> examples.actors.ChangeUserNameResponse.ResponseStatus 259 | 2, // 1: examples.actors.UserActor.ChangeUserName:input_type -> examples.actors.ChangeUserNamePayload 260 | 3, // 2: examples.actors.UserActor.ChangeUserName:output_type -> examples.actors.ChangeUserNameResponse 261 | 2, // [2:3] is the sub-list for method output_type 262 | 1, // [1:2] is the sub-list for method input_type 263 | 1, // [1:1] is the sub-list for extension type_name 264 | 1, // [1:1] is the sub-list for extension extendee 265 | 0, // [0:1] is the sub-list for field type_name 266 | } 267 | 268 | func init() { file_user_example_proto_init() } 269 | func file_user_example_proto_init() { 270 | if File_user_example_proto != nil { 271 | return 272 | } 273 | type x struct{} 274 | out := protoimpl.TypeBuilder{ 275 | File: protoimpl.DescBuilder{ 276 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 277 | RawDescriptor: file_user_example_proto_rawDesc, 278 | NumEnums: 1, 279 | NumMessages: 3, 280 | NumExtensions: 0, 281 | NumServices: 1, 282 | }, 283 | GoTypes: file_user_example_proto_goTypes, 284 | DependencyIndexes: file_user_example_proto_depIdxs, 285 | EnumInfos: file_user_example_proto_enumTypes, 286 | MessageInfos: file_user_example_proto_msgTypes, 287 | }.Build() 288 | File_user_example_proto = out.File 289 | file_user_example_proto_rawDesc = nil 290 | file_user_example_proto_goTypes = nil 291 | file_user_example_proto_depIdxs = nil 292 | } 293 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /spawn/protos/google/api/http.proto: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | syntax = "proto3"; 16 | 17 | package google.api; 18 | 19 | option cc_enable_arenas = true; 20 | option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations"; 21 | option java_multiple_files = true; 22 | option java_outer_classname = "HttpProto"; 23 | option java_package = "com.google.api"; 24 | option objc_class_prefix = "GAPI"; 25 | 26 | // Defines the HTTP configuration for an API service. It contains a list of 27 | // [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method 28 | // to one or more HTTP REST API methods. 29 | message Http { 30 | // A list of HTTP configuration rules that apply to individual API methods. 31 | // 32 | // **NOTE:** All service configuration rules follow "last one wins" order. 33 | repeated HttpRule rules = 1; 34 | 35 | // When set to true, URL path parameters will be fully URI-decoded except in 36 | // cases of single segment matches in reserved expansion, where "%2F" will be 37 | // left encoded. 38 | // 39 | // The default behavior is to not decode RFC 6570 reserved characters in multi 40 | // segment matches. 41 | bool fully_decode_reserved_expansion = 2; 42 | } 43 | 44 | // # gRPC Transcoding 45 | // 46 | // gRPC Transcoding is a feature for mapping between a gRPC method and one or 47 | // more HTTP REST endpoints. It allows developers to build a single API service 48 | // that supports both gRPC APIs and REST APIs. Many systems, including [Google 49 | // APIs](https://github.com/googleapis/googleapis), 50 | // [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC 51 | // Gateway](https://github.com/grpc-ecosystem/grpc-gateway), 52 | // and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature 53 | // and use it for large scale production services. 54 | // 55 | // `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies 56 | // how different portions of the gRPC request message are mapped to the URL 57 | // path, URL query parameters, and HTTP request body. It also controls how the 58 | // gRPC response message is mapped to the HTTP response body. `HttpRule` is 59 | // typically specified as an `google.api.http` annotation on the gRPC method. 60 | // 61 | // Each mapping specifies a URL path template and an HTTP method. The path 62 | // template may refer to one or more fields in the gRPC request message, as long 63 | // as each field is a non-repeated field with a primitive (non-message) type. 64 | // The path template controls how fields of the request message are mapped to 65 | // the URL path. 66 | // 67 | // Example: 68 | // 69 | // service Messaging { 70 | // rpc GetMessage(GetMessageRequest) returns (Message) { 71 | // option (google.api.http) = { 72 | // get: "/v1/{name=messages/*}" 73 | // }; 74 | // } 75 | // } 76 | // message GetMessageRequest { 77 | // string name = 1; // Mapped to URL path. 78 | // } 79 | // message Message { 80 | // string text = 1; // The resource content. 81 | // } 82 | // 83 | // This enables an HTTP REST to gRPC mapping as below: 84 | // 85 | // HTTP | gRPC 86 | // -----|----- 87 | // `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` 88 | // 89 | // Any fields in the request message which are not bound by the path template 90 | // automatically become HTTP query parameters if there is no HTTP request body. 91 | // For example: 92 | // 93 | // service Messaging { 94 | // rpc GetMessage(GetMessageRequest) returns (Message) { 95 | // option (google.api.http) = { 96 | // get:"/v1/messages/{message_id}" 97 | // }; 98 | // } 99 | // } 100 | // message GetMessageRequest { 101 | // message SubMessage { 102 | // string subfield = 1; 103 | // } 104 | // string message_id = 1; // Mapped to URL path. 105 | // int64 revision = 2; // Mapped to URL query parameter `revision`. 106 | // SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. 107 | // } 108 | // 109 | // This enables a HTTP JSON to RPC mapping as below: 110 | // 111 | // HTTP | gRPC 112 | // -----|----- 113 | // `GET /v1/messages/123456?revision=2&sub.subfield=foo` | 114 | // `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: 115 | // "foo"))` 116 | // 117 | // Note that fields which are mapped to URL query parameters must have a 118 | // primitive type or a repeated primitive type or a non-repeated message type. 119 | // In the case of a repeated type, the parameter can be repeated in the URL 120 | // as `...?param=A¶m=B`. In the case of a message type, each field of the 121 | // message is mapped to a separate parameter, such as 122 | // `...?foo.a=A&foo.b=B&foo.c=C`. 123 | // 124 | // For HTTP methods that allow a request body, the `body` field 125 | // specifies the mapping. Consider a REST update method on the 126 | // message resource collection: 127 | // 128 | // service Messaging { 129 | // rpc UpdateMessage(UpdateMessageRequest) returns (Message) { 130 | // option (google.api.http) = { 131 | // patch: "/v1/messages/{message_id}" 132 | // body: "message" 133 | // }; 134 | // } 135 | // } 136 | // message UpdateMessageRequest { 137 | // string message_id = 1; // mapped to the URL 138 | // Message message = 2; // mapped to the body 139 | // } 140 | // 141 | // The following HTTP JSON to RPC mapping is enabled, where the 142 | // representation of the JSON in the request body is determined by 143 | // protos JSON encoding: 144 | // 145 | // HTTP | gRPC 146 | // -----|----- 147 | // `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: 148 | // "123456" message { text: "Hi!" })` 149 | // 150 | // The special name `*` can be used in the body mapping to define that 151 | // every field not bound by the path template should be mapped to the 152 | // request body. This enables the following alternative definition of 153 | // the update method: 154 | // 155 | // service Messaging { 156 | // rpc UpdateMessage(Message) returns (Message) { 157 | // option (google.api.http) = { 158 | // patch: "/v1/messages/{message_id}" 159 | // body: "*" 160 | // }; 161 | // } 162 | // } 163 | // message Message { 164 | // string message_id = 1; 165 | // string text = 2; 166 | // } 167 | // 168 | // 169 | // The following HTTP JSON to RPC mapping is enabled: 170 | // 171 | // HTTP | gRPC 172 | // -----|----- 173 | // `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: 174 | // "123456" text: "Hi!")` 175 | // 176 | // Note that when using `*` in the body mapping, it is not possible to 177 | // have HTTP parameters, as all fields not bound by the path end in 178 | // the body. This makes this option more rarely used in practice when 179 | // defining REST APIs. The common usage of `*` is in custom methods 180 | // which don't use the URL at all for transferring data. 181 | // 182 | // It is possible to define multiple HTTP methods for one RPC by using 183 | // the `additional_bindings` option. Example: 184 | // 185 | // service Messaging { 186 | // rpc GetMessage(GetMessageRequest) returns (Message) { 187 | // option (google.api.http) = { 188 | // get: "/v1/messages/{message_id}" 189 | // additional_bindings { 190 | // get: "/v1/users/{user_id}/messages/{message_id}" 191 | // } 192 | // }; 193 | // } 194 | // } 195 | // message GetMessageRequest { 196 | // string message_id = 1; 197 | // string user_id = 2; 198 | // } 199 | // 200 | // This enables the following two alternative HTTP JSON to RPC mappings: 201 | // 202 | // HTTP | gRPC 203 | // -----|----- 204 | // `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` 205 | // `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: 206 | // "123456")` 207 | // 208 | // ## Rules for HTTP mapping 209 | // 210 | // 1. Leaf request fields (recursive expansion nested messages in the request 211 | // message) are classified into three categories: 212 | // - Fields referred by the path template. They are passed via the URL path. 213 | // - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP 214 | // request body. 215 | // - All other fields are passed via the URL query parameters, and the 216 | // parameter name is the field path in the request message. A repeated 217 | // field can be represented as multiple query parameters under the same 218 | // name. 219 | // 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields 220 | // are passed via URL path and HTTP request body. 221 | // 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all 222 | // fields are passed via URL path and URL query parameters. 223 | // 224 | // ### Path template syntax 225 | // 226 | // Template = "/" Segments [ Verb ] ; 227 | // Segments = Segment { "/" Segment } ; 228 | // Segment = "*" | "**" | LITERAL | Variable ; 229 | // Variable = "{" FieldPath [ "=" Segments ] "}" ; 230 | // FieldPath = IDENT { "." IDENT } ; 231 | // Verb = ":" LITERAL ; 232 | // 233 | // The syntax `*` matches a single URL path segment. The syntax `**` matches 234 | // zero or more URL path segments, which must be the last part of the URL path 235 | // except the `Verb`. 236 | // 237 | // The syntax `Variable` matches part of the URL path as specified by its 238 | // template. A variable template must not contain other variables. If a variable 239 | // matches a single path segment, its template may be omitted, e.g. `{var}` 240 | // is equivalent to `{var=*}`. 241 | // 242 | // The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` 243 | // contains any reserved character, such characters should be percent-encoded 244 | // before the matching. 245 | // 246 | // If a variable contains exactly one path segment, such as `"{var}"` or 247 | // `"{var=*}"`, when such a variable is expanded into a URL path on the client 248 | // side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The 249 | // server side does the reverse decoding. Such variables show up in the 250 | // [Discovery 251 | // Document](https://developers.google.com/discovery/v1/reference/apis) as 252 | // `{var}`. 253 | // 254 | // If a variable contains multiple path segments, such as `"{var=foo/*}"` 255 | // or `"{var=**}"`, when such a variable is expanded into a URL path on the 256 | // client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. 257 | // The server side does the reverse decoding, except "%2F" and "%2f" are left 258 | // unchanged. Such variables show up in the 259 | // [Discovery 260 | // Document](https://developers.google.com/discovery/v1/reference/apis) as 261 | // `{+var}`. 262 | // 263 | // ## Using gRPC API Service Configuration 264 | // 265 | // gRPC API Service Configuration (service config) is a configuration language 266 | // for configuring a gRPC service to become a user-facing product. The 267 | // service config is simply the YAML representation of the `google.api.Service` 268 | // proto message. 269 | // 270 | // As an alternative to annotating your proto file, you can configure gRPC 271 | // transcoding in your service config YAML files. You do this by specifying a 272 | // `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same 273 | // effect as the proto annotation. This can be particularly useful if you 274 | // have a proto that is reused in multiple services. Note that any transcoding 275 | // specified in the service config will override any matching transcoding 276 | // configuration in the proto. 277 | // 278 | // Example: 279 | // 280 | // http: 281 | // rules: 282 | // # Selects a gRPC method and applies HttpRule to it. 283 | // - selector: example.v1.Messaging.GetMessage 284 | // get: /v1/messages/{message_id}/{sub.subfield} 285 | // 286 | // ## Special notes 287 | // 288 | // When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the 289 | // proto to JSON conversion must follow the [proto3 290 | // specification](https://developers.google.com/protocol-buffers/docs/proto3#json). 291 | // 292 | // While the single segment variable follows the semantics of 293 | // [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String 294 | // Expansion, the multi segment variable **does not** follow RFC 6570 Section 295 | // 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion 296 | // does not expand special characters like `?` and `#`, which would lead 297 | // to invalid URLs. As the result, gRPC Transcoding uses a custom encoding 298 | // for multi segment variables. 299 | // 300 | // The path variables **must not** refer to any repeated or mapped field, 301 | // because client libraries are not capable of handling such variable expansion. 302 | // 303 | // The path variables **must not** capture the leading "/" character. The reason 304 | // is that the most common use case "{var}" does not capture the leading "/" 305 | // character. For consistency, all path variables must share the same behavior. 306 | // 307 | // Repeated message fields must not be mapped to URL query parameters, because 308 | // no client library can support such complicated mapping. 309 | // 310 | // If an API needs to use a JSON array for request or response body, it can map 311 | // the request or response body to a repeated field. However, some gRPC 312 | // Transcoding implementations may not support this feature. 313 | message HttpRule { 314 | // Selects a method to which this rule applies. 315 | // 316 | // Refer to [selector][google.api.DocumentationRule.selector] for syntax details. 317 | string selector = 1; 318 | 319 | // Determines the URL pattern is matched by this rules. This pattern can be 320 | // used with any of the {get|put|post|delete|patch} methods. A custom method 321 | // can be defined using the 'custom' field. 322 | oneof pattern { 323 | // Maps to HTTP GET. Used for listing and getting information about 324 | // resources. 325 | string get = 2; 326 | 327 | // Maps to HTTP PUT. Used for replacing a resource. 328 | string put = 3; 329 | 330 | // Maps to HTTP POST. Used for creating a resource or performing an action. 331 | string post = 4; 332 | 333 | // Maps to HTTP DELETE. Used for deleting a resource. 334 | string delete = 5; 335 | 336 | // Maps to HTTP PATCH. Used for updating a resource. 337 | string patch = 6; 338 | 339 | // The custom pattern is used for specifying an HTTP method that is not 340 | // included in the `pattern` field, such as HEAD, or "*" to leave the 341 | // HTTP method unspecified for this rule. The wild-card rule is useful 342 | // for services that provide content to Web (HTML) clients. 343 | CustomHttpPattern custom = 8; 344 | } 345 | 346 | // The name of the request field whose value is mapped to the HTTP request 347 | // body, or `*` for mapping all request fields not captured by the path 348 | // pattern to the HTTP body, or omitted for not having any HTTP request body. 349 | // 350 | // NOTE: the referred field must be present at the top-level of the request 351 | // message type. 352 | string body = 7; 353 | 354 | // Optional. The name of the response field whose value is mapped to the HTTP 355 | // response body. When omitted, the entire response message will be used 356 | // as the HTTP response body. 357 | // 358 | // NOTE: The referred field must be present at the top-level of the response 359 | // message type. 360 | string response_body = 12; 361 | 362 | // Additional HTTP bindings for the selector. Nested bindings must 363 | // not contain an `additional_bindings` field themselves (that is, 364 | // the nesting may only be one level deep). 365 | repeated HttpRule additional_bindings = 11; 366 | } 367 | 368 | // A custom pattern is used for defining custom HTTP verb. 369 | message CustomHttpPattern { 370 | // The name of this custom HTTP verb. 371 | string kind = 1; 372 | 373 | // The path matched by this custom verb. 374 | string path = 2; 375 | } 376 | -------------------------------------------------------------------------------- /spawn/system/system.go: -------------------------------------------------------------------------------- 1 | package system 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "io" 7 | "log" 8 | "net/http" 9 | "os" 10 | "os/signal" 11 | "sync" 12 | "syscall" 13 | 14 | "github.com/eigr/spawn-go-sdk/spawn/actors" 15 | protocol "github.com/eigr/spawn-go-sdk/spawn/eigr/functions/protocol/actors" 16 | 17 | "strings" 18 | 19 | "google.golang.org/protobuf/proto" 20 | "google.golang.org/protobuf/reflect/protoreflect" 21 | "google.golang.org/protobuf/reflect/protoregistry" 22 | "google.golang.org/protobuf/types/known/anypb" 23 | ) 24 | 25 | // System represents the Spawn system. 26 | type System struct { 27 | actors map[string]*actors.Actor 28 | name string 29 | proxyPort int 30 | exposePort int 31 | url string 32 | stopCh chan struct{} 33 | server *http.Server 34 | wg sync.WaitGroup 35 | } 36 | 37 | type invocationOptions map[string]interface{} 38 | 39 | // Creating an alias for InvocationOptions, now called Options 40 | type Options = invocationOptions 41 | 42 | // NewSystem creates a new Spawn system. 43 | func NewSystem(name string) *System { 44 | return &System{ 45 | actors: make(map[string]*actors.Actor), 46 | name: name, 47 | url: "http://localhost", // Default URL 48 | stopCh: make(chan struct{}), 49 | } 50 | } 51 | 52 | // UseProxyPort sets the proxy port for the system. 53 | func (s *System) UseProxyPort(port int) *System { 54 | s.proxyPort = port 55 | return s 56 | } 57 | 58 | // ExposePort sets the port to expose the ActorHost. 59 | func (s *System) ExposePort(port int) *System { 60 | s.exposePort = port 61 | return s 62 | } 63 | 64 | // RegisterActor registers a single actor in the system. 65 | func (s *System) RegisterActor(actor *actors.Actor) *System { 66 | s.actors[actor.Name] = actor 67 | return s 68 | } 69 | 70 | // BuildActor creates an actor and returns it. 71 | func (s *System) BuildActor(config actors.ActorConfig) *actors.Actor { 72 | return actors.ActorOf(config) 73 | } 74 | 75 | // Start initializes the system by registering all configured actors with the sidecar. 76 | func (s *System) Start() error { 77 | if len(s.actors) == 0 { 78 | return fmt.Errorf("no actors registered in the system") 79 | } 80 | 81 | go s.startServer() 82 | 83 | // Converts actors into a Protobuf representation map 84 | actorProtos := s.convertActorsToProtobuf() 85 | 86 | registration := &protocol.RegistrationRequest{ 87 | ServiceInfo: &protocol.ServiceInfo{ 88 | ServiceName: "spawn-go-sdk", 89 | ServiceVersion: "v0.1.0", 90 | ServiceRuntime: "go1.23", 91 | SupportLibraryName: "spawn-go-sdk", 92 | SupportLibraryVersion: "v0.1.0", 93 | ProtocolMajorVersion: 1, 94 | ProtocolMinorVersion: 1, 95 | }, 96 | ActorSystem: &protocol.ActorSystem{ 97 | Name: s.name, 98 | Registry: &protocol.Registry{ 99 | Actors: actorProtos, 100 | }, 101 | }, 102 | } 103 | 104 | data, err := proto.Marshal(registration) 105 | if err != nil { 106 | return fmt.Errorf("failed to serialize registration request: %w", err) 107 | } 108 | 109 | resp, err := s.postToSidecar(data) 110 | if err != nil { 111 | return err 112 | } 113 | 114 | defer resp.Body.Close() 115 | if resp.StatusCode != http.StatusOK { 116 | return fmt.Errorf("failed to register actors, status code: %d", resp.StatusCode) 117 | } 118 | 119 | go s.listenForTermination() 120 | 121 | log.Println("Actors successfully registered and system started") 122 | ///s.wg.Wait() 123 | return nil 124 | } 125 | 126 | // Await waits for the system to stop. 127 | func (s *System) Await() { 128 | s.wg.Add(1) 129 | defer s.wg.Done() 130 | // Wait until `stopCh` channel is closed 131 | <-s.stopCh 132 | } 133 | 134 | // client API 135 | func (s *System) Invoke(system string, actorName string, action string, request proto.Message, options Options) (proto.Message, error) { 136 | log.Printf("Invoking actor: %s, action: %s", actorName, action) 137 | parent, hasParent := options["parent"] 138 | async, hasAsync := options["async"] 139 | metadata, hasMetadata := options["metadata"] 140 | 141 | req := &protocol.InvocationRequest{} 142 | req.System = &protocol.ActorSystem{Name: system} 143 | 144 | actor := &protocol.Actor{ 145 | Id: &protocol.ActorId{ 146 | Name: actorName, 147 | System: system, 148 | }, 149 | } 150 | 151 | if hasParent { 152 | if parentStr, ok := parent.(string); ok { 153 | actor.Id.Parent = parentStr 154 | req.RegisterRef = actorName 155 | } else { 156 | return nil, fmt.Errorf("parent must be a string") 157 | } 158 | } 159 | if hasAsync { 160 | if asyncBool, ok := async.(bool); ok { 161 | req.Async = asyncBool 162 | } else { 163 | return nil, fmt.Errorf("async must be a bool") 164 | } 165 | } 166 | if hasMetadata { 167 | req.Metadata = metadata.(map[string]string) 168 | } 169 | 170 | req.Actor = actor 171 | req.ActionName = action 172 | 173 | if request != nil { 174 | payload, err := anypb.New(request) 175 | if err != nil { 176 | return nil, fmt.Errorf("failed to encode payload to make an Actor InvocationRequest: %w", err) 177 | } 178 | 179 | req.Payload = &protocol.InvocationRequest_Value{Value: payload} 180 | } 181 | 182 | r, err := proto.Marshal(req) 183 | if err != nil { 184 | log.Fatalln("Failed to encode Actor InvocationRequest:", err) 185 | } 186 | 187 | // call proxy to invoke actor 188 | responseBytes, err := s.invokeActor(actorName, r) 189 | if err != nil { 190 | return nil, err 191 | } 192 | 193 | resp := &protocol.InvocationResponse{} 194 | if err := proto.Unmarshal(responseBytes, resp); err != nil { 195 | log.Fatalln("Failed to parse Actor InvocationResponse:", err) 196 | } 197 | 198 | log.Printf("Actor invocation response: %v", resp) 199 | 200 | if resp.Status.GetStatus() != protocol.Status_OK { 201 | return nil, fmt.Errorf("actor invocation failed: %s", resp.Status) 202 | } 203 | 204 | var message proto.Message 205 | 206 | switch p := resp.GetPayload().(type) { 207 | case *protocol.InvocationResponse_Value: 208 | iany := p.Value 209 | log.Printf("Received response payload: %v", iany) 210 | msg, err := unmarshalAny(iany) 211 | log.Printf("Unmarshalled response payload: %v", msg) 212 | if err != nil { 213 | return nil, fmt.Errorf("error unmarshalling response value: %v", err) 214 | } 215 | message = msg 216 | case *protocol.InvocationResponse_Noop: 217 | message = nil 218 | default: 219 | return nil, fmt.Errorf("unknown payload type") 220 | } 221 | 222 | return message, nil 223 | } 224 | 225 | // private functions 226 | 227 | func (s *System) listenForTermination() { 228 | // Add a goroutine to the WaitGroup to wait for its completion 229 | s.wg.Add(1) 230 | defer s.wg.Done() 231 | 232 | // Create a channel to capture signals 233 | signalChan := make(chan os.Signal, 1) 234 | 235 | // Report SIGINT and SIGTERM signals 236 | signal.Notify(signalChan, syscall.SIGTERM) 237 | 238 | // Block until a termination signal is received 239 | sig := <-signalChan 240 | log.Printf("Received %s, shutting down gracefully...", sig) 241 | 242 | // Tenta fechar o servidor HTTP 243 | if err := s.server.Close(); err != nil { 244 | log.Printf("Error closing the server: %v", err) 245 | } 246 | 247 | close(s.stopCh) 248 | } 249 | 250 | // postToSidecar sends the serialized data to the Spawn sidecar API. 251 | func (s *System) postToSidecar(data []byte) (*http.Response, error) { 252 | url := fmt.Sprintf("%s:%d/api/v1/system", s.url, s.proxyPort) 253 | req, err := http.NewRequest("POST", url, bytes.NewReader(data)) 254 | if err != nil { 255 | return nil, fmt.Errorf("failed to create HTTP request: %w", err) 256 | } 257 | 258 | req.Header.Set("User-Agent", "user-function-client/0.1.0") 259 | req.Header.Set("Accept", "application/octet-stream") 260 | req.Header.Set("Content-Type", "application/octet-stream") 261 | 262 | client := &http.Client{} 263 | return client.Do(req) 264 | } 265 | 266 | // convertActorsToProtobuf converts the registered actors into a map with actor names as keys and their Protobuf representation as values. 267 | func (s *System) convertActorsToProtobuf() map[string]*protocol.Actor { 268 | actorMap := make(map[string]*protocol.Actor, len(s.actors)) 269 | 270 | for _, actor := range s.actors { 271 | // Converting actions 272 | actions := make([]*protocol.Action, 0, len(actor.Actions)) 273 | for actionName := range actor.Actions { 274 | actions = append(actions, &protocol.Action{ 275 | Name: actionName, 276 | }) 277 | } 278 | 279 | // Creating snapshot strategy 280 | var snapshotStrategy *protocol.ActorSnapshotStrategy 281 | if actor.SnapshotTimeout > 0 { 282 | snapshotStrategy = &protocol.ActorSnapshotStrategy{ 283 | Strategy: &protocol.ActorSnapshotStrategy_Timeout{ 284 | Timeout: &protocol.TimeoutStrategy{ 285 | Timeout: actor.SnapshotTimeout, 286 | }, 287 | }, 288 | } 289 | } 290 | 291 | // Creating deactivation strategy 292 | var deactivationStrategy *protocol.ActorDeactivationStrategy 293 | if actor.DeactivatedTimeout > 0 { 294 | deactivationStrategy = &protocol.ActorDeactivationStrategy{ 295 | Strategy: &protocol.ActorDeactivationStrategy_Timeout{ 296 | Timeout: &protocol.TimeoutStrategy{ 297 | Timeout: actor.DeactivatedTimeout, 298 | }, 299 | }, 300 | } 301 | } 302 | 303 | // Configuring ActorSettings 304 | settings := &protocol.ActorSettings{ 305 | Kind: mapKindFromGoToProto(actor.Kind), 306 | Stateful: actor.Stateful, 307 | SnapshotStrategy: snapshotStrategy, 308 | DeactivationStrategy: deactivationStrategy, 309 | } 310 | 311 | // Configuring pool size if the actor kind is pooled 312 | if actor.Kind == actors.Pooled { 313 | settings.MinPoolSize = actor.MinPoolSize 314 | settings.MaxPoolSize = actor.MaxPoolSize 315 | } 316 | 317 | // Adding the actor to the map 318 | actorMap[actor.Name] = &protocol.Actor{ 319 | Id: &protocol.ActorId{ 320 | Name: actor.Name, 321 | System: s.name, 322 | }, 323 | State: &protocol.ActorState{}, 324 | Metadata: &protocol.Metadata{}, 325 | Settings: settings, 326 | Actions: actions, 327 | TimerActions: nil, // TODO: Implement timer actions 328 | } 329 | } 330 | 331 | return actorMap 332 | } 333 | 334 | func mapKindFromGoToProto(kind actors.Kind) protocol.Kind { 335 | switch kind { 336 | case actors.Named: 337 | return protocol.Kind_NAMED 338 | case actors.Unnamed: 339 | return protocol.Kind_UNNAMED 340 | case actors.Pooled: 341 | return protocol.Kind_POOLED 342 | case actors.Task: 343 | return protocol.Kind_TASK 344 | case actors.Projection: 345 | return protocol.Kind_PROJECTION 346 | default: 347 | return protocol.Kind_UNKNOW_KIND 348 | } 349 | } 350 | 351 | func (s *System) startServer() { 352 | http.HandleFunc("/api/v1/actors/actions", s.handleActorInvocation) 353 | addr := fmt.Sprintf(":%d", s.exposePort) 354 | log.Printf("ActorHost server started on port %d\n", s.exposePort) 355 | 356 | s.server = &http.Server{Addr: addr} 357 | 358 | // Adds the goroutine to the WaitGroup to wait for its completion 359 | s.wg.Add(1) 360 | defer s.wg.Done() 361 | 362 | if err := s.server.ListenAndServe(); err != nil && err != http.ErrServerClosed { 363 | log.Fatalf("ActorHost server failed: %v", err) 364 | } 365 | } 366 | 367 | func (s *System) handleActorInvocation(w http.ResponseWriter, r *http.Request) { 368 | body, err := io.ReadAll(r.Body) 369 | if err != nil { 370 | http.Error(w, fmt.Sprintf("failed to read request body: %v", err), http.StatusInternalServerError) 371 | return 372 | } 373 | 374 | var actorInvocation protocol.ActorInvocation 375 | if err := proto.Unmarshal(body, &actorInvocation); err != nil { 376 | http.Error(w, fmt.Sprintf("failed to unmarshal protobuf: %v", err), http.StatusBadRequest) 377 | return 378 | } 379 | 380 | // Process the invocation 381 | log.Printf("Received actor invocation: %v", &actorInvocation) 382 | resp := s.processActorInvocation(&actorInvocation) 383 | 384 | payloadBytes, err := proto.Marshal(resp) 385 | if err != nil { 386 | http.Error(w, fmt.Sprintf("failed to marshal protobuf response: %v", err), http.StatusInternalServerError) 387 | return 388 | } 389 | 390 | w.Header().Set("Content-Type", "application/octet-stream") 391 | w.WriteHeader(http.StatusOK) 392 | w.Write(payloadBytes) 393 | } 394 | 395 | func (s *System) processActorInvocation(actorInvocation *protocol.ActorInvocation) *protocol.ActorInvocationResponse { 396 | log.Printf("Processing actor invocation: %v", actorInvocation) 397 | 398 | actorName := actorInvocation.Actor.Name 399 | actionName := actorInvocation.ActionName 400 | requestContext := actorInvocation.CurrentContext 401 | actualStateAny := requestContext.State 402 | 403 | var req proto.Message 404 | switch payload := actorInvocation.Payload.(type) { 405 | case *protocol.ActorInvocation_Value: 406 | // Deserialize the payload 407 | request, err := unmarshalAny(payload.Value) 408 | if err != nil { 409 | log.Printf("Failed to unmarshal payload: %v", err) 410 | return &protocol.ActorInvocationResponse{ActorName: actorName, ActorSystem: s.name} 411 | } 412 | req = request 413 | case *protocol.ActorInvocation_Noop: 414 | log.Printf("No operation payload received for actor: %s", actorName) 415 | } 416 | 417 | actor, ok := s.actors[actorName] 418 | if !ok { 419 | log.Printf("Actor not found: %s", actorName) 420 | return &protocol.ActorInvocationResponse{ActorName: actorName, ActorSystem: s.name} 421 | } 422 | 423 | actionHandler, ok := actor.Actions[actionName] 424 | if !ok { 425 | log.Printf("Action not found: %s for actor %s", actionName, actorName) 426 | return &protocol.ActorInvocationResponse{ActorName: actorName, ActorSystem: s.name} 427 | } 428 | 429 | fmt.Printf("Marshalled Any: %v\n", actualStateAny) 430 | // Unmarshal the actor's current state 431 | var stateValue proto.Message 432 | if actualStateAny == nil { 433 | log.Printf("State not found for actor %s", actorName) 434 | } else { 435 | actualStateValue, err := unmarshalAny(actualStateAny) 436 | if err != nil { 437 | log.Printf("Failed to unmarshal state for actor %s: %v", actorName, err) 438 | return &protocol.ActorInvocationResponse{ActorName: actorName, ActorSystem: s.name} 439 | } 440 | 441 | stateValue = actualStateValue 442 | } 443 | 444 | // Invoke the action handler 445 | value, err := actionHandler(&actors.ActorContext{CurrentState: stateValue}, req) 446 | if err != nil { 447 | log.Printf("Error invoking action: %s for actor %s, error: %v", actionName, actorName, err) 448 | return &protocol.ActorInvocationResponse{ActorName: actorName, ActorSystem: s.name} 449 | } 450 | 451 | log.Printf("Action [%s] response: %s for actor %s", actionName, value, actorName) 452 | 453 | // Marshal the returned value into an Any type 454 | //payloadAny, err := anypb.New(value) 455 | // if err != nil { 456 | // log.Printf("Failed to marshal response payload: %v", err) 457 | // return &protocol.ActorInvocationResponse{} 458 | // } 459 | 460 | // Create the updated context 461 | var updatedState *anypb.Any = actualStateAny 462 | if value.State != nil { 463 | us, err := anypb.New(value.State) 464 | if err != nil { 465 | log.Printf("Failed to marshal updated state: %v", err) 466 | return &protocol.ActorInvocationResponse{ActorName: actorName, ActorSystem: s.name} 467 | } 468 | 469 | updatedState = us 470 | } 471 | 472 | updatedContext := &protocol.Context{ 473 | State: updatedState, 474 | } 475 | 476 | log.Printf("Value Response: %v", value.Response) 477 | responPayload, err := anypb.New(value.Response) 478 | if err != nil { 479 | log.Printf("Failed to marshal response payload: %v", err) 480 | return &protocol.ActorInvocationResponse{ActorName: actorName, ActorSystem: s.name} 481 | } 482 | 483 | return &protocol.ActorInvocationResponse{ 484 | ActorName: actorName, 485 | ActorSystem: s.name, 486 | UpdatedContext: updatedContext, 487 | Payload: &protocol.ActorInvocationResponse_Value{Value: responPayload}, 488 | Workflow: nil, // Populate if needed 489 | Checkpoint: false, // Example: enable checkpointing 490 | } 491 | } 492 | 493 | func unmarshalAny(iany *anypb.Any) (proto.Message, error) { 494 | if iany == nil { 495 | return nil, fmt.Errorf("input Any message is nil") 496 | } 497 | 498 | // Extract the message type name from the TypeUrl 499 | msgName := strings.TrimPrefix(iany.GetTypeUrl(), "type.googleapis.com/") 500 | 501 | // Lookup the message type in the global registry 502 | mt, err := protoregistry.GlobalTypes.FindMessageByName(protoreflect.FullName(msgName)) 503 | if err != nil { 504 | return nil, fmt.Errorf("message type %s not found: %v", msgName, err) 505 | } 506 | 507 | // Create a new instance of the message type 508 | message := mt.New().Interface() 509 | 510 | // Unmarshal the Any value into the message instance 511 | err = proto.Unmarshal(iany.GetValue(), message) 512 | if err != nil { 513 | return nil, fmt.Errorf("unmarshalling failed: %v", err) 514 | } 515 | 516 | return message, nil 517 | } 518 | 519 | func (s *System) invokeActor(actorName string, requestBytes []byte) ([]byte, error) { 520 | // Monta a URL de invocação do ator remoto 521 | url := fmt.Sprintf("%s:%d/api/v1/system/%s/actors/%s/invoke", s.url, s.proxyPort, s.name, actorName) 522 | 523 | // Configura os cabeçalhos HTTP 524 | req, err := http.NewRequest("POST", url, bytes.NewBuffer(requestBytes)) 525 | if err != nil { 526 | return nil, fmt.Errorf("erro ao criar requisição: %v", err) 527 | } 528 | 529 | req.Header.Set("User-Agent", "user-function-client/0.1.0") 530 | req.Header.Set("Accept", "application/octet-stream") 531 | req.Header.Set("Content-Type", "application/octet-stream") 532 | 533 | // Envia a requisição HTTP POST 534 | client := &http.Client{} 535 | resp, err := client.Do(req) 536 | if err != nil { 537 | return nil, fmt.Errorf("erro ao enviar requisição: %v", err) 538 | } 539 | defer resp.Body.Close() 540 | 541 | // Verifica a resposta 542 | if resp.StatusCode != http.StatusOK { 543 | body, _ := io.ReadAll(resp.Body) 544 | return nil, fmt.Errorf("falha na invocação do ator. Status: %d, Erro: %s", resp.StatusCode, string(body)) 545 | } 546 | 547 | // Lê o conteúdo da resposta 548 | respBody, err := io.ReadAll(resp.Body) 549 | if err != nil { 550 | return nil, fmt.Errorf("erro ao ler resposta: %v", err) 551 | } 552 | 553 | return respBody, nil 554 | } 555 | -------------------------------------------------------------------------------- /spawn/protos/eigr/functions/protocol/actors/protocol.proto: -------------------------------------------------------------------------------- 1 | // The Spawn Protocol 2 | // 3 | // Spawn is divided into two main parts namely: 4 | // 5 | // 1. A sidecar proxy that exposes the server part of the Spawn Protocol in 6 | // the form of an HTTP API. 7 | // 2. A user function, written in any language that supports HTTP, that 8 | // exposes the client part of the Spawn Protocol. 9 | // 10 | // Both are client and server of their counterparts. 11 | // 12 | // In turn, the proxy exposes an HTTP endpoint for registering a user function 13 | // a.k.a ActorSystem. 14 | // 15 | // A user function that wants to register actors in Proxy Spawn must proceed by 16 | // making a POST request to the following endpoint: 17 | // 18 | // ` 19 | // POST /api/v1/system HTTP 1.1 20 | // HOST: localhost 21 | // User-Agent: user-function-client/0.1.0 (this is just example) 22 | // Accept: application/octet-stream 23 | // Content-Type: application/octet-stream 24 | // 25 | // registration request type bytes encoded here :-) 26 | // ` 27 | // 28 | // The general flow of a registration action is as follows: 29 | // 30 | // ╔═══════════════════╗ ╔═══════════════════╗ 31 | // ╔═══════════════════╗ ║ User Function ║ ║Local Spawn 32 | // Sidecar║ ║ Actor ║ ╚═══════════════════╝ 33 | // ╚═══════════════════╝ ╚═══════════════════╝ 34 | // ║ ║ ║ ║ ║ ║ ║ HTTP 35 | // POST ║ ║ ║ 36 | // Registration ║ ║ 37 | // ║ Request ║ ║ 38 | // ╠─────────────────────────────────────▶║ ║ ║ ║ Upfront start 39 | // Actors with ║ ║ ╠───────BEAM Distributed Protocol─────▶║ ║ ║ ║ 40 | // ║ ║ ╠───┐Initialize ║ ║ ║ │ 41 | // State ║ ║ ║ │ Store ║ ║ 42 | // ║◀──┘ ║ HTTP Registration ║ ║ ║ Response ║ ║ 43 | // ║◀─────────────────────────────────────╣ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ 44 | // ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ 45 | // 46 | // ███████████ ███████████ ███████████ 47 | // 48 | // 49 | // ## Spawning Actors 50 | // 51 | // Actors are usually created at the beginning of the SDK's communication flow 52 | // with the Proxy by the registration step described above. However, some use 53 | // cases require that Actors can be created ***on the fly***. In other words, 54 | // Spawn is used to bring to life Actors previously registered as Unnameds, 55 | // giving them a name and thus creating a concrete instance at runtime for that 56 | // Actor. Actors created with the Spawn feature are generally used when you want 57 | // to share a behavior while maintaining the isolation characteristics of the 58 | // actors. For these situations we have the Spawning flow described below. 59 | // 60 | // A user function that wants to Spawning new Actors in Proxy Spawn must proceed 61 | // by making a POST request to the following endpoint: 62 | // 63 | // ``` 64 | // POST /system/:system_name/actors/spawn HTTP 1.1 65 | // HOST: localhost 66 | // User-Agent: user-function-client/0.1.0 (this is just example) 67 | // Accept: application/octet-stream 68 | // Content-Type: application/octet-stream 69 | // 70 | // SpawnRequest type bytes encoded here :-) 71 | // ``` 72 | // 73 | // The general flow of a Spawning Actors is as follows: 74 | // 75 | // ``` 76 | // +----------------+ +---------------------+ +-------+ | User Function | | 77 | // Local Spawn Sidecar | | Actor | 78 | // +----------------+ +---------------------+ +-------+ 79 | // | | | | HTTP 80 | // POST SpawnRequest | | 81 | // |------------------------------------------------------>| | | | | | 82 | // | Upfront start Actors with BEAM Distributed Protocol | | 83 | // |---------------------------------------------------->| | | | | | 84 | // |Initialize Statestore | | |---------------------- | | | | | | 85 | // |<--------------------- | | | | HTTP SpawnResponse | | 86 | // |<------------------------------------------------------| | | | | 87 | // ``` 88 | // 89 | // Once the system has been initialized, that is, the registration step has been 90 | // successfully completed, then the user function will be able to make requests 91 | // to the System Actors. This is done through a post request to the Proxy at the 92 | // `/system/:name/actors/:actor_name/invoke` endpoint. 93 | // 94 | // A user function that wants to call actors in Proxy Spawn must proceed by 95 | // making a POST request as the follow: 96 | // 97 | // ` 98 | // POST /system/:name/actors/:actor_name/invoke HTTP 1.1 99 | // HOST: localhost 100 | // User-Agent: user-function-client/0.1.0 (this is just example) 101 | // Accept: application/octet-stream 102 | // Content-Type: application/octet-stream 103 | // 104 | // invocation request type bytes encoded here :-) 105 | // ` 106 | // 107 | // Assuming that two user functions were registered in different separate 108 | // Proxies, the above request would go the following way: 109 | // 110 | // ╔═══════════════════╗ ╔═══════════════════╗ 111 | // ╔═════════════════════════╗ ╔═════════════════════════════╗ ║ User 112 | // Function ║ ║Local Spawn Sidecar║ ║ Remote 113 | // User Function B ║ ║Remote Spawn Sidecar/Actor B ║ 114 | // ╚═══════════════════╝ ╚═══════════════════╝ 115 | // ╚═════════════════════════╝ ╚═════════════════════════════╝ 116 | // ║ HTTP POST ║ ║ ║ ║ Registration ║ ║ ║ ║ 117 | // Request ║ ║ ║ 118 | // ╠─────────────────────────────────────▶║ ║ ║ ║ ╠───┐ ║ ║ ║ ║ │Lookup 119 | // for ║ ║ ║ 120 | // ║ │ Actor ║ ║ ║ ║◀──┘ ║ ║ ║ ║ ║ BEAM 121 | // Distributed ║ ║ 122 | // ╠─────────────────────────────────────╬────────────protocol 123 | // call──────────▶║ ║ ║ ║ ║ ║ ║ ║ 124 | // HTTP POST: ║ ║ ║ 125 | // ║◀──────/api/v1/actors/actions───────╣ ║ ║ ║ ║ ║ ║ ╠───┐ ║ ║ ║ ║ 126 | // │Handle request, ║ ║ ║ ║ │execute action ║ ║ ║ 127 | // ║◀──┘ ║ ║ ║ ║ Reply with 128 | // the ║ ║ ║ 129 | // ╠────────────result and the ────────▶║ ║ ║ ║ new state 130 | // of ║────┐ ║ ║ ║ ║ │ 131 | // ║ ║ ║ ║ │Store new State ║ 132 | // ║ Send response to the ║ ║ ◀──┘ ║ Respond to 133 | // user with ║◀─────────Spawn Sidecar 134 | // A────────────╬────────────────────────────────────╣ ║ result value 135 | // ║ ║ ║ 136 | // ║◀─────────────────────────────────────╣ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║ 137 | // 138 | // ███████████ ████████████ ███████████ 139 | // ███████████ 140 | // 141 | // 142 | syntax = "proto3"; 143 | 144 | package eigr.functions.protocol; 145 | 146 | import "eigr/functions/protocol/actors/actor.proto"; 147 | import "google/protobuf/any.proto"; 148 | import "google/protobuf/timestamp.proto"; 149 | 150 | option java_package = "io.eigr.functions.protocol"; 151 | option go_package = "spawn/eigr/functions/protocol/actors"; 152 | 153 | // Context is where current and/or updated state is stored 154 | // to be transmitted to/from proxy and user function 155 | // 156 | // Params: 157 | // * state: Actor state passed back and forth between proxy and user function. 158 | // * metadata: Meta information that comes in invocations 159 | // * tags: Meta information stored in the actor 160 | // * caller: ActorId of who is calling target actor 161 | // * self: ActorId of itself 162 | message Context { 163 | 164 | google.protobuf.Any state = 1; 165 | 166 | map metadata = 4; 167 | 168 | map tags = 5; 169 | 170 | // Who is calling target actor 171 | eigr.functions.protocol.actors.ActorId caller = 2; 172 | 173 | // The target actor itself 174 | eigr.functions.protocol.actors.ActorId self = 3; 175 | } 176 | 177 | // Noop is used when the input or output value of a function or method 178 | // does not matter to the caller of a Workflow or when the user just wants to 179 | // receive the Context in the request, that is, he does not care about the input 180 | // value only with the state. 181 | message Noop {} 182 | 183 | // JSON is an alternative that some SDKs can opt in 184 | // it will bypass any type validation in spawn actors state / payloads 185 | message JSONType { string content = 1; } 186 | 187 | message RegistrationRequest { 188 | 189 | ServiceInfo service_info = 1; 190 | 191 | eigr.functions.protocol.actors.ActorSystem actor_system = 2; 192 | } 193 | 194 | message RegistrationResponse { 195 | 196 | RequestStatus status = 1; 197 | 198 | ProxyInfo proxy_info = 2; 199 | } 200 | 201 | message ServiceInfo { 202 | 203 | // The name of the actor system, eg, "my-actor-system". 204 | string service_name = 1; 205 | 206 | // The version of the service. 207 | string service_version = 2; 208 | 209 | // A description of the runtime for the service. Can be anything, but examples 210 | // might be: 211 | // - node v10.15.2 212 | // - OpenJDK Runtime Environment 1.8.0_192-b12 213 | string service_runtime = 3; 214 | 215 | // If using a support library, the name of that library, eg "spawn-jvm" 216 | string support_library_name = 4; 217 | 218 | // The version of the support library being used. 219 | string support_library_version = 5; 220 | 221 | // Spawn protocol major version accepted by the support library. 222 | int32 protocol_major_version = 6; 223 | 224 | // Spawn protocol minor version accepted by the support library. 225 | int32 protocol_minor_version = 7; 226 | } 227 | 228 | message SpawnRequest { 229 | repeated eigr.functions.protocol.actors.ActorId actors = 1; 230 | } 231 | 232 | message SpawnResponse { RequestStatus status = 1; } 233 | 234 | message ProxyInfo { 235 | 236 | int32 protocol_major_version = 1; 237 | 238 | int32 protocol_minor_version = 2; 239 | 240 | string proxy_name = 3; 241 | 242 | string proxy_version = 4; 243 | } 244 | 245 | // When a Host Function is invoked it returns the updated state and return value 246 | // to the call. It can also return a number of side effects to other Actors as a 247 | // result of its computation. These side effects will be forwarded to the 248 | // respective Actors asynchronously and should not affect the Host Function's 249 | // response to its caller. Internally side effects is just a special kind of 250 | // InvocationRequest. Useful for handle handle `recipient list` and `Composed 251 | // Message Processor` patterns: 252 | // https://www.enterpriseintegrationpatterns.com/patterns/messaging/RecipientList.html 253 | // https://www.enterpriseintegrationpatterns.com/patterns/messaging/DistributionAggregate.html 254 | message SideEffect { InvocationRequest request = 1; } 255 | 256 | // Broadcast a message to many Actors 257 | // Useful for handle `recipient list`, `publish-subscribe channel`, and 258 | // `scatter-gatther` patterns: 259 | // https://www.enterpriseintegrationpatterns.com/patterns/messaging/RecipientList.html 260 | // https://www.enterpriseintegrationpatterns.com/patterns/messaging/PublishSubscribeChannel.html 261 | // https://www.enterpriseintegrationpatterns.com/patterns/messaging/BroadcastAggregate.html 262 | message Broadcast { 263 | // Target topic or channel 264 | // Change this to channel 265 | string channel_group = 1; 266 | 267 | // Payload 268 | oneof payload { 269 | google.protobuf.Any value = 3; 270 | Noop noop = 4; 271 | } 272 | } 273 | 274 | // Sends the output of a action of an Actor to the input of another action of an 275 | // Actor Useful for handle `pipes` pattern: 276 | // https://www.enterpriseintegrationpatterns.com/patterns/messaging/PipesAndFilters.html 277 | message Pipe { 278 | // Target Actor 279 | string actor = 1; 280 | 281 | // Action. 282 | string action_name = 2; 283 | } 284 | 285 | // Sends the input of a action of an Actor to the input of another action of an 286 | // Actor Useful for handle `content-basead router` pattern 287 | // https://www.enterpriseintegrationpatterns.com/patterns/messaging/ContentBasedRouter.html 288 | message Forward { 289 | // Target Actor 290 | string actor = 1; 291 | 292 | // Action. 293 | string action_name = 2; 294 | } 295 | 296 | // Facts are emitted by actions and represent the internal state of the moment 297 | // at that moment. These are treated by Projections so that visualizations can 298 | // be built around these states. 299 | message Fact { 300 | string uuid = 1; 301 | google.protobuf.Any state = 2; 302 | map metadata = 3; 303 | google.protobuf.Timestamp timestamp = 4; 304 | } 305 | 306 | // Container for archicetural message patterns 307 | message Workflow { 308 | 309 | Broadcast broadcast = 2; 310 | 311 | repeated SideEffect effects = 1; 312 | 313 | oneof routing { 314 | Pipe pipe = 3; 315 | Forward forward = 4; 316 | } 317 | } 318 | 319 | // The user function when it wants to send a message to an Actor uses the 320 | // InvocationRequest message type. 321 | // 322 | // Params: 323 | // * system: See ActorSystem message. 324 | // * actor: The target Actor, i.e. the one that the user function is calling 325 | // to perform some computation. 326 | // * caller: The caller Actor 327 | // * action_name: The function or method on the target Actor that will receive 328 | // this request 329 | // and perform some useful computation with the sent data. 330 | // * value: This is the value sent by the user function to be computed by the 331 | // request's target Actor action. 332 | // * async: Indicates whether the action should be processed synchronously, 333 | // where a response should be sent back to the user function, 334 | // or whether the action should be processed asynchronously, i.e. no 335 | // response sent to the caller and no waiting. 336 | // * metadata: Meta information or headers 337 | // * register_ref: If the invocation should register the specific actor with 338 | // the given name without having to call register before 339 | message InvocationRequest { 340 | 341 | eigr.functions.protocol.actors.ActorSystem system = 1; 342 | 343 | eigr.functions.protocol.actors.Actor actor = 2; 344 | 345 | string action_name = 3; 346 | 347 | oneof payload { 348 | google.protobuf.Any value = 4; 349 | Noop noop = 7; 350 | } 351 | 352 | bool async = 5; 353 | 354 | eigr.functions.protocol.actors.ActorId caller = 6; 355 | 356 | map metadata = 8; 357 | 358 | int64 scheduled_to = 9; 359 | 360 | bool pooled = 10; 361 | 362 | string register_ref = 11; 363 | } 364 | 365 | // ActorInvocation is a translation message between a local invocation made via 366 | // InvocationRequest and the real Actor that intends to respond to this 367 | // invocation and that can be located anywhere in the cluster. 368 | // 369 | // Params: 370 | // * actor: The ActorId handling the InvocationRequest request, also called 371 | // the target Actor. 372 | // * action_name: The function or method on the target Actor that will receive 373 | // this request 374 | // and perform some useful computation with the sent data. 375 | // * current_context: The current Context with current state value of the 376 | // target Actor. 377 | // That is, the same as found via matching in %Actor{name: 378 | // target_actor, state: %ActorState{state: value} = 379 | // actor_state}. In this case, the Context type will contain 380 | // in the value attribute the same `value` as the matching 381 | // above. 382 | // * payload: The value to be passed to the function or method corresponding 383 | // to action_name. 384 | message ActorInvocation { 385 | 386 | eigr.functions.protocol.actors.ActorId actor = 1; 387 | 388 | string action_name = 2; 389 | 390 | Context current_context = 3; 391 | 392 | oneof payload { 393 | google.protobuf.Any value = 4; 394 | Noop noop = 5; 395 | } 396 | 397 | eigr.functions.protocol.actors.ActorId caller = 6; 398 | } 399 | 400 | // The user function's response after executing the action originated by the 401 | // local proxy request via ActorInvocation. 402 | // 403 | // Params: 404 | // actor_name: The name of the Actor handling the InvocationRequest request, 405 | // also called the target Actor. actor_system: The name of ActorSystem 406 | // registered in Registration step. updated_context: The Context with updated 407 | // state value of the target Actor after user function has processed a 408 | // request. value: The value that the original request proxy will forward in 409 | // response to the InvocationRequest type request. 410 | // This is the final response from the point of view of the user who 411 | // invoked the Actor call and its subsequent processing. 412 | message ActorInvocationResponse { 413 | 414 | string actor_name = 1; 415 | 416 | string actor_system = 2; 417 | 418 | Context updated_context = 3; 419 | 420 | oneof payload { 421 | google.protobuf.Any value = 4; 422 | Noop noop = 6; 423 | } 424 | 425 | Workflow workflow = 5; 426 | 427 | bool checkpoint = 7; 428 | } 429 | 430 | // InvocationResponse is the response that the proxy that received the 431 | // InvocationRequest request will forward to the request's original user 432 | // function. 433 | // 434 | // Params: 435 | // status: Status of request. Could be one of [UNKNOWN, OK, ACTOR_NOT_FOUND, 436 | // ERROR]. system: The original ActorSystem of the InvocationRequest request. 437 | // actor: The target Actor originally sent in the InvocationRequest message. 438 | // value: The value resulting from the request processing that the target 439 | // Actor made. 440 | // This value must be passed by the user function to the one who 441 | // requested the initial request in InvocationRequest. 442 | message InvocationResponse { 443 | 444 | RequestStatus status = 1; 445 | 446 | eigr.functions.protocol.actors.ActorSystem system = 2; 447 | 448 | eigr.functions.protocol.actors.Actor actor = 3; 449 | 450 | oneof payload { 451 | google.protobuf.Any value = 4; 452 | Noop noop = 5; 453 | } 454 | } 455 | 456 | enum Status { 457 | 458 | UNKNOWN = 0; 459 | 460 | OK = 1; 461 | 462 | ACTOR_NOT_FOUND = 2; 463 | 464 | ERROR = 3; 465 | } 466 | 467 | message RequestStatus { 468 | 469 | Status status = 1; 470 | 471 | string message = 2; 472 | } 473 | --------------------------------------------------------------------------------