Compare commits
96 Commits
Author | SHA1 | Date | |
---|---|---|---|
fd8c454bae | |||
1cc8b37503 | |||
cd47eab010 | |||
9136addd1e | |||
4ce1ef631b | |||
4618fae641 | |||
b2eba3120e | |||
|
04703cb8fa | ||
6da3bbabed | |||
81016aa16f | |||
|
042998ff76 | ||
97d5936efd | |||
|
d6777af891 | ||
c2f178001c | |||
ffe5f1c9be | |||
416d494e50 | |||
7dd1dfbff6 | |||
|
e11dc06067 | ||
2cc17551ca | |||
d8493a3628 | |||
e9a396d424 | |||
fed13e1293 | |||
|
62fdcf6a1f | ||
2f0e291247 | |||
|
39f7605f91 | ||
e2efc934b3 | |||
2d5fb587a0 | |||
6a30a4f408 | |||
f80e6c1a66 | |||
2aa8768aed | |||
0ab763b505 | |||
68b6f6904b | |||
31e996fc2e | |||
14f3b149e4 | |||
6714e48f4f | |||
547199f0b8 | |||
|
be637e8324 | ||
67e9e7e880 | |||
|
8a6a259404 | ||
2b3e1acd22 | |||
|
2816fd756a | ||
5353c56034 | |||
|
b93dcbb165 | ||
d76f9f20b6 | |||
|
4cb133546d | ||
c0ca60b7c9 | |||
|
7a096d6605 | ||
1c5c86668b | |||
|
e7b5a90b5c | ||
677f00c3c0 | |||
7365c5f1cd | |||
505c59ba75 | |||
7a39d86018 | |||
06a0a2f336 | |||
|
776ce8591a | ||
48aaef3842 | |||
36aa9f6a28 | |||
|
4e54cd6f7d | ||
7886f3160d | |||
0e86aff88c | |||
|
5d23148038 | ||
8c61439bc5 | |||
7ad1a9c38e | |||
5c829fe029 | |||
3e1ffcb989 | |||
c1e0ce26b5 | |||
26e34124e0 | |||
c1526f70ce | |||
28d23f388f | |||
d3d67eca97 | |||
919bf1486f | |||
88ef21ba9e | |||
|
254b01f75a | ||
|
325b8a43ef | ||
|
d94860c32d | ||
|
778095179d | ||
f71ae35f12 | |||
|
4d27c79081 | ||
|
1eebef8dbc | ||
|
cd2c0b65e1 | ||
|
97e0bf75bb | ||
|
9f56d8b6b5 | ||
|
21f608d728 | ||
ba283695dd | |||
b18465083b | |||
|
11020aa6e5 | ||
|
43c0eb4fda | ||
5ab606c2b5 | |||
6c661c9d72 | |||
a215521821 | |||
|
ec5af022b3 | ||
|
bd88f6e485 | ||
|
34a39be017 | ||
|
360703d8bb | ||
2660a0d94d | |||
|
6e9a693b51 |
19
.github/dependabot.yml
vendored
Normal file
19
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
|
||||
# Maintain dependencies for GitHub Actions
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
# Maintain dependencies for Golang
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "daily"
|
20
.github/renovate.json
vendored
20
.github/renovate.json
vendored
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
],
|
||||
"postUpdateOptions": ["gomodTidy"],
|
||||
"packageRules": [
|
||||
{
|
||||
"matchUpdateTypes": ["minor", "patch", "pin", "digest"],
|
||||
"automerge": true
|
||||
},
|
||||
{
|
||||
"groupName": "all deps",
|
||||
"separateMajorMinor": true,
|
||||
"groupSlug": "all",
|
||||
"packagePatterns": [
|
||||
"*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
13
.github/stale.sh
vendored
13
.github/stale.sh
vendored
@@ -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
|
20
.github/workflows/autoapprove.yml
vendored
Normal file
20
.github/workflows/autoapprove.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: "autoapprove"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [assigned, opened, synchronize, reopened]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
autoapprove:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: approve
|
||||
uses: hmarr/auto-approve-action@v2
|
||||
if: github.actor == 'vtolstov' || github.actor == 'dependabot[bot]'
|
||||
id: approve
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
21
.github/workflows/automerge.yml
vendored
Normal file
21
.github/workflows/automerge.yml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
name: "automerge"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [assigned, opened, synchronize, reopened]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
automerge:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.actor == 'vtolstov'
|
||||
steps:
|
||||
- name: merge
|
||||
id: merge
|
||||
run: gh pr merge --auto --merge "$PR_URL"
|
||||
env:
|
||||
PR_URL: ${{github.event.pull_request.html_url}}
|
||||
GITHUB_TOKEN: ${{secrets.TOKEN}}
|
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
@@ -3,6 +3,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- v3
|
||||
jobs:
|
||||
test:
|
||||
name: test
|
||||
@@ -11,9 +12,9 @@ jobs:
|
||||
- name: setup
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16
|
||||
go-version: 1.17
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
@@ -31,9 +32,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
uses: golangci/golangci-lint-action@v3.1.0
|
||||
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.
|
||||
|
78
.github/workflows/codeql-analysis.yml
vendored
Normal file
78
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
# For most projects, this workflow file will not need changing; you simply need
|
||||
# to commit it to your repository.
|
||||
#
|
||||
# You may wish to alter this file to override the set of languages analyzed,
|
||||
# or to provide custom queries or build logic.
|
||||
#
|
||||
# ******** NOTE ********
|
||||
# We have attempted to detect the languages in your repository. Please check
|
||||
# the `language` matrix defined below to confirm you have the correct set of
|
||||
# supported CodeQL languages.
|
||||
#
|
||||
name: "codeql"
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["prbuild"]
|
||||
types:
|
||||
- completed
|
||||
push:
|
||||
branches: [ master, v3 ]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [ master, v3 ]
|
||||
schedule:
|
||||
- cron: '34 1 * * 0'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: analyze
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [ 'go' ]
|
||||
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
|
||||
# Learn more:
|
||||
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
|
||||
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: setup
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.17
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: init
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
# By default, queries listed here will override any specified in a config file.
|
||||
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: analyze
|
||||
uses: github/codeql-action/analyze@v1
|
27
.github/workflows/dependabot-automerge.yml
vendored
Normal file
27
.github/workflows/dependabot-automerge.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: "dependabot-automerge"
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [assigned, opened, synchronize, reopened]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
automerge:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.actor == 'dependabot[bot]'
|
||||
steps:
|
||||
- name: metadata
|
||||
id: metadata
|
||||
uses: dependabot/fetch-metadata@v1.3.0
|
||||
with:
|
||||
github-token: "${{ secrets.TOKEN }}"
|
||||
- name: merge
|
||||
id: merge
|
||||
if: ${{contains(steps.metadata.outputs.dependency-names, 'go.unistack.org')}}
|
||||
run: gh pr merge --auto --merge "$PR_URL"
|
||||
env:
|
||||
PR_URL: ${{github.event.pull_request.html_url}}
|
||||
GITHUB_TOKEN: ${{secrets.TOKEN}}
|
9
.github/workflows/pr.yml
vendored
9
.github/workflows/pr.yml
vendored
@@ -3,6 +3,7 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- v3
|
||||
jobs:
|
||||
test:
|
||||
name: test
|
||||
@@ -11,9 +12,9 @@ jobs:
|
||||
- name: setup
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16
|
||||
go-version: 1.17
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
@@ -31,9 +32,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
- name: lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
uses: golangci/golangci-lint-action@v3.1.0
|
||||
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.
|
||||
|
44
.golangci.yml
Normal file
44
.golangci.yml
Normal 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
8
go.mod
@@ -1,10 +1,8 @@
|
||||
module github.com/unistack-org/micro-server-http/v3
|
||||
module go.unistack.org/micro-server-http/v3
|
||||
|
||||
go 1.16
|
||||
|
||||
require (
|
||||
github.com/unistack-org/micro/v3 v3.3.14
|
||||
golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d
|
||||
go.unistack.org/micro/v3 v3.9.0
|
||||
golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba
|
||||
)
|
||||
|
||||
//replace github.com/unistack-org/micro/v3 => ../../micro
|
||||
|
161
go.sum
161
go.sum
@@ -1,19 +1,164 @@
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||
github.com/ef-ds/deque v1.0.4/go.mod h1:gXDnTC3yqvBcHbq2lcExjtAcVrOnJCbMcZXmuj8Z4tg=
|
||||
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/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
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.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/gnostic v0.6.6 h1:MVSM2r2j9aRUvYNym66JGW96Ddd5MN4sTi59yktb6yk=
|
||||
github.com/google/gnostic v0.6.6/go.mod h1:Nm8234We1lq6iB9OmlgNv3nH91XLLVZHCDayfA3xq+E=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
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.3.14 h1:CAkDMjHZT8/D6GGF5h3gK84m6tlWZC17IGPb2GkAn/4=
|
||||
github.com/unistack-org/micro/v3 v3.3.14/go.mod h1:ETGcQQUcjxGaD44LUMX+0fgo8Loh7ExldfIPLvfUmDo=
|
||||
golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d h1:BgJvlyh+UqCUaPlscHJ+PN8GcpfrFdr7NHjd1JL0+Gs=
|
||||
golang.org/x/net v0.0.0-20210415231046-e915ea6b2b7d/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/silas/dag v0.0.0-20211117232152-9d50aa809f35/go.mod h1:7RTUFBdIRC9nZ7/3RyRNH1bdqIShrDejd1YbLwgPS+I=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.unistack.org/micro-proto/v3 v3.2.7 h1:zG6d69kHc+oij2lwQ3AfrCgdjiEVRG2A7TlsxjusWs4=
|
||||
go.unistack.org/micro-proto/v3 v3.2.7/go.mod h1:ZltVWNECD5yK+40+OCONzGw4OtmSdTpVi8/KFgo9dqM=
|
||||
go.unistack.org/micro/v3 v3.9.0 h1:n5w7Y0QlFA0Rhh5XON1f1MfdmY+4BMQopYmX6Uy7tdU=
|
||||
go.unistack.org/micro/v3 v3.9.0/go.mod h1:7ssIWk+PJXvb2nSl8NUnQRs32JJEId2IDi9PobrQlKo=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba h1:6u6sik+bn/y7vILcYkK3iwTBWN7WtBvB0+SZswQnbf8=
|
||||
golang.org/x/net v0.0.0-20220121210141-e204ce36a2ba/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
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=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
|
297
handler.go
297
handler.go
@@ -9,55 +9,41 @@ import (
|
||||
"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"
|
||||
"github.com/unistack-org/micro/v3/register"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
rflutil "github.com/unistack-org/micro/v3/util/reflect"
|
||||
rutil "github.com/unistack-org/micro/v3/util/router"
|
||||
"go.unistack.org/micro/v3/errors"
|
||||
"go.unistack.org/micro/v3/logger"
|
||||
"go.unistack.org/micro/v3/metadata"
|
||||
"go.unistack.org/micro/v3/register"
|
||||
"go.unistack.org/micro/v3/server"
|
||||
rhttp "go.unistack.org/micro/v3/util/http"
|
||||
rflutil "go.unistack.org/micro/v3/util/reflect"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
type httpHandler struct {
|
||||
name string
|
||||
opts server.HandlerOptions
|
||||
sopts server.Options
|
||||
eps []*register.Endpoint
|
||||
hd interface{}
|
||||
handlers map[string][]patHandler
|
||||
handlers *rhttp.Trie
|
||||
name string
|
||||
eps []*register.Endpoint
|
||||
sopts server.Options
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
func (h *httpHandler) newCodec(ct string) (codec.Codec, error) {
|
||||
h.RLock()
|
||||
defer h.RUnlock()
|
||||
|
||||
if idx := strings.IndexRune(ct, ';'); idx >= 0 {
|
||||
ct = ct[:idx]
|
||||
}
|
||||
|
||||
if cf, ok := h.sopts.Codecs[ct]; ok {
|
||||
return cf, nil
|
||||
}
|
||||
return nil, codec.ErrUnknownContentType
|
||||
}
|
||||
|
||||
func (h *httpHandler) Name() string {
|
||||
return h.name
|
||||
}
|
||||
@@ -75,102 +61,112 @@ func (h *httpHandler) Options() server.HandlerOptions {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
// check for http.HandlerFunc handlers
|
||||
if ph, _, ok := h.pathHandlers.Search(r.Method, r.URL.Path); ok {
|
||||
ph.(http.HandlerFunc)(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
ct := DefaultContentType
|
||||
if htype := r.Header.Get("Content-Type"); htype != "" {
|
||||
if htype := r.Header.Get(metadata.HeaderContentType); htype != "" {
|
||||
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) + 8)
|
||||
}
|
||||
|
||||
ctx := metadata.NewContext(r.Context(), nil)
|
||||
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)
|
||||
h.errorHandler(ctx, nil, w, r, fmt.Errorf("path must starts with /"), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
matches := make(map[string]interface{})
|
||||
|
||||
var match bool
|
||||
var hldr *patHandler
|
||||
var handler *httpHandler
|
||||
|
||||
for _, shdlr := range h.handlers {
|
||||
hdlr := shdlr.(*httpHandler)
|
||||
fh, mp, ok := hdlr.handlers.Search(r.Method, path)
|
||||
if ok {
|
||||
match = true
|
||||
for k, v := range mp {
|
||||
matches[k] = v
|
||||
}
|
||||
hldr = fh.(*patHandler)
|
||||
handler = hdlr
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !match && h.registerRPC {
|
||||
microMethod, mok := md.Get(metadata.HeaderEndpoint)
|
||||
if mok {
|
||||
serviceMethod := strings.Split(microMethod, ".")
|
||||
if len(serviceMethod) == 2 {
|
||||
if shdlr, ok := h.handlers[serviceMethod[0]]; ok {
|
||||
hdlr := shdlr.(*httpHandler)
|
||||
fh, mp, ok := hdlr.handlers.Search(http.MethodPost, "/"+microMethod)
|
||||
if ok {
|
||||
match = true
|
||||
for k, v := range mp {
|
||||
matches[k] = v
|
||||
}
|
||||
hldr = fh.(*patHandler)
|
||||
handler = hdlr
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !match && h.hd != nil {
|
||||
if hdlr, ok := h.hd.Handler().(http.Handler); ok {
|
||||
hdlr.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
} else if !match {
|
||||
h.errorHandler(ctx, nil, w, r, fmt.Errorf("not matching route found"), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
// get fields from url values
|
||||
if len(r.URL.RawQuery) > 0 {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
cf, err := h.newCodec(ct)
|
||||
if err != nil {
|
||||
h.errorHandler(ctx, nil, w, r, err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
components := strings.Split(path[1:], "/")
|
||||
l := len(components)
|
||||
var verb string
|
||||
idx := strings.LastIndex(components[l-1], ":")
|
||||
if idx == 0 {
|
||||
h.errorHandler(ctx, nil, w, r, fmt.Errorf("not found"), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if idx > 0 {
|
||||
c := components[l-1]
|
||||
components[l-1], verb = c[:idx], c[idx+1:]
|
||||
}
|
||||
|
||||
matches := make(map[string]interface{})
|
||||
|
||||
var match bool
|
||||
var hldr patHandler
|
||||
var handler *httpHandler
|
||||
for _, hpat := range h.handlers {
|
||||
handlertmp := hpat.(*httpHandler)
|
||||
for _, hldrtmp := range handlertmp.handlers[r.Method] {
|
||||
mp, err := hldrtmp.pat.Match(components, verb)
|
||||
if err == nil {
|
||||
match = true
|
||||
for k, v := range mp {
|
||||
matches[k] = v
|
||||
}
|
||||
hldr = hldrtmp
|
||||
handler = handlertmp
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !match {
|
||||
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, handler, w, r, err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
for k, v := range umd {
|
||||
matches[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
var argv, replyv reflect.Value
|
||||
|
||||
// Decode the argument value.
|
||||
@@ -190,51 +186,53 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
replyv = reflect.New(hldr.mtype.ReplyType.Elem())
|
||||
|
||||
function := hldr.mtype.method.Func
|
||||
//function := hldr.rcvr
|
||||
var returnValues []reflect.Value
|
||||
|
||||
if err = cf.ReadBody(r.Body, argv.Interface()); err != nil && err != io.EOF {
|
||||
buf, err := io.ReadAll(r.Body)
|
||||
if err != nil && err != io.EOF {
|
||||
h.errorHandler(ctx, handler, w, r, err, http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err = cf.Unmarshal(buf, argv.Interface()); err != nil {
|
||||
h.errorHandler(ctx, handler, w, r, err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
matches = rflutil.FlattenMap(matches)
|
||||
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, handler, w, r, err, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
hr := &rpcRequest{
|
||||
codec: cf,
|
||||
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
|
||||
}
|
||||
@@ -253,36 +251,47 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
ct = DefaultContentType
|
||||
}
|
||||
|
||||
if appErr := fn(ctx, hr, replyv.Interface()); appErr != nil {
|
||||
switch verr := appErr.(type) {
|
||||
case *errors.Error:
|
||||
scode = int(verr.Code)
|
||||
b, err = cf.Marshal(verr)
|
||||
case *Error:
|
||||
b, err = cf.Marshal(verr.err)
|
||||
default:
|
||||
b, err = cf.Marshal(appErr)
|
||||
}
|
||||
} else {
|
||||
b, err = cf.Marshal(replyv.Interface())
|
||||
}
|
||||
if err != nil && handler.sopts.Logger.V(logger.ErrorLevel) {
|
||||
handler.sopts.Logger.Errorf(handler.sopts.Context, "handler err: %v", err)
|
||||
return
|
||||
}
|
||||
scode := int(200)
|
||||
appErr := fn(ctx, hr, replyv.Interface())
|
||||
|
||||
w.Header().Set(metadata.HeaderContentType, ct)
|
||||
if md, ok := metadata.FromOutgoingContext(ctx); ok {
|
||||
for k, v := range md {
|
||||
w.Header().Set(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("content-Type", ct)
|
||||
if scode != 0 {
|
||||
w.WriteHeader(scode)
|
||||
} else {
|
||||
//handler.sopts.Logger.Warn(handler.sopts.Context, "response code not set in handler via SetRspCode(ctx, http.StatusXXX)")
|
||||
w.WriteHeader(200)
|
||||
if nct := w.Header().Get(metadata.HeaderContentType); 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)
|
||||
buf, err = cf.Marshal(verr)
|
||||
case *Error:
|
||||
buf, err = cf.Marshal(verr.err)
|
||||
default:
|
||||
buf, err = cf.Marshal(appErr)
|
||||
}
|
||||
} else {
|
||||
buf, err = cf.Marshal(replyv.Interface())
|
||||
}
|
||||
|
||||
if err != nil && handler.sopts.Logger.V(logger.ErrorLevel) {
|
||||
handler.sopts.Logger.Errorf(handler.sopts.Context, "handler err: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if nscode := GetRspCode(ctx); nscode != 0 {
|
||||
scode = nscode
|
||||
}
|
||||
w.WriteHeader(scode)
|
||||
|
||||
if _, cerr := w.Write(buf); cerr != nil {
|
||||
handler.sopts.Logger.Errorf(ctx, "write failed: %v", cerr)
|
||||
}
|
||||
w.Write(b)
|
||||
}
|
||||
|
261
http.go
261
http.go
@@ -1,54 +1,53 @@
|
||||
// Package http implements a go-micro.Server
|
||||
package http
|
||||
package http // import "go.unistack.org/micro-server-http/v3"
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/unistack-org/micro/v3/broker"
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/logger"
|
||||
"github.com/unistack-org/micro/v3/register"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
rutil "github.com/unistack-org/micro/v3/util/router"
|
||||
"go.unistack.org/micro/v3/broker"
|
||||
"go.unistack.org/micro/v3/codec"
|
||||
"go.unistack.org/micro/v3/logger"
|
||||
"go.unistack.org/micro/v3/register"
|
||||
"go.unistack.org/micro/v3/server"
|
||||
rhttp "go.unistack.org/micro/v3/util/http"
|
||||
"golang.org/x/net/netutil"
|
||||
)
|
||||
|
||||
var _ server.Server = &httpServer{}
|
||||
|
||||
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 *rhttp.Trie
|
||||
opts server.Options
|
||||
registerRPC bool
|
||||
sync.RWMutex
|
||||
opts server.Options
|
||||
handlers map[string]server.Handler
|
||||
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
|
||||
errorHandler func(context.Context, server.Handler, http.ResponseWriter, *http.Request, error, int)
|
||||
pathHandlers map[*regexp.Regexp]http.HandlerFunc
|
||||
contentTypeHandlers map[string]http.HandlerFunc
|
||||
init bool
|
||||
}
|
||||
|
||||
func (h *httpServer) newCodec(ct string) (codec.Codec, error) {
|
||||
h.RLock()
|
||||
defer h.RUnlock()
|
||||
|
||||
if idx := strings.IndexRune(ct, ';'); idx >= 0 {
|
||||
ct = ct[:idx]
|
||||
}
|
||||
|
||||
if cf, ok := h.opts.Codecs[ct]; ok {
|
||||
h.RLock()
|
||||
cf, ok := h.opts.Codecs[ct]
|
||||
h.RUnlock()
|
||||
if ok {
|
||||
return cf, nil
|
||||
}
|
||||
return nil, codec.ErrUnknownContentType
|
||||
@@ -67,7 +66,6 @@ func (h *httpServer) Init(opts ...server.Option) error {
|
||||
}
|
||||
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
|
||||
for _, o := range opts {
|
||||
o(&h.opts)
|
||||
@@ -79,123 +77,125 @@ func (h *httpServer) Init(opts ...server.Option) error {
|
||||
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 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 {
|
||||
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.pathHandlers = rhttp.NewTrie()
|
||||
}
|
||||
|
||||
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 pm, ps := range phs.h {
|
||||
for pp, ph := range ps {
|
||||
if err := h.pathHandlers.Insert([]string{pm}, pp, ph); err != nil {
|
||||
h.Unlock()
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
h.Lock()
|
||||
if hdlr, ok := handler.(*httpHandler); ok {
|
||||
if _, ok := hdlr.hd.(http.Handler); ok {
|
||||
h.hd = handler
|
||||
} else {
|
||||
if h.handlers == nil {
|
||||
h.handlers = make(map[string]server.Handler)
|
||||
}
|
||||
h.handlers[handler.Name()] = handler
|
||||
}
|
||||
} else {
|
||||
// passed unknown handler
|
||||
hdlr, ok := handler.(*httpHandler)
|
||||
if !ok {
|
||||
h.Lock()
|
||||
h.hd = handler
|
||||
h.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// passed http.Handler like some muxer
|
||||
if _, ok := hdlr.hd.(http.Handler); ok {
|
||||
h.Lock()
|
||||
h.hd = handler
|
||||
h.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// passed micro compat handler
|
||||
h.Lock()
|
||||
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, ®ister.Endpoint{
|
||||
Name: name,
|
||||
Metadata: metadata,
|
||||
})
|
||||
}
|
||||
eps := make([]*register.Endpoint, 0, len(options.Metadata))
|
||||
for name, metadata := range options.Metadata {
|
||||
eps = append(eps, ®ister.Endpoint{
|
||||
Name: name,
|
||||
Metadata: metadata,
|
||||
})
|
||||
}
|
||||
|
||||
hdlr := &httpHandler{
|
||||
eps: eps,
|
||||
hd: handler,
|
||||
opts: options,
|
||||
sopts: h.opts,
|
||||
eps: eps,
|
||||
hd: handler,
|
||||
opts: options,
|
||||
sopts: h.opts,
|
||||
handlers: rhttp.NewTrie(),
|
||||
}
|
||||
|
||||
tp := reflect.TypeOf(handler)
|
||||
|
||||
/*
|
||||
for m := 0; m < tp.NumMethod(); m++ {
|
||||
if e := register.ExtractEndpoint(tp.Method(m)); e != nil {
|
||||
e.Name = name + "." + e.Name
|
||||
|
||||
for k, v := range options.Metadata[e.Name] {
|
||||
e.Metadata[k] = v
|
||||
}
|
||||
|
||||
eps = append(eps, e)
|
||||
}
|
||||
}
|
||||
|
||||
if len(options.Metadata) == 0 {
|
||||
if h.registerRPC {
|
||||
h.opts.Logger.Infof(h.opts.Context, "register rpc handler for http.MethodPost %s /%s", hn, hn)
|
||||
if err := hdlr.handlers.Insert([]string{http.MethodPost}, "/"+hn, pth); err != nil {
|
||||
h.opts.Logger.Errorf(h.opts.Context, "cant add rpc handler for http.MethodPost %s /%s", hn, hn)
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
hdlr.handlers = make(map[string][]patHandler)
|
||||
for hn, md := range options.Metadata {
|
||||
cmp, err := rutil.Parse(md["Path"])
|
||||
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
|
||||
}
|
||||
|
||||
var method reflect.Method
|
||||
mname := hn[strings.Index(hn, ".")+1:]
|
||||
for m := 0; m < tp.NumMethod(); m++ {
|
||||
@@ -217,15 +217,26 @@ func (h *httpServer) NewHandler(handler interface{}, opts ...server.HandlerOptio
|
||||
h.opts.Logger.Errorf(h.opts.Context, "%v", err)
|
||||
continue
|
||||
} else if mtype == nil {
|
||||
h.opts.Logger.Errorf(h.opts.Context, "nil mtype for %s", mname)
|
||||
continue
|
||||
}
|
||||
|
||||
rcvr := reflect.ValueOf(handler)
|
||||
name := reflect.Indirect(rcvr).Type().Name()
|
||||
|
||||
pth := patHandler{pat: pat, mtype: mtype, name: name, rcvr: rcvr}
|
||||
pth := &patHandler{mtype: mtype, name: name, rcvr: rcvr}
|
||||
hdlr.name = name
|
||||
hdlr.handlers[md["Method"]] = append(hdlr.handlers[md["Method"]], pth)
|
||||
|
||||
if err := hdlr.handlers.Insert([]string{md["Method"]}, md["Path"], pth); err != nil {
|
||||
h.opts.Logger.Errorf(h.opts.Context, "cant add handler for %s %s", md["Method"], md["Path"])
|
||||
}
|
||||
|
||||
if h.registerRPC {
|
||||
h.opts.Logger.Infof(h.opts.Context, "register rpc handler for http.MethodPost %s /%s", hn, hn)
|
||||
if err := hdlr.handlers.Insert([]string{http.MethodPost}, "/"+hn, pth); err != nil {
|
||||
h.opts.Logger.Errorf(h.opts.Context, "cant add rpc handler for http.MethodPost %s /%s", hn, hn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hdlr
|
||||
@@ -248,13 +259,15 @@ 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
|
||||
}
|
||||
|
||||
@@ -284,12 +297,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
|
||||
@@ -306,7 +317,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,8 +332,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
|
||||
@@ -339,6 +348,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}
|
||||
@@ -346,6 +356,7 @@ func (h *httpServer) Register() error {
|
||||
|
||||
h.registered = true
|
||||
h.rsvc = service
|
||||
h.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -361,7 +372,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 {
|
||||
@@ -387,6 +398,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
|
||||
}
|
||||
@@ -437,6 +449,7 @@ func (h *httpServer) Start() error {
|
||||
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 {
|
||||
@@ -450,9 +463,12 @@ func (h *httpServer) Start() error {
|
||||
}
|
||||
}
|
||||
|
||||
if handler == nil && h.hd == nil {
|
||||
switch {
|
||||
case handler == nil && h.hd == nil:
|
||||
handler = h
|
||||
} else if handler == nil && h.hd != nil {
|
||||
case len(h.handlers) > 0 && h.hd != nil:
|
||||
handler = h
|
||||
case handler == nil && h.hd != nil:
|
||||
if hdlr, ok := h.hd.Handler().(http.Handler); ok {
|
||||
handler = hdlr
|
||||
}
|
||||
@@ -468,7 +484,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 {
|
||||
@@ -492,9 +508,17 @@ func (h *httpServer) Start() error {
|
||||
}
|
||||
|
||||
if srvFunc != nil {
|
||||
go srvFunc(ts)
|
||||
go func() {
|
||||
if cerr := srvFunc(ts); cerr != nil && !errors.Is(cerr, net.ErrClosed) {
|
||||
h.opts.Logger.Error(h.opts.Context, cerr)
|
||||
}
|
||||
}()
|
||||
} else {
|
||||
go http.Serve(ts, fn)
|
||||
go func() {
|
||||
if cerr := http.Serve(ts, fn); cerr != nil && !errors.Is(cerr, net.ErrClosed) {
|
||||
h.opts.Logger.Error(h.opts.Context, cerr)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
go func() {
|
||||
@@ -518,25 +542,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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -549,8 +574,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)
|
||||
@@ -559,6 +582,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
|
||||
@@ -578,13 +603,13 @@ func (h *httpServer) Name() string {
|
||||
return h.opts.Name
|
||||
}
|
||||
|
||||
func NewServer(opts ...server.Option) server.Server {
|
||||
func NewServer(opts ...server.Option) *httpServer {
|
||||
options := server.NewOptions(opts...)
|
||||
return &httpServer{
|
||||
opts: options,
|
||||
exit: make(chan chan error),
|
||||
subscribers: make(map[*httpSubscriber][]broker.Subscriber),
|
||||
errorHandler: DefaultErrorHandler,
|
||||
pathHandlers: make(map[*regexp.Regexp]http.HandlerFunc),
|
||||
pathHandlers: rhttp.NewTrie(),
|
||||
}
|
||||
}
|
||||
|
20
message.go
20
message.go
@@ -1,27 +1,23 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/metadata"
|
||||
"go.unistack.org/micro/v3/codec"
|
||||
"go.unistack.org/micro/v3/metadata"
|
||||
)
|
||||
|
||||
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 {
|
||||
return r.topic
|
||||
}
|
||||
|
||||
func (r *httpMessage) Payload() interface{} {
|
||||
return r.payload
|
||||
}
|
||||
|
||||
func (r *httpMessage) ContentType() string {
|
||||
return r.contentType
|
||||
}
|
||||
@@ -30,8 +26,8 @@ func (r *httpMessage) Header() metadata.Metadata {
|
||||
return r.header
|
||||
}
|
||||
|
||||
func (r *httpMessage) Body() []byte {
|
||||
return r.body
|
||||
func (r *httpMessage) Body() interface{} {
|
||||
return r.payload
|
||||
}
|
||||
|
||||
func (r *httpMessage) Codec() codec.Codec {
|
||||
|
81
options.go
81
options.go
@@ -5,19 +5,22 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
"go.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}
|
||||
}
|
||||
|
||||
// GetError return underline error
|
||||
func GetError(err interface{}) interface{} {
|
||||
if verr, ok := err.(*Error); ok {
|
||||
return verr.err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Error struct holds error
|
||||
type Error struct {
|
||||
err interface{}
|
||||
@@ -28,6 +31,13 @@ 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 {
|
||||
@@ -65,42 +75,57 @@ func ErrorHandler(fn func(ctx context.Context, s server.Handler, w http.Response
|
||||
return server.SetOption(errorHandlerKey{}, fn)
|
||||
}
|
||||
|
||||
type pathHandlerKey struct{}
|
||||
type pathHandlerVal struct {
|
||||
h map[string]http.HandlerFunc
|
||||
}
|
||||
type (
|
||||
pathHandlerKey struct{}
|
||||
pathHandlerVal struct {
|
||||
h map[string]map[string]http.HandlerFunc
|
||||
}
|
||||
)
|
||||
|
||||
// PathHandler specifies http handler for path regexp
|
||||
func PathHandler(path string, h http.HandlerFunc) server.Option {
|
||||
func PathHandler(method, path string, handler 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 = &pathHandlerVal{h: make(map[string]map[string]http.HandlerFunc)}
|
||||
}
|
||||
v.h[path] = h
|
||||
m, ok := v.h[method]
|
||||
if !ok {
|
||||
m = make(map[string]http.HandlerFunc)
|
||||
v.h[method] = m
|
||||
}
|
||||
m[path] = handler
|
||||
o.Context = context.WithValue(o.Context, pathHandlerKey{}, v)
|
||||
}
|
||||
}
|
||||
|
||||
type contentTypeHandlerKey struct{}
|
||||
type contentTypeHandlerVal struct {
|
||||
h map[string]http.HandlerFunc
|
||||
type registerRPCHandlerKey struct{}
|
||||
|
||||
// RegisterRPCHandler registers compatibility endpoints with /ServiceName.ServiceEndpoint method POST
|
||||
func RegisterRPCHandler(b bool) server.Option {
|
||||
return server.SetOption(registerRPCHandlerKey{}, b)
|
||||
}
|
||||
|
||||
// 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 headerKey struct{}
|
||||
|
||||
type handlerOptions struct {
|
||||
headers []string
|
||||
cookies []string
|
||||
}
|
||||
|
||||
type FillRequestOption func(*handlerOptions)
|
||||
|
||||
func Header(headers ...string) FillRequestOption {
|
||||
return func(o *handlerOptions) {
|
||||
o.headers = append(o.headers, headers...)
|
||||
}
|
||||
}
|
||||
|
||||
func Cookie(cookies ...string) FillRequestOption {
|
||||
return func(o *handlerOptions) {
|
||||
o.cookies = append(o.cookies, cookies...)
|
||||
}
|
||||
}
|
||||
|
37
request.go
37
request.go
@@ -3,31 +3,34 @@ package http
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/metadata"
|
||||
"go.unistack.org/micro/v3/codec"
|
||||
"go.unistack.org/micro/v3/metadata"
|
||||
"go.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
|
||||
body []byte
|
||||
method string
|
||||
endpoint string
|
||||
contentType string
|
||||
service string
|
||||
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 +46,7 @@ func (r *rpcRequest) Method() string {
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Endpoint() string {
|
||||
return r.method
|
||||
return r.endpoint
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Codec() codec.Codec {
|
||||
@@ -78,7 +81,7 @@ func (r *rpcMessage) Topic() string {
|
||||
return r.topic
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Payload() interface{} {
|
||||
func (r *rpcMessage) Body() interface{} {
|
||||
return r.payload
|
||||
}
|
||||
|
||||
@@ -86,10 +89,6 @@ func (r *rpcMessage) Header() metadata.Metadata {
|
||||
return r.header
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Body() []byte {
|
||||
return r.body
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Codec() codec.Codec {
|
||||
return r.codec
|
||||
}
|
||||
|
11
server.go
11
server.go
@@ -7,14 +7,14 @@ import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
"go.unistack.org/micro/v3/server"
|
||||
)
|
||||
|
||||
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)
|
||||
|
@@ -7,23 +7,19 @@ import (
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/unistack-org/micro/v3/broker"
|
||||
"github.com/unistack-org/micro/v3/codec"
|
||||
"github.com/unistack-org/micro/v3/metadata"
|
||||
"github.com/unistack-org/micro/v3/register"
|
||||
"github.com/unistack-org/micro/v3/server"
|
||||
)
|
||||
|
||||
const (
|
||||
subSig = "func(context.Context, interface{}) error"
|
||||
"go.unistack.org/micro/v3/broker"
|
||||
"go.unistack.org/micro/v3/codec"
|
||||
"go.unistack.org/micro/v3/metadata"
|
||||
"go.unistack.org/micro/v3/register"
|
||||
"go.unistack.org/micro/v3/server"
|
||||
)
|
||||
|
||||
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))
|
||||
|
||||
@@ -155,7 +151,7 @@ func (s *httpServer) createSubHandler(sb *httpSubscriber, opts server.Options) b
|
||||
vals = append(vals, reflect.ValueOf(ctx))
|
||||
}
|
||||
|
||||
vals = append(vals, reflect.ValueOf(msg.Payload()))
|
||||
vals = append(vals, reflect.ValueOf(msg.Body()))
|
||||
|
||||
returnValues := handler.method.Call(vals)
|
||||
if err := returnValues[0].Interface(); err != nil {
|
||||
@@ -174,7 +170,6 @@ func (s *httpServer) createSubHandler(sb *httpSubscriber, opts server.Options) b
|
||||
contentType: ct,
|
||||
payload: req.Interface(),
|
||||
header: msg.Header,
|
||||
body: msg.Body,
|
||||
codec: cf,
|
||||
})
|
||||
}()
|
||||
|
55
util.go
Normal file
55
util.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"go.unistack.org/micro/v3/metadata"
|
||||
rutil "go.unistack.org/micro/v3/util/reflect"
|
||||
)
|
||||
|
||||
func FillRequest(ctx context.Context, req interface{}, opts ...FillRequestOption) error {
|
||||
var err error
|
||||
options := handlerOptions{}
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
md, ok := metadata.FromIncomingContext(ctx)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
for idx := 0; idx < len(options.headers)/2; idx += 2 {
|
||||
k := http.CanonicalHeaderKey(options.headers[idx])
|
||||
v, ok := md[k]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if err = rutil.SetFieldByPath(req, v, k); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
cookies := strings.Split(md["Cookie"], ";")
|
||||
cmd := make(map[string]string, len(cookies))
|
||||
for _, cookie := range cookies {
|
||||
kv := strings.Split(cookie, "=")
|
||||
if len(kv) != 2 {
|
||||
continue
|
||||
}
|
||||
cmd[strings.TrimSpace(kv[0])] = strings.TrimSpace(kv[1])
|
||||
}
|
||||
for idx := 0; idx < len(options.cookies)/2; idx += 2 {
|
||||
k := http.CanonicalHeaderKey(options.cookies[idx])
|
||||
v, ok := cmd[k]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if err = rutil.SetFieldByPath(req, v, k); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
56
util_test.go
Normal file
56
util_test.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"go.unistack.org/micro/v3/metadata"
|
||||
)
|
||||
|
||||
func TestFillrequest(t *testing.T) {
|
||||
md := metadata.New(1)
|
||||
md.Set("ClientID", "xxx")
|
||||
type request struct {
|
||||
Token string
|
||||
ClientID string
|
||||
}
|
||||
ctx := context.Background()
|
||||
hreq, _ := http.NewRequestWithContext(ctx, http.MethodGet, "/v1", nil)
|
||||
cookie1 := &http.Cookie{Name: "Token", Value: "zzz"}
|
||||
cookie2 := &http.Cookie{Name: "Token", Value: "zzz"}
|
||||
hreq.AddCookie(cookie1)
|
||||
hreq.AddCookie(cookie2)
|
||||
|
||||
buf := bytes.NewBuffer(nil)
|
||||
_ = hreq.Write(buf)
|
||||
var cookie string
|
||||
var line string
|
||||
var err error
|
||||
for {
|
||||
line, err = buf.ReadString('\n')
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
if strings.Contains(line, "Cookie") {
|
||||
cookie = strings.TrimSpace(strings.Split(line, ":")[1])
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
md.Set("Cookie", cookie)
|
||||
ctx = metadata.NewIncomingContext(ctx, md)
|
||||
req := &request{}
|
||||
|
||||
if err := FillRequest(ctx, req, Cookie("Token", "true"), Header("ClientID", "true")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if req.ClientID != "xxx" {
|
||||
t.Fatalf("FillRequest error: %#+v", req)
|
||||
}
|
||||
if req.Token != "zzz" {
|
||||
t.Fatalf("FillRequest error: %#+v", req)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user