Compare commits

...

202 Commits

Author SHA1 Message Date
707476bbd4 Merge pull request 'update for latest micro' (#198) from register into v3
All checks were successful
test / test (push) Successful in 2m56s
Reviewed-on: #198
2024-12-27 01:56:50 +03:00
228251bc55 v3 (#197)
Some checks failed
test / test (push) Has been cancelled
## Pull Request template
Please, go through these steps before clicking submit on this PR.

1. Give a descriptive title to your PR.
2. Provide a description of your changes.
3. Make sure you have some relevant tests.
4. Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes (if applicable).

**PLEASE REMOVE THIS TEMPLATE BEFORE SUBMITTING**

Reviewed-on: #197
Co-authored-by: Evstigneev Denis <danteevstigneev@yandex.ru>
Co-committed-by: Evstigneev Denis <danteevstigneev@yandex.ru>
2024-12-27 01:56:04 +03:00
d1c87fb28f Merge branch 'v3' into register
Some checks failed
lint / lint (pull_request) Failing after 3m2s
test / test (pull_request) Failing after 1m44s
2024-12-27 01:38:37 +03:00
b2e9d1044f update for latest micro
Some checks failed
prbuild / lint (pull_request) Successful in 2m34s
prbuild / test (pull_request) Failing after 4m35s
codeql / analyze (go) (pull_request) Failing after 6m40s
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-12-27 01:31:28 +03:00
a0e009d8a5 Update workflows (#196)
All checks were successful
test / test (push) Successful in 3m9s
Co-authored-by: Aleksandr Tolstikhin <atolstikhin@mtsbank.ru>
Reviewed-on: #196
Co-authored-by: Александр Толстихин <tolstihin1996@mail.ru>
Co-committed-by: Александр Толстихин <tolstihin1996@mail.ru>
2024-12-11 00:39:04 +03:00
21e5406e96 add spa handler
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-12-07 01:21:14 +03:00
469c0e3acb Merge pull request '[BUG] если кодек не найден для переданного контент тайма отдавать спец ошибку' (#192) from atolstikhin/micro-server-http:v3 into v3
Reviewed-on: #192
2024-12-04 23:08:57 +03:00
7ec7aadfbf create outgoing metadata automatic on request
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-12-04 11:33:11 +03:00
dace6eef67 update micro, add Health/Live/Ready checks
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-12-02 15:47:30 +03:00
Aleksandr Tolstikhin
85afe16150 Editing Status of request 2024-11-27 04:17:47 +07:00
Aleksandr Tolstikhin
ee6e245835 Replacing of status 2024-11-27 00:50:30 +07:00
2deb9d3df9 handler/meter: export Options
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-11-17 19:26:42 +03:00
f071b4b145 add server type in metrics and tracing
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-11-10 20:18:20 +03:00
44a2f58a69 fixup endpoint name in tracing and metrics
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-11-10 18:30:19 +03:00
13432d94bb update for latest micro logger changes
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-10-12 13:25:09 +03:00
8d7d145e16 update returning errors (#190)
fix error handling in handler

Reviewed-on: #190
Co-authored-by: Evstigneev Denis <danteevstigneev@yandex.ru>
Co-committed-by: Evstigneev Denis <danteevstigneev@yandex.ru>
2024-10-10 14:29:01 +03:00
57a7ee9b50 Merge pull request '#348-v3 add check method in should be skipped' (#189) from kgorbunov/micro-server-http:#348-v3 into v3
Reviewed-on: #189
Reviewed-by: Василий Толстов <v.tolstov@unistack.org>
2024-09-20 16:52:49 +03:00
Gorbunov Kirill Andreevich
e1db2d8c1a #348 Add check should not be trace and meter handler 2024-09-20 16:05:48 +03:00
Gorbunov Kirill Andreevich
d47b434a53 Merge remote-tracking branch 'upstream/v3' into v3 2024-09-20 09:52:29 +03:00
249ef06c28 update to latest micro
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-09-17 12:47:19 +03:00
0838d2ab9b skip special endpoints
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-05-04 19:38:21 +03:00
c95efdbf53 fixup logs
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-04-24 18:25:31 +03:00
c81960af51 add metrics and tracing
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-04-23 22:21:27 +03:00
1c36c1685f regen
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-04-10 00:15:54 +03:00
e889545210 fixup logger
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-04-10 00:06:50 +03:00
Кирилл Горбунов
526e414d60 flush_v3 (#188)
## Pull Request template
Please, go through these steps before clicking submit on this PR.

1. Give a descriptive title to your PR.
2. Provide a description of your changes.
3. Make sure you have some relevant tests.
4. Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes (if applicable).

**PLEASE REMOVE THIS TEMPLATE BEFORE SUBMITTING**

Co-authored-by: Gorbunov Kirill Andreevich <kgorbunov@mtsbank.ru>
Reviewed-on: #188
Co-authored-by: Кирилл Горбунов <kirya_gorbunov_2015@mail.ru>
Co-committed-by: Кирилл Горбунов <kirya_gorbunov_2015@mail.ru>
2024-03-26 14:52:33 +03:00
db423dff58 fixup cors handling
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-03-20 12:27:14 +03:00
542d4cec00 improve cors
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-03-18 16:38:18 +03:00
0ecd1da0dc improve cors
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-03-18 16:25:52 +03:00
Кирилл Горбунов
7c669c636d Merge pull request 'v3' (#3) from unistack-org/micro-server-http:v3 into v3
Reviewed-on: kgorbunov/micro-server-http#3
2024-03-18 16:11:24 +03:00
0a8755ecb7 fixup
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-03-18 15:57:08 +03:00
9c29d92d7f fixup cors path handler
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-03-18 15:45:43 +03:00
b871c1be38 add cors option
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-03-18 14:51:40 +03:00
74bb12e75e Merge pull request 'fix nil ptr' (#184) from devstigneev/micro-server-http:issue_179_v3 into v3
Reviewed-on: #184
2024-03-12 22:05:32 +03:00
49a95c183b Merge remote-tracking branch 'main/v3' into issue_179_v3
# Conflicts:
#	http.go
2024-03-12 16:48:51 +03:00
5e6bd93a6b fix nil ptr 2024-03-12 16:44:34 +03:00
9ef26caf40 fixup panic
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-03-12 00:50:08 +03:00
b3e58d2cb6 fixup handlers
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-03-12 00:03:51 +03:00
b89d9fdc5b fixup headers
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-03-11 23:30:37 +03:00
Кирилл Горбунов
95dcdd6025 gzip for v3 #153 (#183)
Co-authored-by: Кирилл Горбунов <kirya_gorbunov_2015@mail.ru>
Co-committed-by: Кирилл Горбунов <kirya_gorbunov_2015@mail.ru>
2024-03-11 13:21:11 +03:00
abe5be3ddc Merge pull request 'prepare for v3' (#181) from devstigneev/micro-server-http:issue_179_v3 into v3
Reviewed-on: #181
2024-03-09 13:59:21 +03:00
c3e6cdd973 prepare for v3 2024-03-09 10:06:13 +03:00
76dcf3af67 fixup redirect
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-02-10 23:46:19 +03:00
3e30960694 handler/pprof: clean prefix
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-02-09 00:16:34 +03:00
1643393377 Merge pull request 'handler/pprof: initial import' (#178) from pprof into v3
Reviewed-on: #178
2024-02-08 23:49:17 +03:00
313ae201af handler/pprof: initial import
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2024-02-08 23:48:33 +03:00
069eaf4485 Merge pull request 'copy incoming content-type' (#177) from ct into v3
Reviewed-on: #177
2023-12-20 09:26:28 +03:00
fd670155aa copy incoming content-type
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-12-20 09:26:06 +03:00
0e3a199e16 Merge pull request 'fix swagger handler' (#172) from handler-swagger into v3
Reviewed-on: #172
2023-08-14 13:43:50 +03:00
a665b69706 fix swagger handler
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-08-14 13:43:19 +03:00
90b7b7ec1c fix swagger handler
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-08-14 13:42:51 +03:00
63ae848043 Merge pull request 'add tls headers' (#170) from tls_header into v3
Reviewed-on: #170
2023-08-03 10:43:47 +03:00
4d378bbd51 add tls headers
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-08-03 10:43:33 +03:00
60d165f907 add tls headers
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-08-03 10:42:54 +03:00
5a37de7d74 Merge pull request 'handler/swagger: initial import' (#169) from swagger into v3
Reviewed-on: #169
2023-06-18 17:29:16 +03:00
c7d8b6a3a4 handler/swagger: initial import
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-06-18 17:28:29 +03:00
cd3e2526b4 Merge pull request 'fix query param struct filling' (#167) from matchesfix into v3
Reviewed-on: #167
2023-05-29 12:27:16 +03:00
10ae1741fc fix query param struct filling
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-05-29 12:26:56 +03:00
ca6cea861f Merge pull request 'add scheme to metadata' (#165) from scheme-v3 into v3
Reviewed-on: #165
2023-05-19 23:25:59 +03:00
002d5c9c53 add scheme to metadata
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-05-19 23:25:22 +03:00
1d25e59860 Merge pull request 'move down path handler after specific handler' (#163) from path-handler-v3 into v3
Reviewed-on: #163
2023-05-19 23:04:16 +03:00
ce26e8bf63 move down path handler after specific handler
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-05-19 23:03:04 +03:00
8e09142b90 Merge pull request 'check subscribe errors' (#162) from subscribeerr into v3
Reviewed-on: #162
2023-05-13 16:09:47 +03:00
13bf2bbb1e check subscribe errors
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-05-13 16:09:21 +03:00
ba292901d7 fixup build
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-05-09 21:14:55 +03:00
6d1b6c7014 allow to expose some method via http.HandlerFunc
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-05-09 21:13:11 +03:00
1276f99159 export Server to allow to cast
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-05-09 21:12:47 +03:00
ee5cbbbcb6 Merge pull request 'issue-155: add swagger-ui handler' (#157) from swaggerui into v3
Reviewed-on: #157
2023-05-04 06:51:42 +03:00
ce0abd2de3 issue-155: add swagger-ui handler
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-05-04 06:48:09 +03:00
647f731f50 Merge pull request 'return method not allowed error' (#152) from methodNotAllowed into v3
Reviewed-on: #152
2023-03-09 08:42:50 +03:00
724ffb8c3a return method not allowed error
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-03-09 08:42:04 +03:00
25f306425b Merge pull request #150 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.10.14
Bump go.unistack.org/micro/v3 from 3.10.13 to 3.10.14
2023-02-27 21:04:56 +03:00
dependabot[bot]
dad2d8d5bd Bump go.unistack.org/micro/v3 from 3.10.13 to 3.10.14
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.10.13 to 3.10.14.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.10.13...v3.10.14)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 18:02:27 +00:00
ca148cd8fc Merge pull request #149 from unistack-org/handlers
import from main repo
2023-02-26 14:54:47 +03:00
cd8b3e37f2 import from main repo
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-02-26 14:53:09 +03:00
c908274c8b import from main repo
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-02-26 14:51:34 +03:00
fd3793d50f Merge pull request #148 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.10.13
Bump go.unistack.org/micro/v3 from 3.10.12 to 3.10.13
2023-02-22 20:16:33 +03:00
dependabot[bot]
e67021895e Bump go.unistack.org/micro/v3 from 3.10.12 to 3.10.13
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.10.12 to 3.10.13.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.10.12...v3.10.13)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-22 17:14:50 +00:00
9f4dbbf296 Merge pull request #147 from unistack-org/handlerEndpoints
provide HandlerEndpoints
2023-02-21 23:58:00 +03:00
eea8ae605b provide HandlerEndpoints
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-02-21 23:56:07 +03:00
4341600c01 Merge pull request #146 from unistack-org/metadata
change metadata type
2023-02-21 17:17:34 +03:00
d3fc61eada change metadata type
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-02-21 17:15:22 +03:00
e8281da860 change metadata type
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-02-21 17:14:50 +03:00
9bc1629e77 Merge pull request #145 from unistack-org/update
add HandlerMetadata server.HandlerOption
2023-02-13 23:39:03 +03:00
c27a8b7cf8 add HandlerMetadata server.HandlerOption
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-02-13 23:36:50 +03:00
6b845853e2 Merge pull request #144 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.10.10
Bump go.unistack.org/micro/v3 from 3.10.9 to 3.10.10
2023-02-13 21:04:15 +03:00
dependabot[bot]
dbc3c12eed Bump go.unistack.org/micro/v3 from 3.10.9 to 3.10.10
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.10.9 to 3.10.10.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.10.9...v3.10.10)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 18:01:59 +00:00
7f1a55958e Merge pull request #143 from unistack-org/headers
dont mangle header names
2023-02-13 00:12:07 +03:00
02f9d6d8f7 dont mangle header names
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-02-13 00:09:54 +03:00
82beddb09b add http header option (#142)
* add http header option
2023-02-11 01:18:16 +03:00
6cb3a1c4c4 Merge pull request #141 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.10.9
Bump go.unistack.org/micro/v3 from 3.10.8 to 3.10.9
2023-02-08 20:04:53 +03:00
dependabot[bot]
2ff786cb03 Bump go.unistack.org/micro/v3 from 3.10.8 to 3.10.9
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.10.8 to 3.10.9.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.10.8...v3.10.9)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-08 17:03:00 +00:00
282065f90e Merge pull request #140 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.10.8
Bump go.unistack.org/micro/v3 from 3.10.6 to 3.10.8
2023-02-07 20:04:04 +03:00
dependabot[bot]
b16e6ebd31 Bump go.unistack.org/micro/v3 from 3.10.6 to 3.10.8
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.10.6 to 3.10.8.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.10.6...v3.10.8)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-07 17:02:19 +00:00
68f4c164d0 Merge pull request #139 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.10.6
Bump go.unistack.org/micro/v3 from 3.10.5 to 3.10.6
2023-02-06 20:05:40 +03:00
dependabot[bot]
d0fee2ca23 Bump go.unistack.org/micro/v3 from 3.10.5 to 3.10.6
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.10.5 to 3.10.6.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.10.5...v3.10.6)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 17:03:59 +00:00
034298b7e0 Merge pull request #138 from unistack-org/errorHandler
return after errorHandler
2023-02-05 11:33:13 +03:00
f93c35b611 Merge branch 'v3' into errorHandler 2023-02-05 11:31:42 +03:00
b5148e90cb return after errorHandler
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-02-05 11:29:51 +03:00
dependabot[bot]
a8d47d0c1c Bump dependabot/fetch-metadata from 1.3.5 to 1.3.6 (#135)
Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 1.3.5 to 1.3.6.
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](https://github.com/dependabot/fetch-metadata/compare/v1.3.5...v1.3.6)

---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-30 21:21:45 +03:00
7d4e32298c Merge pull request #136 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.10.5
Bump go.unistack.org/micro/v3 from 3.10.4 to 3.10.5
2023-01-30 20:08:01 +03:00
dependabot[bot]
14ff546fc1 Bump go.unistack.org/micro/v3 from 3.10.4 to 3.10.5
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.10.4 to 3.10.5.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.10.4...v3.10.5)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-30 17:06:09 +00:00
dependabot[bot]
c37d057669 Bump golangci/golangci-lint-action from 3.3.1 to 3.4.0 (#134)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 3.3.1 to 3.4.0.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v3.3.1...v3.4.0)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-24 09:54:56 +03:00
b925441ea7 Merge pull request #133 from unistack-org/eh
fix error handler
2023-01-23 09:26:31 +03:00
984d09384f Merge branch 'v3' into eh 2023-01-23 09:24:49 +03:00
7c15ee784a fix error handler
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-01-23 09:23:38 +03:00
f2607d5439 Merge pull request #132 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.10.4
Bump go.unistack.org/micro/v3 from 3.10.1 to 3.10.4
2023-01-18 20:04:47 +03:00
dependabot[bot]
8e607dcc26 Bump go.unistack.org/micro/v3 from 3.10.1 to 3.10.4
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.10.1 to 3.10.4.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.10.1...v3.10.4)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-18 17:03:05 +00:00
929aae7456 Merge pull request #131 from unistack-org/endpoint
fix endpoint
2023-01-17 23:42:28 +03:00
5ba7742619 fix endpoint
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2023-01-17 23:40:24 +03:00
dece47ae0e Merge pull request #130 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.10.1
Bump go.unistack.org/micro/v3 from 3.10.0 to 3.10.1
2023-01-17 20:05:34 +03:00
dependabot[bot]
db5e66e375 Bump go.unistack.org/micro/v3 from 3.10.0 to 3.10.1
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.10.0 to 3.10.1.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.10.0...v3.10.1)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-17 17:03:51 +00:00
39d3aabf62 Merge pull request #129 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.10.0
Bump go.unistack.org/micro/v3 from 3.9.18 to 3.10.0
2023-01-09 20:08:34 +03:00
dependabot[bot]
25469792df Bump go.unistack.org/micro/v3 from 3.9.18 to 3.10.0
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.9.18 to 3.10.0.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.9.18...v3.10.0)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-09 17:06:34 +00:00
7f278036f6 Merge pull request #128 from unistack-org/util_http_method_not_allowed
util/http: trie support method not allowed
2022-12-28 00:00:49 +03:00
05625d2df4 util/http: trie support method not allowed
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-12-27 23:59:02 +03:00
82bfa00c3d Merge pull request #127 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.9.17
Bump go.unistack.org/micro/v3 from 3.9.15 to 3.9.17
2022-12-26 20:08:18 +03:00
dependabot[bot]
740b5ee635 Bump go.unistack.org/micro/v3 from 3.9.15 to 3.9.17
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.9.15 to 3.9.17.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.9.15...v3.9.17)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-26 17:06:05 +00:00
9a096bc471 Merge pull request #126 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.9.15
Bump go.unistack.org/micro/v3 from 3.9.13 to 3.9.15
2022-11-28 20:07:35 +03:00
dependabot[bot]
04b27524ee Bump go.unistack.org/micro/v3 from 3.9.13 to 3.9.15
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.9.13 to 3.9.15.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.9.13...v3.9.15)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-28 17:05:54 +00:00
dependabot[bot]
57758b4f80 Bump hmarr/auto-approve-action from 2 to 3 (#125)
Bumps [hmarr/auto-approve-action](https://github.com/hmarr/auto-approve-action) from 2 to 3.
- [Release notes](https://github.com/hmarr/auto-approve-action/releases)
- [Commits](https://github.com/hmarr/auto-approve-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: hmarr/auto-approve-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-28 16:26:01 +03:00
9c809a04eb Merge pull request #124 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.9.13
Bump go.unistack.org/micro/v3 from 3.9.11 to 3.9.13
2022-11-14 20:07:35 +03:00
dependabot[bot]
dd0e7e748d Bump go.unistack.org/micro/v3 from 3.9.11 to 3.9.13
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.9.11 to 3.9.13.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.9.11...v3.9.13)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-11-14 17:05:39 +00:00
dependabot[bot]
31b048858d Bump golangci/golangci-lint-action from 3.2.0 to 3.3.1 (#123)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 3.2.0 to 3.3.1.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v3.2.0...v3.3.1)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-14 07:22:40 +03:00
dependabot[bot]
bf0f643d78 Bump dependabot/fetch-metadata from 1.3.4 to 1.3.5 (#122)
Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 1.3.4 to 1.3.5.
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](https://github.com/dependabot/fetch-metadata/compare/v1.3.4...v1.3.5)

---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-12 18:20:42 +03:00
dependabot[bot]
1bdd010340 Bump dependabot/fetch-metadata from 1.3.3 to 1.3.4 (#120)
Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 1.3.3 to 1.3.4.
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](https://github.com/dependabot/fetch-metadata/compare/v1.3.3...v1.3.4)

---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-10-04 12:50:27 +03:00
dependabot[bot]
30ec3ae03e Bump dependabot/fetch-metadata from 1.3.1 to 1.3.3 (#118)
Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 1.3.1 to 1.3.3.
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](https://github.com/dependabot/fetch-metadata/compare/v1.3.1...v1.3.3)

---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-08-28 17:24:37 +03:00
a11adb8a1e Merge pull request #119 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.9.11
Bump go.unistack.org/micro/v3 from 3.9.10 to 3.9.11
2022-07-11 20:26:08 +03:00
dependabot[bot]
e8678e2da6 Bump go.unistack.org/micro/v3 from 3.9.10 to 3.9.11
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.9.10 to 3.9.11.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.9.10...v3.9.11)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-11 17:24:27 +00:00
faf698cfcb Merge pull request #116 from unistack-org/cleanup
update to latest micro
2022-06-27 00:45:29 +03:00
461123dba0 Merge branch 'v3' into cleanup 2022-06-27 00:43:41 +03:00
7d649e8156 update to latest micro
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-06-27 00:41:18 +03:00
dependabot[bot]
d5e0423985 Bump golangci/golangci-lint-action from 3.1.0 to 3.2.0 (#115)
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 3.1.0 to 3.2.0.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v3.1.0...v3.2.0)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-06-25 22:50:01 +03:00
2e2a9e8f01 Merge pull request #114 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.9.8
Bump go.unistack.org/micro/v3 from 3.9.7 to 3.9.8
2022-05-03 20:24:59 +03:00
dependabot[bot]
685951339e Bump go.unistack.org/micro/v3 from 3.9.7 to 3.9.8
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.9.7 to 3.9.8.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.9.7...v3.9.8)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-05-03 17:22:48 +00:00
dependabot[bot]
31e882cc1e Bump github/codeql-action from 1 to 2 (#113)
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 1 to 2.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v1...v2)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-26 23:42:10 +03:00
dependabot[bot]
f5db9193de Bump dependabot/fetch-metadata from 1.3.0 to 1.3.1 (#112)
Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](https://github.com/dependabot/fetch-metadata/compare/v1.3.0...v1.3.1)

---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-21 23:49:41 +03:00
9932138d52 Merge pull request #111 from unistack-org/dependabot/github_actions/actions/setup-go-3
Bump actions/setup-go from 2 to 3
2022-04-11 22:56:14 +03:00
dependabot[bot]
a2a83bbae5 Bump actions/setup-go from 2 to 3
Bumps [actions/setup-go](https://github.com/actions/setup-go) from 2 to 3.
- [Release notes](https://github.com/actions/setup-go/releases)
- [Commits](https://github.com/actions/setup-go/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/setup-go
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-08 17:17:24 +00:00
19946951f8 Merge pull request #110 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.9.7
Bump go.unistack.org/micro/v3 from 3.9.5 to 3.9.7
2022-03-30 20:21:18 +03:00
dependabot[bot]
9711b1b4ed Bump go.unistack.org/micro/v3 from 3.9.5 to 3.9.7
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.9.5 to 3.9.7.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.9.5...v3.9.7)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-30 17:19:07 +00:00
31c53e8172 Merge pull request #109 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.9.5
Bump go.unistack.org/micro/v3 from 3.9.2 to 3.9.5
2022-03-28 20:24:52 +03:00
dependabot[bot]
1c9f81edd4 Bump go.unistack.org/micro/v3 from 3.9.2 to 3.9.5
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.9.2 to 3.9.5.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.9.2...v3.9.5)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-28 17:23:06 +00:00
9679408349 Merge pull request #108 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.9.2
Bump go.unistack.org/micro/v3 from 3.9.1 to 3.9.2
2022-03-25 20:22:06 +03:00
dependabot[bot]
47786523cc Bump go.unistack.org/micro/v3 from 3.9.1 to 3.9.2
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.9.1 to 3.9.2.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.9.1...v3.9.2)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-25 17:20:25 +00:00
0d47683c9a Merge pull request #106 from unistack-org/dependabot/github_actions/actions/cache-3
Bump actions/cache from 2 to 3
2022-03-22 23:08:00 +03:00
dependabot[bot]
ad44db22b9 Bump actions/cache from 2 to 3
Bumps [actions/cache](https://github.com/actions/cache) from 2 to 3.
- [Release notes](https://github.com/actions/cache/releases)
- [Commits](https://github.com/actions/cache/compare/v2...v3)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-22 17:41:29 +00:00
2be7d79739 Merge pull request #107 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.9.1
Bump go.unistack.org/micro/v3 from 3.9.0 to 3.9.1
2022-03-22 20:40:44 +03:00
dependabot[bot]
0124e922e5 Bump go.unistack.org/micro/v3 from 3.9.0 to 3.9.1
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.9.0 to 3.9.1.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.9.0...v3.9.1)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-22 17:20:17 +00:00
fd8c454bae Merge pull request #105 from unistack-org/cleanup
server: remove unparsed body from request and message
2022-03-21 15:43:42 +03:00
1cc8b37503 comment
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-03-21 15:41:40 +03:00
cd47eab010 Merge branch 'v3' into cleanup 2022-03-21 15:31:47 +03:00
9136addd1e Merge branch 'master' into v3 2022-03-21 15:31:11 +03:00
4ce1ef631b server: remove unparsed body from request and message
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-03-21 15:29:40 +03:00
4618fae641 update go version
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-03-07 13:46:39 +03:00
b2eba3120e Merge pull request #104 from unistack-org/dependabot/github_actions/golangci/golangci-lint-action-3.1.0
Bump golangci/golangci-lint-action from 2 to 3.1.0
2022-03-07 13:29:04 +03:00
dependabot[bot]
04703cb8fa Bump golangci/golangci-lint-action from 2 to 3.1.0
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 2 to 3.1.0.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v2...v3.1.0)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-07 09:43:58 +00:00
6da3bbabed update workflows
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-03-05 19:10:02 +03:00
81016aa16f Merge pull request #101 from unistack-org/dependabot/github_actions/golangci/golangci-lint-action-3.1.0
Bump golangci/golangci-lint-action from 2 to 3.1.0
2022-03-01 00:37:45 +03:00
dependabot[bot]
042998ff76 Bump golangci/golangci-lint-action from 2 to 3.1.0
Bumps [golangci/golangci-lint-action](https://github.com/golangci/golangci-lint-action) from 2 to 3.1.0.
- [Release notes](https://github.com/golangci/golangci-lint-action/releases)
- [Commits](https://github.com/golangci/golangci-lint-action/compare/v2...v3.1.0)

---
updated-dependencies:
- dependency-name: golangci/golangci-lint-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-28 17:25:55 +00:00
97d5936efd Merge pull request #99 from unistack-org/dependabot/github_actions/dependabot/fetch-metadata-1.2.1
Bump dependabot/fetch-metadata from 1.1.1 to 1.2.1
2022-02-25 09:39:21 +03:00
dependabot[bot]
d6777af891 Bump dependabot/fetch-metadata from 1.1.1 to 1.2.1
Bumps [dependabot/fetch-metadata](https://github.com/dependabot/fetch-metadata) from 1.1.1 to 1.2.1.
- [Release notes](https://github.com/dependabot/fetch-metadata/releases)
- [Commits](https://github.com/dependabot/fetch-metadata/compare/v1.1.1...v1.2.1)

---
updated-dependencies:
- dependency-name: dependabot/fetch-metadata
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-02-23 17:18:42 +00:00
c2f178001c Merge pull request #97 from unistack-org/master
merge master
2022-02-01 11:23:02 +03:00
ffe5f1c9be Merge pull request #96 from unistack-org/codec
lazy codec init
2022-02-01 11:22:39 +03:00
416d494e50 lazy codec init
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-02-01 11:22:18 +03:00
7dd1dfbff6 Merge pull request #95 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.8.21
Bump go.unistack.org/micro/v3 from 3.8.20 to 3.8.21
2022-01-31 20:24:07 +03:00
dependabot[bot]
e11dc06067 Bump go.unistack.org/micro/v3 from 3.8.20 to 3.8.21
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.8.20 to 3.8.21.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.8.20...v3.8.21)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-31 17:22:15 +00:00
2cc17551ca Merge pull request #94 from unistack-org/master
merge master
2022-01-30 20:44:27 +03:00
d8493a3628 Merge pull request #93 from unistack-org/oldrpc
fixup old rpc http server
2022-01-30 20:43:48 +03:00
e9a396d424 fixup old rpc http server
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-01-30 20:43:27 +03:00
fed13e1293 Merge pull request #92 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.8.20
Bump go.unistack.org/micro/v3 from 3.8.19 to 3.8.20
2022-01-26 20:18:32 +03:00
dependabot[bot]
62fdcf6a1f Bump go.unistack.org/micro/v3 from 3.8.19 to 3.8.20
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.8.19 to 3.8.20.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.8.19...v3.8.20)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-26 17:16:44 +00:00
2f0e291247 Merge pull request #91 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.8.19
Bump go.unistack.org/micro/v3 from 3.8.18 to 3.8.19
2022-01-25 20:21:31 +03:00
dependabot[bot]
39f7605f91 Bump go.unistack.org/micro/v3 from 3.8.18 to 3.8.19
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.8.18 to 3.8.19.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.8.18...v3.8.19)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-25 17:19:31 +00:00
e2efc934b3 Merge branch 'master' into v3 2022-01-24 20:31:05 +03:00
2d5fb587a0 ignore net.ErrClosed
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-01-24 20:29:52 +03:00
6a30a4f408 Merge pull request #90 from unistack-org/master
merge master
2022-01-23 02:41:15 +03:00
f80e6c1a66 Merge pull request #89 from unistack-org/reorder
reorder path checking, priority in internal routes
2022-01-23 02:40:40 +03:00
2aa8768aed reorder path checking, priority in internal routes
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-01-23 02:40:24 +03:00
0ab763b505 Merge pull request #88 from unistack-org/master
merge master
2022-01-23 02:01:01 +03:00
68b6f6904b Merge pull request #87 from unistack-org/combine_handler
combine native and micro http handlers
2022-01-23 02:00:33 +03:00
31e996fc2e combine native and micro http handlers
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-01-23 02:00:15 +03:00
14f3b149e4 Merge pull request #86 from unistack-org/master
merge master
2022-01-22 01:11:43 +03:00
6714e48f4f internal rewrite to be more performant (#85)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2022-01-22 01:10:24 +03:00
547199f0b8 Merge pull request #84 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.8.18
Bump go.unistack.org/micro/v3 from 3.8.15 to 3.8.18
2022-01-21 20:21:16 +03:00
dependabot[bot]
be637e8324 Bump go.unistack.org/micro/v3 from 3.8.15 to 3.8.18
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.8.15 to 3.8.18.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.8.15...v3.8.18)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-21 17:19:27 +00:00
67e9e7e880 Merge pull request #83 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.8.15
Bump go.unistack.org/micro/v3 from 3.8.14 to 3.8.15
2022-01-19 20:22:00 +03:00
dependabot[bot]
8a6a259404 Bump go.unistack.org/micro/v3 from 3.8.14 to 3.8.15
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.8.14 to 3.8.15.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.8.14...v3.8.15)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-19 17:20:18 +00:00
2b3e1acd22 Merge pull request #82 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.8.14
Bump go.unistack.org/micro/v3 from 3.8.13 to 3.8.14
2022-01-10 20:23:32 +03:00
dependabot[bot]
2816fd756a Bump go.unistack.org/micro/v3 from 3.8.13 to 3.8.14
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.8.13 to 3.8.14.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.8.13...v3.8.14)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-10 17:21:25 +00:00
5353c56034 Merge pull request #81 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.8.13
Bump go.unistack.org/micro/v3 from 3.8.11 to 3.8.13
2021-12-28 20:17:33 +03:00
dependabot[bot]
b93dcbb165 Bump go.unistack.org/micro/v3 from 3.8.11 to 3.8.13
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.8.11 to 3.8.13.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.8.11...v3.8.13)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-28 17:15:29 +00:00
d76f9f20b6 Merge pull request #79 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.8.11
Bump go.unistack.org/micro/v3 from 3.8.10 to 3.8.11
2021-11-24 20:24:37 +03:00
dependabot[bot]
4cb133546d Bump go.unistack.org/micro/v3 from 3.8.10 to 3.8.11
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.8.10 to 3.8.11.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.8.10...v3.8.11)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-24 17:22:53 +00:00
c0ca60b7c9 Merge pull request #78 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.8.10
Bump go.unistack.org/micro/v3 from 3.8.7 to 3.8.10
2021-11-19 20:24:19 +03:00
dependabot[bot]
7a096d6605 Bump go.unistack.org/micro/v3 from 3.8.7 to 3.8.10
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.8.7 to 3.8.10.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.8.7...v3.8.10)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-19 17:22:25 +00:00
1c5c86668b Merge pull request #76 from unistack-org/dependabot/go_modules/go.unistack.org/micro/v3-3.8.7
Bump go.unistack.org/micro/v3 from 3.8.5 to 3.8.7
2021-10-27 23:34:41 +03:00
dependabot[bot]
e7b5a90b5c Bump go.unistack.org/micro/v3 from 3.8.5 to 3.8.7
Bumps [go.unistack.org/micro/v3](https://github.com/unistack-org/micro) from 3.8.5 to 3.8.7.
- [Release notes](https://github.com/unistack-org/micro/releases)
- [Commits](https://github.com/unistack-org/micro/compare/v3.8.5...v3.8.7)

---
updated-dependencies:
- dependency-name: go.unistack.org/micro/v3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-27 20:25:03 +00:00
677f00c3c0 update workflows
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-10-27 23:19:52 +03:00
7365c5f1cd guard import
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-10-26 22:55:51 +03:00
505c59ba75 fill request with header and cookie data
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-10-26 22:36:04 +03:00
7a39d86018 remove debug print
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2021-10-21 14:28:32 +03:00
48 changed files with 3881 additions and 645 deletions

View File

@@ -0,0 +1,29 @@
name: lint
on:
pull_request:
types: [opened, reopened, synchronize]
branches:
- master
- v3
- v4
jobs:
lint:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v4
with:
filter: 'blob:none'
- name: setup go
uses: actions/setup-go@v5
with:
cache-dependency-path: "**/*.sum"
go-version: 'stable'
- name: setup deps
run: go get -v ./...
- name: run lint
uses: https://github.com/golangci/golangci-lint-action@v6
with:
version: 'latest'

View File

@@ -0,0 +1,34 @@
name: test
on:
pull_request:
types: [opened, reopened, synchronize]
branches:
- master
- v3
- v4
push:
branches:
- master
- v3
- v4
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v4
with:
filter: 'blob:none'
- name: setup go
uses: actions/setup-go@v5
with:
cache-dependency-path: "**/*.sum"
go-version: 'stable'
- name: setup deps
run: go get -v ./...
- name: run test
env:
INTEGRATION_TESTS: yes
run: go test -mod readonly -v ./...

View File

@@ -0,0 +1,53 @@
name: test
on:
pull_request:
types: [opened, reopened, synchronize]
branches:
- master
- v3
- v4
push:
branches:
- master
- v3
- v4
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: checkout code
uses: actions/checkout@v4
with:
filter: 'blob:none'
- name: checkout tests
uses: actions/checkout@v4
with:
ref: master
filter: 'blob:none'
repository: unistack-org/micro-tests
path: micro-tests
- name: setup go
uses: actions/setup-go@v5
with:
cache-dependency-path: "**/*.sum"
go-version: 'stable'
- name: setup go work
env:
GOWORK: /workspace/${{ github.repository_owner }}/go.work
run: |
go work init
go work use .
go work use micro-tests
- name: setup deps
env:
GOWORK: /workspace/${{ github.repository_owner }}/go.work
run: go get -v ./...
- name: run tests
env:
INTEGRATION_TESTS: yes
GOWORK: /workspace/${{ github.repository_owner }}/go.work
run: |
cd micro-tests
go test -mod readonly -v ./... || true

View File

@@ -1,19 +0,0 @@
# 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"

View File

@@ -1,46 +0,0 @@
name: build
on:
push:
branches:
- master
jobs:
test:
name: test
runs-on: ubuntu-latest
steps:
- name: setup
uses: actions/setup-go@v2
with:
go-version: 1.16
- name: checkout
uses: actions/checkout@v2
- name: cache
uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-
- name: deps
run: go get -v -t -d ./...
- name: test
env:
INTEGRATION_TESTS: yes
run: go test -mod readonly -v ./...
lint:
name: lint
runs-on: ubuntu-latest
steps:
- name: checkout
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
# Optional: working directory, useful for monorepos
# working-directory: somedir
# Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true

View File

@@ -1,75 +0,0 @@
# 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 ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
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 repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
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: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -1,66 +0,0 @@
name: "prautomerge"
on:
workflow_run:
workflows: ["prbuild"]
types:
- completed
permissions:
contents: write
pull-requests: write
jobs:
Dependabot-Automerge:
runs-on: ubuntu-latest
# Contains workaround to execute if dependabot updates the PR by checking for the base branch in the linked PR
# The the github.event.workflow_run.event value is 'push' and not 'pull_request'
# dont work with multiple workflows when last returns success
if: >-
github.event.workflow_run.conclusion == 'success'
&& github.actor == 'dependabot[bot]'
&& github.event.sender.login == 'dependabot[bot]'
&& github.event.sender.type == 'Bot'
&& (github.event.workflow_run.event == 'pull_request'
|| (github.event.workflow_run.event == 'push' && github.event.workflow_run.pull_requests[0].base.ref == github.event.repository.default_branch ))
steps:
- name: Approve Changes and Merge changes if label 'dependencies' is set
uses: actions/github-script@v5
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
console.log(context.payload.workflow_run);
var labelNames = await github.paginate(
github.issues.listLabelsOnIssue,
{
repo: context.repo.repo,
owner: context.repo.owner,
issue_number: context.payload.workflow_run.pull_requests[0].number,
},
(response) => response.data.map(
(label) => label.name
)
);
console.log(labelNames);
if (labelNames.includes('dependencies')) {
console.log('Found label');
await github.pulls.createReview({
repo: context.repo.repo,
owner: context.repo.owner,
pull_number: context.payload.workflow_run.pull_requests[0].number,
event: 'APPROVE'
});
console.log('Approved PR');
await github.pulls.merge({
repo: context.repo.repo,
owner: context.repo.owner,
pull_number: context.payload.workflow_run.pull_requests[0].number,
});
console.log('Merged PR');
}

View File

@@ -1,46 +0,0 @@
name: prbuild
on:
pull_request:
branches:
- master
jobs:
test:
name: test
runs-on: ubuntu-latest
steps:
- name: setup
uses: actions/setup-go@v2
with:
go-version: 1.16
- name: checkout
uses: actions/checkout@v2
- name: cache
uses: actions/cache@v2
with:
path: ~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: ${{ runner.os }}-go-
- name: deps
run: go get -v -t -d ./...
- name: test
env:
INTEGRATION_TESTS: yes
run: go test -mod readonly -v ./...
lint:
name: lint
runs-on: ubuntu-latest
steps:
- name: checkout
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
# Optional: working directory, useful for monorepos
# working-directory: somedir
# Optional: golangci-lint command line arguments.
# args: --issues-exit-code=0
# Optional: show only new issues if it's a pull request. The default value is `false`.
# only-new-issues: true

24
.gitignore vendored Normal file
View File

@@ -0,0 +1,24 @@
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
# Go workspace file
go.work
# General
.DS_Store
.idea
.vscode

View File

@@ -1,44 +1,5 @@
run:
concurrency: 4
concurrency: 8
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

25
go.mod
View File

@@ -1,8 +1,25 @@
module github.com/unistack-org/micro-server-http/v3
module go.unistack.org/micro-server-http/v3
go 1.22.0
go 1.16
require (
github.com/unistack-org/micro/v3 v3.7.6
golang.org/x/net v0.0.0-20210928044308-7d9f5e0b762b
go.unistack.org/micro-client-http/v3 v3.9.15
go.unistack.org/micro-codec-yaml/v3 v3.10.3
go.unistack.org/micro-proto/v3 v3.4.1
go.unistack.org/micro/v3 v3.11.30
golang.org/x/net v0.33.0
)
require (
github.com/ash3in/uuidv8 v1.2.0 // indirect
github.com/google/gnostic v0.7.0 // indirect
github.com/google/gnostic-models v0.6.9 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/matoous/go-nanoid v1.5.1 // indirect
golang.org/x/sys v0.28.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20241223144023-3abc09e42ca8 // indirect
google.golang.org/grpc v1.69.2 // indirect
google.golang.org/protobuf v1.36.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

1556
go.sum

File diff suppressed because it is too large Load Diff

View File

@@ -6,23 +6,29 @@ import (
"io"
"net/http"
"reflect"
"slices"
"strconv"
"strings"
"sync"
"time"
"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"
rhttp "github.com/unistack-org/micro/v3/util/http"
rflutil "github.com/unistack-org/micro/v3/util/reflect"
"go.unistack.org/micro/v3/errors"
"go.unistack.org/micro/v3/logger"
"go.unistack.org/micro/v3/metadata"
"go.unistack.org/micro/v3/meter"
"go.unistack.org/micro/v3/options"
"go.unistack.org/micro/v3/semconv"
"go.unistack.org/micro/v3/server"
"go.unistack.org/micro/v3/tracer"
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)
if _, cerr := w.Write([]byte(err.Error())); cerr != nil {
logger.DefaultLogger.Errorf(ctx, "write failed: %v", cerr)
logger.DefaultLogger.Error(ctx, "write error", cerr)
}
}
DefaultContentType = "application/json"
@@ -32,15 +38,13 @@ type patHandler struct {
mtype *methodType
rcvr reflect.Value
name string
pat *rhttp.Trie
}
type httpHandler struct {
opts server.HandlerOptions
hd interface{}
handlers map[string][]patHandler
handlers *rhttp.Trie
name string
eps []*register.Endpoint
sopts server.Options
sync.RWMutex
}
@@ -53,93 +57,486 @@ func (h *httpHandler) Handler() interface{} {
return h.hd
}
func (h *httpHandler) Endpoints() []*register.Endpoint {
return h.eps
}
func (h *httpHandler) Options() server.HandlerOptions {
return h.opts
}
func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if ph, _, ok := h.pathHandlers.Search(r.Method, r.URL.Path); ok {
ph.(http.HandlerFunc)(w, r)
return
func (h *Server) HTTPHandlerFunc(handler interface{}) (http.HandlerFunc, error) {
if handler == nil {
return nil, fmt.Errorf("invalid handler specified: %v", handler)
}
rtype := reflect.TypeOf(handler)
if rtype.NumIn() != 3 {
return nil, fmt.Errorf("invalid handler, NumIn != 3: %v", rtype.NumIn())
}
argType := rtype.In(1)
replyType := rtype.In(2)
// First arg need not be a pointer.
if !isExportedOrBuiltinType(argType) {
return nil, fmt.Errorf("invalid handler, argument type not exported: %v", argType)
}
if replyType.Kind() != reflect.Ptr {
return nil, fmt.Errorf("invalid handler, reply type not a pointer: %v", replyType)
}
// Reply type must be exported.
if !isExportedOrBuiltinType(replyType) {
return nil, fmt.Errorf("invalid handler, reply type not exported: %v", replyType)
}
if rtype.NumOut() != 1 {
return nil, fmt.Errorf("invalid handler, has wrong number of outs: %v", rtype.NumOut())
}
// The return type of the method must be error.
if returnType := rtype.Out(0); returnType != typeOfError {
return nil, fmt.Errorf("invalid handler, returns %v not error", returnType.String())
}
return func(w http.ResponseWriter, r *http.Request) {
ct := DefaultContentType
if htype := r.Header.Get(metadata.HeaderContentType); htype != "" {
ct = htype
}
ctx := context.WithValue(r.Context(), rspCodeKey{}, &rspCodeVal{})
ctx = context.WithValue(ctx, rspHeaderKey{}, &rspHeaderVal{})
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
md = metadata.New(len(r.Header) + 8)
}
for k, v := range r.Header {
md[k] = strings.Join(v, ", ")
}
md["RemoteAddr"] = r.RemoteAddr
md["Method"] = r.Method
md["URL"] = r.URL.String()
md["Proto"] = r.Proto
md["Content-Length"] = fmt.Sprintf("%d", r.ContentLength)
md["Transfer-Encoding"] = strings.Join(r.TransferEncoding, ",")
md["Host"] = r.Host
md["RequestURI"] = r.RequestURI
if r.TLS != nil {
md["TLS"] = "true"
md["TLS-ALPN"] = r.TLS.NegotiatedProtocol
md["TLS-ServerName"] = r.TLS.ServerName
}
ctx = metadata.NewIncomingContext(ctx, md)
path := r.URL.Path
if r.Body != nil {
defer r.Body.Close()
}
matches := make(map[string]interface{})
var match bool
var hldr *patHandler
var handler *httpHandler
for _, shdlr := range h.handlers {
hdlr := shdlr.(*httpHandler)
fh, mp, err := hdlr.handlers.Search(r.Method, path)
if err == nil {
match = true
for k, v := range mp {
matches[k] = v
}
hldr = fh.(*patHandler)
handler = hdlr
break
} else if err == rhttp.ErrMethodNotAllowed && !h.registerRPC {
w.WriteHeader(http.StatusMethodNotAllowed)
_, _ = w.Write([]byte("not matching route found"))
return
}
}
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, err := hdlr.handlers.Search(http.MethodPost, "/"+microMethod)
if err == nil {
// match = true
for k, v := range mp {
matches[k] = v
}
hldr = fh.(*patHandler)
handler = hdlr
}
}
}
}
}
// get fields from url values
if len(r.URL.RawQuery) > 0 {
umd, cerr := rflutil.URLMap(r.URL.RawQuery)
if cerr != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(cerr.Error()))
return
}
for k, v := range umd {
matches[k] = v
}
}
cf, err := h.newCodec(ct)
if err != nil {
w.WriteHeader(http.StatusUnsupportedMediaType)
return
}
var argv, replyv reflect.Value
// Decode the argument value.
argIsValue := false // if true, need to indirect before calling.
if hldr.mtype.ArgType.Kind() == reflect.Ptr {
argv = reflect.New(hldr.mtype.ArgType.Elem())
} else {
argv = reflect.New(hldr.mtype.ArgType)
argIsValue = true
}
if argIsValue {
argv = argv.Elem()
}
// reply value
replyv = reflect.New(hldr.mtype.ReplyType.Elem())
function := hldr.mtype.method.Func
var returnValues []reflect.Value
if r.Body != nil {
var buf []byte
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
}
hr := &rpcRequest{
codec: cf,
service: handler.sopts.Name,
contentType: ct,
method: fmt.Sprintf("%s.%s", hldr.name, hldr.mtype.method.Name),
endpoint: fmt.Sprintf("%s.%s", hldr.name, hldr.mtype.method.Name),
payload: argv.Interface(),
header: md,
}
// define the handler func
fn := func(fctx context.Context, req server.Request, rsp interface{}) (err error) {
returnValues = function.Call([]reflect.Value{hldr.rcvr, hldr.mtype.prepareContext(fctx), argv, reflect.ValueOf(rsp)})
// The return value for the method is an error.
if rerr := returnValues[0].Interface(); rerr != nil {
err = rerr.(error)
}
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
h.opts.Hooks.EachPrev(func(hook options.Hook) {
if h, ok := hook.(server.HookHandler); ok {
fn = h(fn)
}
})
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(metadata.HeaderContentType, ct)
if md, ok := metadata.FromOutgoingContext(ctx); ok {
for k, v := range md {
w.Header().Set(k, v)
}
}
if md := getRspHeader(ctx); md != nil {
for k, v := range md {
for _, vv := range v {
w.Header().Add(k, vv)
}
}
}
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.StatusInternalServerError)
return
}
}
var buf []byte
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.Error(handler.sopts.Context, "handler error", err)
return
}
if nscode := GetRspCode(ctx); nscode != 0 {
scode = nscode
}
w.WriteHeader(scode)
if _, cerr := w.Write(buf); cerr != nil {
handler.sopts.Logger.Error(ctx, "write failed", cerr)
}
}, nil
}
func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
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
}
}
ts := time.Now()
ctx := context.WithValue(r.Context(), rspCodeKey{}, &rspCodeVal{})
ctx = context.WithValue(ctx, rspHeaderKey{}, &rspHeaderVal{})
md, ok := metadata.FromIncomingContext(ctx)
if !ok {
md = metadata.New(len(r.Header))
md = metadata.New(len(r.Header) + 8)
}
for k, v := range r.Header {
md.Set(k, strings.Join(v, ", "))
md[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)
md["RemoteAddr"] = r.RemoteAddr
if r.TLS != nil {
md["Scheme"] = "https"
} else {
md["Scheme"] = "http"
}
md["Method"] = r.Method
md["URL"] = r.URL.String()
md["Proto"] = r.Proto
md["ContentLength"] = fmt.Sprintf("%d", r.ContentLength)
if len(r.TransferEncoding) > 0 {
md["TransferEncoding"] = strings.Join(r.TransferEncoding, ",")
}
md["Host"] = r.Host
md["RequestURI"] = r.RequestURI
ctx = metadata.NewIncomingContext(ctx, md)
defer r.Body.Close()
ctx = metadata.NewOutgoingContext(ctx, metadata.New(0))
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, nil, w, r, err, 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 hldr *patHandler
var handler *httpHandler
fmt.Printf("try to find handler\n")
for _, hpat := range h.handlers {
handlertmp := hpat.(*httpHandler)
for _, hldrtmp := range handlertmp.handlers[r.Method] {
fmt.Printf("ssss method %v path %v %#+v\n", r.Method, path, hldrtmp)
_, mp, ok := hldrtmp.pat.Search(r.Method, path)
if ok {
match = true
for k, v := range mp {
matches[k] = v
for _, shdlr := range h.handlers {
hdlr := shdlr.(*httpHandler)
fh, mp, err := hdlr.handlers.Search(r.Method, path)
if err == nil {
match = true
for k, v := range mp {
matches[k] = v
}
hldr = fh.(*patHandler)
handler = hdlr
break
} else if err == rhttp.ErrMethodNotAllowed && !h.registerRPC {
h.errorHandler(ctx, nil, w, r, fmt.Errorf("not matching route found"), http.StatusMethodNotAllowed)
return
}
}
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, err := hdlr.handlers.Search(http.MethodPost, "/"+microMethod)
if err == nil {
match = true
for k, v := range mp {
matches[k] = v
}
hldr = fh.(*patHandler)
handler = hdlr
}
}
hldr = hldrtmp
handler = handlertmp
break
}
}
}
if !match {
var sp tracer.Span
if !match && h.hd != nil {
if hdlr, ok := h.hd.Handler().(http.Handler); ok {
endpointName := fmt.Sprintf("%s.%s", hldr.name, hldr.mtype.method.Name)
if !slices.Contains(tracer.DefaultSkipEndpoints, endpointName) {
ctx, sp = h.opts.Tracer.Start(ctx, "rpc-server",
tracer.WithSpanKind(tracer.SpanKindServer),
tracer.WithSpanLabels(
"endpoint", endpointName,
),
)
defer func() {
n := GetRspCode(ctx)
if s, _ := sp.Status(); s != tracer.SpanStatusError && n > 399 {
sp.SetStatus(tracer.SpanStatusError, http.StatusText(n))
}
sp.Finish()
}()
}
if !slices.Contains(meter.DefaultSkipEndpoints, endpointName) {
h.opts.Meter.Counter(semconv.ServerRequestInflight, "endpoint", endpointName, "server", "http").Inc()
defer func() {
n := GetRspCode(ctx)
if n > 399 {
h.opts.Meter.Counter(semconv.ServerRequestTotal, "endpoint", endpointName, "server", "http", "status", "success", "code", strconv.Itoa(n)).Inc()
} else {
h.opts.Meter.Counter(semconv.ServerRequestTotal, "endpoint", endpointName, "server", "http", "status", "failure", "code", strconv.Itoa(n)).Inc()
}
te := time.Since(ts)
h.opts.Meter.Summary(semconv.ServerRequestLatencyMicroseconds, "endpoint", endpointName, "server", "http").Update(te.Seconds())
h.opts.Meter.Histogram(semconv.ServerRequestDurationSeconds, "endpoint", endpointName, "server", "http").Update(te.Seconds())
h.opts.Meter.Counter(semconv.ServerRequestInflight, "endpoint", endpointName, "server", "http").Dec()
}()
}
hdlr.ServeHTTP(w, r.WithContext(ctx))
return
}
} else if !match {
// check for http.HandlerFunc handlers
if !slices.Contains(tracer.DefaultSkipEndpoints, r.URL.Path) {
ctx, sp = h.opts.Tracer.Start(ctx, "rpc-server",
tracer.WithSpanKind(tracer.SpanKindServer),
tracer.WithSpanLabels(
"endpoint", r.URL.Path,
"server", "http",
),
)
defer func() {
if n := GetRspCode(ctx); n > 399 {
sp.SetStatus(tracer.SpanStatusError, http.StatusText(n))
} else {
sp.SetStatus(tracer.SpanStatusError, http.StatusText(http.StatusNotFound))
}
sp.Finish()
}()
}
if ph, _, err := h.pathHandlers.Search(r.Method, r.URL.Path); err == nil {
ph.(http.HandlerFunc)(w, r.WithContext(ctx))
return
}
h.errorHandler(ctx, nil, w, r, fmt.Errorf("not matching route found"), http.StatusNotFound)
return
}
endpointName := fmt.Sprintf("%s.%s", hldr.name, hldr.mtype.method.Name)
topts := []tracer.SpanOption{
tracer.WithSpanKind(tracer.SpanKindServer),
tracer.WithSpanLabels(
"endpoint", endpointName,
"server", "http",
),
}
if slices.Contains(tracer.DefaultSkipEndpoints, endpointName) {
topts = append(topts, tracer.WithSpanRecord(false))
}
ctx, sp = h.opts.Tracer.Start(ctx, "rpc-server", topts...)
if !slices.Contains(meter.DefaultSkipEndpoints, handler.name) {
defer func() {
te := time.Since(ts)
h.opts.Meter.Summary(semconv.ServerRequestLatencyMicroseconds, "endpoint", handler.name, "server", "http").Update(te.Seconds())
h.opts.Meter.Histogram(semconv.ServerRequestDurationSeconds, "endpoint", handler.name, "server", "http").Update(te.Seconds())
h.opts.Meter.Counter(semconv.ServerRequestInflight, "endpoint", handler.name, "server", "http").Dec()
n := GetRspCode(ctx)
if n > 399 {
h.opts.Meter.Counter(semconv.ServerRequestTotal, "endpoint", handler.name, "server", "http", "status", "failure", "code", strconv.Itoa(n)).Inc()
} else {
h.opts.Meter.Counter(semconv.ServerRequestTotal, "endpoint", handler.name, "server", "http", "status", "success", "code", strconv.Itoa(n)).Inc()
}
}()
}
defer func() {
n := GetRspCode(ctx)
if n > 399 {
if s, _ := sp.Status(); s != tracer.SpanStatusError {
sp.SetStatus(tracer.SpanStatusError, http.StatusText(n))
}
}
sp.Finish()
}()
// get fields from url values
if len(r.URL.RawQuery) > 0 {
umd, cerr := rflutil.URLMap(r.URL.RawQuery)
@@ -152,6 +549,16 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
if r.Body != nil {
defer r.Body.Close()
}
cf, err := h.newCodec(ct)
if err != nil {
h.errorHandler(ctx, nil, w, r, err, http.StatusBadRequest)
return
}
var argv, replyv reflect.Value
// Decode the argument value.
@@ -171,24 +578,29 @@ 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 {
h.errorHandler(ctx, handler, w, r, err, http.StatusInternalServerError)
return
if r.Body != nil {
var buf []byte
buf, err = io.ReadAll(r.Body)
r.Body.Close()
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
if len(matches) > 0 {
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
}
}
hr := &rpcRequest{
@@ -196,14 +608,14 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
service: handler.sopts.Name,
contentType: ct,
method: fmt.Sprintf("%s.%s", hldr.name, hldr.mtype.method.Name),
body: b,
endpoint: fmt.Sprintf("%s.%s", hldr.name, hldr.mtype.method.Name),
payload: argv.Interface(),
header: md,
}
// define the handler func
fn := func(fctx context.Context, req server.Request, rsp interface{}) (err error) {
returnValues = function.Call([]reflect.Value{hldr.rcvr, hldr.mtype.prepareContext(fctx), reflect.ValueOf(argv.Interface()), reflect.ValueOf(rsp)})
returnValues = function.Call([]reflect.Value{hldr.rcvr, hldr.mtype.prepareContext(fctx), argv, reflect.ValueOf(rsp)})
// The return value for the method is an error.
if rerr := returnValues[0].Interface(); rerr != nil {
@@ -221,13 +633,18 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
metadata.SetOutgoingContext(ctx, md)
if err != nil && sp != nil {
sp.SetStatus(tracer.SpanStatusError, err.Error())
}
return err
}
// wrap the handler func
for i := len(handler.sopts.HdlrWrappers); i > 0; i-- {
fn = handler.sopts.HdlrWrappers[i-1](fn)
}
h.opts.Hooks.EachPrev(func(hook options.Hook) {
if h, ok := hook.(server.HookHandler); ok {
fn = h(fn)
}
})
if ct == "application/x-www-form-urlencoded" {
cf, err = h.newCodec(DefaultContentType)
@@ -241,44 +658,53 @@ func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
scode := int(200)
appErr := fn(ctx, hr, replyv.Interface())
w.Header().Set("Content-Type", ct)
w.Header().Set(metadata.HeaderContentType, 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 md := getRspHeader(ctx); md != nil {
for k, v := range md {
for _, vv := range v {
w.Header().Add(k, vv)
}
}
}
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)
h.errorHandler(ctx, nil, w, r, err, http.StatusInternalServerError)
return
}
}
var buf []byte
if appErr != nil {
switch verr := appErr.(type) {
case *errors.Error:
scode = int(verr.Code)
b, err = cf.Marshal(verr)
buf, err = cf.Marshal(verr)
case *Error:
b, err = cf.Marshal(verr.err)
buf, err = cf.Marshal(verr.err)
default:
b, err = cf.Marshal(appErr)
buf, err = cf.Marshal(appErr)
}
} else {
b, err = cf.Marshal(replyv.Interface())
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 {
if err != nil {
if handler.sopts.Logger.V(logger.ErrorLevel) {
handler.sopts.Logger.Error(handler.sopts.Context, "handler error", err)
}
scode = http.StatusInternalServerError
} else if nscode := GetRspCode(ctx); nscode != 0 {
scode = nscode
}
w.WriteHeader(scode)
if _, cerr := w.Write(b); cerr != nil {
logger.DefaultLogger.Errorf(ctx, "write failed: %v", cerr)
if _, cerr := w.Write(buf); cerr != nil {
handler.sopts.Logger.Error(ctx, "respoonse write error", cerr)
}
}

12
handler/generate.go Normal file
View File

@@ -0,0 +1,12 @@
package handler
import (
// import required packages
_ "go.unistack.org/micro-proto/v3/openapiv3"
)
//go:generate sh -c "curl -L https://github.com/swagger-api/swagger-ui/archive/refs/tags/v4.18.3.zip -o - | bsdtar -C swagger-ui --strip-components=2 -xv swagger-ui-4.18.3/dist && rm swagger-ui/*.map swagger-ui/*-es-*.js swagger-ui/swagger-ui.js swagger-ui/swagger-initializer.js"
//go:generate sh -c "protoc -I./ -I$(go list -f '{{ .Dir }}' -m go.unistack.org/micro-proto/v3) --go-micro_out='components=micro|http|server',standalone=false,debug=true,paths=source_relative:./ ./meter/meter.proto"
//go:generate sh -c "protoc -I./ -I$(go list -f '{{ .Dir }}' -m go.unistack.org/micro-proto/v3) --go-micro_out='components=micro|http|server',standalone=false,debug=true,paths=source_relative:./ ./health/health.proto"

View File

@@ -0,0 +1,77 @@
//go:build ignore
package graphql_handler
import (
"context"
"fmt"
"github.com/99designs/gqlgen/graphql"
"go.unistack.org/micro/v3/logger"
"go.unistack.org/micro/v3/store"
)
var _ graphql.Cache = (*cacheWrapper)(nil)
type Handler struct {
opts Options
}
type Option func(*Options)
type Options struct {
cache *cacheWrapper
Path string
}
type cacheWrapper struct {
s store.Store
l logger.Logger
}
func (c *cacheWrapper) Get(ctx context.Context, key string) (interface{}, bool) {
var val interface{}
if err := c.s.Read(ctx, key, val); err != nil && err != store.ErrNotFound {
c.l.Error(ctx, fmt.Sprintf("cache.Get %s failed", key), err)
return nil, false
}
return val, true
}
func (c *cacheWrapper) Add(ctx context.Context, key string, val interface{}) {
if err := c.s.Write(ctx, key, val); err != nil {
c.l.Error(ctx, fmt.Sprintf("cache.Add %s failed", key), err)
}
}
func Store(s store.Store) Option {
return func(o *Options) {
if o.cache == nil {
o.cache = &cacheWrapper{}
}
o.cache.s = s
}
}
func Logger(l logger.Logger) Option {
return func(o *Options) {
if o.cache == nil {
o.cache = &cacheWrapper{}
}
o.cache.l = l
}
}
func Path(path string) Option {
return func(o *Options) {
o.Path = path
}
}
func NewHandler(opts ...Option) *Handler {
options := Options{}
for _, o := range opts {
o(&options)
}
return &Handler{opts: options}
}

136
handler/health/health.go Normal file
View File

@@ -0,0 +1,136 @@
package health_handler
import (
"context"
codecpb "go.unistack.org/micro-proto/v3/codec"
"go.unistack.org/micro/v3/errors"
)
var _ HealthServiceServer = &Handler{}
type Handler struct {
opts Options
}
type (
CheckFunc func(context.Context) error
Option func(*Options)
)
type Stater interface {
Live() bool
Ready() bool
Health() bool
}
type Options struct {
Version string
Name string
Staters []Stater
LiveChecks []CheckFunc
ReadyChecks []CheckFunc
HealthChecks []CheckFunc
}
func Service(s ...Stater) Option {
return func(o *Options) {
o.Staters = append(o.Staters, s...)
}
}
func LiveChecks(fns ...CheckFunc) Option {
return func(o *Options) {
o.LiveChecks = append(o.LiveChecks, fns...)
}
}
func ReadyChecks(fns ...CheckFunc) Option {
return func(o *Options) {
o.ReadyChecks = append(o.ReadyChecks, fns...)
}
}
func HealthChecks(fns ...CheckFunc) Option {
return func(o *Options) {
o.HealthChecks = append(o.HealthChecks, fns...)
}
}
func Name(name string) Option {
return func(o *Options) {
o.Name = name
}
}
func Version(version string) Option {
return func(o *Options) {
o.Version = version
}
}
func NewHandler(opts ...Option) *Handler {
options := Options{}
for _, o := range opts {
o(&options)
}
return &Handler{opts: options}
}
func (h *Handler) Healthy(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
var err error
for _, s := range h.opts.Staters {
if !s.Health() {
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
}
}
for _, fn := range h.opts.HealthChecks {
if err = fn(ctx); err != nil {
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
}
}
return nil
}
func (h *Handler) Live(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
var err error
for _, s := range h.opts.Staters {
if !s.Live() {
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
}
}
for _, fn := range h.opts.LiveChecks {
if err = fn(ctx); err != nil {
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
}
}
return nil
}
func (h *Handler) Ready(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
var err error
for _, s := range h.opts.Staters {
if !s.Ready() {
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
}
}
for _, fn := range h.opts.ReadyChecks {
if err = fn(ctx); err != nil {
return errors.ServiceUnavailable(h.opts.Name, "%v", err)
}
}
return nil
}
func (h *Handler) Version(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
rsp.Data = []byte(h.opts.Version)
return nil
}

View File

@@ -0,0 +1,71 @@
syntax = "proto3";
package micro.server.http.v3.handler.health;
option go_package = "go.unistack.org/micro-server-http/v3/handler/health;health_handler";
import "api/annotations.proto";
import "openapiv3/annotations.proto";
import "codec/frame.proto";
service HealthService {
rpc Healthy(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv3.openapiv3_operation) = {
operation_id: "Healthy";
responses: {
default: {
reference: {
_ref: "micro.codec.Frame";
};
};
};
};
option (micro.api.http) = {
get: "/health";
additional_bindings: { get: "/healthz"; }
};
};
rpc Live(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv3.openapiv3_operation) = {
operation_id: "Live";
responses: {
default: {
reference: {
_ref: "micro.codec.Frame";
};
};
};
};
option (micro.api.http) = {
get: "/live";
additional_bindings: { get: "/livez"; }
};
};
rpc Ready(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv3.openapiv3_operation) = {
operation_id: "Ready";
responses: {
default: {
reference: {
_ref: "micro.codec.Frame";
};
};
};
};
option (micro.api.http) = { get: "/ready";
additional_bindings: { get: "/readyz"; }
};
};
rpc Version(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv3.openapiv3_operation) = {
operation_id: "Version";
responses: {
default: {
reference: {
_ref: "micro.codec.Frame";
};
};
};
};
option (micro.api.http) = { get: "/version"; };
};
};

View File

@@ -0,0 +1,31 @@
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
// versions:
// - protoc-gen-go-micro v3.10.4
// - protoc v5.28.3
// source: health/health.proto
package health_handler
import (
context "context"
codec "go.unistack.org/micro-proto/v3/codec"
client "go.unistack.org/micro/v3/client"
)
var (
HealthServiceName = "HealthService"
)
type HealthServiceClient interface {
Healthy(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
Live(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
Ready(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
Version(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
}
type HealthServiceServer interface {
Healthy(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
Live(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
Ready(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
Version(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
}

View File

@@ -0,0 +1,186 @@
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
// protoc-gen-go-micro version: v3.10.4
// source: health/health.proto
package health_handler
import (
context "context"
v31 "go.unistack.org/micro-client-http/v3"
codec "go.unistack.org/micro-proto/v3/codec"
v3 "go.unistack.org/micro-server-http/v3"
client "go.unistack.org/micro/v3/client"
server "go.unistack.org/micro/v3/server"
http "net/http"
)
var (
HealthServiceServerEndpoints = []v3.EndpointMetadata{
{
Name: "HealthService.Healthy",
Path: "/health",
Method: "GET",
Body: "",
Stream: false,
},
{
Name: "HealthService.Healthy",
Path: "/healthz",
Method: "GET",
Body: "",
Stream: false,
},
{
Name: "HealthService.Live",
Path: "/live",
Method: "GET",
Body: "",
Stream: false,
},
{
Name: "HealthService.Live",
Path: "/livez",
Method: "GET",
Body: "",
Stream: false,
},
{
Name: "HealthService.Ready",
Path: "/ready",
Method: "GET",
Body: "",
Stream: false,
},
{
Name: "HealthService.Ready",
Path: "/readyz",
Method: "GET",
Body: "",
Stream: false,
},
{
Name: "HealthService.Version",
Path: "/version",
Method: "GET",
Body: "",
Stream: false,
},
}
)
type healthServiceClient struct {
c client.Client
name string
}
func NewHealthServiceClient(name string, c client.Client) HealthServiceClient {
return &healthServiceClient{c: c, name: name}
}
func (c *healthServiceClient) Healthy(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
errmap := make(map[string]interface{}, 1)
errmap["default"] = &codec.Frame{}
opts = append(opts,
v31.ErrorMap(errmap),
)
opts = append(opts,
v31.Method(http.MethodGet),
v31.Path("/health"),
)
rsp := &codec.Frame{}
err := c.c.Call(ctx, c.c.NewRequest(c.name, "HealthService.Healthy", req), rsp, opts...)
if err != nil {
return nil, err
}
return rsp, nil
}
func (c *healthServiceClient) Live(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
errmap := make(map[string]interface{}, 1)
errmap["default"] = &codec.Frame{}
opts = append(opts,
v31.ErrorMap(errmap),
)
opts = append(opts,
v31.Method(http.MethodGet),
v31.Path("/live"),
)
rsp := &codec.Frame{}
err := c.c.Call(ctx, c.c.NewRequest(c.name, "HealthService.Live", req), rsp, opts...)
if err != nil {
return nil, err
}
return rsp, nil
}
func (c *healthServiceClient) Ready(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
errmap := make(map[string]interface{}, 1)
errmap["default"] = &codec.Frame{}
opts = append(opts,
v31.ErrorMap(errmap),
)
opts = append(opts,
v31.Method(http.MethodGet),
v31.Path("/ready"),
)
rsp := &codec.Frame{}
err := c.c.Call(ctx, c.c.NewRequest(c.name, "HealthService.Ready", req), rsp, opts...)
if err != nil {
return nil, err
}
return rsp, nil
}
func (c *healthServiceClient) Version(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
errmap := make(map[string]interface{}, 1)
errmap["default"] = &codec.Frame{}
opts = append(opts,
v31.ErrorMap(errmap),
)
opts = append(opts,
v31.Method(http.MethodGet),
v31.Path("/version"),
)
rsp := &codec.Frame{}
err := c.c.Call(ctx, c.c.NewRequest(c.name, "HealthService.Version", req), rsp, opts...)
if err != nil {
return nil, err
}
return rsp, nil
}
type healthServiceServer struct {
HealthServiceServer
}
func (h *healthServiceServer) Healthy(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
return h.HealthServiceServer.Healthy(ctx, req, rsp)
}
func (h *healthServiceServer) Live(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
return h.HealthServiceServer.Live(ctx, req, rsp)
}
func (h *healthServiceServer) Ready(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
return h.HealthServiceServer.Ready(ctx, req, rsp)
}
func (h *healthServiceServer) Version(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
return h.HealthServiceServer.Version(ctx, req, rsp)
}
func RegisterHealthServiceServer(s server.Server, sh HealthServiceServer, opts ...server.HandlerOption) error {
type healthService interface {
Healthy(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
Live(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
Ready(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
Version(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
}
type HealthService struct {
healthService
}
h := &healthServiceServer{sh}
var nopts []server.HandlerOption
nopts = append(nopts, v3.HandlerEndpoints(HealthServiceServerEndpoints))
return s.Handle(s.NewHandler(&HealthService{h}, append(nopts, opts...)...))
}

132
handler/meter/meter.go Normal file
View File

@@ -0,0 +1,132 @@
package meter_handler
import (
"bytes"
"compress/gzip"
"context"
"io"
"strings"
"sync"
codecpb "go.unistack.org/micro-proto/v3/codec"
"go.unistack.org/micro/v3/logger"
"go.unistack.org/micro/v3/metadata"
"go.unistack.org/micro/v3/meter"
)
const (
contentEncodingHeader = "Content-Encoding"
acceptEncodingHeader = "Accept-Encoding"
)
var gzipPool = sync.Pool{
New: func() interface{} {
return gzip.NewWriter(nil)
},
}
var bufPool = sync.Pool{
New: func() interface{} {
return bytes.NewBuffer(nil)
},
}
// guard to fail early
var _ MeterServiceServer = &Handler{}
type Handler struct {
Options Options
}
type Option func(*Options)
type Options struct {
Meter meter.Meter
Name string
MeterOptions []meter.Option
DisableCompress bool
}
func Meter(m meter.Meter) Option {
return func(o *Options) {
o.Meter = m
}
}
func Name(name string) Option {
return func(o *Options) {
o.Name = name
}
}
func DisableCompress(g bool) Option {
return func(o *Options) {
o.DisableCompress = g
}
}
func MeterOptions(opts ...meter.Option) Option {
return func(o *Options) {
o.MeterOptions = append(o.MeterOptions, opts...)
}
}
func NewOptions(opts ...Option) Options {
options := Options{Meter: meter.DefaultMeter, DisableCompress: false}
for _, o := range opts {
o(&options)
}
return options
}
func NewHandler(opts ...Option) *Handler {
options := NewOptions(opts...)
return &Handler{Options: options}
}
func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
log, ok := logger.FromContext(ctx)
if !ok {
log = logger.DefaultLogger
}
buf := bufPool.Get().(*bytes.Buffer)
defer bufPool.Put(buf)
buf.Reset()
w := io.Writer(buf)
if md, ok := metadata.FromOutgoingContext(ctx); gzipAccepted(md) && ok && !h.Options.DisableCompress {
omd, _ := metadata.FromOutgoingContext(ctx)
omd.Set(contentEncodingHeader, "gzip")
gz := gzipPool.Get().(*gzip.Writer)
defer gzipPool.Put(gz)
gz.Reset(w)
defer gz.Close()
w = gz
gz.Flush()
}
if err := h.Options.Meter.Write(w, h.Options.MeterOptions...); err != nil {
log.Error(ctx, "http/meter write failed", err)
return nil
}
rsp.Data = buf.Bytes()
return nil
}
// gzipAccepted returns whether the client will accept gzip-encoded content.
func gzipAccepted(md metadata.Metadata) bool {
a, ok := md.Get(acceptEncodingHeader)
if !ok {
return false
}
if strings.Contains(a, "gzip") {
return true
}
return false
}

24
handler/meter/meter.proto Normal file
View File

@@ -0,0 +1,24 @@
syntax = "proto3";
package micro.server.http.v3.handler.meter;
option go_package = "go.unistack.org/micro-server-http/v3/handler/meter;meter_handler";
import "api/annotations.proto";
import "openapiv3/annotations.proto";
import "codec/frame.proto";
service MeterService {
rpc Metrics(micro.codec.Frame) returns (micro.codec.Frame) {
option (micro.openapiv3.openapiv3_operation) = {
operation_id: "Metrics";
responses: {
default: {
reference: {
_ref: "micro.codec.Frame";
};
};
};
};
option (micro.api.http) = { get: "/metrics"; };
};
};

View File

@@ -0,0 +1,25 @@
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
// versions:
// - protoc-gen-go-micro v3.10.4
// - protoc v5.28.3
// source: meter/meter.proto
package meter_handler
import (
context "context"
codec "go.unistack.org/micro-proto/v3/codec"
client "go.unistack.org/micro/v3/client"
)
var (
MeterServiceName = "MeterService"
)
type MeterServiceClient interface {
Metrics(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error)
}
type MeterServiceServer interface {
Metrics(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
}

View File

@@ -0,0 +1,75 @@
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
// protoc-gen-go-micro version: v3.10.4
// source: meter/meter.proto
package meter_handler
import (
context "context"
v31 "go.unistack.org/micro-client-http/v3"
codec "go.unistack.org/micro-proto/v3/codec"
v3 "go.unistack.org/micro-server-http/v3"
client "go.unistack.org/micro/v3/client"
server "go.unistack.org/micro/v3/server"
http "net/http"
)
var (
MeterServiceServerEndpoints = []v3.EndpointMetadata{
{
Name: "MeterService.Metrics",
Path: "/metrics",
Method: "GET",
Body: "",
Stream: false,
},
}
)
type meterServiceClient struct {
c client.Client
name string
}
func NewMeterServiceClient(name string, c client.Client) MeterServiceClient {
return &meterServiceClient{c: c, name: name}
}
func (c *meterServiceClient) Metrics(ctx context.Context, req *codec.Frame, opts ...client.CallOption) (*codec.Frame, error) {
errmap := make(map[string]interface{}, 1)
errmap["default"] = &codec.Frame{}
opts = append(opts,
v31.ErrorMap(errmap),
)
opts = append(opts,
v31.Method(http.MethodGet),
v31.Path("/metrics"),
)
rsp := &codec.Frame{}
err := c.c.Call(ctx, c.c.NewRequest(c.name, "MeterService.Metrics", req), rsp, opts...)
if err != nil {
return nil, err
}
return rsp, nil
}
type meterServiceServer struct {
MeterServiceServer
}
func (h *meterServiceServer) Metrics(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error {
return h.MeterServiceServer.Metrics(ctx, req, rsp)
}
func RegisterMeterServiceServer(s server.Server, sh MeterServiceServer, opts ...server.HandlerOption) error {
type meterService interface {
Metrics(ctx context.Context, req *codec.Frame, rsp *codec.Frame) error
}
type MeterService struct {
meterService
}
h := &meterServiceServer{sh}
var nopts []server.HandlerOption
nopts = append(nopts, v3.HandlerEndpoints(MeterServiceServerEndpoints))
return s.Handle(s.NewHandler(&MeterService{h}, append(nopts, opts...)...))
}

46
handler/pprof/pprof.go Normal file
View File

@@ -0,0 +1,46 @@
package pprof_handler
import (
"expvar"
"net/http"
"net/http/pprof"
"path"
"strings"
)
func NewHandler(prefixPath string, initFuncs ...func()) http.HandlerFunc {
for _, fn := range initFuncs {
fn()
}
return func(w http.ResponseWriter, r *http.Request) {
switch {
case strings.EqualFold(r.RequestURI, prefixPath) && r.RequestURI[len(r.RequestURI)-1] != '/':
http.Redirect(w, r, r.RequestURI+"/", http.StatusMovedPermanently)
case strings.HasPrefix(r.RequestURI, path.Join(prefixPath, "cmdline")):
pprof.Cmdline(w, r)
case strings.HasPrefix(r.RequestURI, path.Join(prefixPath, "profile")):
pprof.Profile(w, r)
case strings.HasPrefix(r.RequestURI, path.Join(prefixPath, "symbol")):
pprof.Symbol(w, r)
case strings.HasPrefix(r.RequestURI, path.Join(prefixPath, "trace")):
pprof.Trace(w, r)
case strings.HasPrefix(r.RequestURI, path.Join(prefixPath, "goroutine")):
pprof.Handler("goroutine").ServeHTTP(w, r)
case strings.HasPrefix(r.RequestURI, path.Join(prefixPath, "threadcreate")):
pprof.Handler("threadcreate").ServeHTTP(w, r)
case strings.HasPrefix(r.RequestURI, path.Join(prefixPath, "mutex")):
pprof.Handler("mutex").ServeHTTP(w, r)
case strings.HasPrefix(r.RequestURI, path.Join(prefixPath, "heap")):
pprof.Handler("heap").ServeHTTP(w, r)
case strings.HasPrefix(r.RequestURI, path.Join(prefixPath, "block")):
pprof.Handler("block").ServeHTTP(w, r)
case strings.HasPrefix(r.RequestURI, path.Join(prefixPath, "allocs")):
pprof.Handler("allocs").ServeHTTP(w, r)
case strings.HasPrefix(r.RequestURI, path.Join(prefixPath, "vars")):
expvar.Handler().ServeHTTP(w, r)
default:
pprof.Index(w, r)
}
}
}

19
handler/spa/spa.go Normal file
View File

@@ -0,0 +1,19 @@
package spa
import (
"io/fs"
"net/http"
"strings"
)
// Handler serve files from dir and redirect to index if file not exists
var Handler = func(prefix string, dir fs.FS) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
f := http.StripPrefix(prefix, http.FileServer(http.FS(dir)))
if _, err := fs.Stat(dir, strings.TrimPrefix(r.RequestURI, prefix)); err != nil {
r.RequestURI = prefix
r.URL.Path = prefix
}
f.ServeHTTP(w, r)
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 665 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 628 B

View File

@@ -0,0 +1,16 @@
html {
box-sizing: border-box;
overflow: -moz-scrollbars-vertical;
overflow-y: scroll;
}
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
margin: 0;
background: #fafafa;
}

View File

@@ -0,0 +1,19 @@
<!-- HTML for static distribution bundle build -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Swagger UI</title>
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="index.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
</head>
<body>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script src="./swagger-initializer.js" charset="UTF-8"> </script>
</body>
</html>

View File

@@ -0,0 +1,79 @@
<!doctype html>
<html lang="en-US">
<head>
<title>Swagger UI: OAuth2 Redirect</title>
</head>
<body>
<script>
'use strict';
function run () {
var oauth2 = window.opener.swaggerUIRedirectOauth2;
var sentState = oauth2.state;
var redirectUrl = oauth2.redirectUrl;
var isValid, qp, arr;
if (/code|token|error/.test(window.location.hash)) {
qp = window.location.hash.substring(1).replace('?', '&');
} else {
qp = location.search.substring(1);
}
arr = qp.split("&");
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
qp = qp ? JSON.parse('{' + arr.join() + '}',
function (key, value) {
return key === "" ? value : decodeURIComponent(value);
}
) : {};
isValid = qp.state === sentState;
if ((
oauth2.auth.schema.get("flow") === "accessCode" ||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
oauth2.auth.schema.get("flow") === "authorization_code"
) && !oauth2.auth.code) {
if (!isValid) {
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "warning",
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
});
}
if (qp.code) {
delete oauth2.state;
oauth2.auth.code = qp.code;
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
} else {
let oauthErrorMsg;
if (qp.error) {
oauthErrorMsg = "["+qp.error+"]: " +
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
(qp.error_uri ? "More info: "+qp.error_uri : "");
}
oauth2.errCb({
authId: oauth2.auth.name,
source: "auth",
level: "error",
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
});
}
} else {
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
}
window.close();
}
if (document.readyState !== 'loading') {
run();
} else {
document.addEventListener('DOMContentLoaded', function () {
run();
});
}
</script>
</body>
</html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,142 @@
package swaggerui_handler
import (
"embed"
"html/template"
"net/http"
"path"
"reflect"
)
//go:embed *.js *.css *.html *.png
var assets embed.FS
var (
Handler = func(prefix string) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet || path.Base(r.URL.Path) != "swagger-initializer.js" {
http.StripPrefix(prefix, http.FileServer(http.FS(assets))).ServeHTTP(w, r)
return
}
tpl := template.New("swagger-initializer.js").Funcs(TemplateFuncs)
ptpl, err := tpl.Parse(Template)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
if err := ptpl.Execute(w, Config); err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
}
}
TemplateFuncs = template.FuncMap{
"isInt": func(i interface{}) bool {
v := reflect.ValueOf(i)
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
return true
default:
return false
}
},
"isBool": func(i interface{}) bool {
v := reflect.ValueOf(i)
switch v.Kind() {
case reflect.Bool:
return true
default:
return false
}
},
"isString": func(i interface{}) bool {
v := reflect.ValueOf(i)
switch v.Kind() {
case reflect.String:
return true
default:
return false
}
},
"isSlice": func(i interface{}) bool {
v := reflect.ValueOf(i)
switch v.Kind() {
case reflect.Slice:
return true
default:
return false
}
},
"isMap": func(i interface{}) bool {
v := reflect.ValueOf(i)
switch v.Kind() {
case reflect.Map:
return true
default:
return false
}
},
}
Template = `
window.onload = function() {
//<editor-fold desc="Changeable Configuration Block">
window.ui = SwaggerUIBundle({
{{- range $k, $v := . }}
{{- if (eq (printf "%s" $v) "") -}}
{{- continue -}}
{{ end }}
{{ $k }}: {{ if isBool $v -}}
{{- $v -}},
{{- else if isInt $v -}}
{{- $v -}},
{{- else if isString $v -}}
"{{- $v -}}",
{{- else if and (isSlice $v) (or (eq (printf "%s" $k) "presets") (eq (printf "%s" $k) "plugins")) -}}
[
{{- range $v }}
{{ . }},
{{- end }}
],
{{- end -}}
{{ end }}
});
//</editor-fold>
};`
Config = map[string]interface{}{
"configUrl": "",
"dom_id": "#swagger-ui",
/*
"domNode": "",
"spec": "",
"urls": []interface{}{
map[string]interface{}{
"url": "",
"name": "",
},
},
},
*/
"url": "https://petstore.swagger.io/v2/swagger.json",
"deepLinking": true,
"displayOperationId": false,
"defaultModelsExpandDepth": 1,
"defaultModelExpandDepth": 1,
"displayRequestDuration": true,
"filter": true,
"operationsSorter": "alpha",
"showExtensions": true,
"tryItOutEnabled": true,
"presets": []string{
"SwaggerUIBundle.presets.apis",
"SwaggerUIStandalonePreset",
},
"plugins": []string{
"SwaggerUIBundle.plugins.DownloadUrl",
},
"layout": "StandaloneLayout",
}
)

View File

@@ -0,0 +1,15 @@
package swaggerui_handler
import (
"net/http"
"testing"
)
func TestTemplate(t *testing.T) {
t.Skip()
h := http.NewServeMux()
h.HandleFunc("/", Handler(""))
if err := http.ListenAndServe(":8080", h); err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,61 @@
package swagger_handler
import (
"io/fs"
"net/http"
yamlcodec "go.unistack.org/micro-codec-yaml/v3"
rutil "go.unistack.org/micro/v3/util/reflect"
)
// Handler append to generated swagger data from dst map[string]interface{}
var Handler = func(dst map[string]interface{}, fsys fs.FS) http.HandlerFunc {
c := yamlcodec.NewCodec()
return func(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusNotFound)
return
}
path := r.URL.Path
if len(path) > 1 && path[0] == '/' {
path = path[1:]
}
buf, err := fs.ReadFile(fsys, path)
if err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
if dst == nil {
w.WriteHeader(http.StatusOK)
_, _ = w.Write(buf)
return
}
var src interface{}
if err = c.Unmarshal(buf, src); err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
if err = rutil.Merge(src, dst); err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
if buf, err = c.Marshal(src); err != nil {
w.WriteHeader(http.StatusInternalServerError)
_, _ = w.Write([]byte(err.Error()))
return
}
w.WriteHeader(http.StatusOK)
_, _ = w.Write(buf)
}
}

362
http.go
View File

@@ -1,9 +1,10 @@
// 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"
@@ -11,46 +12,39 @@ import (
"sort"
"strings"
"sync"
"sync/atomic"
"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"
rhttp "github.com/unistack-org/micro/v3/util/http"
"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 httpAllMethods = []string{
http.MethodConnect,
http.MethodDelete,
http.MethodGet,
http.MethodHead,
http.MethodOptions,
http.MethodPatch,
http.MethodPost,
http.MethodPut,
http.MethodTrace,
}
var _ server.Server = (*Server)(nil)
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
contentTypeHandlers map[string]http.HandlerFunc
opts server.Options
registerRPC bool
type Server 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
stateLive *atomic.Uint32
stateReady *atomic.Uint32
stateHealth *atomic.Uint32
registerRPC bool
sync.RWMutex
registered bool
init bool
}
func (h *httpServer) newCodec(ct string) (codec.Codec, error) {
func (h *Server) newCodec(ct string) (codec.Codec, error) {
if idx := strings.IndexRune(ct, ';'); idx >= 0 {
ct = ct[:idx]
}
@@ -63,14 +57,14 @@ func (h *httpServer) newCodec(ct string) (codec.Codec, error) {
return nil, codec.ErrUnknownContentType
}
func (h *httpServer) Options() server.Options {
func (h *Server) Options() server.Options {
h.Lock()
opts := h.opts
h.Unlock()
return opts
}
func (h *httpServer) Init(opts ...server.Option) error {
func (h *Server) Init(opts ...server.Option) error {
if len(opts) == 0 && h.init {
return nil
}
@@ -89,22 +83,19 @@ func (h *httpServer) Init(opts ...server.Option) error {
if h.pathHandlers == nil {
h.pathHandlers = rhttp.NewTrie()
}
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 {
h.pathHandlers.Insert(httpAllMethods, pp, ph)
}
}
if phs, ok := h.opts.Context.Value(contentTypeHandlerKey{}).(*contentTypeHandlerVal); ok && phs.h != nil {
for pp, ph := range phs.h {
h.contentTypeHandlers[pp] = ph
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()
@@ -122,10 +113,6 @@ func (h *httpServer) Init(opts ...server.Option) error {
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
@@ -134,10 +121,7 @@ func (h *httpServer) Init(opts ...server.Option) error {
h.RUnlock()
return err
}
if err := h.opts.Transport.Init(); err != nil {
h.RUnlock()
return err
}
h.RUnlock()
h.Lock()
@@ -147,7 +131,8 @@ func (h *httpServer) Init(opts ...server.Option) error {
return nil
}
func (h *httpServer) Handle(handler server.Handler) error {
func (h *Server) Handle(handler server.Handler) error {
// passed unknown handler
hdlr, ok := handler.(*httpHandler)
if !ok {
h.Lock()
@@ -156,6 +141,7 @@ func (h *httpServer) Handle(handler server.Handler) error {
return nil
}
// passed http.Handler like some muxer
if _, ok := hdlr.hd.(http.Handler); ok {
h.Lock()
h.hd = handler
@@ -163,6 +149,7 @@ func (h *httpServer) Handle(handler server.Handler) error {
return nil
}
// passed micro compat handler
h.Lock()
if h.handlers == nil {
h.handlers = make(map[string]server.Handler)
@@ -173,32 +160,35 @@ func (h *httpServer) Handle(handler server.Handler) error {
return nil
}
func (h *httpServer) NewHandler(handler interface{}, opts ...server.HandlerOption) server.Handler {
func (h *Server) NewHandler(handler interface{}, opts ...server.HandlerOption) server.Handler {
options := server.NewHandlerOptions(opts...)
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{
eps: eps,
hd: handler,
opts: options,
sopts: h.opts,
hd: handler,
opts: options,
sopts: h.opts,
handlers: rhttp.NewTrie(),
}
tp := reflect.TypeOf(handler)
type nilHandler struct{}
hdlr.handlers = make(map[string][]patHandler)
/*
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)
}
}
}
*/
registerCORS := false
if v, ok := options.Context.Value(registerCORSHandlerKey{}).(bool); ok && v {
registerCORS = true
}
for hn, md := range options.Metadata {
pat := rhttp.NewTrie()
pat.Insert([]string{md["Method"]}, md["Path"], &nilHandler{})
var method reflect.Method
mname := hn[strings.Index(hn, ".")+1:]
for m := 0; m < tp.NumMethod(); m++ {
@@ -211,44 +201,114 @@ func (h *httpServer) NewHandler(handler interface{}, opts ...server.HandlerOptio
}
if method.Name == "" && h.opts.Logger.V(logger.ErrorLevel) {
h.opts.Logger.Errorf(h.opts.Context, "nil method for %s", mname)
h.opts.Logger.Error(h.opts.Context, fmt.Sprintf("nil method for %s", mname))
continue
}
mtype, err := prepareEndpoint(method)
if err != nil && h.opts.Logger.V(logger.ErrorLevel) {
h.opts.Logger.Errorf(h.opts.Context, "%v", err)
h.opts.Logger.Error(h.opts.Context, "endpoint error", err)
continue
} else if mtype == nil {
h.opts.Logger.Error(h.opts.Context, fmt.Sprintf("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 !h.registerRPC {
methods := []string{md["Method"]}
if registerCORS {
methods = append(methods, http.MethodOptions)
}
if err := hdlr.handlers.Insert(methods, md["Path"], pth); err != nil {
h.opts.Logger.Error(h.opts.Context, fmt.Sprintf("cant add handler for %v %s", methods, md["Path"]))
}
if h.registerRPC {
methods := []string{http.MethodPost}
if registerCORS {
methods = append(methods, http.MethodOptions)
}
if err := hdlr.handlers.Insert(methods, "/"+hn, pth); err != nil {
h.opts.Logger.Error(h.opts.Context, fmt.Sprintf("cant add rpc handler for http.MethodPost %s /%s", hn, hn))
}
}
}
metadata, ok := options.Context.Value(handlerEndpointsKey{}).([]EndpointMetadata)
if !ok {
return hdlr
}
for _, md := range metadata {
hn := md.Name
var method reflect.Method
mname := hn[strings.Index(hn, ".")+1:]
for m := 0; m < tp.NumMethod(); m++ {
mn := tp.Method(m)
if mn.Name != mname {
continue
}
method = mn
break
}
if method.Name == "" && h.opts.Logger.V(logger.ErrorLevel) {
h.opts.Logger.Error(h.opts.Context, fmt.Sprintf("nil method for %s", mname))
continue
}
rpat := rhttp.NewTrie()
rpat.Insert([]string{http.MethodPost}, "/"+hn, &nilHandler{})
mtype, err := prepareEndpoint(method)
if err != nil && h.opts.Logger.V(logger.ErrorLevel) {
h.opts.Logger.Error(h.opts.Context, "prepare endpoint error", err)
continue
} else if mtype == nil {
h.opts.Logger.Error(h.opts.Context, fmt.Sprintf("nil mtype for %s", mname))
continue
}
pth = patHandler{pat: rpat, mtype: mtype, name: name, rcvr: rcvr}
hdlr.handlers[http.MethodPost] = append(hdlr.handlers[http.MethodPost], pth)
rcvr := reflect.ValueOf(handler)
name := reflect.Indirect(rcvr).Type().Name()
pth := &patHandler{mtype: mtype, name: name, rcvr: rcvr}
hdlr.name = name
methods := []string{md.Method}
if registerCORS {
methods = append(methods, http.MethodOptions)
}
if err := hdlr.handlers.Insert(methods, md.Path, pth); err != nil {
h.opts.Logger.Error(h.opts.Context, fmt.Sprintf("cant add handler for %s %s", md.Method, md.Path))
}
if h.registerRPC {
methods := []string{http.MethodPost}
if registerCORS {
methods = append(methods, http.MethodOptions)
}
h.opts.Logger.Info(h.opts.Context, fmt.Sprintf("register rpc handler for http.MethodPost %s /%s", hn, hn))
if err := hdlr.handlers.Insert(methods, "/"+hn, pth); err != nil {
h.opts.Logger.Error(h.opts.Context, fmt.Sprintf("cant add rpc handler for http.MethodPost %s /%s", hn, hn))
}
}
}
return hdlr
}
func (h *httpServer) NewSubscriber(topic string, handler interface{}, opts ...server.SubscriberOption) server.Subscriber {
func (h *Server) NewSubscriber(topic string, handler interface{}, opts ...server.SubscriberOption) server.Subscriber {
return newSubscriber(topic, handler, opts...)
}
func (h *httpServer) Subscribe(sb server.Subscriber) error {
func (h *Server) Subscribe(sb server.Subscriber) error {
sub, ok := sb.(*httpSubscriber)
if !ok {
return fmt.Errorf("invalid subscriber: expected *httpSubscriber")
@@ -273,12 +333,8 @@ func (h *httpServer) Subscribe(sb server.Subscriber) error {
return nil
}
func (h *httpServer) Register() error {
var eps []*register.Endpoint
func (h *Server) Register() error {
h.RLock()
for _, hdlr := range h.handlers {
eps = append(eps, hdlr.Endpoints()...)
}
rsvc := h.rsvc
config := h.opts
h.RUnlock()
@@ -295,8 +351,6 @@ func (h *httpServer) Register() error {
if err != nil {
return err
}
service.Nodes[0].Metadata["protocol"] = "http"
service.Endpoints = eps
h.Lock()
subscriberList := make([]*httpSubscriber, 0, len(h.subscribers))
@@ -308,9 +362,6 @@ func (h *httpServer) Register() error {
return subscriberList[i].topic > subscriberList[j].topic
})
for _, e := range subscriberList {
service.Endpoints = append(service.Endpoints, e.Endpoints()...)
}
h.Unlock()
h.RLock()
@@ -319,7 +370,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.Info(config.Context, fmt.Sprintf("Register [%s] Registering node: %s", config.Register.String(), service.Nodes[0].ID))
}
}
@@ -334,6 +385,17 @@ func (h *httpServer) Register() error {
}
h.Lock()
h.registered = true
h.rsvc = service
h.Unlock()
return nil
}
func (h *Server) subscribe() error {
config := h.opts
for sb := range h.subscribers {
handler := h.createSubHandler(sb, config)
var opts []broker.SubscribeOption
@@ -347,6 +409,7 @@ func (h *httpServer) Register() error {
}
opts = append(opts, broker.SubscribeContext(subCtx))
opts = append(opts, broker.SubscribeAutoAck(sb.Options().AutoAck))
opts = append(opts, broker.SubscribeBodyOnly(sb.Options().BodyOnly))
sub, err := config.Broker.Subscribe(subCtx, sb.Topic(), handler, opts...)
if err != nil {
@@ -356,14 +419,10 @@ func (h *httpServer) Register() error {
h.subscribers[sb] = []broker.Subscriber{sub}
}
h.registered = true
h.rsvc = service
h.Unlock()
return nil
}
func (h *httpServer) Deregister() error {
func (h *Server) Deregister() error {
h.RLock()
config := h.opts
h.RUnlock()
@@ -374,7 +433,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.Info(config.Context, "Deregistering node: "+service.Nodes[0].ID)
}
if err := server.DefaultDeregisterFunc(service, config); err != nil {
@@ -398,10 +457,10 @@ func (h *httpServer) Deregister() error {
}
for _, sub := range subs {
config.Logger.Infof(config.Context, "Unsubscribing from topic: %s", sub.Topic())
config.Logger.Info(config.Context, "Unsubscribing from topic: "+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)
config.Logger.Error(config.Context, fmt.Sprintf("failed to unsubscribe topic: %s, error", sb.Topic()), err)
return err
}
}
@@ -411,7 +470,7 @@ func (h *httpServer) Deregister() error {
return nil
}
func (h *httpServer) Start() error {
func (h *Server) Start() error {
h.RLock()
config := h.opts
h.RUnlock()
@@ -441,7 +500,7 @@ func (h *httpServer) Start() error {
}
if config.Logger.V(logger.InfoLevel) {
config.Logger.Infof(config.Context, "Listening on %s", ts.Addr().String())
config.Logger.Info(config.Context, "Listening on "+ts.Addr().String())
}
h.Lock()
@@ -449,7 +508,6 @@ func (h *httpServer) Start() error {
h.Unlock()
var handler http.Handler
var srvFunc func(net.Listener) error
// nolint: nestif
if h.opts.Context != nil {
@@ -465,9 +523,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
}
@@ -483,7 +544,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.Error(config.Context, fmt.Sprintf("Server %s-%s register check error", config.Name, config.ID), err)
}
} else {
if err = h.Register(); err != nil {
@@ -491,8 +552,13 @@ func (h *httpServer) Start() error {
}
}
if err := h.subscribe(); err != nil {
return err
}
fn := handler
var hs *http.Server
if h.opts.Context != nil {
if mwf, ok := h.opts.Context.Value(middlewareKey{}).([]func(http.Handler) http.Handler); ok && len(mwf) > 0 {
// wrap the handler func
@@ -500,25 +566,22 @@ func (h *httpServer) Start() error {
fn = mwf[i-1](fn)
}
}
if hs, ok := h.opts.Context.Value(serverKey{}).(*http.Server); ok && hs != nil {
var ok bool
if hs, ok = h.opts.Context.Value(serverKey{}).(*http.Server); ok && hs != nil {
hs.Handler = fn
srvFunc = hs.Serve
} else {
hs = &http.Server{Handler: fn}
}
}
if srvFunc != nil {
go func() {
if cerr := srvFunc(ts); cerr != nil && !strings.Contains(cerr.Error(), "use of closed network connection") {
h.opts.Logger.Error(h.opts.Context, cerr)
}
}()
} else {
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() {
if cerr := hs.Serve(ts); cerr != nil && !errors.Is(cerr, http.ErrServerClosed) {
h.opts.Logger.Error(h.opts.Context, "serve error", cerr)
}
h.stateLive.Store(0)
h.stateReady.Store(0)
h.stateHealth.Store(0)
}()
go func() {
t := new(time.Ticker)
@@ -544,28 +607,28 @@ func (h *httpServer) Start() error {
// 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.Error(config.Context, fmt.Sprintf("Server %s-%s register check error, 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.Error(config.Context, fmt.Sprintf("Server %s-%s deregister error", 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.Error(config.Context, fmt.Sprintf("Server %s-%s register check error", 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.Error(config.Context, fmt.Sprintf("Server %s-%s register error", config.Name, config.ID), err)
}
}
if err := h.Register(); err != nil {
config.Logger.Errorf(config.Context, "Server register error: %s", err)
config.Logger.Error(config.Context, "Server register error", err)
}
// wait for exit
case ch = <-h.exit:
@@ -575,40 +638,71 @@ func (h *httpServer) Start() error {
// deregister
if err := h.Deregister(); err != nil {
config.Logger.Errorf(config.Context, "Server deregister error: %s", err)
config.Logger.Error(config.Context, "Server deregister error", err)
}
if err := config.Broker.Disconnect(config.Context); err != nil {
config.Logger.Errorf(config.Context, "Broker disconnect error: %s", err)
config.Logger.Error(config.Context, "Broker disconnect error", err)
}
ch <- ts.Close()
ctx, cancel := context.WithTimeout(context.Background(), h.opts.GracefulTimeout)
defer cancel()
err := hs.Shutdown(ctx)
if err != nil {
err = hs.Close()
}
ch <- err
}()
h.stateLive.Store(1)
h.stateReady.Store(1)
h.stateHealth.Store(1)
return nil
}
func (h *httpServer) Stop() error {
func (h *Server) Stop() error {
ch := make(chan error)
h.exit <- ch
return <-ch
}
func (h *httpServer) String() string {
func (h *Server) String() string {
return "http"
}
func (h *httpServer) Name() string {
func (h *Server) Name() string {
return h.opts.Name
}
func NewServer(opts ...server.Option) server.Server {
func (h *Server) Live() bool {
return h.stateLive.Load() == 1
}
func (h *Server) Ready() bool {
return h.stateReady.Load() == 1
}
func (h *Server) Health() bool {
return h.stateHealth.Load() == 1
}
func NewServer(opts ...server.Option) *Server {
options := server.NewOptions(opts...)
return &httpServer{
eh := DefaultErrorHandler
if v, ok := options.Context.Value(errorHandlerKey{}).(errorHandler); ok && v != nil {
eh = v
}
return &Server{
stateLive: &atomic.Uint32{},
stateReady: &atomic.Uint32{},
stateHealth: &atomic.Uint32{},
opts: options,
exit: make(chan chan error),
subscribers: make(map[*httpSubscriber][]broker.Subscriber),
errorHandler: DefaultErrorHandler,
errorHandler: eh,
pathHandlers: rhttp.NewTrie(),
}
}

View File

@@ -1,8 +1,8 @@
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 {
@@ -11,17 +11,12 @@ type httpMessage struct {
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 +25,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 {

View File

@@ -5,7 +5,7 @@ import (
"fmt"
"net/http"
"github.com/unistack-org/micro/v3/server"
"go.unistack.org/micro/v3/server"
)
// SetError pass error to caller
@@ -38,6 +38,20 @@ type (
}
)
type (
rspHeaderKey struct{}
rspHeaderVal struct {
h http.Header
}
)
// SetRspHeader add response headers
func SetRspHeader(ctx context.Context, h http.Header) {
if rsp, ok := ctx.Value(rspHeaderKey{}).(*rspHeaderVal); ok {
rsp.h = h
}
}
// 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 {
@@ -45,9 +59,17 @@ func SetRspCode(ctx context.Context, code int) {
}
}
// getRspHeader get http.Header from context
func getRspHeader(ctx context.Context) http.Header {
if rsp, ok := ctx.Value(rspHeaderKey{}).(*rspHeaderVal); ok {
return rsp.h
}
return nil
}
// GetRspCode used internally by generated http server handler
func GetRspCode(ctx context.Context) int {
var code int
code := int(200)
if rsp, ok := ctx.Value(rspCodeKey{}).(*rspCodeVal); ok {
code = rsp.code
}
@@ -63,59 +85,44 @@ func Middleware(mw ...func(http.Handler) http.Handler) server.Option {
type serverKey struct{}
// Server provide ability to pass *http.Server
func Server(hs *http.Server) server.Option {
// HTTPServer provide ability to pass *http.Server
func HTTPServer(hs *http.Server) server.Option {
return server.SetOption(serverKey{}, hs)
}
type errorHandler func(ctx context.Context, s server.Handler, w http.ResponseWriter, r *http.Request, err error, status int)
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 {
func ErrorHandler(fn errorHandler) server.Option {
return server.SetOption(errorHandlerKey{}, fn)
}
type (
pathHandlerKey struct{}
pathHandlerVal struct {
h map[string]http.HandlerFunc
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
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)
m, ok := v.h[method]
if !ok {
v = &contentTypeHandlerVal{h: make(map[string]http.HandlerFunc)}
m = make(map[string]http.HandlerFunc)
v.h[method] = m
}
v.h[ct] = h
o.Context = context.WithValue(o.Context, contentTypeHandlerKey{}, v)
m[path] = handler
o.Context = context.WithValue(o.Context, pathHandlerKey{}, v)
}
}
@@ -125,3 +132,43 @@ type registerRPCHandlerKey struct{}
func RegisterRPCHandler(b bool) server.Option {
return server.SetOption(registerRPCHandlerKey{}, b)
}
type registerCORSHandlerKey struct{}
// RegisterCORSHandler registers cors endpoints with /ServiceName.ServiceEndpoint method POPTIONSOST
func RegisterCORSHandler(b bool) server.HandlerOption {
return server.SetHandlerOption(registerCORSHandlerKey{}, b)
}
type handlerEndpointsKey struct{}
type EndpointMetadata struct {
Name string
Path string
Method string
Body string
Stream bool
}
func HandlerEndpoints(md []EndpointMetadata) server.HandlerOption {
return server.SetHandlerOption(handlerEndpointsKey{}, md)
}
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...)
}
}

View File

@@ -1,11 +1,9 @@
package http
import (
"io"
"github.com/unistack-org/micro/v3/codec"
"github.com/unistack-org/micro/v3/metadata"
"github.com/unistack-org/micro/v3/server"
"go.unistack.org/micro/v3/codec"
"go.unistack.org/micro/v3/metadata"
"go.unistack.org/micro/v3/server"
)
var (
@@ -14,7 +12,7 @@ var (
)
type rpcRequest struct {
rw io.ReadWriter
// rw io.ReadWriter
payload interface{}
codec codec.Codec
header metadata.Metadata
@@ -22,7 +20,6 @@ type rpcRequest struct {
endpoint string
contentType string
service string
body []byte
stream bool
}
@@ -32,7 +29,6 @@ type rpcMessage struct {
header metadata.Metadata
topic string
contentType string
body []byte
}
func (r *rpcRequest) ContentType() string {
@@ -60,11 +56,7 @@ func (r *rpcRequest) Header() metadata.Metadata {
}
func (r *rpcRequest) Read() ([]byte, error) {
f := &codec.Frame{}
if err := r.codec.ReadBody(r.rw, f); err != nil {
return nil, err
}
return f.Data, nil
return nil, nil
}
func (r *rpcRequest) Stream() bool {
@@ -83,7 +75,7 @@ func (r *rpcMessage) Topic() string {
return r.topic
}
func (r *rpcMessage) Payload() interface{} {
func (r *rpcMessage) Body() interface{} {
return r.payload
}
@@ -91,10 +83,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
}

View File

@@ -7,7 +7,7 @@ import (
"unicode"
"unicode/utf8"
"github.com/unistack-org/micro/v3/server"
"go.unistack.org/micro/v3/server"
)
type methodType struct {

View File

@@ -1,17 +1,15 @@
package http
import (
"bytes"
"context"
"fmt"
"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"
"go.unistack.org/micro/v3/broker"
"go.unistack.org/micro/v3/metadata"
"go.unistack.org/micro/v3/options"
"go.unistack.org/micro/v3/server"
)
var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
@@ -28,14 +26,12 @@ type httpSubscriber struct {
typ reflect.Type
subscriber interface{}
handlers []*handler
endpoints []*register.Endpoint
opts server.SubscriberOptions
}
func newSubscriber(topic string, sub interface{}, opts ...server.SubscriberOption) server.Subscriber {
options := server.NewSubscriberOptions(opts...)
var endpoints []*register.Endpoint
var handlers []*handler
if typ := reflect.TypeOf(sub); typ.Kind() == reflect.Func {
@@ -52,18 +48,7 @@ func newSubscriber(topic string, sub interface{}, opts ...server.SubscriberOptio
}
handlers = append(handlers, h)
ep := &register.Endpoint{
Name: "Func",
Request: register.ExtractSubValue(typ),
Metadata: metadata.New(2),
}
ep.Metadata.Set("topic", topic)
ep.Metadata.Set("subscriber", "true")
endpoints = append(endpoints, ep)
} else {
hdlr := reflect.ValueOf(sub)
name := reflect.Indirect(hdlr).Type().Name()
for m := 0; m < typ.NumMethod(); m++ {
method := typ.Method(m)
h := &handler{
@@ -79,14 +64,6 @@ func newSubscriber(topic string, sub interface{}, opts ...server.SubscriberOptio
}
handlers = append(handlers, h)
ep := &register.Endpoint{
Name: name + "." + method.Name,
Request: register.ExtractSubValue(method.Type),
Metadata: metadata.New(2),
}
ep.Metadata.Set("topic", topic)
ep.Metadata.Set("subscriber", "true")
endpoints = append(endpoints, ep)
}
}
@@ -96,12 +73,11 @@ func newSubscriber(topic string, sub interface{}, opts ...server.SubscriberOptio
topic: topic,
subscriber: sub,
handlers: handlers,
endpoints: endpoints,
opts: options,
}
}
func (s *httpServer) createSubHandler(sb *httpSubscriber, opts server.Options) broker.Handler {
func (s *Server) createSubHandler(sb *httpSubscriber, opts server.Options) broker.Handler {
return func(p broker.Event) error {
msg := p.Message()
ct := msg.Header["Content-Type"]
@@ -111,7 +87,6 @@ func (s *httpServer) createSubHandler(sb *httpSubscriber, opts server.Options) b
}
hdr := metadata.Copy(msg.Header)
delete(hdr, "Content-Type")
ctx := metadata.NewIncomingContext(context.Background(), hdr)
results := make(chan error, len(sb.handlers))
@@ -132,13 +107,7 @@ func (s *httpServer) createSubHandler(sb *httpSubscriber, opts server.Options) b
req = req.Elem()
}
buf := bytes.NewBuffer(msg.Body)
if err := cf.ReadHeader(buf, &codec.Message{}, codec.Event); err != nil {
return err
}
if err := cf.ReadBody(buf, req.Interface()); err != nil {
if err := cf.Unmarshal(msg.Body, req.Interface()); err != nil {
return err
}
@@ -151,7 +120,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 {
@@ -160,9 +129,11 @@ func (s *httpServer) createSubHandler(sb *httpSubscriber, opts server.Options) b
return nil
}
for i := len(opts.SubWrappers); i > 0; i-- {
fn = opts.SubWrappers[i-1](fn)
}
opts.Hooks.EachPrev(func(hook options.Hook) {
if h, ok := hook.(server.HookSubHandler); ok {
fn = h(fn)
}
})
go func() {
results <- fn(ctx, &httpMessage{
@@ -170,7 +141,6 @@ func (s *httpServer) createSubHandler(sb *httpSubscriber, opts server.Options) b
contentType: ct,
payload: req.Interface(),
header: msg.Header,
body: msg.Body,
codec: cf,
})
}()
@@ -200,10 +170,6 @@ func (s *httpSubscriber) Subscriber() interface{} {
return s.subscriber
}
func (s *httpSubscriber) Endpoints() []*register.Endpoint {
return s.endpoints
}
func (s *httpSubscriber) Options() server.SubscriberOptions {
return s.opts
}

55
util.go Normal file
View 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
}

100
util_test.go Normal file
View File

@@ -0,0 +1,100 @@
package http
import (
"bytes"
"context"
"net/http"
"strings"
"testing"
"go.unistack.org/micro/v3/metadata"
"go.unistack.org/micro/v3/options"
"go.unistack.org/micro/v3/server"
)
func Test_Hook(t *testing.T) {
opts := server.Options{}
var fn server.HandlerFunc = func(fctx context.Context, req server.Request, rsp interface{}) (err error) {
// fmt.Println("1")
return nil
}
var fn2 server.HandlerWrapper = func(next server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
// fmt.Println("2")
return next(ctx, req, rsp)
}
}
var fn3 server.HandlerWrapper = func(next server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
// fmt.Println("3")
return next(ctx, req, rsp)
}
}
var fn4 server.HandlerWrapper = func(next server.HandlerFunc) server.HandlerFunc {
return func(ctx context.Context, req server.Request, rsp interface{}) error {
// fmt.Println("4")
return next(ctx, req, rsp)
}
}
opts.Hooks = append(opts.Hooks, fn2, fn3, fn4)
opts.Hooks.EachNext(func(hook options.Hook) {
if h, ok := hook.(server.HandlerWrapper); ok {
// fmt.Printf("h %#+v\n", h)
fn = h(fn)
}
})
err := fn(nil, nil, nil)
if err != nil {
t.Fatal(err)
}
}
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)
}
}