summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValery Piashchynski <[email protected]>2021-09-07 18:12:26 +0300
committerValery Piashchynski <[email protected]>2021-09-07 18:12:26 +0300
commit2f41909aeb6a01ae1a0b5ebabe9a9afc1360744a (patch)
tree9609019ad2ba4b6ae3a241aa5e6f68872b89feaf
parent6749db4a2d39fa70b426bcf50edf66a176c07f57 (diff)
Initial commit for the GRPC plugin
Signed-off-by: Valery Piashchynski <[email protected]>
-rwxr-xr-x.golangci.yml1
-rwxr-xr-xMakefile4
-rw-r--r--go.mod15
-rw-r--r--go.sum35
-rw-r--r--plugins/grpc/codec.go35
-rw-r--r--plugins/grpc/codec_test.go79
-rw-r--r--plugins/grpc/plugin.go11
-rw-r--r--plugins/grpc/protoc-gen-php-grpc/main.go68
-rw-r--r--plugins/grpc/protoc-gen-php-grpc/php/generate.go57
-rw-r--r--plugins/grpc/protoc-gen-php-grpc/php/keywords.go139
-rw-r--r--plugins/grpc/protoc-gen-php-grpc/php/ns.go103
-rw-r--r--plugins/grpc/protoc-gen-php-grpc/php/template.go103
-rw-r--r--tests/plugins/grpc/grpc_plugin_test.go7
-rw-r--r--tests/plugins/grpc/plugin_test.go178
-rw-r--r--tests/plugins/grpc/testdata/import/Import/ServiceInterface.php32
-rw-r--r--tests/plugins/grpc/testdata/import/service.proto17
-rw-r--r--tests/plugins/grpc/testdata/import/sub/message.proto7
-rw-r--r--tests/plugins/grpc/testdata/import_custom/Test/CustomImport/ServiceInterface.php32
-rw-r--r--tests/plugins/grpc/testdata/import_custom/service.proto19
-rw-r--r--tests/plugins/grpc/testdata/import_custom/sub/message.proto14
-rw-r--r--tests/plugins/grpc/testdata/php_namespace/Test/CustomNamespace/ServiceInterface.php22
-rw-r--r--tests/plugins/grpc/testdata/php_namespace/service.proto15
-rw-r--r--tests/plugins/grpc/testdata/simple/TestSimple/SimpleServiceInterface.php22
-rw-r--r--tests/plugins/grpc/testdata/simple/simple.proto13
-rw-r--r--tests/plugins/grpc/testdata/use_empty/Test/ServiceInterface.php23
-rw-r--r--tests/plugins/grpc/testdata/use_empty/service.proto10
-rwxr-xr-xtests/plugins/grpcplugbin0 -> 6024075 bytes
-rwxr-xr-xtests/plugins/grpcpluginbin0 -> 6024075 bytes
28 files changed, 1042 insertions, 19 deletions
diff --git a/.golangci.yml b/.golangci.yml
index f6ead63e..f623ed70 100755
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -91,3 +91,4 @@ issues:
- noctx
- gosimple
- revive
+ - gochecknoinits
diff --git a/Makefile b/Makefile
index 8390e910..d0a695ec 100755
--- a/Makefile
+++ b/Makefile
@@ -20,8 +20,10 @@ test_coverage:
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/server_cmd.txt -covermode=atomic ./plugins/server
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/struct_jobs.txt -covermode=atomic ./plugins/jobs/job
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/pipeline_jobs.txt -covermode=atomic ./plugins/jobs/pipeline
+ go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/grpc_plugin.txt -covermode=atomic ./plugins/grpc
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/jobs_core.txt -covermode=atomic ./tests/plugins/jobs
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/kv_plugin.txt -covermode=atomic ./tests/plugins/kv
+ go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/grpc_plugin.txt -covermode=atomic ./tests/plugins/grpc
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/broadcast_plugin.txt -covermode=atomic ./tests/plugins/broadcast
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/websockets.txt -covermode=atomic ./tests/plugins/websockets
go test -v -race -cover -tags=debug -coverpkg=./... -coverprofile=./coverage-ci/http.txt -covermode=atomic ./tests/plugins/http
@@ -53,11 +55,13 @@ test: ## Run application tests
go test -v -race -tags=debug ./plugins/http/config
go test -v -race -tags=debug ./plugins/server
go test -v -race -tags=debug ./plugins/jobs/job
+ go test -v -race -tags=debug ./tests/plugins/grpc
go test -v -race -tags=debug ./tests/plugins/jobs
go test -v -race -tags=debug ./tests/plugins/kv
go test -v -race -tags=debug ./tests/plugins/broadcast
go test -v -race -tags=debug ./tests/plugins/websockets
go test -v -race -tags=debug ./plugins/websockets
+ go test -v -race -tags=debug ./plugins/grpc
go test -v -race -tags=debug ./tests/plugins/http
go test -v -race -tags=debug ./tests/plugins/informer
go test -v -race -tags=debug ./tests/plugins/reload
diff --git a/go.mod b/go.mod
index 85421a96..97e2bdc6 100644
--- a/go.mod
+++ b/go.mod
@@ -6,9 +6,9 @@ require (
github.com/Shopify/toxiproxy v2.1.4+incompatible
// ========= AWS SDK v2
github.com/aws/aws-sdk-go-v2 v1.9.0
- github.com/aws/aws-sdk-go-v2/config v1.7.0
+ github.com/aws/aws-sdk-go-v2/config v1.8.0
github.com/aws/aws-sdk-go-v2/credentials v1.4.0
- github.com/aws/aws-sdk-go-v2/service/sqs v1.8.0
+ github.com/aws/aws-sdk-go-v2/service/sqs v1.9.0
github.com/aws/smithy-go v1.8.0
// =====================
github.com/beanstalkd/go-beanstalk v0.1.0
@@ -37,9 +37,10 @@ require (
go.etcd.io/bbolt v1.3.6
go.uber.org/multierr v1.7.0
go.uber.org/zap v1.19.0
- golang.org/x/net v0.0.0-20210825183410-e898025ed96a
+ golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
- golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e
+ golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34
+ google.golang.org/grpc v1.40.0
google.golang.org/protobuf v1.27.1
gopkg.in/natefinch/lumberjack.v2 v2.0.0
)
@@ -62,12 +63,12 @@ require (
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/magiconair/properties v1.8.5 // indirect
github.com/mattn/go-colorable v0.1.8 // indirect
- github.com/mattn/go-isatty v0.0.13 // indirect
+ github.com/mattn/go-isatty v0.0.14 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.1 // indirect
- github.com/pelletier/go-toml v1.9.3 // indirect
+ github.com/pelletier/go-toml v1.9.4 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_model v0.2.0 // indirect
github.com/prometheus/common v0.30.0 // indirect
@@ -87,7 +88,7 @@ require (
go.uber.org/atomic v1.9.0 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.5 // indirect
- gopkg.in/ini.v1 v1.62.0 // indirect
+ gopkg.in/ini.v1 v1.63.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)
diff --git a/go.sum b/go.sum
index e144019b..6096347d 100644
--- a/go.sum
+++ b/go.sum
@@ -40,6 +40,7 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/toxiproxy v2.1.4+incompatible h1:TKdv8HiTLgE5wdJuEML90aBgNWsokNbMijUGhmcoBJc=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA=
@@ -59,8 +60,8 @@ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmV
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go-v2 v1.9.0 h1:+S+dSqQCN3MSU5vJRu1HqHrq00cJn6heIMU7X9hcsoo=
github.com/aws/aws-sdk-go-v2 v1.9.0/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
-github.com/aws/aws-sdk-go-v2/config v1.7.0 h1:J2cZ7qe+3IpqBEXnHUrFrOjoB9BlsXg7j53vxcl5IVg=
-github.com/aws/aws-sdk-go-v2/config v1.7.0/go.mod h1:w9+nMZ7soXCe5nT46Ri354SNhXDQ6v+V5wqDjnZE+GY=
+github.com/aws/aws-sdk-go-v2/config v1.8.0 h1:O8EMFBOl6tue5gdJJV6U3Ikyl3lqgx6WrulCYrcy2SQ=
+github.com/aws/aws-sdk-go-v2/config v1.8.0/go.mod h1:w9+nMZ7soXCe5nT46Ri354SNhXDQ6v+V5wqDjnZE+GY=
github.com/aws/aws-sdk-go-v2/credentials v1.4.0 h1:kmvesfjY861FzlCU9mvAfe01D9aeXcG2ZuC+k9F2YLM=
github.com/aws/aws-sdk-go-v2/credentials v1.4.0/go.mod h1:dgGR+Qq7Wjcd4AOAW5Rf5Tnv3+x7ed6kETXyS9WCuAY=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.5.0 h1:OxTAgH8Y4BXHD6PGCJ8DHx2kaZPCQfSTqmDsdRZFezE=
@@ -69,8 +70,8 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.2.2 h1:d95cddM3yTm4qffj3P6EnP+TzX1S
github.com/aws/aws-sdk-go-v2/internal/ini v1.2.2/go.mod h1:BQV0agm+JEhqR+2RT5e1XTFIDcAAV0eW6z2trp+iduw=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.0 h1:VNJ5NLBteVXEwE2F1zEXVmyIH58mZ6kIQGJoC7C+vkg=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.0/go.mod h1:R1KK+vY8AfalhG1AOu5e35pOD2SdoPKQCFLTvnxiohk=
-github.com/aws/aws-sdk-go-v2/service/sqs v1.8.0 h1:BI05Jbkaqp5IDxiobr3B59mX07lfpLJDv5NwAEx3wSs=
-github.com/aws/aws-sdk-go-v2/service/sqs v1.8.0/go.mod h1:BXA1CVaEd9TBOQ8G2ke7lMWdVggAeh35+h2HDO50z7s=
+github.com/aws/aws-sdk-go-v2/service/sqs v1.9.0 h1:g6EHC3RFpgbRR8/Yk6BTbzfPn+E3o6J3zWPrcjvVJTw=
+github.com/aws/aws-sdk-go-v2/service/sqs v1.9.0/go.mod h1:BXA1CVaEd9TBOQ8G2ke7lMWdVggAeh35+h2HDO50z7s=
github.com/aws/aws-sdk-go-v2/service/sso v1.4.0 h1:sHXMIKYS6YiLPzmKSvDpPmOpJDHxmAUgbiF49YNVztg=
github.com/aws/aws-sdk-go-v2/service/sso v1.4.0/go.mod h1:+1fpWnL96DL23aXPpMGbsmKe8jLTEfbjuQoA4WS1VaA=
github.com/aws/aws-sdk-go-v2/service/sts v1.7.0 h1:1at4e5P+lvHNl2nUktdM2/v+rpICg/QSEr9TO/uW9vU=
@@ -92,6 +93,8 @@ github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQ
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
+github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -102,6 +105,7 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -115,6 +119,7 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fasthttp/websocket v1.4.3 h1:qjhRJ/rTy4KB8oBxljEC00SDt6HUY9jLRfM601SUdS4=
github.com/fasthttp/websocket v1.4.3/go.mod h1:5r4oKssgS7W6Zn6mPWap3NWzNPJNzUUh3baWTOhcYQk=
@@ -280,8 +285,8 @@ github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-isatty v0.0.13 h1:qdl+GuBjcsKKDco5BsxPJlId98mSWNKqYA+Co0SC1yA=
-github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
+github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
@@ -314,8 +319,9 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
-github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
+github.com/pelletier/go-toml v1.9.4 h1:tjENF6MfZAg8e4ZmZTeWaWiT2vXtsoO6+iuOjFhECwM=
+github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -364,6 +370,7 @@ github.com/smartystreets/assertions v1.1.1 h1:T/YLemO5Yp7KPzS+lVtu+WsHn8yoSwTfIt
github.com/smartystreets/assertions v1.1.1/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
+github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -428,6 +435,7 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
@@ -527,8 +535,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20210825183410-e898025ed96a h1:bRuuGXV8wwSdGTB+CtJf+FjgO1APK1CoO39T4BN/XBw=
-golang.org/x/net v0.0.0-20210825183410-e898025ed96a/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f h1:w6wWR0H+nyVpbSAQbzVEIACVyr/h8l/BEkY6Sokc7Eg=
+golang.org/x/net v0.0.0-20210903162142-ad29c8ab022f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -614,8 +622,8 @@ golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e h1:XMgFehsDnnLGtjvjOfqWSUzt0alpTR1RSEuznObga2c=
-golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34 h1:GkvMjFtXUmahfDtashnc1mnrCtuBVcwse5QV2lUk/tI=
+golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -782,6 +790,8 @@ google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
+google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -804,8 +814,9 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.38.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/ini.v1 v1.63.0 h1:2t0h8NA59dpVQpa5Yh8cIcR6nHAeBIEk0zlLVqfw4N4=
+gopkg.in/ini.v1 v1.63.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
diff --git a/plugins/grpc/codec.go b/plugins/grpc/codec.go
new file mode 100644
index 00000000..5938e238
--- /dev/null
+++ b/plugins/grpc/codec.go
@@ -0,0 +1,35 @@
+package grpc
+
+import "google.golang.org/grpc/encoding"
+
+type rawMessage []byte
+
+func (r rawMessage) Reset() {}
+func (rawMessage) ProtoMessage() {}
+func (rawMessage) String() string { return "rawMessage" }
+
+type codec struct{ base encoding.Codec }
+
+// Marshal returns the wire format of v. rawMessages would be returned without encoding.
+func (c *codec) Marshal(v interface{}) ([]byte, error) {
+ if raw, ok := v.(rawMessage); ok {
+ return raw, nil
+ }
+
+ return c.base.Marshal(v)
+}
+
+// Unmarshal parses the wire format into v. rawMessages would not be unmarshalled.
+func (c *codec) Unmarshal(data []byte, v interface{}) error {
+ if raw, ok := v.(*rawMessage); ok {
+ *raw = data
+ return nil
+ }
+
+ return c.base.Unmarshal(data, v)
+}
+
+// String return codec name.
+func (c *codec) String() string {
+ return "raw:" + c.base.Name()
+}
diff --git a/plugins/grpc/codec_test.go b/plugins/grpc/codec_test.go
new file mode 100644
index 00000000..5f94b745
--- /dev/null
+++ b/plugins/grpc/codec_test.go
@@ -0,0 +1,79 @@
+package grpc
+
+import (
+ "testing"
+
+ json "github.com/json-iterator/go"
+ "github.com/stretchr/testify/assert"
+)
+
+type jsonCodec struct{}
+
+func (jsonCodec) Marshal(v interface{}) ([]byte, error) {
+ return json.Marshal(v)
+}
+
+func (jsonCodec) Unmarshal(data []byte, v interface{}) error {
+ return json.Unmarshal(data, v)
+}
+
+func (jsonCodec) Name() string {
+ return "json"
+}
+
+func TestCodec_String(t *testing.T) {
+ c := codec{jsonCodec{}}
+
+ assert.Equal(t, "raw:json", c.String())
+
+ r := rawMessage{}
+ r.Reset()
+ r.ProtoMessage()
+ assert.Equal(t, "rawMessage", r.String())
+}
+
+func TestCodec_Unmarshal_ByPass(t *testing.T) {
+ c := codec{jsonCodec{}}
+
+ s := struct {
+ Name string
+ }{}
+
+ assert.NoError(t, c.Unmarshal([]byte(`{"name":"name"}`), &s))
+ assert.Equal(t, "name", s.Name)
+}
+
+func TestCodec_Marshal_ByPass(t *testing.T) {
+ c := codec{jsonCodec{}}
+
+ s := struct {
+ Name string
+ }{
+ Name: "name",
+ }
+
+ d, err := c.Marshal(s)
+ assert.NoError(t, err)
+
+ assert.Equal(t, `{"Name":"name"}`, string(d))
+}
+
+func TestCodec_Unmarshal_Raw(t *testing.T) {
+ c := codec{jsonCodec{}}
+
+ s := rawMessage{}
+
+ assert.NoError(t, c.Unmarshal([]byte(`{"name":"name"}`), &s))
+ assert.Equal(t, `{"name":"name"}`, string(s))
+}
+
+func TestCodec_Marshal_Raw(t *testing.T) {
+ c := codec{jsonCodec{}}
+
+ s := rawMessage(`{"Name":"name"}`)
+
+ d, err := c.Marshal(s)
+ assert.NoError(t, err)
+
+ assert.Equal(t, `{"Name":"name"}`, string(d))
+}
diff --git a/plugins/grpc/plugin.go b/plugins/grpc/plugin.go
new file mode 100644
index 00000000..5da60d75
--- /dev/null
+++ b/plugins/grpc/plugin.go
@@ -0,0 +1,11 @@
+package grpc
+
+import "github.com/spiral/errors"
+
+type Plugin struct {
+}
+
+func (p *Plugin) Init() error {
+ const op = errors.Op("grpc_plugin_init")
+ return nil
+}
diff --git a/plugins/grpc/protoc-gen-php-grpc/main.go b/plugins/grpc/protoc-gen-php-grpc/main.go
new file mode 100644
index 00000000..c9c4a573
--- /dev/null
+++ b/plugins/grpc/protoc-gen-php-grpc/main.go
@@ -0,0 +1,68 @@
+// MIT License
+//
+// Copyright (c) 2018 SpiralScout
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package main
+
+import (
+ "io"
+ "io/ioutil"
+ "os"
+
+ "github.com/spiral/roadrunner/v2/plugins/grpc/protoc-gen-php-grpc/php"
+ "google.golang.org/protobuf/proto"
+ plugin "google.golang.org/protobuf/types/pluginpb"
+)
+
+func main() {
+ req, err := readRequest(os.Stdin)
+ if err != nil {
+ panic(err)
+ }
+
+ if err = writeResponse(os.Stdout, php.Generate(req)); err != nil {
+ panic(err)
+ }
+}
+
+func readRequest(in io.Reader) (*plugin.CodeGeneratorRequest, error) {
+ data, err := ioutil.ReadAll(in)
+ if err != nil {
+ return nil, err
+ }
+
+ req := new(plugin.CodeGeneratorRequest)
+ if err = proto.Unmarshal(data, req); err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func writeResponse(out io.Writer, resp *plugin.CodeGeneratorResponse) error {
+ data, err := proto.Marshal(resp)
+ if err != nil {
+ return err
+ }
+
+ _, err = out.Write(data)
+ return err
+}
diff --git a/plugins/grpc/protoc-gen-php-grpc/php/generate.go b/plugins/grpc/protoc-gen-php-grpc/php/generate.go
new file mode 100644
index 00000000..03c48ac8
--- /dev/null
+++ b/plugins/grpc/protoc-gen-php-grpc/php/generate.go
@@ -0,0 +1,57 @@
+// MIT License
+//
+// Copyright (c) 2018 SpiralScout
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package php
+
+import (
+ desc "google.golang.org/protobuf/types/descriptorpb"
+ plugin "google.golang.org/protobuf/types/pluginpb"
+)
+
+// Generate generates needed service classes
+func Generate(req *plugin.CodeGeneratorRequest) *plugin.CodeGeneratorResponse {
+ resp := &plugin.CodeGeneratorResponse{}
+
+ for _, file := range req.ProtoFile {
+ for _, service := range file.Service {
+ resp.File = append(resp.File, generate(req, file, service))
+ }
+ }
+
+ return resp
+}
+
+func generate(
+ req *plugin.CodeGeneratorRequest,
+ file *desc.FileDescriptorProto,
+ service *desc.ServiceDescriptorProto,
+) *plugin.CodeGeneratorResponse_File {
+ return &plugin.CodeGeneratorResponse_File{
+ Name: str(filename(file, service.Name)),
+ Content: str(body(req, file, service)),
+ }
+}
+
+// helper to convert string into string pointer
+func str(str string) *string {
+ return &str
+}
diff --git a/plugins/grpc/protoc-gen-php-grpc/php/keywords.go b/plugins/grpc/protoc-gen-php-grpc/php/keywords.go
new file mode 100644
index 00000000..32579e33
--- /dev/null
+++ b/plugins/grpc/protoc-gen-php-grpc/php/keywords.go
@@ -0,0 +1,139 @@
+// MIT License
+//
+// Copyright (c) 2018 SpiralScout
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package php
+
+import (
+ "bytes"
+ "strings"
+ "unicode"
+)
+
+// @see https://github.com/protocolbuffers/protobuf/blob/master/php/ext/google/protobuf/protobuf.c#L168
+var reservedKeywords = []string{
+ "abstract", "and", "array", "as", "break",
+ "callable", "case", "catch", "class", "clone",
+ "const", "continue", "declare", "default", "die",
+ "do", "echo", "else", "elseif", "empty",
+ "enddeclare", "endfor", "endforeach", "endif", "endswitch",
+ "endwhile", "eval", "exit", "extends", "final",
+ "for", "foreach", "function", "global", "goto",
+ "if", "implements", "include", "include_once", "instanceof",
+ "insteadof", "interface", "isset", "list", "namespace",
+ "new", "or", "print", "private", "protected",
+ "public", "require", "require_once", "return", "static",
+ "switch", "throw", "trait", "try", "unset",
+ "use", "var", "while", "xor", "int",
+ "float", "bool", "string", "true", "false",
+ "null", "void", "iterable",
+}
+
+// Check if given name/keyword is reserved by php.
+func isReserved(name string) bool {
+ name = strings.ToLower(name)
+ for _, k := range reservedKeywords {
+ if name == k {
+ return true
+ }
+ }
+
+ return false
+}
+
+// generate php namespace or path
+func namespace(pkg *string, sep string) string {
+ if pkg == nil {
+ return ""
+ }
+
+ result := bytes.NewBuffer(nil)
+ for _, p := range strings.Split(*pkg, ".") {
+ result.WriteString(identifier(p, ""))
+ result.WriteString(sep)
+ }
+
+ return strings.Trim(result.String(), sep)
+}
+
+// create php identifier for class or message
+func identifier(name string, suffix string) string {
+ name = Camelize(name)
+ if suffix != "" {
+ return name + Camelize(suffix)
+ }
+
+ return name
+}
+
+func resolveReserved(identifier string, pkg string) string {
+ if isReserved(strings.ToLower(identifier)) {
+ if pkg == ".google.protobuf" {
+ return "GPB" + identifier
+ }
+ return "PB" + identifier
+ }
+
+ return identifier
+}
+
+// Camelize "dino_party" -> "DinoParty"
+func Camelize(word string) string {
+ words := splitAtCaseChangeWithTitlecase(word)
+ return strings.Join(words, "")
+}
+
+func splitAtCaseChangeWithTitlecase(s string) []string {
+ words := make([]string, 0)
+ word := make([]rune, 0)
+ for _, c := range s {
+ spacer := isSpacerChar(c)
+ if len(word) > 0 {
+ if unicode.IsUpper(c) || spacer {
+ words = append(words, string(word))
+ word = make([]rune, 0)
+ }
+ }
+ if !spacer {
+ if len(word) > 0 {
+ word = append(word, unicode.ToLower(c))
+ } else {
+ word = append(word, unicode.ToUpper(c))
+ }
+ }
+ }
+ words = append(words, string(word))
+ return words
+}
+
+func isSpacerChar(c rune) bool {
+ switch {
+ case c == rune("_"[0]):
+ return true
+ case c == rune(" "[0]):
+ return true
+ case c == rune(":"[0]):
+ return true
+ case c == rune("-"[0]):
+ return true
+ }
+ return false
+}
diff --git a/plugins/grpc/protoc-gen-php-grpc/php/ns.go b/plugins/grpc/protoc-gen-php-grpc/php/ns.go
new file mode 100644
index 00000000..c1dc3898
--- /dev/null
+++ b/plugins/grpc/protoc-gen-php-grpc/php/ns.go
@@ -0,0 +1,103 @@
+package php
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+
+ desc "google.golang.org/protobuf/types/descriptorpb"
+ plugin "google.golang.org/protobuf/types/pluginpb"
+)
+
+// manages internal name representation of the package
+type ns struct {
+ // Package defines file package.
+ Package string
+
+ // Root namespace of the package
+ Namespace string
+
+ // Import declares what namespaces to be imported
+ Import map[string]string
+}
+
+// newNamespace creates new work namespace.
+func newNamespace(req *plugin.CodeGeneratorRequest, file *desc.FileDescriptorProto, service *desc.ServiceDescriptorProto) *ns {
+ ns := &ns{
+ Package: *file.Package,
+ Namespace: namespace(file.Package, "\\"),
+ Import: make(map[string]string),
+ }
+
+ if file.Options != nil && file.Options.PhpNamespace != nil {
+ ns.Namespace = *file.Options.PhpNamespace
+ }
+
+ for k := range service.Method {
+ ns.importMessage(req, service.Method[k].InputType)
+ ns.importMessage(req, service.Method[k].OutputType)
+ }
+
+ return ns
+}
+
+// importMessage registers new import message namespace (only the namespace).
+func (ns *ns) importMessage(req *plugin.CodeGeneratorRequest, msg *string) {
+ if msg == nil {
+ return
+ }
+
+ chunks := strings.Split(*msg, ".")
+ pkg := strings.Join(chunks[:len(chunks)-1], ".")
+
+ result := bytes.NewBuffer(nil)
+ for _, p := range chunks[:len(chunks)-1] {
+ result.WriteString(identifier(p, ""))
+ result.WriteString(`\`)
+ }
+
+ if pkg == "."+ns.Package {
+ // root package
+ return
+ }
+
+ for _, f := range req.ProtoFile {
+ if pkg == "."+*f.Package {
+ if f.Options != nil && f.Options.PhpNamespace != nil {
+ // custom imported namespace
+ ns.Import[pkg] = *f.Options.PhpNamespace
+ return
+ }
+ }
+ }
+
+ ns.Import[pkg] = strings.Trim(result.String(), `\`)
+}
+
+// resolve message alias
+func (ns *ns) resolve(msg *string) string {
+ chunks := strings.Split(*msg, ".")
+ pkg := strings.Join(chunks[:len(chunks)-1], ".")
+
+ if pkg == "."+ns.Package {
+ // root message
+ return identifier(chunks[len(chunks)-1], "")
+ }
+
+ for iPkg, ns := range ns.Import {
+ if pkg == iPkg {
+ // use last namespace chunk
+ nsChunks := strings.Split(ns, `\`)
+ identifier := identifier(chunks[len(chunks)-1], "")
+
+ return fmt.Sprintf(
+ `%s\%s`,
+ nsChunks[len(nsChunks)-1],
+ resolveReserved(identifier, pkg),
+ )
+ }
+ }
+
+ // fully clarified name (fallback)
+ return "\\" + namespace(msg, "\\")
+}
diff --git a/plugins/grpc/protoc-gen-php-grpc/php/template.go b/plugins/grpc/protoc-gen-php-grpc/php/template.go
new file mode 100644
index 00000000..e00c6fdd
--- /dev/null
+++ b/plugins/grpc/protoc-gen-php-grpc/php/template.go
@@ -0,0 +1,103 @@
+// MIT License
+//
+// Copyright (c) 2018 SpiralScout
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package php
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+ "text/template"
+
+ desc "google.golang.org/protobuf/types/descriptorpb"
+ plugin "google.golang.org/protobuf/types/pluginpb"
+)
+
+const phpBody = `<?php
+# Generated by the protocol buffer compiler (spiral/php-grpc). DO NOT EDIT!
+# source: {{ .File.Name }}
+{{ $ns := .Namespace -}}
+{{if $ns.Namespace}}
+namespace {{ $ns.Namespace }};
+{{end}}
+use Spiral\GRPC;
+{{- range $n := $ns.Import}}
+use {{ $n }};
+{{- end}}
+
+interface {{ .Service.Name | interface }} extends GRPC\ServiceInterface
+{
+ // GRPC specific service name.
+ public const NAME = "{{ .File.Package }}.{{ .Service.Name }}";{{ "\n" }}
+{{- range $m := .Service.Method}}
+ /**
+ * @param GRPC\ContextInterface $ctx
+ * @param {{ name $ns $m.InputType }} $in
+ * @return {{ name $ns $m.OutputType }}
+ *
+ * @throws GRPC\Exception\InvokeException
+ */
+ public function {{ $m.Name }}(GRPC\ContextInterface $ctx, {{ name $ns $m.InputType }} $in): {{ name $ns $m.OutputType }};
+{{end -}}
+}
+`
+
+// generate php filename
+func filename(file *desc.FileDescriptorProto, name *string) string {
+ ns := namespace(file.Package, "/")
+ if file.Options != nil && file.Options.PhpNamespace != nil {
+ ns = strings.ReplaceAll(*file.Options.PhpNamespace, `\`, `/`)
+ }
+
+ return fmt.Sprintf("%s/%s.php", ns, identifier(*name, "interface"))
+}
+
+// generate php file body
+func body(req *plugin.CodeGeneratorRequest, file *desc.FileDescriptorProto, service *desc.ServiceDescriptorProto) string {
+ out := bytes.NewBuffer(nil)
+
+ data := struct {
+ Namespace *ns
+ File *desc.FileDescriptorProto
+ Service *desc.ServiceDescriptorProto
+ }{
+ Namespace: newNamespace(req, file, service),
+ File: file,
+ Service: service,
+ }
+
+ tpl := template.Must(template.New("phpBody").Funcs(template.FuncMap{
+ "interface": func(name *string) string {
+ return identifier(*name, "interface")
+ },
+ "name": func(ns *ns, name *string) string {
+ return ns.resolve(name)
+ },
+ }).Parse(phpBody))
+
+ err := tpl.Execute(out, data)
+ if err != nil {
+ panic(err)
+ }
+
+ return out.String()
+}
diff --git a/tests/plugins/grpc/grpc_plugin_test.go b/tests/plugins/grpc/grpc_plugin_test.go
new file mode 100644
index 00000000..85dd5723
--- /dev/null
+++ b/tests/plugins/grpc/grpc_plugin_test.go
@@ -0,0 +1,7 @@
+package grpc_test
+
+import "testing"
+
+func GrpcInit(t *testing.T) {
+
+}
diff --git a/tests/plugins/grpc/plugin_test.go b/tests/plugins/grpc/plugin_test.go
new file mode 100644
index 00000000..74a71c62
--- /dev/null
+++ b/tests/plugins/grpc/plugin_test.go
@@ -0,0 +1,178 @@
+package grpc
+
+import (
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func init() {
+ err := build()
+ if err != nil {
+ panic(err)
+ }
+}
+
+func build() error {
+ cmd := exec.Command("go", "build", "-o", "plugin", "../../../plugins/grpc/protoc-gen-php-grpc")
+ return cmd.Run()
+}
+
+func protoc(t *testing.T, args []string) {
+ cmd := exec.Command("protoc", "--plugin=protoc-gen-php-grpc=./plugin")
+ cmd.Args = append(cmd.Args, args...)
+ out, err := cmd.CombinedOutput()
+
+ if len(out) > 0 || err != nil {
+ t.Log("RUNNING: ", strings.Join(cmd.Args, " "))
+ }
+
+ if len(out) > 0 {
+ t.Log(string(out))
+ }
+
+ if err != nil {
+ t.Fatalf("protoc: %v", err)
+ }
+}
+
+func Test_Simple(t *testing.T) {
+ workdir, _ := os.Getwd()
+ tmpdir, err := ioutil.TempDir("", "proto-test")
+ require.NoError(t, err)
+
+ defer func() {
+ assert.NoError(t, os.RemoveAll(tmpdir))
+ }()
+
+ args := []string{
+ "-Itestdata",
+ "--php-grpc_out=" + tmpdir,
+ "simple/simple.proto",
+ }
+
+ protoc(t, args)
+
+ assertEqualFiles(
+ t,
+ workdir+"/testdata/simple/TestSimple/SimpleServiceInterface.php",
+ tmpdir+"/TestSimple/SimpleServiceInterface.php",
+ )
+}
+
+func Test_PhpNamespaceOption(t *testing.T) {
+ workdir, _ := os.Getwd()
+ tmpdir, err := ioutil.TempDir("", "proto-test")
+ require.NoError(t, err)
+
+ defer func() {
+ assert.NoError(t, os.RemoveAll(tmpdir))
+ }()
+
+ args := []string{
+ "-Itestdata",
+ "--php-grpc_out=" + tmpdir,
+ "php_namespace/service.proto",
+ }
+ protoc(t, args)
+
+ assertEqualFiles(
+ t,
+ workdir+"/testdata/php_namespace/Test/CustomNamespace/ServiceInterface.php",
+ tmpdir+"/Test/CustomNamespace/ServiceInterface.php",
+ )
+}
+
+func Test_UseImportedMessage(t *testing.T) {
+ workdir, _ := os.Getwd()
+ tmpdir, err := ioutil.TempDir("", "proto-test")
+ require.NoError(t, err)
+
+ defer func() {
+ assert.NoError(t, os.RemoveAll(tmpdir))
+ }()
+
+ args := []string{
+ "-Itestdata",
+ "--php-grpc_out=" + tmpdir,
+ "import/service.proto",
+ }
+ protoc(t, args)
+
+ assertEqualFiles(
+ t,
+ workdir+"/testdata/import/Import/ServiceInterface.php",
+ tmpdir+"/Import/ServiceInterface.php",
+ )
+}
+
+func Test_PhpNamespaceOptionInUse(t *testing.T) {
+ workdir, _ := os.Getwd()
+ tmpdir, err := ioutil.TempDir("", "proto-test")
+ require.NoError(t, err)
+
+ defer func() {
+ assert.NoError(t, os.RemoveAll(tmpdir))
+ }()
+
+ args := []string{
+ "-Itestdata",
+ "--php-grpc_out=" + tmpdir,
+ "import_custom/service.proto",
+ }
+ protoc(t, args)
+
+ assertEqualFiles(
+ t,
+ workdir+"/testdata/import_custom/Test/CustomImport/ServiceInterface.php",
+ tmpdir+"/Test/CustomImport/ServiceInterface.php",
+ )
+}
+
+func Test_UseOfGoogleEmptyMessage(t *testing.T) {
+ workdir, _ := os.Getwd()
+ tmpdir, err := ioutil.TempDir("", "proto-test")
+ require.NoError(t, err)
+
+ defer func() {
+ assert.NoError(t, os.RemoveAll(tmpdir))
+ }()
+
+ args := []string{
+ "-Itestdata",
+ "--php-grpc_out=" + tmpdir,
+ "use_empty/service.proto",
+ }
+ protoc(t, args)
+
+ assertEqualFiles(
+ t,
+ workdir+"/testdata/use_empty/Test/ServiceInterface.php",
+ tmpdir+"/Test/ServiceInterface.php",
+ )
+
+ assert.NoError(t, os.RemoveAll("plugin"))
+}
+
+func assertEqualFiles(t *testing.T, original, generated string) {
+ assert.FileExists(t, generated)
+
+ originalData, err := ioutil.ReadFile(original)
+ if err != nil {
+ t.Fatal("Can't find original file for comparison")
+ }
+
+ generatedData, err := ioutil.ReadFile(generated)
+ if err != nil {
+ t.Fatal("Can't find generated file for comparison")
+ }
+
+ // every OS has a special boy
+ r := strings.NewReplacer("\r\n", "", "\n", "")
+ assert.Equal(t, r.Replace(string(originalData)), r.Replace(string(generatedData)))
+}
diff --git a/tests/plugins/grpc/testdata/import/Import/ServiceInterface.php b/tests/plugins/grpc/testdata/import/Import/ServiceInterface.php
new file mode 100644
index 00000000..13e58daf
--- /dev/null
+++ b/tests/plugins/grpc/testdata/import/Import/ServiceInterface.php
@@ -0,0 +1,32 @@
+<?php
+# Generated by the protocol buffer compiler (spiral/php-grpc). DO NOT EDIT!
+# source: import/service.proto
+
+namespace Import;
+
+use Spiral\GRPC;
+use Import\Sub;
+
+interface ServiceInterface extends GRPC\ServiceInterface
+{
+ // GRPC specific service name.
+ public const NAME = "import.Service";
+
+ /**
+ * @param GRPC\ContextInterface $ctx
+ * @param Message $in
+ * @return Message
+ *
+ * @throws GRPC\Exception\InvokeException
+ */
+ public function SimpleMethod(GRPC\ContextInterface $ctx, Message $in): Message;
+
+ /**
+ * @param GRPC\ContextInterface $ctx
+ * @param Sub\Message $in
+ * @return Sub\Message
+ *
+ * @throws GRPC\Exception\InvokeException
+ */
+ public function ImportMethod(GRPC\ContextInterface $ctx, Sub\Message $in): Sub\Message;
+}
diff --git a/tests/plugins/grpc/testdata/import/service.proto b/tests/plugins/grpc/testdata/import/service.proto
new file mode 100644
index 00000000..5d888f09
--- /dev/null
+++ b/tests/plugins/grpc/testdata/import/service.proto
@@ -0,0 +1,17 @@
+syntax = "proto3";
+
+package import;
+
+import "import/sub/message.proto";
+
+service Service {
+ rpc SimpleMethod (Message) returns (Message) {
+ }
+
+ rpc ImportMethod (import.sub.Message) returns (import.sub.Message) {
+ }
+}
+
+message Message {
+ int64 id = 1;
+} \ No newline at end of file
diff --git a/tests/plugins/grpc/testdata/import/sub/message.proto b/tests/plugins/grpc/testdata/import/sub/message.proto
new file mode 100644
index 00000000..1db0313b
--- /dev/null
+++ b/tests/plugins/grpc/testdata/import/sub/message.proto
@@ -0,0 +1,7 @@
+syntax = "proto3";
+
+package import.sub;
+
+message Message {
+ int64 id = 1;
+} \ No newline at end of file
diff --git a/tests/plugins/grpc/testdata/import_custom/Test/CustomImport/ServiceInterface.php b/tests/plugins/grpc/testdata/import_custom/Test/CustomImport/ServiceInterface.php
new file mode 100644
index 00000000..b010ce4f
--- /dev/null
+++ b/tests/plugins/grpc/testdata/import_custom/Test/CustomImport/ServiceInterface.php
@@ -0,0 +1,32 @@
+<?php
+# Generated by the protocol buffer compiler (spiral/php-grpc). DO NOT EDIT!
+# source: import_custom/service.proto
+
+namespace Test\CustomImport;
+
+use Spiral\GRPC;
+use Test\CustomImport\Message;
+
+interface ServiceInterface extends GRPC\ServiceInterface
+{
+ // GRPC specific service name.
+ public const NAME = "import.Service";
+
+ /**
+ * @param GRPC\ContextInterface $ctx
+ * @param Message $in
+ * @return Message
+ *
+ * @throws GRPC\Exception\InvokeException
+ */
+ public function SimpleMethod(GRPC\ContextInterface $ctx, Message $in): Message;
+
+ /**
+ * @param GRPC\ContextInterface $ctx
+ * @param Message\Message $in
+ * @return Message\Message
+ *
+ * @throws GRPC\Exception\InvokeException
+ */
+ public function ImportMethod(GRPC\ContextInterface $ctx, Message\Message $in): Message\Message;
+}
diff --git a/tests/plugins/grpc/testdata/import_custom/service.proto b/tests/plugins/grpc/testdata/import_custom/service.proto
new file mode 100644
index 00000000..872aaae3
--- /dev/null
+++ b/tests/plugins/grpc/testdata/import_custom/service.proto
@@ -0,0 +1,19 @@
+syntax = "proto3";
+
+package import;
+
+option php_namespace = "Test\\CustomImport";
+
+import "import_custom/sub/message.proto";
+
+service Service {
+ rpc SimpleMethod (Message) returns (Message) {
+ }
+
+ rpc ImportMethod (import.sub.Message) returns (import.sub.Message) {
+ }
+}
+
+message Message {
+ int64 id = 1;
+} \ No newline at end of file
diff --git a/tests/plugins/grpc/testdata/import_custom/sub/message.proto b/tests/plugins/grpc/testdata/import_custom/sub/message.proto
new file mode 100644
index 00000000..5d722ca3
--- /dev/null
+++ b/tests/plugins/grpc/testdata/import_custom/sub/message.proto
@@ -0,0 +1,14 @@
+syntax = "proto3";
+
+package import.sub;
+option php_namespace = "Test\\CustomImport\\Message";
+
+
+service Service {
+ rpc AnotherMethod (Message) returns (Message) {
+ }
+}
+
+message Message {
+ int64 id = 1;
+} \ No newline at end of file
diff --git a/tests/plugins/grpc/testdata/php_namespace/Test/CustomNamespace/ServiceInterface.php b/tests/plugins/grpc/testdata/php_namespace/Test/CustomNamespace/ServiceInterface.php
new file mode 100644
index 00000000..2090ba97
--- /dev/null
+++ b/tests/plugins/grpc/testdata/php_namespace/Test/CustomNamespace/ServiceInterface.php
@@ -0,0 +1,22 @@
+<?php
+# Generated by the protocol buffer compiler (spiral/php-grpc). DO NOT EDIT!
+# source: php_namespace/service.proto
+
+namespace Test\CustomNamespace;
+
+use Spiral\GRPC;
+
+interface ServiceInterface extends GRPC\ServiceInterface
+{
+ // GRPC specific service name.
+ public const NAME = "testPhpNamespace.Service";
+
+ /**
+ * @param GRPC\ContextInterface $ctx
+ * @param SimpleMessage $in
+ * @return SimpleMessage
+ *
+ * @throws GRPC\Exception\InvokeException
+ */
+ public function SimpleMethod(GRPC\ContextInterface $ctx, SimpleMessage $in): SimpleMessage;
+}
diff --git a/tests/plugins/grpc/testdata/php_namespace/service.proto b/tests/plugins/grpc/testdata/php_namespace/service.proto
new file mode 100644
index 00000000..a3bfa3c0
--- /dev/null
+++ b/tests/plugins/grpc/testdata/php_namespace/service.proto
@@ -0,0 +1,15 @@
+syntax = "proto3";
+
+package testPhpNamespace;
+
+option php_namespace = "Test\\CustomNamespace";
+
+service Service {
+ rpc SimpleMethod (SimpleMessage) returns (SimpleMessage) {
+ }
+}
+
+message SimpleMessage {
+ int32 id = 1;
+ string name = 2;
+} \ No newline at end of file
diff --git a/tests/plugins/grpc/testdata/simple/TestSimple/SimpleServiceInterface.php b/tests/plugins/grpc/testdata/simple/TestSimple/SimpleServiceInterface.php
new file mode 100644
index 00000000..f9e84bf7
--- /dev/null
+++ b/tests/plugins/grpc/testdata/simple/TestSimple/SimpleServiceInterface.php
@@ -0,0 +1,22 @@
+<?php
+# Generated by the protocol buffer compiler (spiral/php-grpc). DO NOT EDIT!
+# source: simple/simple.proto
+
+namespace TestSimple;
+
+use Spiral\GRPC;
+
+interface SimpleServiceInterface extends GRPC\ServiceInterface
+{
+ // GRPC specific service name.
+ public const NAME = "testSimple.SimpleService";
+
+ /**
+ * @param GRPC\ContextInterface $ctx
+ * @param SimpleMessage $in
+ * @return SimpleMessage
+ *
+ * @throws GRPC\Exception\InvokeException
+ */
+ public function SimpleMethod(GRPC\ContextInterface $ctx, SimpleMessage $in): SimpleMessage;
+}
diff --git a/tests/plugins/grpc/testdata/simple/simple.proto b/tests/plugins/grpc/testdata/simple/simple.proto
new file mode 100644
index 00000000..aca3c1d9
--- /dev/null
+++ b/tests/plugins/grpc/testdata/simple/simple.proto
@@ -0,0 +1,13 @@
+syntax = "proto3";
+
+package testSimple;
+
+service SimpleService {
+ rpc SimpleMethod (SimpleMessage) returns (SimpleMessage) {
+ }
+}
+
+message SimpleMessage {
+ int32 id = 1;
+ string name = 2;
+} \ No newline at end of file
diff --git a/tests/plugins/grpc/testdata/use_empty/Test/ServiceInterface.php b/tests/plugins/grpc/testdata/use_empty/Test/ServiceInterface.php
new file mode 100644
index 00000000..fe6d345a
--- /dev/null
+++ b/tests/plugins/grpc/testdata/use_empty/Test/ServiceInterface.php
@@ -0,0 +1,23 @@
+<?php
+# Generated by the protocol buffer compiler (spiral/php-grpc). DO NOT EDIT!
+# source: use_empty/service.proto
+
+namespace Test;
+
+use Spiral\GRPC;
+use Google\Protobuf;
+
+interface ServiceInterface extends GRPC\ServiceInterface
+{
+ // GRPC specific service name.
+ public const NAME = "test.Service";
+
+ /**
+ * @param GRPC\ContextInterface $ctx
+ * @param Protobuf\GPBEmpty $in
+ * @return Protobuf\GPBEmpty
+ *
+ * @throws GRPC\Exception\InvokeException
+ */
+ public function Test(GRPC\ContextInterface $ctx, Protobuf\GPBEmpty $in): Protobuf\GPBEmpty;
+}
diff --git a/tests/plugins/grpc/testdata/use_empty/service.proto b/tests/plugins/grpc/testdata/use_empty/service.proto
new file mode 100644
index 00000000..8c68d8d3
--- /dev/null
+++ b/tests/plugins/grpc/testdata/use_empty/service.proto
@@ -0,0 +1,10 @@
+syntax = "proto3";
+
+package test;
+
+import "google/protobuf/empty.proto";
+
+service Service {
+ rpc Test (google.protobuf.Empty) returns (google.protobuf.Empty) {
+ }
+} \ No newline at end of file
diff --git a/tests/plugins/grpcplug b/tests/plugins/grpcplug
new file mode 100755
index 00000000..21785aeb
--- /dev/null
+++ b/tests/plugins/grpcplug
Binary files differ
diff --git a/tests/plugins/grpcplugin b/tests/plugins/grpcplugin
new file mode 100755
index 00000000..21785aeb
--- /dev/null
+++ b/tests/plugins/grpcplugin
Binary files differ