Compare commits
2 Commits
v3.11.20
...
741a6f181b
| Author | SHA1 | Date | |
|---|---|---|---|
| 741a6f181b | |||
| 7f971ee6c3 |
24
.gitignore
vendored
24
.gitignore
vendored
@@ -1,24 +0,0 @@
|
|||||||
# 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
|
|
||||||
10
README.md
10
README.md
@@ -9,8 +9,8 @@ to create a HTTP Server that could potentially be used for REST based API servic
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
httpServer "github.com/unistack-org/micro-server-http"
|
httpServer "go.unistack.org/micro-server-http/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -37,9 +37,9 @@ Or as part of a service
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/unistack-org/micro/v3"
|
"go.unistack.org/micro/v4"
|
||||||
"github.com/unistack-org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
httpServer "github.com/unistack-org/micro-server-http"
|
httpServer "go.unistack.org/micro-server-http/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
23
go.mod
23
go.mod
@@ -1,23 +1,16 @@
|
|||||||
module go.unistack.org/micro-server-http/v3
|
module go.unistack.org/micro-server-http/v4
|
||||||
|
|
||||||
go 1.18
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
go.unistack.org/micro-codec-yaml/v3 v3.10.0
|
go.unistack.org/micro-proto/v4 v4.0.0
|
||||||
go.unistack.org/micro-proto/v3 v3.3.1
|
go.unistack.org/micro/v4 v4.0.1
|
||||||
go.unistack.org/micro/v3 v3.10.52
|
golang.org/x/net v0.7.0
|
||||||
golang.org/x/net v0.22.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/protobuf v1.5.4 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/google/gnostic v0.7.0 // indirect
|
github.com/google/gnostic v0.6.9 // indirect
|
||||||
github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect
|
google.golang.org/protobuf v1.28.1 // indirect
|
||||||
golang.org/x/sys v0.18.0 // indirect
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect
|
|
||||||
google.golang.org/grpc v1.62.1 // indirect
|
|
||||||
google.golang.org/protobuf v1.33.0 // indirect
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
|
||||||
)
|
)
|
||||||
|
|||||||
349
handler.go
349
handler.go
@@ -9,13 +9,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/errors"
|
"go.unistack.org/micro/v4/errors"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
"go.unistack.org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
rhttp "go.unistack.org/micro/v3/util/http"
|
rhttp "go.unistack.org/micro/v4/util/http"
|
||||||
rflutil "go.unistack.org/micro/v3/util/reflect"
|
rflutil "go.unistack.org/micro/v4/util/reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -60,286 +60,13 @@ func (h *httpHandler) Options() server.HandlerOptions {
|
|||||||
return h.opts
|
return h.opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) HTTPHandlerFunc(handler interface{}) (http.HandlerFunc, error) {
|
func (h *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
if handler == nil {
|
// check for http.HandlerFunc handlers
|
||||||
return nil, fmt.Errorf("invalid handler specified: %v", handler)
|
if ph, _, err := h.pathHandlers.Search(r.Method, r.URL.Path); err == nil {
|
||||||
|
ph.(http.HandlerFunc)(w, r)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
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.StatusBadRequest)
|
|
||||||
_, _ = w.Write([]byte(err.Error()))
|
|
||||||
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
|
|
||||||
for i := len(handler.sopts.HdlrWrappers); i > 0; i-- {
|
|
||||||
fn = handler.sopts.HdlrWrappers[i-1](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.StatusBadRequest)
|
|
||||||
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.Errorf(handler.sopts.Context, "handler err: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if nscode := GetRspCode(ctx); nscode != 0 {
|
|
||||||
scode = nscode
|
|
||||||
}
|
|
||||||
w.WriteHeader(scode)
|
|
||||||
|
|
||||||
if _, cerr := w.Write(buf); cerr != nil {
|
|
||||||
handler.sopts.Logger.Errorf(ctx, "write failed: %v", cerr)
|
|
||||||
}
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
||||||
ct := DefaultContentType
|
ct := DefaultContentType
|
||||||
if htype := r.Header.Get(metadata.HeaderContentType); htype != "" {
|
if htype := r.Header.Get(metadata.HeaderContentType); htype != "" {
|
||||||
ct = htype
|
ct = htype
|
||||||
@@ -355,22 +82,17 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
md[k] = strings.Join(v, ", ")
|
md[k] = strings.Join(v, ", ")
|
||||||
}
|
}
|
||||||
md["RemoteAddr"] = r.RemoteAddr
|
md["RemoteAddr"] = r.RemoteAddr
|
||||||
if r.TLS != nil {
|
|
||||||
md["Scheme"] = "https"
|
|
||||||
} else {
|
|
||||||
md["Scheme"] = "http"
|
|
||||||
}
|
|
||||||
md["Method"] = r.Method
|
md["Method"] = r.Method
|
||||||
md["URL"] = r.URL.String()
|
md["URL"] = r.URL.String()
|
||||||
md["Proto"] = r.Proto
|
md["Proto"] = r.Proto
|
||||||
md["ContentLength"] = fmt.Sprintf("%d", r.ContentLength)
|
md["ContentLength"] = fmt.Sprintf("%d", r.ContentLength)
|
||||||
if len(r.TransferEncoding) > 0 {
|
md["TransferEncoding"] = strings.Join(r.TransferEncoding, ",")
|
||||||
md["TransferEncoding"] = strings.Join(r.TransferEncoding, ",")
|
|
||||||
}
|
|
||||||
md["Host"] = r.Host
|
md["Host"] = r.Host
|
||||||
md["RequestURI"] = r.RequestURI
|
md["RequestURI"] = r.RequestURI
|
||||||
ctx = metadata.NewIncomingContext(ctx, md)
|
ctx = metadata.NewIncomingContext(ctx, md)
|
||||||
|
|
||||||
|
defer r.Body.Close()
|
||||||
|
|
||||||
path := r.URL.Path
|
path := r.URL.Path
|
||||||
if !strings.HasPrefix(path, "/") {
|
if !strings.HasPrefix(path, "/") {
|
||||||
h.errorHandler(ctx, nil, w, r, fmt.Errorf("path must starts with /"), http.StatusBadRequest)
|
h.errorHandler(ctx, nil, w, r, fmt.Errorf("path must starts with /"), http.StatusBadRequest)
|
||||||
@@ -427,11 +149,6 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if !match {
|
} else if !match {
|
||||||
// check for http.HandlerFunc handlers
|
|
||||||
if ph, _, err := h.pathHandlers.Search(r.Method, r.URL.Path); err == nil {
|
|
||||||
ph.(http.HandlerFunc)(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
h.errorHandler(ctx, nil, w, r, fmt.Errorf("not matching route found"), http.StatusNotFound)
|
h.errorHandler(ctx, nil, w, r, fmt.Errorf("not matching route found"), http.StatusNotFound)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -448,10 +165,6 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if r.Body != nil {
|
|
||||||
defer r.Body.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
cf, err := h.newCodec(ct)
|
cf, err := h.newCodec(ct)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
h.errorHandler(ctx, nil, w, r, err, http.StatusBadRequest)
|
h.errorHandler(ctx, nil, w, r, err, http.StatusBadRequest)
|
||||||
@@ -479,26 +192,21 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
function := hldr.mtype.method.Func
|
function := hldr.mtype.method.Func
|
||||||
var returnValues []reflect.Value
|
var returnValues []reflect.Value
|
||||||
|
|
||||||
if r.Body != nil {
|
buf, err := io.ReadAll(r.Body)
|
||||||
var buf []byte
|
if err != nil && err != io.EOF {
|
||||||
buf, err = io.ReadAll(r.Body)
|
h.errorHandler(ctx, handler, w, r, err, http.StatusInternalServerError)
|
||||||
if err != nil && err != io.EOF {
|
return
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(matches) > 0 {
|
if err = cf.Unmarshal(buf, argv.Interface()); err != nil {
|
||||||
matches = rflutil.FlattenMap(matches)
|
h.errorHandler(ctx, handler, w, r, err, http.StatusBadRequest)
|
||||||
if err = rflutil.Merge(argv.Interface(), matches, rflutil.SliceAppend(true), rflutil.Tags([]string{"protobuf", "json"})); err != nil {
|
return
|
||||||
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{
|
hr := &rpcRequest{
|
||||||
@@ -571,7 +279,6 @@ func (h *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var buf []byte
|
|
||||||
if appErr != nil {
|
if appErr != nil {
|
||||||
switch verr := appErr.(type) {
|
switch verr := appErr.(type) {
|
||||||
case *errors.Error:
|
case *errors.Error:
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
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"
|
|
||||||
8
handler/health/generate.go
Normal file
8
handler/health/generate.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package health
|
||||||
|
|
||||||
|
//go:generate sh -c "protoc -I./ -I$(go list -f '{{ .Dir }}' -m go.unistack.org/micro-proto/v4) --go-micro_out='components=micro|http|server',standalone=false,debug=true,paths=source_relative:./ health.proto"
|
||||||
|
|
||||||
|
import (
|
||||||
|
// import required packages
|
||||||
|
_ "go.unistack.org/micro-proto/v4/openapiv3"
|
||||||
|
)
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
package health // import "go.unistack.org/micro-server-http/v3/handler/health"
|
package health // import "go.unistack.org/micro-server-http/v4/handler/health"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
codecpb "go.unistack.org/micro-proto/v3/codec"
|
codecpb "go.unistack.org/micro-proto/v4/codec"
|
||||||
"go.unistack.org/micro/v3/errors"
|
"go.unistack.org/micro/v4/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ HealthServiceServer = &Handler{}
|
var _ HealthServiceServer = &Handler{}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package micro.server.http.v3.handler.health;
|
package micro.server.http.v4.handler.health;
|
||||||
option go_package = "go.unistack.org/micro-server-http/v3/handler/health;health";
|
option go_package = "go.unistack.org/micro-server-http/v4/handler/health;health";
|
||||||
|
|
||||||
import "api/annotations.proto";
|
import "api/annotations.proto";
|
||||||
import "openapiv3/annotations.proto";
|
import "openapiv3/annotations.proto";
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
|
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-micro v3.10.2
|
// - protoc-gen-go-micro v4.10.2
|
||||||
// - protoc v3.21.12
|
// - protoc v4.21.12
|
||||||
// source: health.proto
|
// source: health.proto
|
||||||
|
|
||||||
package health
|
package health
|
||||||
|
|
||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
codec "go.unistack.org/micro-proto/v3/codec"
|
codec "go.unistack.org/micro-proto/v4/codec"
|
||||||
v3 "go.unistack.org/micro-server-http/v3"
|
v4 "go.unistack.org/micro-server-http/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
HealthServiceName = "HealthService"
|
HealthServiceName = "HealthService"
|
||||||
)
|
)
|
||||||
var (
|
var (
|
||||||
HealthServiceServerEndpoints = []v3.EndpointMetadata{
|
HealthServiceServerEndpoints = []v4.EndpointMetadata{
|
||||||
{
|
{
|
||||||
Name: "HealthService.Live",
|
Name: "HealthService.Live",
|
||||||
Path: "/live",
|
Path: "/live",
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
|
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
|
||||||
// protoc-gen-go-micro version: v3.10.2
|
// protoc-gen-go-micro version: v4.10.2
|
||||||
// source: health.proto
|
// source: health.proto
|
||||||
|
|
||||||
package health
|
package health
|
||||||
|
|
||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
codec "go.unistack.org/micro-proto/v3/codec"
|
codec "go.unistack.org/micro-proto/v4/codec"
|
||||||
v3 "go.unistack.org/micro-server-http/v3"
|
v4 "go.unistack.org/micro-server-http/v4"
|
||||||
server "go.unistack.org/micro/v3/server"
|
server "go.unistack.org/micro/v4/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
type healthServiceServer struct {
|
type healthServiceServer struct {
|
||||||
@@ -38,6 +38,6 @@ func RegisterHealthServiceServer(s server.Server, sh HealthServiceServer, opts .
|
|||||||
}
|
}
|
||||||
h := &healthServiceServer{sh}
|
h := &healthServiceServer{sh}
|
||||||
var nopts []server.HandlerOption
|
var nopts []server.HandlerOption
|
||||||
nopts = append(nopts, v3.HandlerEndpoints(HealthServiceServerEndpoints))
|
nopts = append(nopts, v4.HandlerEndpoints(HealthServiceServerEndpoints))
|
||||||
return s.Handle(s.NewHandler(&HealthService{h}, append(nopts, opts...)...))
|
return s.Handle(s.NewHandler(&HealthService{h}, append(nopts, opts...)...))
|
||||||
}
|
}
|
||||||
|
|||||||
8
handler/meter/generate.go
Normal file
8
handler/meter/generate.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package meter
|
||||||
|
|
||||||
|
//go:generate sh -c "protoc -I./ -I$(go list -f '{{ .Dir }}' -m go.unistack.org/micro-proto/v4) --go-micro_out='components=micro|http|server',standalone=false,debug=true,paths=source_relative:./ meter.proto"
|
||||||
|
|
||||||
|
import (
|
||||||
|
// import required packages
|
||||||
|
_ "go.unistack.org/micro-proto/v4/openapiv3"
|
||||||
|
)
|
||||||
@@ -1,36 +1,14 @@
|
|||||||
package meter // import "go.unistack.org/micro-server-http/v3/handler/meter"
|
package meter // import "go.unistack.org/micro-server-http/v4/handler/meter"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"compress/gzip"
|
|
||||||
"context"
|
"context"
|
||||||
"io"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
codecpb "go.unistack.org/micro-proto/v3/codec"
|
codecpb "go.unistack.org/micro-proto/v4/codec"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/errors"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/meter"
|
||||||
"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
|
// guard to fail early
|
||||||
var _ MeterServiceServer = &Handler{}
|
var _ MeterServiceServer = &Handler{}
|
||||||
|
|
||||||
@@ -78,46 +56,12 @@ func NewHandler(opts ...Option) *Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
|
func (h *Handler) Metrics(ctx context.Context, req *codecpb.Frame, rsp *codecpb.Frame) error {
|
||||||
log, ok := logger.FromContext(ctx)
|
buf := bytes.NewBuffer(nil)
|
||||||
if !ok {
|
if err := h.opts.Meter.Write(buf, h.opts.MeterOptions...); err != nil {
|
||||||
log = logger.DefaultLogger
|
return errors.InternalServerError(h.opts.Name, "%v", err)
|
||||||
}
|
|
||||||
|
|
||||||
buf := bufPool.Get().(*bytes.Buffer)
|
|
||||||
defer bufPool.Put(buf)
|
|
||||||
buf.Reset()
|
|
||||||
|
|
||||||
w := io.Writer(buf)
|
|
||||||
|
|
||||||
if md, ok := metadata.FromIncomingContext(ctx); gzipAccepted(md) && ok {
|
|
||||||
md.Set(contentEncodingHeader, "gzip")
|
|
||||||
gz := gzipPool.Get().(*gzip.Writer)
|
|
||||||
defer gzipPool.Put(gz)
|
|
||||||
|
|
||||||
gz.Reset(w)
|
|
||||||
defer gz.Close()
|
|
||||||
|
|
||||||
w = gz
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := h.opts.Meter.Write(w, h.opts.MeterOptions...); err != nil {
|
|
||||||
log.Error(ctx, "http/meter write failed", err)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rsp.Data = buf.Bytes()
|
rsp.Data = buf.Bytes()
|
||||||
|
|
||||||
return nil
|
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
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package micro.server.http.v3.handler.meter;
|
package micro.server.http.v4.handler.meter;
|
||||||
option go_package = "go.unistack.org/micro-server-http/v3/handler/meter;meter";
|
option go_package = "go.unistack.org/micro-server-http/v4/handler/meter;meter";
|
||||||
|
|
||||||
import "api/annotations.proto";
|
import "api/annotations.proto";
|
||||||
import "openapiv3/annotations.proto";
|
import "openapiv3/annotations.proto";
|
||||||
|
|||||||
@@ -1,22 +1,22 @@
|
|||||||
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
|
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// - protoc-gen-go-micro v3.10.2
|
// - protoc-gen-go-micro v4.10.2
|
||||||
// - protoc v3.21.12
|
// - protoc v4.21.12
|
||||||
// source: meter.proto
|
// source: meter.proto
|
||||||
|
|
||||||
package meter
|
package meter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
codec "go.unistack.org/micro-proto/v3/codec"
|
codec "go.unistack.org/micro-proto/v4/codec"
|
||||||
v3 "go.unistack.org/micro-server-http/v3"
|
v4 "go.unistack.org/micro-server-http/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
MeterServiceName = "MeterService"
|
MeterServiceName = "MeterService"
|
||||||
)
|
)
|
||||||
var (
|
var (
|
||||||
MeterServiceServerEndpoints = []v3.EndpointMetadata{
|
MeterServiceServerEndpoints = []v4.EndpointMetadata{
|
||||||
{
|
{
|
||||||
Name: "MeterService.Metrics",
|
Name: "MeterService.Metrics",
|
||||||
Path: "/metrics",
|
Path: "/metrics",
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
|
// Code generated by protoc-gen-go-micro. DO NOT EDIT.
|
||||||
// protoc-gen-go-micro version: v3.10.2
|
// protoc-gen-go-micro version: v4.10.2
|
||||||
// source: meter.proto
|
// source: meter.proto
|
||||||
|
|
||||||
package meter
|
package meter
|
||||||
|
|
||||||
import (
|
import (
|
||||||
context "context"
|
context "context"
|
||||||
codec "go.unistack.org/micro-proto/v3/codec"
|
codec "go.unistack.org/micro-proto/v4/codec"
|
||||||
v3 "go.unistack.org/micro-server-http/v3"
|
v4 "go.unistack.org/micro-server-http/v4"
|
||||||
server "go.unistack.org/micro/v3/server"
|
server "go.unistack.org/micro/v4/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
type meterServiceServer struct {
|
type meterServiceServer struct {
|
||||||
@@ -28,6 +28,6 @@ func RegisterMeterServiceServer(s server.Server, sh MeterServiceServer, opts ...
|
|||||||
}
|
}
|
||||||
h := &meterServiceServer{sh}
|
h := &meterServiceServer{sh}
|
||||||
var nopts []server.HandlerOption
|
var nopts []server.HandlerOption
|
||||||
nopts = append(nopts, v3.HandlerEndpoints(MeterServiceServerEndpoints))
|
nopts = append(nopts, v4.HandlerEndpoints(MeterServiceServerEndpoints))
|
||||||
return s.Handle(s.NewHandler(&MeterService{h}, append(nopts, opts...)...))
|
return s.Handle(s.NewHandler(&MeterService{h}, append(nopts, opts...)...))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
package pprof
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 665 B |
Binary file not shown.
|
Before Width: | Height: | Size: 628 B |
@@ -1,16 +0,0 @@
|
|||||||
html {
|
|
||||||
box-sizing: border-box;
|
|
||||||
overflow: -moz-scrollbars-vertical;
|
|
||||||
overflow-y: scroll;
|
|
||||||
}
|
|
||||||
|
|
||||||
*,
|
|
||||||
*:before,
|
|
||||||
*:after {
|
|
||||||
box-sizing: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
background: #fafafa;
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
<!-- 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>
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
<!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>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
window.onload = function() {
|
|
||||||
//<editor-fold desc="Changeable Configuration Block">
|
|
||||||
|
|
||||||
// the following lines will be replaced by docker/configurator, when it runs in a docker-container
|
|
||||||
window.ui = SwaggerUIBundle({
|
|
||||||
url: "{{ .SWAGGER }}",
|
|
||||||
dom_id: '#swagger-ui',
|
|
||||||
deepLinking: true,
|
|
||||||
presets: [
|
|
||||||
SwaggerUIBundle.presets.apis,
|
|
||||||
SwaggerUIStandalonePreset
|
|
||||||
],
|
|
||||||
plugins: [
|
|
||||||
SwaggerUIBundle.plugins.DownloadUrl
|
|
||||||
],
|
|
||||||
layout: "StandaloneLayout"
|
|
||||||
});
|
|
||||||
|
|
||||||
//</editor-fold>
|
|
||||||
};
|
|
||||||
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
@@ -1,142 +0,0 @@
|
|||||||
package swaggerui // import "go.unistack.org/micro-server-http/v3/handler/swagger-ui"
|
|
||||||
|
|
||||||
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",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package swaggerui
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
package swagger
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
132
http.go
132
http.go
@@ -1,5 +1,5 @@
|
|||||||
// Package http implements a go-micro.Server
|
// Package http implements a go-micro.Server
|
||||||
package http // import "go.unistack.org/micro-server-http/v3"
|
package http // import "go.unistack.org/micro-server-http/v4"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -14,18 +14,18 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/logger"
|
"go.unistack.org/micro/v4/logger"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
"go.unistack.org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
rhttp "go.unistack.org/micro/v3/util/http"
|
rhttp "go.unistack.org/micro/v4/util/http"
|
||||||
"golang.org/x/net/netutil"
|
"golang.org/x/net/netutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ server.Server = (*Server)(nil)
|
var _ server.Server = &httpServer{}
|
||||||
|
|
||||||
type Server struct {
|
type httpServer struct {
|
||||||
hd server.Handler
|
hd server.Handler
|
||||||
rsvc *register.Service
|
rsvc *register.Service
|
||||||
handlers map[string]server.Handler
|
handlers map[string]server.Handler
|
||||||
@@ -35,13 +35,12 @@ type Server struct {
|
|||||||
pathHandlers *rhttp.Trie
|
pathHandlers *rhttp.Trie
|
||||||
opts server.Options
|
opts server.Options
|
||||||
registerRPC bool
|
registerRPC bool
|
||||||
registerCORS bool
|
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
registered bool
|
registered bool
|
||||||
init bool
|
init bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) newCodec(ct string) (codec.Codec, error) {
|
func (h *httpServer) newCodec(ct string) (codec.Codec, error) {
|
||||||
if idx := strings.IndexRune(ct, ';'); idx >= 0 {
|
if idx := strings.IndexRune(ct, ';'); idx >= 0 {
|
||||||
ct = ct[:idx]
|
ct = ct[:idx]
|
||||||
}
|
}
|
||||||
@@ -54,14 +53,14 @@ func (h *Server) newCodec(ct string) (codec.Codec, error) {
|
|||||||
return nil, codec.ErrUnknownContentType
|
return nil, codec.ErrUnknownContentType
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) Options() server.Options {
|
func (h *httpServer) Options() server.Options {
|
||||||
h.Lock()
|
h.Lock()
|
||||||
opts := h.opts
|
opts := h.opts
|
||||||
h.Unlock()
|
h.Unlock()
|
||||||
return opts
|
return opts
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) Init(opts ...server.Option) error {
|
func (h *httpServer) Init(opts ...server.Option) error {
|
||||||
if len(opts) == 0 && h.init {
|
if len(opts) == 0 && h.init {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -85,10 +84,6 @@ func (h *Server) Init(opts ...server.Option) error {
|
|||||||
h.registerRPC = v
|
h.registerRPC = v
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, ok := h.opts.Context.Value(registerCORSHandlerKey{}).(bool); ok {
|
|
||||||
h.registerCORS = v
|
|
||||||
}
|
|
||||||
|
|
||||||
if phs, ok := h.opts.Context.Value(pathHandlerKey{}).(*pathHandlerVal); ok && phs.h != nil {
|
if phs, ok := h.opts.Context.Value(pathHandlerKey{}).(*pathHandlerVal); ok && phs.h != nil {
|
||||||
for pm, ps := range phs.h {
|
for pm, ps := range phs.h {
|
||||||
for pp, ph := range ps {
|
for pp, ph := range ps {
|
||||||
@@ -135,7 +130,7 @@ func (h *Server) Init(opts ...server.Option) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) Handle(handler server.Handler) error {
|
func (h *httpServer) Handle(handler server.Handler) error {
|
||||||
// passed unknown handler
|
// passed unknown handler
|
||||||
hdlr, ok := handler.(*httpHandler)
|
hdlr, ok := handler.(*httpHandler)
|
||||||
if !ok {
|
if !ok {
|
||||||
@@ -164,7 +159,7 @@ func (h *Server) Handle(handler server.Handler) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) NewHandler(handler interface{}, opts ...server.HandlerOption) server.Handler {
|
func (h *httpServer) NewHandler(handler interface{}, opts ...server.HandlerOption) server.Handler {
|
||||||
options := server.NewHandlerOptions(opts...)
|
options := server.NewHandlerOptions(opts...)
|
||||||
|
|
||||||
eps := make([]*register.Endpoint, 0, len(options.Metadata))
|
eps := make([]*register.Endpoint, 0, len(options.Metadata))
|
||||||
@@ -228,29 +223,13 @@ func (h *Server) NewHandler(handler interface{}, opts ...server.HandlerOption) s
|
|||||||
pth := &patHandler{mtype: mtype, name: name, rcvr: rcvr}
|
pth := &patHandler{mtype: mtype, name: name, rcvr: rcvr}
|
||||||
hdlr.name = name
|
hdlr.name = name
|
||||||
|
|
||||||
methods := []string{md["Method"]}
|
if err := hdlr.handlers.Insert([]string{md["Method"]}, md["Path"], pth); err != nil {
|
||||||
if h.registerCORS {
|
h.opts.Logger.Errorf(h.opts.Context, "cant add handler for %s %s", md["Method"], md["Path"])
|
||||||
logger.Infof(h.opts.Context, "register cors handler for http.MethodOptions %s", md["Path"])
|
|
||||||
methods = append(methods, http.MethodOptions)
|
|
||||||
} else {
|
|
||||||
logger.Infof(h.opts.Context, "not register cors handler for http.MethodOptions %s", md["Path"])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := hdlr.handlers.Insert(methods, md["Path"], pth); err != nil {
|
|
||||||
logger.Errorf(h.opts.Context, "cant add handler for %v %s", methods, md["Path"])
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Infof(h.opts.Context, fmt.Sprintf("try to detect rpc handlers usage %v", h.registerRPC))
|
|
||||||
if h.registerRPC {
|
if h.registerRPC {
|
||||||
methods := []string{http.MethodPost}
|
h.opts.Logger.Infof(h.opts.Context, "register rpc handler for http.MethodPost %s /%s", hn, hn)
|
||||||
if h.registerCORS {
|
if err := hdlr.handlers.Insert([]string{http.MethodPost}, "/"+hn, pth); err != nil {
|
||||||
logger.Infof(h.opts.Context, "register cors handler for %v %s", methods, "/"+hn)
|
|
||||||
methods = append(methods, http.MethodOptions)
|
|
||||||
} else {
|
|
||||||
logger.Infof(h.opts.Context, "not register cors handler for %v %s", methods, "/"+hn)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := hdlr.handlers.Insert(methods, "/"+hn, pth); err != nil {
|
|
||||||
h.opts.Logger.Errorf(h.opts.Context, "cant add rpc handler for http.MethodPost %s /%s", hn, hn)
|
h.opts.Logger.Errorf(h.opts.Context, "cant add rpc handler for http.MethodPost %s /%s", hn, hn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -309,11 +288,11 @@ func (h *Server) NewHandler(handler interface{}, opts ...server.HandlerOption) s
|
|||||||
return hdlr
|
return hdlr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) NewSubscriber(topic string, handler interface{}, opts ...server.SubscriberOption) server.Subscriber {
|
func (h *httpServer) NewSubscriber(topic string, handler interface{}, opts ...server.SubscriberOption) server.Subscriber {
|
||||||
return newSubscriber(topic, handler, opts...)
|
return newSubscriber(topic, handler, opts...)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) Subscribe(sb server.Subscriber) error {
|
func (h *httpServer) Subscribe(sb server.Subscriber) error {
|
||||||
sub, ok := sb.(*httpSubscriber)
|
sub, ok := sb.(*httpSubscriber)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("invalid subscriber: expected *httpSubscriber")
|
return fmt.Errorf("invalid subscriber: expected *httpSubscriber")
|
||||||
@@ -338,7 +317,7 @@ func (h *Server) Subscribe(sb server.Subscriber) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) Register() error {
|
func (h *httpServer) Register() error {
|
||||||
var eps []*register.Endpoint
|
var eps []*register.Endpoint
|
||||||
h.RLock()
|
h.RLock()
|
||||||
for _, hdlr := range h.handlers {
|
for _, hdlr := range h.handlers {
|
||||||
@@ -399,17 +378,6 @@ func (h *Server) Register() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
h.Lock()
|
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 {
|
for sb := range h.subscribers {
|
||||||
handler := h.createSubHandler(sb, config)
|
handler := h.createSubHandler(sb, config)
|
||||||
var opts []broker.SubscribeOption
|
var opts []broker.SubscribeOption
|
||||||
@@ -433,10 +401,14 @@ func (h *Server) subscribe() error {
|
|||||||
h.subscribers[sb] = []broker.Subscriber{sub}
|
h.subscribers[sb] = []broker.Subscriber{sub}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
h.registered = true
|
||||||
|
h.rsvc = service
|
||||||
|
h.Unlock()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) Deregister() error {
|
func (h *httpServer) Deregister() error {
|
||||||
h.RLock()
|
h.RLock()
|
||||||
config := h.opts
|
config := h.opts
|
||||||
h.RUnlock()
|
h.RUnlock()
|
||||||
@@ -484,7 +456,7 @@ func (h *Server) Deregister() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) Start() error {
|
func (h *httpServer) Start() error {
|
||||||
h.RLock()
|
h.RLock()
|
||||||
config := h.opts
|
config := h.opts
|
||||||
h.RUnlock()
|
h.RUnlock()
|
||||||
@@ -522,6 +494,7 @@ func (h *Server) Start() error {
|
|||||||
h.Unlock()
|
h.Unlock()
|
||||||
|
|
||||||
var handler http.Handler
|
var handler http.Handler
|
||||||
|
var srvFunc func(net.Listener) error
|
||||||
|
|
||||||
// nolint: nestif
|
// nolint: nestif
|
||||||
if h.opts.Context != nil {
|
if h.opts.Context != nil {
|
||||||
@@ -566,13 +539,8 @@ func (h *Server) Start() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := h.subscribe(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
fn := handler
|
fn := handler
|
||||||
|
|
||||||
var hs *http.Server
|
|
||||||
if h.opts.Context != nil {
|
if h.opts.Context != nil {
|
||||||
if mwf, ok := h.opts.Context.Value(middlewareKey{}).([]func(http.Handler) http.Handler); ok && len(mwf) > 0 {
|
if mwf, ok := h.opts.Context.Value(middlewareKey{}).([]func(http.Handler) http.Handler); ok && len(mwf) > 0 {
|
||||||
// wrap the handler func
|
// wrap the handler func
|
||||||
@@ -580,19 +548,25 @@ func (h *Server) Start() error {
|
|||||||
fn = mwf[i-1](fn)
|
fn = mwf[i-1](fn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var ok bool
|
if hs, ok := h.opts.Context.Value(serverKey{}).(*http.Server); ok && hs != nil {
|
||||||
if hs, ok = h.opts.Context.Value(serverKey{}).(*http.Server); ok && hs != nil {
|
|
||||||
hs.Handler = fn
|
hs.Handler = fn
|
||||||
} else {
|
srvFunc = hs.Serve
|
||||||
hs = &http.Server{Handler: fn}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
go func() {
|
if srvFunc != nil {
|
||||||
if cerr := hs.Serve(ts); cerr != nil && !errors.Is(cerr, net.ErrClosed) {
|
go func() {
|
||||||
h.opts.Logger.Error(h.opts.Context, cerr)
|
if cerr := srvFunc(ts); cerr != nil && !errors.Is(cerr, net.ErrClosed) {
|
||||||
}
|
h.opts.Logger.Error(h.opts.Context, cerr)
|
||||||
}()
|
}
|
||||||
|
}()
|
||||||
|
} else {
|
||||||
|
go func() {
|
||||||
|
if cerr := http.Serve(ts, fn); cerr != nil && !errors.Is(cerr, net.ErrClosed) {
|
||||||
|
h.opts.Logger.Error(h.opts.Context, cerr)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
t := new(time.Ticker)
|
t := new(time.Ticker)
|
||||||
@@ -656,41 +630,33 @@ func (h *Server) Start() error {
|
|||||||
config.Logger.Errorf(config.Context, "Broker disconnect error: %s", err)
|
config.Logger.Errorf(config.Context, "Broker disconnect error: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), h.opts.GracefulTimeout)
|
ch <- ts.Close()
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
err := hs.Shutdown(ctx)
|
|
||||||
if err != nil {
|
|
||||||
err = hs.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
ch <- err
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) Stop() error {
|
func (h *httpServer) Stop() error {
|
||||||
ch := make(chan error)
|
ch := make(chan error)
|
||||||
h.exit <- ch
|
h.exit <- ch
|
||||||
return <-ch
|
return <-ch
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) String() string {
|
func (h *httpServer) String() string {
|
||||||
return "http"
|
return "http"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Server) Name() string {
|
func (h *httpServer) Name() string {
|
||||||
return h.opts.Name
|
return h.opts.Name
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(opts ...server.Option) *Server {
|
func NewServer(opts ...server.Option) *httpServer {
|
||||||
options := server.NewOptions(opts...)
|
options := server.NewOptions(opts...)
|
||||||
eh := DefaultErrorHandler
|
eh := DefaultErrorHandler
|
||||||
if v, ok := options.Context.Value(errorHandlerKey{}).(errorHandler); ok && v != nil {
|
if v, ok := options.Context.Value(errorHandlerKey{}).(errorHandler); ok && v != nil {
|
||||||
eh = v
|
eh = v
|
||||||
}
|
}
|
||||||
return &Server{
|
return &httpServer{
|
||||||
opts: options,
|
opts: options,
|
||||||
exit: make(chan chan error),
|
exit: make(chan chan error),
|
||||||
subscribers: make(map[*httpSubscriber][]broker.Subscriber),
|
subscribers: make(map[*httpSubscriber][]broker.Subscriber),
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package http
|
package http
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
type httpMessage struct {
|
type httpMessage struct {
|
||||||
|
|||||||
13
options.go
13
options.go
@@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SetError pass error to caller
|
// SetError pass error to caller
|
||||||
@@ -85,8 +85,8 @@ func Middleware(mw ...func(http.Handler) http.Handler) server.Option {
|
|||||||
|
|
||||||
type serverKey struct{}
|
type serverKey struct{}
|
||||||
|
|
||||||
// HTTPServer provide ability to pass *http.Server
|
// Server provide ability to pass *http.Server
|
||||||
func HTTPServer(hs *http.Server) server.Option {
|
func Server(hs *http.Server) server.Option {
|
||||||
return server.SetOption(serverKey{}, hs)
|
return server.SetOption(serverKey{}, hs)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,13 +133,6 @@ func RegisterRPCHandler(b bool) server.Option {
|
|||||||
return server.SetOption(registerRPCHandlerKey{}, b)
|
return server.SetOption(registerRPCHandlerKey{}, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
type registerCORSHandlerKey struct{}
|
|
||||||
|
|
||||||
// RegisterCORSHandler registers cors endpoints with /ServiceName.ServiceEndpoint method POPTIONSOST
|
|
||||||
func RegisterCORSHandler(b bool) server.Option {
|
|
||||||
return server.SetOption(registerCORSHandlerKey{}, b)
|
|
||||||
}
|
|
||||||
|
|
||||||
type handlerEndpointsKey struct{}
|
type handlerEndpointsKey struct{}
|
||||||
|
|
||||||
type EndpointMetadata struct {
|
type EndpointMetadata struct {
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package http
|
|||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"unicode"
|
"unicode"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
type methodType struct {
|
type methodType struct {
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/broker"
|
"go.unistack.org/micro/v4/broker"
|
||||||
"go.unistack.org/micro/v3/codec"
|
"go.unistack.org/micro/v4/codec"
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
"go.unistack.org/micro/v3/register"
|
"go.unistack.org/micro/v4/register"
|
||||||
"go.unistack.org/micro/v3/server"
|
"go.unistack.org/micro/v4/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
|
var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
|
||||||
@@ -101,7 +101,7 @@ func newSubscriber(topic string, sub interface{}, opts ...server.SubscriberOptio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) createSubHandler(sb *httpSubscriber, opts server.Options) broker.Handler {
|
func (s *httpServer) createSubHandler(sb *httpSubscriber, opts server.Options) broker.Handler {
|
||||||
return func(p broker.Event) error {
|
return func(p broker.Event) error {
|
||||||
msg := p.Message()
|
msg := p.Message()
|
||||||
ct := msg.Header["Content-Type"]
|
ct := msg.Header["Content-Type"]
|
||||||
@@ -111,6 +111,7 @@ func (s *Server) createSubHandler(sb *httpSubscriber, opts server.Options) broke
|
|||||||
}
|
}
|
||||||
|
|
||||||
hdr := metadata.Copy(msg.Header)
|
hdr := metadata.Copy(msg.Header)
|
||||||
|
delete(hdr, "Content-Type")
|
||||||
ctx := metadata.NewIncomingContext(context.Background(), hdr)
|
ctx := metadata.NewIncomingContext(context.Background(), hdr)
|
||||||
|
|
||||||
results := make(chan error, len(sb.handlers))
|
results := make(chan error, len(sb.handlers))
|
||||||
|
|||||||
4
util.go
4
util.go
@@ -5,8 +5,8 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
rutil "go.unistack.org/micro/v3/util/reflect"
|
rutil "go.unistack.org/micro/v4/util/reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
func FillRequest(ctx context.Context, req interface{}, opts ...FillRequestOption) error {
|
func FillRequest(ctx context.Context, req interface{}, opts ...FillRequestOption) error {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"go.unistack.org/micro/v3/metadata"
|
"go.unistack.org/micro/v4/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFillrequest(t *testing.T) {
|
func TestFillrequest(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user