Compare commits

...

78 Commits

Author SHA1 Message Date
3e1ffcb989 add all http request metadata
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-08-11 12:47:44 +03:00
c1e0ce26b5 add ability to register RPC endpoint
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-07-14 13:43:45 +03:00
26e34124e0 update all
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-07-06 19:12:46 +03:00
c1526f70ce dont display unneded error message
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-07-06 19:10:54 +03:00
28d23f388f fixup new codec detection
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-14 14:17:33 +03:00
d3d67eca97 allow to response with different content-type
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-13 15:46:47 +03:00
919bf1486f fixup
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-13 12:11:54 +03:00
88ef21ba9e fix broker disconnect
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-13 10:59:38 +03:00
Renovate Bot
254b01f75a Update golang.org/x/net commit hash to 4163338 2021-05-10 13:29:05 +00:00
Renovate Bot
325b8a43ef Update golang.org/x/net commit hash to 81045d8 2021-05-10 12:01:05 +00:00
Renovate Bot
d94860c32d Update golang.org/x/net commit hash to 16afe75 2021-05-08 09:19:14 +00:00
Renovate Bot
778095179d Update golang.org/x/net commit hash to 0714010 2021-05-05 23:20:59 +00:00
f71ae35f12 fix content-type override
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-05 13:32:12 +03:00
Renovate Bot
4d27c79081 Update golang.org/x/net commit hash to 0287a6f 2021-05-05 05:21:33 +00:00
Renovate Bot
1eebef8dbc Update golang.org/x/net commit hash to bbd867f 2021-05-04 16:38:19 +00:00
Renovate Bot
cd2c0b65e1 Update golang.org/x/net commit hash to 7fd8e65 2021-05-03 09:44:49 +00:00
Renovate Bot
97e0bf75bb Update golang.org/x/net commit hash to e590880 2021-05-02 05:04:21 +00:00
Renovate Bot
9f56d8b6b5 Update golang.org/x/net commit hash to f8dd838 2021-05-01 23:25:24 +00:00
Renovate Bot
21f608d728 Update golang.org/x/net commit hash to aec3718 2021-05-01 16:57:56 +00:00
ba283695dd fix rsp code for wrappers
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-05-01 01:24:09 +03:00
b18465083b fill metadata early
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-30 00:40:15 +03:00
Renovate Bot
11020aa6e5 Update golang.org/x/net commit hash to 89ef3d9 2021-04-28 16:43:11 +00:00
Renovate Bot
43c0eb4fda Update golang.org/x/net commit hash to 85d9c07 2021-04-28 01:42:52 +00:00
5ab606c2b5 update for latest micro
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-27 19:10:35 +03:00
6c661c9d72 lint (#57)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-26 00:43:06 +03:00
a215521821 fieldalignment
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-25 12:09:09 +03:00
Renovate Bot
ec5af022b3 Update golang.org/x/net commit hash to 5f58ad6 2021-04-23 22:20:32 +00:00
Renovate Bot
bd88f6e485 Update golang.org/x/net commit hash to 4e50805 2021-04-22 02:47:31 +00:00
Renovate Bot
34a39be017 Update golang.org/x/net commit hash to 798c215 2021-04-20 23:49:53 +00:00
Renovate Bot
360703d8bb Update golang.org/x/net commit hash to d25e304 2021-04-20 11:33:44 +00:00
2660a0d94d update for latest micro
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-20 12:53:48 +03:00
Renovate Bot
6e9a693b51 Update module github.com/unistack-org/micro/v3 to v3.3.15 2021-04-19 17:06:46 +00:00
renovate[bot]
06d197e356 Update module github.com/unistack-org/micro/v3 to v3.3.14 (#49)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
2021-04-19 02:12:57 +03:00
30609135a4 use DefaultContentType on application/x-www-form-urlencoded
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-18 15:50:41 +03:00
84167d359e extract application/x-www-form-urlencoded handling to codec
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-17 13:54:32 +03:00
145a0f4aa6 minor content-type fixes
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-16 17:14:27 +03:00
Renovate Bot
b2b4d6a5a3 Update golang.org/x/net commit hash to e915ea6 2021-04-16 01:28:59 +00:00
Renovate Bot
f17afa7950 Update golang.org/x/net commit hash to 0645797 2021-04-14 21:16:29 +00:00
bb763c71b5 add content type handlers
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-13 23:42:33 +03:00
622a79bd06 add path handler option
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-13 11:33:03 +03:00
Renovate Bot
0eb3c0b452 Update golang.org/x/net commit hash to afb366f 2021-04-10 12:19:24 +00:00
676634850e allow to set default content type with charset
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-10 12:41:55 +03:00
0d442683ee properly detect content-type
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-10 12:38:17 +03:00
Renovate Bot
c8587ec93a Update module github.com/unistack-org/micro/v3 to v3.3.13 2021-04-10 00:02:08 +00:00
7e35316cf2 rewrite x-www-form-urlencoded
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-04-10 01:24:34 +03:00
Renovate Bot
475452a781 Update golang.org/x/net commit hash to a5a99cb 2021-04-05 21:22:50 +00:00
Renovate Bot
dd0bb7c5d4 Update module github.com/unistack-org/micro/v3 to v3.3.11 2021-04-03 11:43:48 +00:00
Renovate Bot
b74f3762dd Update all deps 2021-04-01 00:46:07 +00:00
Renovate Bot
e30590c707 Update golang.org/x/net commit hash to cb1fcc7 2021-03-31 08:14:56 +00:00
Renovate Bot
132e95dec6 Update golang.org/x/net commit hash to e572328 2021-03-31 00:41:40 +00:00
48620e6297 handle x-form-urlencoded content-type
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-31 00:50:02 +03:00
Renovate Bot
e31185b6dc Update golang.org/x/net commit hash to c8897c2 2021-03-30 16:23:29 +00:00
Renovate Bot
151e45ca30 Update golang.org/x/net commit hash to 22f4162 2021-03-30 12:06:34 +00:00
Renovate Bot
93c4f219e9 Update all deps 2021-03-30 06:47:00 +00:00
Renovate Bot
396654b066 Update module github.com/unistack-org/micro/v3 to v3.3.8 2021-03-29 03:27:06 +00:00
Renovate Bot
a769031246 Update module github.com/unistack-org/micro/v3 to v3.3.7 2021-03-28 20:50:08 +00:00
Renovate Bot
99915c1633 Update golang.org/x/net commit hash to 61e0566 2021-03-27 01:57:17 +00:00
Renovate Bot
c7759d29b8 Update all deps 2021-03-26 17:42:44 +00:00
Renovate Bot
0f97e432a4 Update module github.com/unistack-org/micro/v3 to v3.3.2 2021-03-25 13:14:58 +00:00
Renovate Bot
713b4f96be Update all deps 2021-03-25 00:08:52 +00:00
360b15a3b6 remove Warn on missing rsp code
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-24 23:58:35 +03:00
Renovate Bot
4959b0040b Update golang.org/x/net commit hash to 2c4c8ec 2021-03-24 15:09:22 +00:00
e93c6dc1de cleanup
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-24 15:22:20 +03:00
Renovate Bot
9ad01954dc Update all deps 2021-03-23 17:40:45 +00:00
Renovate Bot
8483b85c94 Update module github.com/unistack-org/micro/v3 to v3.2.24 2021-03-21 17:16:53 +00:00
Renovate Bot
d1a8f76d77 Update module github.com/unistack-org/micro/v3 to v3.2.23 2021-03-16 19:22:28 +00:00
Renovate Bot
9d7f4bfa66 Update golang.org/x/net commit hash to d523dce 2021-03-16 13:48:28 +00:00
Renovate Bot
656dfd4d05 Update golang.org/x/net commit hash to 34ac3e1 2021-03-15 22:07:09 +00:00
Renovate Bot
70e14e6592 Update module github.com/unistack-org/micro/v3 to v3.2.22 2021-03-15 02:19:34 +00:00
39e6d9f586 fixes with ErrorHandler and passed *http.Server
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-09 23:54:46 +03:00
a46c9d395a fix for multiple server registration
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-09 14:20:08 +03:00
Renovate Bot
d3c5a503c6 Update module github.com/unistack-org/micro/v3 to v3.2.20 2021-03-06 23:25:58 +00:00
Renovate Bot
be224692a4 Update module github.com/unistack-org/micro/v3 to v3.2.18 2021-03-06 19:32:16 +00:00
Renovate Bot
0da73b62ae Update module github.com/unistack-org/micro/v3 to v3.2.17 2021-03-05 17:17:15 +00:00
Renovate Bot
a30c2972fd Update module github.com/unistack-org/micro/v3 to v3.2.16 2021-03-04 12:21:58 +00:00
f28de46379 dont panic on nil ErrorHandler
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-01 20:25:09 +03:00
af91220a09 fix metadata
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-03-01 20:25:09 +03:00
Renovate Bot
14bf4a9f30 Update module github.com/unistack-org/micro/v3 to v3.2.15 2021-03-01 13:06:52 +00:00
14 changed files with 481 additions and 196 deletions

View File

@@ -2,6 +2,7 @@
"extends": [
"config:base"
],
"postUpdateOptions": ["gomodTidy"],
"packageRules": [
{
"matchUpdateTypes": ["minor", "patch", "pin", "digest"],

13
.github/stale.sh vendored
View File

@@ -1,13 +0,0 @@
#!/bin/bash -ex
export PATH=$PATH:$(pwd)/bin
export GO111MODULE=on
export GOBIN=$(pwd)/bin
#go get github.com/rvflash/goup@v0.4.1
#goup -v ./...
#go get github.com/psampaz/go-mod-outdated@v0.6.0
go list -u -m -mod=mod -json all | go-mod-outdated -update -direct -ci || true
#go list -u -m -json all | go-mod-outdated -update

View File

@@ -34,10 +34,9 @@ jobs:
uses: actions/checkout@v2
- name: lint
uses: golangci/golangci-lint-action@v2
continue-on-error: true
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.30
version: v1.39
# Optional: working directory, useful for monorepos
# working-directory: somedir
# Optional: golangci-lint command line arguments.

View File

@@ -34,10 +34,9 @@ jobs:
uses: actions/checkout@v2
- name: lint
uses: golangci/golangci-lint-action@v2
continue-on-error: true
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: v1.30
version: v1.39
# Optional: working directory, useful for monorepos
# working-directory: somedir
# Optional: golangci-lint command line arguments.

44
.golangci.yml Normal file
View File

@@ -0,0 +1,44 @@
run:
concurrency: 4
deadline: 5m
issues-exit-code: 1
tests: true
linters-settings:
govet:
check-shadowing: true
enable:
- fieldalignment
linters:
enable:
- govet
- deadcode
- errcheck
- govet
- ineffassign
- staticcheck
- structcheck
- typecheck
- unused
- varcheck
- bodyclose
- gci
- goconst
- gocritic
- gosimple
- gofmt
- gofumpt
- goimports
- golint
- gosec
- makezero
- misspell
- nakedret
- nestif
- nilerr
- noctx
- prealloc
- unconvert
- unparam
disable-all: false

8
go.mod
View File

@@ -1,10 +1,8 @@
module github.com/unistack-org/micro-server-http/v3
go 1.13
go 1.16
require (
github.com/unistack-org/micro/v3 v3.2.14
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110
github.com/unistack-org/micro/v3 v3.4.7
golang.org/x/net v0.0.0-20210614182718-04defd469f4e
)
//replace github.com/unistack-org/micro/v3 => ../../micro

28
go.sum
View File

@@ -1,32 +1,20 @@
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/ef-ds/deque v1.0.4/go.mod h1:gXDnTC3yqvBcHbq2lcExjtAcVrOnJCbMcZXmuj8Z4tg=
github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/heimdalr/dag v1.0.1/go.mod h1:t+ZkR+sjKL4xhlE1B9rwpvwfo+x+2R0363efS+Oghns=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
github.com/silas/dag v0.0.0-20210121180416-41cf55125c34/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
github.com/unistack-org/micro/v3 v3.2.14 h1:BD7JR2W0WlJvJgHN3uPWrE/vNAGyxhIQrIODeDCfoSk=
github.com/unistack-org/micro/v3 v3.2.14/go.mod h1:3j13mSd/rILNjyP0tEVtDxyDkJBtnHUXShNCuPHkC5A=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226101413-39120d07d75e h1:jIQURUJ9mlLvYwTBtRHm9h58rYhSonLvRvgAnP8Nr7I=
golang.org/x/net v0.0.0-20210226101413-39120d07d75e/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
github.com/unistack-org/micro/v3 v3.4.7 h1:zmGFx2J6tIbmr4IGLcc+LNtbftQFZI42bfuNV5xNYM0=
github.com/unistack-org/micro/v3 v3.4.7/go.mod h1:LXmPfbJnJNvL0kQs8HfnkV3Wya2Wb+C7keVq++RCZnk=
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e h1:XpT3nA5TvE525Ne3hInMh6+GETgn27Zfm9dxsThnX2Q=
golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@@ -7,8 +7,8 @@ import (
"net/http"
"reflect"
"strings"
"sync"
"github.com/unistack-org/micro/v3/codec"
"github.com/unistack-org/micro/v3/errors"
"github.com/unistack-org/micro/v3/logger"
"github.com/unistack-org/micro/v3/metadata"
@@ -21,33 +21,28 @@ import (
var (
DefaultErrorHandler = func(ctx context.Context, s server.Handler, w http.ResponseWriter, r *http.Request, err error, status int) {
w.WriteHeader(status)
w.Write([]byte(err.Error()))
if _, cerr := w.Write([]byte(err.Error())); cerr != nil {
logger.DefaultLogger.Errorf(ctx, "write failed: %v", cerr)
}
}
DefaultContentType = "application/json"
)
type patHandler struct {
pat rutil.Pattern
mtype *methodType
name string
rcvr reflect.Value
name string
pat rutil.Pattern
}
type httpHandler struct {
name string
opts server.HandlerOptions
sopts server.Options
eps []*register.Endpoint
hd interface{}
handlers map[string][]patHandler
errorHandler func(context.Context, server.Handler, http.ResponseWriter, *http.Request, error, int)
}
func (h *httpHandler) newCodec(ct string) (codec.Codec, error) {
if cf, ok := h.sopts.Codecs[ct]; ok {
return cf, nil
}
return nil, codec.ErrUnknownContentType
opts server.HandlerOptions
hd interface{}
handlers map[string][]patHandler
name string
eps []*register.Endpoint
sopts server.Options
sync.RWMutex
}
func (h *httpHandler) Name() string {
@@ -66,14 +61,12 @@ func (h *httpHandler) Options() server.HandlerOptions {
return h.opts
}
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ctx := metadata.NewContext(r.Context(), nil)
defer r.Body.Close()
path := r.URL.Path
if !strings.HasPrefix(path, "/") {
h.errorHandler(ctx, h, w, r, fmt.Errorf("path must contains /"), http.StatusBadRequest)
func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
for exp, ph := range h.pathHandlers {
if exp.MatchString(r.URL.String()) {
ph(w, r)
return
}
}
ct := DefaultContentType
@@ -81,9 +74,43 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ct = htype
}
if idx := strings.Index(ct, ":"); idx > 0 {
if ph, ok := h.contentTypeHandlers[ct[:idx]]; ok {
ph(w, r)
return
}
}
ctx := context.WithValue(r.Context(), rspCodeKey{}, &rspCodeVal{})
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
md = metadata.New(len(r.Header))
}
for k, v := range r.Header {
md.Set(k, strings.Join(v, ", "))
}
md.Set("RemoteAddr", r.RemoteAddr)
md.Set("Method", r.Method)
md.Set("URL", r.URL.String())
md.Set("Proto", r.Proto)
md.Set("ContentLength", fmt.Sprintf("%d", r.ContentLength))
md.Set("TransferEncoding", strings.Join(r.TransferEncoding, ","))
md.Set("Host", r.Host)
md.Set("RequestURI", r.RequestURI)
ctx = metadata.NewIncomingContext(ctx, md)
defer r.Body.Close()
path := r.URL.Path
if !strings.HasPrefix(path, "/") {
h.errorHandler(ctx, nil, w, r, fmt.Errorf("path must contains /"), http.StatusBadRequest)
return
}
cf, err := h.newCodec(ct)
if err != nil {
h.errorHandler(ctx, h, w, r, err, http.StatusBadRequest)
h.errorHandler(ctx, nil, w, r, err, http.StatusBadRequest)
return
}
components := strings.Split(path[1:], "/")
@@ -91,7 +118,7 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var verb string
idx := strings.LastIndex(components[l-1], ":")
if idx == 0 {
h.errorHandler(ctx, h, w, r, fmt.Errorf("not found"), http.StatusNotFound)
h.errorHandler(ctx, nil, w, r, fmt.Errorf("not found"), http.StatusNotFound)
return
}
if idx > 0 {
@@ -100,38 +127,38 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
matches := make(map[string]interface{})
var match bool
var hldr patHandler
for _, hldr = range h.handlers[r.Method] {
mp, err := hldr.pat.Match(components, verb)
if err == nil {
match = true
for k, v := range mp {
matches[k] = v
var handler *httpHandler
for _, hpat := range h.handlers {
handlertmp := hpat.(*httpHandler)
for _, hldrtmp := range handlertmp.handlers[r.Method] {
mp, merr := hldrtmp.pat.Match(components, verb)
if merr == nil {
match = true
for k, v := range mp {
matches[k] = v
}
hldr = hldrtmp
handler = handlertmp
break
}
break
}
}
if !match {
h.errorHandler(ctx, h, w, r, fmt.Errorf("not matching route found"), http.StatusNotFound)
h.errorHandler(ctx, nil, w, r, fmt.Errorf("not matching route found"), http.StatusNotFound)
return
}
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
md = metadata.New(0)
}
for k, v := range r.Header {
md.Set(k, strings.Join(v, ", "))
}
// get fields from url values
if len(r.URL.RawQuery) > 0 {
umd, err := rflutil.URLMap(r.URL.RawQuery)
if err != nil {
h.errorHandler(ctx, h, w, r, err, http.StatusBadRequest)
umd, cerr := rflutil.URLMap(r.URL.RawQuery)
if cerr != nil {
h.errorHandler(ctx, handler, w, r, cerr, http.StatusBadRequest)
return
}
for k, v := range umd {
matches[k] = v
@@ -157,60 +184,90 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
replyv = reflect.New(hldr.mtype.ReplyType.Elem())
function := hldr.mtype.method.Func
//function := hldr.rcvr
// function := hldr.rcvr
var returnValues []reflect.Value
if err = cf.ReadBody(r.Body, argv.Interface()); err != nil && err != io.EOF {
h.errorHandler(ctx, h, w, r, err, http.StatusInternalServerError)
h.errorHandler(ctx, handler, w, r, err, http.StatusInternalServerError)
return
}
matches = rflutil.FlattenMap(matches)
if err = rflutil.MergeMap(argv.Interface(), matches); err != nil {
h.errorHandler(ctx, h, w, r, err, http.StatusBadRequest)
if err = rflutil.Merge(argv.Interface(), matches, rflutil.SliceAppend(true), rflutil.Tags([]string{"protobuf", "json"})); err != nil {
h.errorHandler(ctx, handler, w, r, err, http.StatusBadRequest)
return
}
b, err := cf.Marshal(argv.Interface())
if err != nil {
h.errorHandler(ctx, h, w, r, err, http.StatusBadRequest)
h.errorHandler(ctx, handler, w, r, err, http.StatusBadRequest)
return
}
hr := &rpcRequest{
codec: cf,
service: h.sopts.Name,
service: handler.sopts.Name,
contentType: ct,
method: fmt.Sprintf("%s.%s", hldr.name, hldr.mtype.method.Name),
body: b,
payload: argv.Interface(),
header: md,
}
var scode int
// define the handler func
fn := func(fctx context.Context, req server.Request, rsp interface{}) (err error) {
fctx = context.WithValue(fctx, rspCodeKey{}, &rspCodeVal{})
fctx = metadata.NewIncomingContext(fctx, md)
returnValues = function.Call([]reflect.Value{hldr.rcvr, hldr.mtype.prepareContext(fctx), reflect.ValueOf(argv.Interface()), reflect.ValueOf(rsp)})
scode = GetRspCode(fctx)
// The return value for the method is an error.
if rerr := returnValues[0].Interface(); rerr != nil {
err = rerr.(error)
}
if md, ok := metadata.FromOutgoingContext(fctx); ok {
metadata.SetOutgoingContext(ctx, md)
md, ok := metadata.FromOutgoingContext(ctx)
if !ok {
md = metadata.New(0)
}
if nmd, ok := metadata.FromOutgoingContext(fctx); ok {
for k, v := range nmd {
md.Set(k, v)
}
}
metadata.SetOutgoingContext(ctx, md)
return err
}
// wrap the handler func
for i := len(h.sopts.HdlrWrappers); i > 0; i-- {
fn = h.sopts.HdlrWrappers[i-1](fn)
for i := len(handler.sopts.HdlrWrappers); i > 0; i-- {
fn = handler.sopts.HdlrWrappers[i-1](fn)
}
if appErr := fn(ctx, hr, replyv.Interface()); appErr != nil {
if ct == "application/x-www-form-urlencoded" {
cf, err = h.newCodec(DefaultContentType)
if err != nil {
h.errorHandler(ctx, handler, w, r, err, http.StatusInternalServerError)
return
}
ct = DefaultContentType
}
scode := int(200)
appErr := fn(ctx, hr, replyv.Interface())
w.Header().Set("Content-Type", ct)
if md, ok := metadata.FromOutgoingContext(ctx); ok {
for k, v := range md {
w.Header().Set(k, v)
}
}
if nct := w.Header().Get("Content-Type"); nct != ct {
if cf, err = h.newCodec(nct); err != nil {
h.errorHandler(ctx, nil, w, r, err, http.StatusBadRequest)
return
}
}
if appErr != nil {
switch verr := appErr.(type) {
case *errors.Error:
scode = int(verr.Code)
@@ -223,22 +280,18 @@ func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} else {
b, err = cf.Marshal(replyv.Interface())
}
if err != nil && h.sopts.Logger.V(logger.ErrorLevel) {
h.sopts.Logger.Errorf(h.sopts.Context, "handler err: %v", err)
if err != nil && handler.sopts.Logger.V(logger.ErrorLevel) {
handler.sopts.Logger.Errorf(handler.sopts.Context, "handler err: %v", err)
return
}
if md, ok := metadata.FromOutgoingContext(ctx); ok {
for k, v := range md {
w.Header().Set(k, v)
}
if nscode := GetRspCode(ctx); nscode != 0 {
scode = nscode
}
w.WriteHeader(scode)
w.Header().Set("content-Type", ct)
if scode != 0 {
w.WriteHeader(scode)
} else {
h.sopts.Logger.Warn(h.sopts.Context, "response code not set in handler via SetRspCode(ctx, http.StatusXXX)")
if _, cerr := w.Write(b); cerr != nil {
logger.DefaultLogger.Errorf(ctx, "write failed: %v", cerr)
}
w.Write(b)
}

249
http.go
View File

@@ -2,12 +2,13 @@
package http
import (
"context"
"crypto/tls"
"errors"
"fmt"
"net"
"net/http"
"reflect"
"regexp"
"sort"
"strings"
"sync"
@@ -23,19 +24,29 @@ import (
)
type httpServer struct {
hd server.Handler
rsvc *register.Service
handlers map[string]server.Handler
exit chan chan error
subscribers map[*httpSubscriber][]broker.Subscriber
errorHandler func(context.Context, server.Handler, http.ResponseWriter, *http.Request, error, int)
pathHandlers map[*regexp.Regexp]http.HandlerFunc
contentTypeHandlers map[string]http.HandlerFunc
opts server.Options
registerRPC bool
sync.RWMutex
opts server.Options
hd server.Handler
exit chan chan error
subscribers map[*httpSubscriber][]broker.Subscriber
// used for first registration
registered bool
// register service instance
rsvc *register.Service
init bool
}
func (h *httpServer) newCodec(ct string) (codec.Codec, error) {
if cf, ok := h.opts.Codecs[ct]; ok {
if idx := strings.IndexRune(ct, ';'); idx >= 0 {
ct = ct[:idx]
}
h.RLock()
cf, ok := h.opts.Codecs[ct]
h.RUnlock()
if ok {
return cf, nil
}
return nil, codec.ErrUnknownContentType
@@ -49,33 +60,122 @@ func (h *httpServer) Options() server.Options {
}
func (h *httpServer) Init(opts ...server.Option) error {
if len(opts) == 0 && h.init {
return nil
}
h.Lock()
for _, o := range opts {
o(&h.opts)
}
if fn, ok := h.opts.Context.Value(errorHandlerKey{}).(func(ctx context.Context, s server.Handler, w http.ResponseWriter, r *http.Request, err error, status int)); ok && fn != nil {
h.errorHandler = fn
}
if h.handlers == nil {
h.handlers = make(map[string]server.Handler)
}
if h.pathHandlers == nil {
h.pathHandlers = make(map[*regexp.Regexp]http.HandlerFunc)
}
if h.contentTypeHandlers == nil {
h.contentTypeHandlers = make(map[string]http.HandlerFunc)
}
if v, ok := h.opts.Context.Value(registerRPCHandlerKey{}).(bool); ok {
h.registerRPC = v
}
if phs, ok := h.opts.Context.Value(pathHandlerKey{}).(*pathHandlerVal); ok && phs.h != nil {
for pp, ph := range phs.h {
exp, err := regexp.Compile(pp)
if err != nil {
h.Unlock()
return err
}
h.pathHandlers[exp] = ph
}
}
if phs, ok := h.opts.Context.Value(contentTypeHandlerKey{}).(*contentTypeHandlerVal); ok && phs.h != nil {
for pp, ph := range phs.h {
h.contentTypeHandlers[pp] = ph
}
}
h.Unlock()
h.RLock()
if err := h.opts.Register.Init(); err != nil {
h.RUnlock()
return err
}
if err := h.opts.Broker.Init(); err != nil {
h.RUnlock()
return err
}
if err := h.opts.Tracer.Init(); err != nil {
h.RUnlock()
return err
}
if err := h.opts.Auth.Init(); err != nil {
h.RUnlock()
return err
}
if err := h.opts.Logger.Init(); err != nil {
h.RUnlock()
return err
}
if err := h.opts.Meter.Init(); err != nil {
h.RUnlock()
return err
}
if err := h.opts.Transport.Init(); err != nil {
h.RUnlock()
return err
}
h.RUnlock()
h.Lock()
h.init = true
h.Unlock()
return nil
}
func (h *httpServer) Handle(handler server.Handler) error {
hdlr, ok := handler.(*httpHandler)
if !ok {
h.Lock()
h.hd = handler
h.Unlock()
return nil
}
if _, ok := hdlr.hd.(http.Handler); ok {
h.Lock()
h.hd = handler
h.Unlock()
return nil
}
h.Lock()
h.hd = handler
if h.handlers == nil {
h.handlers = make(map[string]server.Handler)
}
h.handlers[handler.Name()] = handler
h.Unlock()
return nil
}
func (h *httpServer) NewHandler(handler interface{}, opts ...server.HandlerOption) server.Handler {
options := server.NewHandlerOptions(opts...)
var eps []*register.Endpoint
if !options.Internal {
for name, metadata := range options.Metadata {
eps = append(eps, &register.Endpoint{
Name: name,
Metadata: metadata,
})
}
eps := make([]*register.Endpoint, 0, len(options.Metadata))
for name, metadata := range options.Metadata {
eps = append(eps, &register.Endpoint{
Name: name,
Metadata: metadata,
})
}
hdlr := &httpHandler{
@@ -146,6 +246,24 @@ func (h *httpServer) NewHandler(handler interface{}, opts ...server.HandlerOptio
pth := patHandler{pat: pat, mtype: mtype, name: name, rcvr: rcvr}
hdlr.name = name
hdlr.handlers[md["Method"]] = append(hdlr.handlers[md["Method"]], pth)
if !h.registerRPC {
continue
}
cmp, err = rutil.Parse("/" + hn)
if err != nil && h.opts.Logger.V(logger.ErrorLevel) {
h.opts.Logger.Errorf(h.opts.Context, "parsing path pattern err: %v", err)
continue
}
tpl = cmp.Compile()
pat, err = rutil.NewPattern(tpl.Version, tpl.OpCodes, tpl.Pool, tpl.Verb)
if err != nil && h.opts.Logger.V(logger.ErrorLevel) {
h.opts.Logger.Errorf(h.opts.Context, "creating new pattern err: %v", err)
continue
}
pth = patHandler{pat: pat, mtype: mtype, name: name, rcvr: rcvr}
hdlr.handlers[http.MethodPost] = append(hdlr.handlers[http.MethodPost], pth)
}
return hdlr
@@ -168,19 +286,24 @@ func (h *httpServer) Subscribe(sb server.Subscriber) error {
return err
}
h.Lock()
defer h.Unlock()
h.RLock()
_, ok = h.subscribers[sub]
h.RUnlock()
if ok {
return fmt.Errorf("subscriber %v already exists", h)
}
h.Lock()
h.subscribers[sub] = nil
h.Unlock()
return nil
}
func (h *httpServer) Register() error {
var eps []*register.Endpoint
h.RLock()
eps := h.hd.Endpoints()
for _, hdlr := range h.handlers {
eps = append(eps, hdlr.Endpoints()...)
}
rsvc := h.rsvc
config := h.opts
h.RUnlock()
@@ -201,12 +324,10 @@ func (h *httpServer) Register() error {
service.Endpoints = eps
h.Lock()
var subscriberList []*httpSubscriber
subscriberList := make([]*httpSubscriber, 0, len(h.subscribers))
for e := range h.subscribers {
// Only advertise non internal subscribers
if !e.Options().Internal {
subscriberList = append(subscriberList, e)
}
subscriberList = append(subscriberList, e)
}
sort.Slice(subscriberList, func(i, j int) bool {
return subscriberList[i].topic > subscriberList[j].topic
@@ -223,7 +344,7 @@ func (h *httpServer) Register() error {
if !registered {
if config.Logger.V(logger.InfoLevel) {
config.Logger.Infof(config.Context, "Register [%s] Registering node: %s", config.Register.String(), service.Nodes[0].Id)
config.Logger.Infof(config.Context, "Register [%s] Registering node: %s", config.Register.String(), service.Nodes[0].ID)
}
}
@@ -238,8 +359,6 @@ func (h *httpServer) Register() error {
}
h.Lock()
defer h.Unlock()
for sb := range h.subscribers {
handler := h.createSubHandler(sb, config)
var opts []broker.SubscribeOption
@@ -256,6 +375,7 @@ func (h *httpServer) Register() error {
sub, err := config.Broker.Subscribe(subCtx, sb.Topic(), handler, opts...)
if err != nil {
h.Unlock()
return err
}
h.subscribers[sb] = []broker.Subscriber{sub}
@@ -263,6 +383,7 @@ func (h *httpServer) Register() error {
h.registered = true
h.rsvc = service
h.Unlock()
return nil
}
@@ -278,7 +399,7 @@ func (h *httpServer) Deregister() error {
}
if config.Logger.V(logger.InfoLevel) {
config.Logger.Infof(config.Context, "Deregistering node: %s", service.Nodes[0].Id)
config.Logger.Infof(config.Context, "Deregistering node: %s", service.Nodes[0].ID)
}
if err := server.DefaultDeregisterFunc(service, config); err != nil {
@@ -304,6 +425,7 @@ func (h *httpServer) Deregister() error {
for _, sub := range subs {
config.Logger.Infof(config.Context, "Unsubscribing from topic: %s", sub.Topic())
if err := sub.Unsubscribe(subCtx); err != nil {
h.Unlock()
config.Logger.Errorf(config.Context, "failed to unsubscribe topic: %s, error: %v", sb.Topic(), err)
return err
}
@@ -317,7 +439,6 @@ func (h *httpServer) Deregister() error {
func (h *httpServer) Start() error {
h.RLock()
config := h.opts
hd := h.hd
h.RUnlock()
// micro: config.Transport.Listen(config.Address)
@@ -352,13 +473,33 @@ func (h *httpServer) Start() error {
h.opts.Address = ts.Addr().String()
h.Unlock()
handler, ok := hd.Handler().(http.Handler)
if !ok {
handler, ok = hd.(http.Handler)
var handler http.Handler
var srvFunc func(net.Listener) error
// nolint: nestif
if h.opts.Context != nil {
if hs, ok := h.opts.Context.Value(serverKey{}).(*http.Server); ok && hs != nil {
if hs.Handler == nil && h.hd != nil {
if hdlr, ok := h.hd.Handler().(http.Handler); ok {
hs.Handler = hdlr
handler = hs.Handler
}
} else {
handler = hs.Handler
}
}
}
if !ok {
return errors.New("Server required http.Handler")
if handler == nil && h.hd == nil {
handler = h
} else if handler == nil && h.hd != nil {
if hdlr, ok := h.hd.Handler().(http.Handler); ok {
handler = hdlr
}
}
if handler == nil {
return fmt.Errorf("cant process with nil handler")
}
if err := config.Broker.Connect(h.opts.Context); err != nil {
@@ -367,7 +508,7 @@ func (h *httpServer) Start() error {
if err := config.RegisterCheck(h.opts.Context); err != nil {
if config.Logger.V(logger.ErrorLevel) {
config.Logger.Errorf(config.Context, "Server %s-%s register check error: %s", config.Name, config.Id, err)
config.Logger.Errorf(config.Context, "Server %s-%s register check error: %s", config.Name, config.ID, err)
}
} else {
if err = h.Register(); err != nil {
@@ -376,7 +517,6 @@ func (h *httpServer) Start() error {
}
fn := handler
var srvFunc func(net.Listener) error
if h.opts.Context != nil {
if mwf, ok := h.opts.Context.Value(middlewareKey{}).([]func(http.Handler) http.Handler); ok && len(mwf) > 0 {
@@ -392,9 +532,17 @@ func (h *httpServer) Start() error {
}
if srvFunc != nil {
go srvFunc(ts)
go func() {
if cerr := srvFunc(ts); cerr != nil {
h.opts.Logger.Error(h.opts.Context, cerr)
}
}()
} else {
go http.Serve(ts, fn)
go func() {
if cerr := http.Serve(ts, fn); cerr != nil && !strings.Contains(cerr.Error(), "use of closed network connection") {
h.opts.Logger.Error(h.opts.Context, cerr)
}
}()
}
go func() {
@@ -418,25 +566,26 @@ func (h *httpServer) Start() error {
registered := h.registered
h.RUnlock()
rerr := config.RegisterCheck(h.opts.Context)
// nolint: nestif
if rerr != nil && registered {
if config.Logger.V(logger.ErrorLevel) {
config.Logger.Errorf(config.Context, "Server %s-%s register check error: %s, deregister it", config.Name, config.Id, rerr)
config.Logger.Errorf(config.Context, "Server %s-%s register check error: %s, deregister it", config.Name, config.ID, rerr)
}
// deregister self in case of error
if err := h.Deregister(); err != nil {
if config.Logger.V(logger.ErrorLevel) {
config.Logger.Errorf(config.Context, "Server %s-%s deregister error: %s", config.Name, config.Id, err)
config.Logger.Errorf(config.Context, "Server %s-%s deregister error: %s", config.Name, config.ID, err)
}
}
} else if rerr != nil && !registered {
if config.Logger.V(logger.ErrorLevel) {
config.Logger.Errorf(config.Context, "Server %s-%s register check error: %s", config.Name, config.Id, rerr)
config.Logger.Errorf(config.Context, "Server %s-%s register check error: %s", config.Name, config.ID, rerr)
}
continue
}
if err := h.Register(); err != nil {
if config.Logger.V(logger.ErrorLevel) {
config.Logger.Errorf(config.Context, "Server %s-%s register error: %s", config.Name, config.Id, err)
config.Logger.Errorf(config.Context, "Server %s-%s register error: %s", config.Name, config.ID, err)
}
}
@@ -449,8 +598,6 @@ func (h *httpServer) Start() error {
}
}
ch <- ts.Close()
// deregister
if err := h.Deregister(); err != nil {
config.Logger.Errorf(config.Context, "Server deregister error: %s", err)
@@ -459,6 +606,8 @@ func (h *httpServer) Start() error {
if err := config.Broker.Disconnect(config.Context); err != nil {
config.Logger.Errorf(config.Context, "Broker disconnect error: %s", err)
}
ch <- ts.Close()
}()
return nil
@@ -481,8 +630,10 @@ func (h *httpServer) Name() string {
func NewServer(opts ...server.Option) server.Server {
options := server.NewOptions(opts...)
return &httpServer{
opts: options,
exit: make(chan chan error),
subscribers: make(map[*httpSubscriber][]broker.Subscriber),
opts: options,
exit: make(chan chan error),
subscribers: make(map[*httpSubscriber][]broker.Subscriber),
errorHandler: DefaultErrorHandler,
pathHandlers: make(map[*regexp.Regexp]http.HandlerFunc),
}
}

View File

@@ -6,12 +6,12 @@ import (
)
type httpMessage struct {
topic string
payload interface{}
contentType string
header metadata.Metadata
body []byte
codec codec.Codec
header metadata.Metadata
topic string
contentType string
body []byte
}
func (r *httpMessage) Topic() string {

View File

@@ -8,23 +8,28 @@ import (
"github.com/unistack-org/micro/v3/server"
)
type rspCodeKey struct{}
type rspCodeVal struct {
code int
}
// SetError pass error to caller
func SetError(err interface{}) error {
return &Error{err: err}
}
// Error struct holds error
type Error struct {
err interface{}
}
// Error func for error interface
func (err *Error) Error() string {
return fmt.Sprintf("%v", err.err)
}
type (
rspCodeKey struct{}
rspCodeVal struct {
code int
}
)
// SetRspCode saves response code in context, must be used by handler to specify http code
func SetRspCode(ctx context.Context, code int) {
if rsp, ok := ctx.Value(rspCodeKey{}).(*rspCodeVal); ok {
@@ -43,12 +48,72 @@ func GetRspCode(ctx context.Context) int {
type middlewareKey struct{}
// Middleware passes http middlewares
func Middleware(mw ...func(http.Handler) http.Handler) server.Option {
return server.SetOption(middlewareKey{}, mw)
}
type serverKey struct{}
// Server provide ability to pass *http.Server
func Server(hs *http.Server) server.Option {
return server.SetOption(serverKey{}, hs)
}
type errorHandlerKey struct{}
// ErrorHandler specifies handler for errors
func ErrorHandler(fn func(ctx context.Context, s server.Handler, w http.ResponseWriter, r *http.Request, err error, status int)) server.Option {
return server.SetOption(errorHandlerKey{}, fn)
}
type (
pathHandlerKey struct{}
pathHandlerVal struct {
h map[string]http.HandlerFunc
}
)
// PathHandler specifies http handler for path regexp
func PathHandler(path string, h http.HandlerFunc) server.Option {
return func(o *server.Options) {
if o.Context == nil {
o.Context = context.Background()
}
v, ok := o.Context.Value(pathHandlerKey{}).(*pathHandlerVal)
if !ok {
v = &pathHandlerVal{h: make(map[string]http.HandlerFunc)}
}
v.h[path] = h
o.Context = context.WithValue(o.Context, pathHandlerKey{}, v)
}
}
type (
contentTypeHandlerKey struct{}
contentTypeHandlerVal struct {
h map[string]http.HandlerFunc
}
)
// ContentTypeHandler specifies http handler for Content-Type
func ContentTypeHandler(ct string, h http.HandlerFunc) server.Option {
return func(o *server.Options) {
if o.Context == nil {
o.Context = context.Background()
}
v, ok := o.Context.Value(contentTypeHandlerKey{}).(*contentTypeHandlerVal)
if !ok {
v = &contentTypeHandlerVal{h: make(map[string]http.HandlerFunc)}
}
v.h[ct] = h
o.Context = context.WithValue(o.Context, contentTypeHandlerKey{}, v)
}
}
type registerRPCHandlerKey struct{}
// RegisterRPCHandler registers compatibility endpoints with /ServiceName.ServiceEndpoint method POST
func RegisterRPCHandler(b bool) server.Option {
return server.SetOption(registerRPCHandlerKey{}, b)
}

View File

@@ -5,29 +5,34 @@ import (
"github.com/unistack-org/micro/v3/codec"
"github.com/unistack-org/micro/v3/metadata"
"github.com/unistack-org/micro/v3/server"
)
var (
_ server.Request = &rpcRequest{}
_ server.Message = &rpcMessage{}
)
type rpcRequest struct {
rw io.ReadWriter
service string
method string
endpoint string
target string
contentType string
payload interface{}
codec codec.Codec
header metadata.Metadata
method string
endpoint string
contentType string
service string
body []byte
stream bool
payload interface{}
}
type rpcMessage struct {
payload interface{}
codec codec.Codec
header metadata.Metadata
topic string
contentType string
payload interface{}
header metadata.Metadata
body []byte
codec codec.Codec
}
func (r *rpcRequest) ContentType() string {
@@ -43,7 +48,7 @@ func (r *rpcRequest) Method() string {
}
func (r *rpcRequest) Endpoint() string {
return r.method
return r.endpoint
}
func (r *rpcRequest) Codec() codec.Codec {

View File

@@ -11,10 +11,10 @@ import (
)
type methodType struct {
method reflect.Method
ArgType reflect.Type
ReplyType reflect.Type
ContextType reflect.Type
method reflect.Method
stream bool
}
@@ -62,15 +62,14 @@ func prepareEndpoint(method reflect.Method) (*methodType, error) {
return nil, fmt.Errorf("method %v of %v has wrong number of ins: %v", mname, mtype, mtype.NumIn())
}
if stream {
switch stream {
case true:
// check stream type
streamType := reflect.TypeOf((*server.Stream)(nil)).Elem()
if !argType.Implements(streamType) {
return nil, fmt.Errorf("%v argument does not implement Streamer interface: %v", mname, argType)
}
} else {
// if not stream check the replyType
default:
// First arg need not be a pointer.
if !isExportedOrBuiltinType(argType) {
return nil, fmt.Errorf("%v argument type not exported: %v", mname, argType)

View File

@@ -14,16 +14,12 @@ import (
"github.com/unistack-org/micro/v3/server"
)
const (
subSig = "func(context.Context, interface{}) error"
)
var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
type handler struct {
method reflect.Value
reqType reflect.Type
ctxType reflect.Type
method reflect.Value
}
type httpSubscriber struct {
@@ -116,7 +112,7 @@ func (s *httpServer) createSubHandler(sb *httpSubscriber, opts server.Options) b
hdr := metadata.Copy(msg.Header)
delete(hdr, "Content-Type")
ctx := metadata.NewContext(context.Background(), hdr)
ctx := metadata.NewIncomingContext(context.Background(), hdr)
results := make(chan error, len(sb.handlers))