From 3d5f87c01be946440d0cdbdfc971314b3b747bb1 Mon Sep 17 00:00:00 2001 From: asim Date: Sun, 7 Jul 2024 18:40:15 +0100 Subject: [PATCH] no one is using that --- api/api.go | 184 ----- api/api_test.go | 151 ----- api/client/client.go | 233 ------- api/client/client_test.go | 24 - api/default.go | 87 --- api/handler/api/api.go | 126 ---- api/handler/api/util.go | 124 ---- api/handler/api/util_test.go | 46 -- api/handler/event/event.go | 147 ---- api/handler/handler.go | 14 - api/handler/http/http.go | 86 --- api/handler/http/http_test.go | 126 ---- api/handler/options.go | 84 --- api/handler/rpc/rpc.go | 564 ---------------- api/handler/rpc/rpc_test.go | 119 ---- api/handler/rpc/stream.go | 245 ------- api/handler/web/web.go | 169 ----- api/internal/proto/message.pb.go | 28 - api/options.go | 45 -- api/proto/api.pb.go | 335 ---------- api/proto/api.pb.micro.go | 21 - api/proto/api.proto | 43 -- api/resolver/grpc/grpc.go | 42 -- api/resolver/host/host.go | 33 - api/resolver/options.go | 33 - api/resolver/path/path.go | 40 -- api/resolver/resolver.go | 46 -- api/resolver/vpath/vpath.go | 72 -- api/router/endpoint.go | 99 --- api/router/options.go | 65 -- api/router/registry/registry.go | 514 -------------- api/router/registry/registry_test.go | 34 - api/router/router.go | 49 -- api/router/static/static.go | 369 ----------- api/router/util/LICENSE.txt | 27 - api/router/util/compile.go | 122 ---- api/router/util/compile_test.go | 122 ---- api/router/util/parse.go | 396 ----------- api/router/util/parse_test.go | 321 --------- api/router/util/pattern.go | 24 - api/router/util/runtime.go | 282 -------- api/router/util/types.go | 66 -- api/router/util/types_test.go | 94 --- api/server/acme/acme.go | 28 - api/server/acme/autocert/autocert.go | 47 -- api/server/acme/autocert/autocert_test.go | 16 - api/server/acme/autocert/cache.go | 37 -- api/server/acme/options.go | 86 --- api/server/cors/cors.go | 57 -- api/server/http/http.go | 118 ---- api/server/http/http_test.go | 115 ---- api/server/options.go | 101 --- api/server/server.go | 15 - .../examples/greeter/greeter.pb.micro.go | 35 - cmd/protoc-gen-micro/plugin/micro/micro.go | 29 - util/file/client.go | 190 ------ util/file/file.go | 15 - util/file/file_test.go | 17 - util/file/handler.go | 156 ----- util/file/proto/file.pb.go | 626 ------------------ util/file/proto/file.pb.micro.go | 161 ----- util/file/proto/file.proto | 69 -- 62 files changed, 7769 deletions(-) delete mode 100644 api/api.go delete mode 100644 api/api_test.go delete mode 100644 api/client/client.go delete mode 100644 api/client/client_test.go delete mode 100644 api/default.go delete mode 100644 api/handler/api/api.go delete mode 100644 api/handler/api/util.go delete mode 100644 api/handler/api/util_test.go delete mode 100644 api/handler/event/event.go delete mode 100644 api/handler/handler.go delete mode 100644 api/handler/http/http.go delete mode 100644 api/handler/http/http_test.go delete mode 100644 api/handler/options.go delete mode 100644 api/handler/rpc/rpc.go delete mode 100644 api/handler/rpc/rpc_test.go delete mode 100644 api/handler/rpc/stream.go delete mode 100644 api/handler/web/web.go delete mode 100644 api/internal/proto/message.pb.go delete mode 100644 api/options.go delete mode 100644 api/proto/api.pb.go delete mode 100644 api/proto/api.pb.micro.go delete mode 100644 api/proto/api.proto delete mode 100644 api/resolver/grpc/grpc.go delete mode 100644 api/resolver/host/host.go delete mode 100644 api/resolver/options.go delete mode 100644 api/resolver/path/path.go delete mode 100644 api/resolver/resolver.go delete mode 100644 api/resolver/vpath/vpath.go delete mode 100644 api/router/endpoint.go delete mode 100644 api/router/options.go delete mode 100644 api/router/registry/registry.go delete mode 100644 api/router/registry/registry_test.go delete mode 100644 api/router/router.go delete mode 100644 api/router/static/static.go delete mode 100644 api/router/util/LICENSE.txt delete mode 100644 api/router/util/compile.go delete mode 100644 api/router/util/compile_test.go delete mode 100644 api/router/util/parse.go delete mode 100644 api/router/util/parse_test.go delete mode 100644 api/router/util/pattern.go delete mode 100644 api/router/util/runtime.go delete mode 100644 api/router/util/types.go delete mode 100644 api/router/util/types_test.go delete mode 100644 api/server/acme/acme.go delete mode 100644 api/server/acme/autocert/autocert.go delete mode 100644 api/server/acme/autocert/autocert_test.go delete mode 100644 api/server/acme/autocert/cache.go delete mode 100644 api/server/acme/options.go delete mode 100644 api/server/cors/cors.go delete mode 100644 api/server/http/http.go delete mode 100644 api/server/http/http_test.go delete mode 100644 api/server/options.go delete mode 100644 api/server/server.go delete mode 100644 util/file/client.go delete mode 100644 util/file/file.go delete mode 100644 util/file/file_test.go delete mode 100644 util/file/handler.go delete mode 100644 util/file/proto/file.pb.go delete mode 100644 util/file/proto/file.pb.micro.go delete mode 100644 util/file/proto/file.proto diff --git a/api/api.go b/api/api.go deleted file mode 100644 index 433c893dfe..0000000000 --- a/api/api.go +++ /dev/null @@ -1,184 +0,0 @@ -// Package api is for building api gateways -package api - -import ( - "context" - "errors" - "regexp" - "strings" - - "go-micro.dev/v5/api/router" - "go-micro.dev/v5/client" - "go-micro.dev/v5/registry" - "go-micro.dev/v5/server" -) - -// API interface provides a way to -// create composable API gateways. -type Api interface { - // Initialize options - Init(...Option) error - // Get the options - Options() Options - // Register an endpoint - Register(*Endpoint) error - // Deregister an endpoint - Deregister(*Endpoint) error - // Run the api - Run(context.Context) error - // Implemenation of api e.g http - String() string -} - -// Options are API options. -type Options struct { - // Router for resolving routes - Router router.Router - // Client to use for RPC - Client client.Client - // Address of the server - Address string -} - -// Option type are API option args. -type Option func(*Options) error - -// Endpoint is a mapping between an RPC method and HTTP endpoint. -type Endpoint struct { - // RPC Method e.g. Greeter.Hello - Name string - // Description e.g what's this endpoint for - Description string - // API Handler e.g rpc, proxy - Handler string - // HTTP Host e.g example.com - Host []string - // HTTP Methods e.g GET, POST - Method []string - // HTTP Path e.g /greeter. Expect POSIX regex - Path []string - // Stream flag - Stream bool -} - -// Service represents an API service. -type Service struct { - // Name of service - Name string - // The endpoint for this service - Endpoint *Endpoint - // Versions of this service - Versions []*registry.Service -} - -func strip(s string) string { - return strings.TrimSpace(s) -} - -func slice(s string) []string { - var sl []string - - for _, p := range strings.Split(s, ",") { - if str := strip(p); len(str) > 0 { - sl = append(sl, strip(p)) - } - } - - return sl -} - -// Encode encodes an endpoint to endpoint metadata. -func Encode(e *Endpoint) map[string]string { - if e == nil { - return nil - } - - // endpoint map - em := make(map[string]string) - - // set vals only if they exist - set := func(k, v string) { - if len(v) == 0 { - return - } - - em[k] = v - } - - set("endpoint", e.Name) - set("description", e.Description) - set("handler", e.Handler) - set("method", strings.Join(e.Method, ",")) - set("path", strings.Join(e.Path, ",")) - set("host", strings.Join(e.Host, ",")) - - return em -} - -// Decode decodes endpoint metadata into an endpoint. -func Decode(e map[string]string) *Endpoint { - if e == nil { - return nil - } - - return &Endpoint{ - Name: e["endpoint"], - Description: e["description"], - Method: slice(e["method"]), - Path: slice(e["path"]), - Host: slice(e["host"]), - Handler: e["handler"], - } -} - -// Validate validates an endpoint to guarantee it won't blow up when being served. -func Validate(e *Endpoint) error { - if e == nil { - return errors.New("endpoint is nil") - } - - if len(e.Name) == 0 { - return errors.New("name required") - } - - for _, p := range e.Path { - ps := p[0] - pe := p[len(p)-1] - - if ps == '^' && pe == '$' { - _, err := regexp.CompilePOSIX(p) - if err != nil { - return err - } - } else if ps == '^' && pe != '$' { - return errors.New("invalid path") - } else if ps != '^' && pe == '$' { - return errors.New("invalid path") - } - } - - if len(e.Handler) == 0 { - return errors.New("invalid handler") - } - - return nil -} - -// WithEndpoint returns a server.HandlerOption with endpoint metadata set -// -// Usage: -// -// proto.RegisterHandler(service.Server(), new(Handler), api.WithEndpoint( -// &api.Endpoint{ -// Name: "Greeter.Hello", -// Path: []string{"/greeter"}, -// }, -// )) -func WithEndpoint(e *Endpoint) server.HandlerOption { - return server.EndpointMetadata(e.Name, Encode(e)) -} - -// NewApi returns a new api gateway. -func NewApi(opts ...Option) Api { - return newApi(opts...) -} diff --git a/api/api_test.go b/api/api_test.go deleted file mode 100644 index f515ddfecc..0000000000 --- a/api/api_test.go +++ /dev/null @@ -1,151 +0,0 @@ -package api - -import ( - "strings" - "testing" -) - -func TestEncoding(t *testing.T) { - testData := []*Endpoint{ - nil, - { - Name: "Foo.Bar", - Description: "A test endpoint", - Handler: "meta", - Host: []string{"foo.com"}, - Method: []string{"GET"}, - Path: []string{"/test"}, - }, - } - - compare := func(expect, got []string) bool { - // no data to compare, return true - if len(expect) == 0 && len(got) == 0 { - return true - } - // no data expected but got some return false - if len(expect) == 0 && len(got) > 0 { - return false - } - - // compare expected with what we got - for _, e := range expect { - var seen bool - for _, g := range got { - if e == g { - seen = true - break - } - } - if !seen { - return false - } - } - - // we're done, return true - return true - } - - for _, d := range testData { - // encode - e := Encode(d) - // decode - de := Decode(e) - - // nil endpoint returns nil - if d == nil { - if e != nil { - t.Fatalf("expected nil got %v", e) - } - if de != nil { - t.Fatalf("expected nil got %v", de) - } - - continue - } - - // check encoded map - name := e["endpoint"] - desc := e["description"] - method := strings.Split(e["method"], ",") - path := strings.Split(e["path"], ",") - host := strings.Split(e["host"], ",") - handler := e["handler"] - - if name != d.Name { - t.Fatalf("expected %v got %v", d.Name, name) - } - if desc != d.Description { - t.Fatalf("expected %v got %v", d.Description, desc) - } - if handler != d.Handler { - t.Fatalf("expected %v got %v", d.Handler, handler) - } - if ok := compare(d.Method, method); !ok { - t.Fatalf("expected %v got %v", d.Method, method) - } - if ok := compare(d.Path, path); !ok { - t.Fatalf("expected %v got %v", d.Path, path) - } - if ok := compare(d.Host, host); !ok { - t.Fatalf("expected %v got %v", d.Host, host) - } - - if de.Name != d.Name { - t.Fatalf("expected %v got %v", d.Name, de.Name) - } - if de.Description != d.Description { - t.Fatalf("expected %v got %v", d.Description, de.Description) - } - if de.Handler != d.Handler { - t.Fatalf("expected %v got %v", d.Handler, de.Handler) - } - if ok := compare(d.Method, de.Method); !ok { - t.Fatalf("expected %v got %v", d.Method, de.Method) - } - if ok := compare(d.Path, de.Path); !ok { - t.Fatalf("expected %v got %v", d.Path, de.Path) - } - if ok := compare(d.Host, de.Host); !ok { - t.Fatalf("expected %v got %v", d.Host, de.Host) - } - } -} - -func TestValidate(t *testing.T) { - epPcre := &Endpoint{ - Name: "Foo.Bar", - Description: "A test endpoint", - Handler: "meta", - Host: []string{"foo.com"}, - Method: []string{"GET"}, - Path: []string{"^/test/?$"}, - } - if err := Validate(epPcre); err != nil { - t.Fatal(err) - } - - epGpath := &Endpoint{ - Name: "Foo.Bar", - Description: "A test endpoint", - Handler: "meta", - Host: []string{"foo.com"}, - Method: []string{"GET"}, - Path: []string{"/test/{id}"}, - } - if err := Validate(epGpath); err != nil { - t.Fatal(err) - } - - epPcreInvalid := &Endpoint{ - Name: "Foo.Bar", - Description: "A test endpoint", - Handler: "meta", - Host: []string{"foo.com"}, - Method: []string{"GET"}, - Path: []string{"/test/?$"}, - } - if err := Validate(epPcreInvalid); err == nil { - t.Fatalf("invalid pcre %v", epPcreInvalid.Path[0]) - } -} diff --git a/api/client/client.go b/api/client/client.go deleted file mode 100644 index ee64e0ed85..0000000000 --- a/api/client/client.go +++ /dev/null @@ -1,233 +0,0 @@ -// Package client provides an api client -package client - -import ( - "bytes" - "encoding/json" - "errors" - "io/ioutil" - "net/http" - "net/url" - "strings" - "time" - - "github.com/gorilla/websocket" - "go-micro.dev/v5/logger" -) - -const ( - // local address for api. - localAddress = "http://localhost:8080" -) - -// Options of the Client. -type Options struct { - // Token for authentication - Token string - // Address of the micro platform. - // By default it connects to live. Change it or use the local flag - // to connect to your local installation. - Address string - // Helper flag to help users connect to the default local address - Local bool - // set a timeout - Timeout time.Duration -} - -// Request is the request of the generic `api-client` call. -type Request struct { - // eg. "go.micro.srv.greeter" - Service string `json:"service"` - // eg. "Say.Hello" - Endpoint string `json:"endpoint"` - // json and then base64 encoded body - Body string `json:"body"` -} - -// Response is the response of the generic `api-client` call. -type Response struct { - // json and base64 encoded response body - Body string `json:"body"` - ID string `json:"id"` - Detail string `json:"detail"` - Status string `json:"status"` - // error fields. Error json example - // {"id":"go.micro.client","code":500,"detail":"malformed method name: \"\"","status":"Internal Server Error"} - Code int `json:"code"` -} - -// Client enables generic calls to micro. -type Client struct { - options Options -} - -// Stream is a websockets stream. -type Stream struct { - conn *websocket.Conn - service, endpoint string -} - -// NewClient returns a generic micro client that connects to live by default. -func NewClient(options *Options) *Client { - ret := new(Client) - ret.options = Options{ - Address: localAddress, - } - - // no options provided - if options == nil { - return ret - } - - if options.Token != "" { - ret.options.Token = options.Token - } - - if options.Local { - ret.options.Address = localAddress - ret.options.Local = true - } - - if options.Timeout > 0 { - ret.options.Timeout = options.Timeout - } - - return ret -} - -// SetToken sets the api auth token. -func (client *Client) SetToken(t string) { - client.options.Token = t -} - -// SetTimeout sets the http client's timeout. -func (client *Client) SetTimeout(d time.Duration) { - client.options.Timeout = d -} - -// Call enables you to access any endpoint of any service on Micro. -func (client *Client) Call(service, endpoint string, request, response interface{}) error { - // example curl: curl -XPOST -d '{"service": "go.micro.srv.greeter", "endpoint": "Say.Hello"}' - // -H 'Content-Type: application/json' http://localhost:8080/client {"body":"eyJtc2ciOiJIZWxsbyAifQ=="} - uri, err := url.Parse(client.options.Address) - if err != nil { - return err - } - - // set the url to go through the v1 api - uri.Path = "/" + service + "/" + endpoint - - b, err := marshalRequest(endpoint, request) - if err != nil { - return err - } - - req, err := http.NewRequest("POST", uri.String(), bytes.NewBuffer(b)) - if err != nil { - return err - } - - // set the token if it exists - if len(client.options.Token) > 0 { - req.Header.Set("Authorization", "Bearer "+client.options.Token) - } - - req.Header.Set("Content-Type", "application/json") - - // if user didn't specify Timeout the default is 0 i.e no timeout - httpClient := &http.Client{ - Timeout: client.options.Timeout, - } - - resp, err := httpClient.Do(req) - if err != nil { - return err - } - - defer func() { - if err = resp.Body.Close(); err != nil { - logger.DefaultLogger.Log(logger.ErrorLevel, err) - } - }() - - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return err - } - - if resp.StatusCode <= 200 || resp.StatusCode > 300 { - return errors.New(string(body)) - } - - return unmarshalResponse(body, response) -} - -// Stream enables the ability to stream via websockets. -func (client *Client) Stream(service, endpoint string, request interface{}) (*Stream, error) { - bytes, err := marshalRequest(endpoint, request) - if err != nil { - return nil, err - } - - uri, err := url.Parse(client.options.Address) - if err != nil { - return nil, err - } - - // set the url to go through the v1 api - uri.Path = "/" + service + "/" + endpoint - - // replace http with websocket - uri.Scheme = strings.Replace(uri.Scheme, "http", "ws", 1) - - // create the headers - header := make(http.Header) - // set the token if it exists - if len(client.options.Token) > 0 { - header.Set("Authorization", "Bearer "+client.options.Token) - } - - header.Set("Content-Type", "application/json") - - // dial the connection, connection not closed as conn is returned - conn, _, err := websocket.DefaultDialer.Dial(uri.String(), header) - if err != nil { - return nil, err - } - - // send the first request - if err := conn.WriteMessage(websocket.TextMessage, bytes); err != nil { - return nil, err - } - - return &Stream{conn, service, endpoint}, nil -} - -// Recv will receive a message from a stream and unmarshal it. -func (s *Stream) Recv(v interface{}) error { - // read response - _, message, err := s.conn.ReadMessage() - if err != nil { - return err - } - - return unmarshalResponse(message, v) -} - -// Send will send a message into the stream. -func (s *Stream) Send(v interface{}) error { - b, err := marshalRequest(s.endpoint, v) - if err != nil { - return err - } - - return s.conn.WriteMessage(websocket.TextMessage, b) -} - -func marshalRequest(_ string, v interface{}) ([]byte, error) { - return json.Marshal(v) -} - -func unmarshalResponse(body []byte, v interface{}) error { - return json.Unmarshal(body, &v) -} diff --git a/api/client/client_test.go b/api/client/client_test.go deleted file mode 100644 index 6e79f3be6e..0000000000 --- a/api/client/client_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package client - -import ( - "os" - "testing" -) - -func TestBasicCall(t *testing.T) { - if v := os.Getenv("IN_TRAVIS_CI"); v == "yes" { - return - } - - response := map[string]interface{}{} - if err := NewClient(&Options{ - Token: os.Getenv("TOKEN"), - }).Call("groups", "list", map[string]interface{}{ - "memberId": "random", - }, &response); err != nil { - t.Fatal(err) - } - if len(response) > 0 { - t.Fatal(len(response)) - } -} diff --git a/api/default.go b/api/default.go deleted file mode 100644 index b56fef672e..0000000000 --- a/api/default.go +++ /dev/null @@ -1,87 +0,0 @@ -package api - -import ( - "context" - - "go-micro.dev/v5/api/handler" - "go-micro.dev/v5/api/handler/rpc" - "go-micro.dev/v5/api/router/registry" - "go-micro.dev/v5/api/server" - "go-micro.dev/v5/api/server/http" -) - -type api struct { - options Options - - server server.Server -} - -func newApi(opts ...Option) Api { - options := NewOptions(opts...) - - rtr := options.Router - - if rtr == nil { - // TODO: make configurable - rtr = registry.NewRouter() - } - - // TODO: make configurable - hdlr := rpc.NewHandler( - handler.WithRouter(rtr), - ) - - // TODO: make configurable - // create a new server - srv := http.NewServer(options.Address) - - // TODO: allow multiple handlers - // define the handler - srv.Handle("/", hdlr) - - return &api{ - options: options, - server: srv, - } -} - -func (a *api) Init(opts ...Option) error { - for _, o := range opts { - o(&a.options) - } - return nil -} - -// Get the options. -func (a *api) Options() Options { - return a.options -} - -// Register a http handler. -func (a *api) Register(*Endpoint) error { - return nil -} - -// Register a route. -func (a *api) Deregister(*Endpoint) error { - return nil -} - -func (a *api) Run(ctx context.Context) error { - if err := a.server.Start(); err != nil { - return err - } - - // wait to finish - <-ctx.Done() - - if err := a.server.Stop(); err != nil { - return err - } - - return nil -} - -func (a *api) String() string { - return "http" -} diff --git a/api/handler/api/api.go b/api/handler/api/api.go deleted file mode 100644 index 7b8647eb8f..0000000000 --- a/api/handler/api/api.go +++ /dev/null @@ -1,126 +0,0 @@ -// Package api provides an http-rpc handler which provides the entire http request over rpc -package api - -import ( - "net/http" - - "go-micro.dev/v5/api/handler" - api "go-micro.dev/v5/api/proto" - "go-micro.dev/v5/api/router" - "go-micro.dev/v5/client" - "go-micro.dev/v5/errors" - "go-micro.dev/v5/selector" - "go-micro.dev/v5/util/ctx" -) - -type apiHandler struct { - opts handler.Options -} - -const ( - // Handler is the name of the Handler. - Handler = "api" -) - -// API handler is the default handler which takes api.Request and returns api.Response. -func (a *apiHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - bsize := handler.DefaultMaxRecvSize - if a.opts.MaxRecvSize > 0 { - bsize = a.opts.MaxRecvSize - } - - r.Body = http.MaxBytesReader(w, r.Body, bsize) - - request, err := requestToProto(r) - if err != nil { - er := errors.InternalServerError("go.micro.api", err.Error()) - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(er.Error())) - - return - } - - var service *router.Route - - if a.opts.Router != nil { - // try get service from router - s, err := a.opts.Router.Route(r) - if err != nil { - er := errors.InternalServerError("go.micro.api", err.Error()) - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(er.Error())) - - return - } - - service = s - } else { - // we have no way of routing the request - er := errors.InternalServerError("go.micro.api", "no route found") - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusInternalServerError) - w.Write([]byte(er.Error())) - - return - } - - // create request and response - c := a.opts.Client - req := c.NewRequest(service.Service, service.Endpoint.Name, request) - rsp := &api.Response{} - - // create the context from headers - cx := ctx.FromRequest(r) - // create strategy: - so := selector.WithStrategy(strategy(service.Versions)) - - if err := c.Call(cx, req, rsp, client.WithSelectOption(so)); err != nil { - w.Header().Set("Content-Type", "application/json") - - ce := errors.Parse(err.Error()) - switch ce.Code { - case 0: - w.WriteHeader(http.StatusInternalServerError) - default: - w.WriteHeader(int(ce.Code)) - } - - w.Write([]byte(ce.Error())) - - return - } else if rsp.StatusCode == 0 { - rsp.StatusCode = http.StatusOK - } - - for _, header := range rsp.GetHeader() { - for _, val := range header.Values { - w.Header().Add(header.Key, val) - } - } - - if len(w.Header().Get("Content-Type")) == 0 { - w.Header().Set("Content-Type", "application/json") - } - - w.WriteHeader(int(rsp.StatusCode)) - - w.Write([]byte(rsp.Body)) -} - -func (a *apiHandler) String() string { - return "api" -} - -// NewHandler returns an api.Handler. -func NewHandler(opts ...handler.Option) handler.Handler { - options := handler.NewOptions(opts...) - - return &apiHandler{ - opts: options, - } -} diff --git a/api/handler/api/util.go b/api/handler/api/util.go deleted file mode 100644 index ae54ad35cd..0000000000 --- a/api/handler/api/util.go +++ /dev/null @@ -1,124 +0,0 @@ -package api - -import ( - "fmt" - "mime" - "net" - "net/http" - "strings" - - "github.com/oxtoacart/bpool" - api "go-micro.dev/v5/api/proto" - "go-micro.dev/v5/registry" - "go-micro.dev/v5/selector" -) - -var ( - // need to calculate later to specify useful defaults. - bufferPool = bpool.NewSizedBufferPool(1024, 8) -) - -func requestToProto(r *http.Request) (*api.Request, error) { - if err := r.ParseForm(); err != nil { - return nil, fmt.Errorf("Error parsing form: %w", err) - } - - req := &api.Request{ - Path: r.URL.Path, - Method: r.Method, - Header: make(map[string]*api.Pair), - Get: make(map[string]*api.Pair), - Post: make(map[string]*api.Pair), - Url: r.URL.String(), - } - - ct, _, err := mime.ParseMediaType(r.Header.Get("Content-Type")) - if err != nil { - ct = "text/plain; charset=UTF-8" // default CT is text/plain - r.Header.Set("Content-Type", ct) - } - - // set the body: - if r.Body != nil { - switch ct { - case "application/x-www-form-urlencoded": - // expect form vals in Post data - default: - buf := bufferPool.Get() - defer bufferPool.Put(buf) - - if _, err = buf.ReadFrom(r.Body); err != nil { - return nil, err - } - - req.Body = buf.String() - } - } - - // Set X-Forwarded-For if it does not exist - if ip, _, err := net.SplitHostPort(r.RemoteAddr); err == nil { - if prior, ok := r.Header["X-Forwarded-For"]; ok { - ip = strings.Join(prior, ", ") + ", " + ip - } - - // Set the header - req.Header["X-Forwarded-For"] = &api.Pair{ - Key: "X-Forwarded-For", - Values: []string{ip}, - } - } - - // Host is stripped from net/http Headers so let's add it - req.Header["Host"] = &api.Pair{ - Key: "Host", - Values: []string{r.Host}, - } - - // Get data - for key, vals := range r.URL.Query() { - header, ok := req.Get[key] - if !ok { - header = &api.Pair{ - Key: key, - } - req.Get[key] = header - } - - header.Values = vals - } - - // Post data - for key, vals := range r.PostForm { - header, ok := req.Post[key] - if !ok { - header = &api.Pair{ - Key: key, - } - req.Post[key] = header - } - - header.Values = vals - } - - for key, vals := range r.Header { - header, ok := req.Header[key] - if !ok { - header = &api.Pair{ - Key: key, - } - req.Header[key] = header - } - - header.Values = vals - } - - return req, nil -} - -// strategy is a hack for selection. -func strategy(services []*registry.Service) selector.Strategy { - return func(_ []*registry.Service) selector.Next { - // ignore input to this function, use services above - return selector.Random(services) - } -} diff --git a/api/handler/api/util_test.go b/api/handler/api/util_test.go deleted file mode 100644 index 9350bcdebb..0000000000 --- a/api/handler/api/util_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package api - -import ( - "net/http" - "net/url" - "testing" -) - -func TestRequestToProto(t *testing.T) { - testData := []*http.Request{ - { - Method: "GET", - Header: http.Header{ - "Header": []string{"test"}, - }, - URL: &url.URL{ - Scheme: "http", - Host: "localhost", - Path: "/foo/bar", - RawQuery: "param1=value1", - }, - }, - } - - for _, d := range testData { - p, err := requestToProto(d) - if err != nil { - t.Fatal(err) - } - if p.Path != d.URL.Path { - t.Fatalf("Expected path %s got %s", d.URL.Path, p.Path) - } - if p.Method != d.Method { - t.Fatalf("Expected method %s got %s", d.Method, p.Method) - } - for k, v := range d.Header { - if val, ok := p.Header[k]; !ok { - t.Fatalf("Expected header %s", k) - } else { - if val.Values[0] != v[0] { - t.Fatalf("Expected val %s, got %s", val.Values[0], v[0]) - } - } - } - } -} diff --git a/api/handler/event/event.go b/api/handler/event/event.go deleted file mode 100644 index c47db57254..0000000000 --- a/api/handler/event/event.go +++ /dev/null @@ -1,147 +0,0 @@ -// Package event provides a handler which publishes an event -package event - -import ( - "encoding/json" - "fmt" - "net/http" - "path" - "regexp" - "strings" - "time" - - "github.com/google/uuid" - "github.com/oxtoacart/bpool" - "go-micro.dev/v5/api/handler" - proto "go-micro.dev/v5/api/proto" - "go-micro.dev/v5/util/ctx" -) - -var ( - bufferPool = bpool.NewSizedBufferPool(1024, 8) -) - -type event struct { - opts handler.Options -} - -var ( - // Handler is the name of this handler. - Handler = "event" - versionRe = regexp.MustCompilePOSIX("^v[0-9]+$") -) - -func eventName(parts []string) string { - return strings.Join(parts, ".") -} - -func evRoute(namespace, myPath string) (string, string) { - myPath = path.Clean(myPath) - myPath = strings.TrimPrefix(myPath, "/") - - if len(myPath) == 0 { - return namespace, Handler - } - - parts := strings.Split(myPath, "/") - - // no path - if len(parts) == 0 { - // topic: namespace - // action: event - return strings.Trim(namespace, "."), Handler - } - - // Treat /v[0-9]+ as versioning - // /v1/foo/bar => topic: v1.foo action: bar - if len(parts) >= 2 && versionRe.MatchString(parts[0]) { - topic := namespace + "." + strings.Join(parts[:2], ".") - action := eventName(parts[1:]) - - return topic, action - } - - // /foo => topic: ns.foo action: foo - // /foo/bar => topic: ns.foo action: bar - topic := namespace + "." + strings.Join(parts[:1], ".") - action := eventName(parts[1:]) - - return topic, action -} - -func (e *event) ServeHTTP(rsp http.ResponseWriter, req *http.Request) { - bsize := handler.DefaultMaxRecvSize - if e.opts.MaxRecvSize > 0 { - bsize = e.opts.MaxRecvSize - } - - req.Body = http.MaxBytesReader(rsp, req.Body, bsize) - - // request to topic:event - // create event - // publish to topic - - topic, action := evRoute(e.opts.Namespace, req.URL.Path) - - // create event - event := &proto.Event{ - Name: action, - // TODO: dedupe event - Id: fmt.Sprintf("%s-%s-%s", topic, action, uuid.New().String()), - Header: make(map[string]*proto.Pair), - Timestamp: time.Now().Unix(), - } - - // set headers - for key, vals := range req.Header { - header, ok := event.Header[key] - if !ok { - header = &proto.Pair{ - Key: key, - } - event.Header[key] = header - } - - header.Values = vals - } - - // set body - if req.Method == http.MethodGet { - bytes, _ := json.Marshal(req.URL.Query()) - event.Data = string(bytes) - } else { - // Read body - buf := bufferPool.Get() - defer bufferPool.Put(buf) - if _, err := buf.ReadFrom(req.Body); err != nil { - http.Error(rsp, err.Error(), http.StatusInternalServerError) - - return - } - event.Data = buf.String() - } - - // get client - c := e.opts.Client - - // create publication - p := c.NewMessage(topic, event) - - // publish event - if err := c.Publish(ctx.FromRequest(req), p); err != nil { - http.Error(rsp, err.Error(), http.StatusInternalServerError) - - return - } -} - -func (e *event) String() string { - return Handler -} - -// NewHandler returns a new event handler. -func NewHandler(opts ...handler.Option) handler.Handler { - return &event{ - opts: handler.NewOptions(opts...), - } -} diff --git a/api/handler/handler.go b/api/handler/handler.go deleted file mode 100644 index 72f9c23e8a..0000000000 --- a/api/handler/handler.go +++ /dev/null @@ -1,14 +0,0 @@ -// Package handler provides http handlers -package handler - -import ( - "net/http" -) - -// Handler represents a HTTP handler that manages a request. -type Handler interface { - // standard http handler - http.Handler - // name of handler - String() string -} diff --git a/api/handler/http/http.go b/api/handler/http/http.go deleted file mode 100644 index cff210250b..0000000000 --- a/api/handler/http/http.go +++ /dev/null @@ -1,86 +0,0 @@ -// Package http is a http reverse proxy handler -package http - -import ( - "errors" - "fmt" - "net/http" - "net/http/httputil" - "net/url" - - "go-micro.dev/v5/api/handler" - "go-micro.dev/v5/api/router" - "go-micro.dev/v5/selector" -) - -const ( - // Handler is the name of the handler. - Handler = "http" -) - -type httpHandler struct { - options handler.Options -} - -func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - service, err := h.getService(r) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - if len(service) == 0 { - w.WriteHeader(http.StatusNotFound) - return - } - - rp, err := url.Parse(service) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - httputil.NewSingleHostReverseProxy(rp).ServeHTTP(w, r) -} - -// getService returns the service for this request from the selector. -func (h *httpHandler) getService(r *http.Request) (string, error) { - var service *router.Route - - if h.options.Router != nil { - // try get service from router - s, err := h.options.Router.Route(r) - if err != nil { - return "", err - } - - service = s - } else { - // we have no way of routing the request - return "", errors.New("no route found") - } - - // create a random selector - next := selector.Random(service.Versions) - - // get the next node - s, err := next() - if err != nil { - return "", nil - } - - return fmt.Sprintf("http://%s", s.Address), nil -} - -func (h *httpHandler) String() string { - return "http" -} - -// NewHandler returns a http proxy handler. -func NewHandler(opts ...handler.Option) handler.Handler { - options := handler.NewOptions(opts...) - - return &httpHandler{ - options: options, - } -} diff --git a/api/handler/http/http_test.go b/api/handler/http/http_test.go deleted file mode 100644 index 9b6ca094f6..0000000000 --- a/api/handler/http/http_test.go +++ /dev/null @@ -1,126 +0,0 @@ -package http - -import ( - "net" - "net/http" - "net/http/httptest" - "testing" - - "go-micro.dev/v5/api/handler" - "go-micro.dev/v5/api/resolver" - "go-micro.dev/v5/api/resolver/vpath" - "go-micro.dev/v5/api/router" - regRouter "go-micro.dev/v5/api/router/registry" - "go-micro.dev/v5/registry" -) - -func testHttp(t *testing.T, path, service, ns string) { - r := registry.NewMemoryRegistry() - - l, err := net.Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatal(err) - } - defer l.Close() - - s := ®istry.Service{ - Name: service, - Nodes: []*registry.Node{ - { - Id: service + "-1", - Address: l.Addr().String(), - }, - }, - } - - r.Register(s) - defer r.Deregister(s) - - // setup the test handler - m := http.NewServeMux() - m.HandleFunc(path, func(w http.ResponseWriter, r *http.Request) { - w.Write([]byte(`you got served`)) - }) - - // start http test serve - go http.Serve(l, m) - - // create new request and writer - w := httptest.NewRecorder() - req, err := http.NewRequest("POST", path, nil) - if err != nil { - t.Fatal(err) - } - - // initialize the handler - rt := regRouter.NewRouter( - router.WithHandler("http"), - router.WithRegistry(r), - router.WithResolver(vpath.NewResolver( - resolver.WithNamespace(resolver.StaticNamespace(ns)), - )), - ) - - p := NewHandler(handler.WithRouter(rt)) - - // execute the handler - p.ServeHTTP(w, req) - - if w.Code != 200 { - t.Fatalf("Expected 200 response got %d %s", w.Code, w.Body.String()) - } - - if w.Body.String() != "you got served" { - t.Fatalf("Expected body: you got served. Got: %s", w.Body.String()) - } -} - -func TestHttpHandler(t *testing.T) { - testData := []struct { - path string - service string - namespace string - }{ - { - "/test/foo", - "go.micro.api.test", - "go.micro.api", - }, - { - "/test/foo/baz", - "go.micro.api.test", - "go.micro.api", - }, - { - "/v1/foo", - "go.micro.api.v1.foo", - "go.micro.api", - }, - { - "/v1/foo/bar", - "go.micro.api.v1.foo", - "go.micro.api", - }, - { - "/v2/baz", - "go.micro.api.v2.baz", - "go.micro.api", - }, - { - "/v2/baz/bar", - "go.micro.api.v2.baz", - "go.micro.api", - }, - { - "/v2/baz/bar", - "v2.baz", - "", - }, - } - - for _, d := range testData { - t.Run(d.service, func(t *testing.T) { - testHttp(t, d.path, d.service, d.namespace) - }) - } -} diff --git a/api/handler/options.go b/api/handler/options.go deleted file mode 100644 index 5267113070..0000000000 --- a/api/handler/options.go +++ /dev/null @@ -1,84 +0,0 @@ -package handler - -import ( - "go-micro.dev/v5/api/router" - "go-micro.dev/v5/client" - "go-micro.dev/v5/logger" -) - -var ( - // DefaultMaxRecvSize is 10MiB. - DefaultMaxRecvSize int64 = 1024 * 1024 * 100 -) - -// Options is the list of api Options. -type Options struct { - Router router.Router - Client client.Client - Logger logger.Logger - Namespace string - MaxRecvSize int64 -} - -// Option is a api Option. -type Option func(o *Options) - -// NewOptions fills in the blanks. -func NewOptions(opts ...Option) Options { - options := Options{ - Logger: logger.DefaultLogger, - } - - for _, o := range opts { - o(&options) - } - - if options.Client == nil { - WithClient(client.DefaultClient)(&options) - } - - if options.MaxRecvSize == 0 { - options.MaxRecvSize = DefaultMaxRecvSize - } - - if options.Logger == nil { - options.Logger = logger.LoggerOrDefault(options.Logger) - } - - return options -} - -// WithNamespace specifies the namespace for the handler. -func WithNamespace(s string) Option { - return func(o *Options) { - o.Namespace = s - } -} - -// WithRouter specifies a router to be used by the handler. -func WithRouter(r router.Router) Option { - return func(o *Options) { - o.Router = r - } -} - -// WithClient sets the client for the handler. -func WithClient(c client.Client) Option { - return func(o *Options) { - o.Client = c - } -} - -// WithMaxRecvSize specifies max body size. -func WithMaxRecvSize(size int64) Option { - return func(o *Options) { - o.MaxRecvSize = size - } -} - -// WithLogger specifies the logger. -func WithLogger(l logger.Logger) Option { - return func(o *Options) { - o.Logger = l - } -} diff --git a/api/handler/rpc/rpc.go b/api/handler/rpc/rpc.go deleted file mode 100644 index d791069161..0000000000 --- a/api/handler/rpc/rpc.go +++ /dev/null @@ -1,564 +0,0 @@ -// Package rpc is a go-micro rpc handler. -package rpc - -import ( - "encoding/json" - "io" - "net/http" - "net/textproto" - "strconv" - "strings" - - jsonpatch "github.com/evanphx/json-patch/v5" - "github.com/oxtoacart/bpool" - "go-micro.dev/v5/api/handler" - "go-micro.dev/v5/api/internal/proto" - "go-micro.dev/v5/api/router" - "go-micro.dev/v5/client" - "go-micro.dev/v5/codec" - "go-micro.dev/v5/codec/jsonrpc" - "go-micro.dev/v5/codec/protorpc" - "go-micro.dev/v5/errors" - log "go-micro.dev/v5/logger" - "go-micro.dev/v5/metadata" - "go-micro.dev/v5/registry" - "go-micro.dev/v5/selector" - "go-micro.dev/v5/util/ctx" - "go-micro.dev/v5/util/qson" -) - -const ( - // Handler is the name of this handler. - Handler = "rpc" - packageID = "go.micro.api" -) - -var ( - // supported json codecs. - jsonCodecs = []string{ - "application/grpc+json", - "application/json", - "application/json-rpc", - } - - // support proto codecs. - protoCodecs = []string{ - "application/grpc", - "application/grpc+proto", - "application/proto", - "application/protobuf", - "application/proto-rpc", - "application/octet-stream", - } - - bufferPool = bpool.NewSizedBufferPool(1024, 8) -) - -type rpcHandler struct { - opts handler.Options -} - -type buffer struct { - io.ReadCloser -} - -func (b *buffer) Write(_ []byte) (int, error) { - return 0, nil -} - -// strategy is a hack for selection. -func strategy(services []*registry.Service) selector.Strategy { - return func(_ []*registry.Service) selector.Next { - // ignore input to this function, use services above - return selector.Random(services) - } -} - -func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - logger := h.opts.Logger - bsize := handler.DefaultMaxRecvSize - - if h.opts.MaxRecvSize > 0 { - bsize = h.opts.MaxRecvSize - } - - r.Body = http.MaxBytesReader(w, r.Body, bsize) - - defer r.Body.Close() - - var service *router.Route - - if h.opts.Router != nil { - // try get service from router - s, err := h.opts.Router.Route(r) - if err != nil { - werr := writeError(w, r, errors.InternalServerError(packageID, err.Error())) - if werr != nil { - logger.Log(log.ErrorLevel, werr) - } - - return - } - - service = s - } else { - // we have no way of routing the request - werr := writeError(w, r, errors.InternalServerError(packageID, "no route found")) - if werr != nil { - logger.Log(log.ErrorLevel, werr) - } - return - } - - contentType := r.Header.Get("Content-Type") - - // Strip charset from Content-Type (like `application/json; charset=UTF-8`) - if idx := strings.IndexRune(contentType, ';'); idx >= 0 { - contentType = contentType[:idx] - } - - // micro client - myClient := h.opts.Client - - // create context - myContext := ctx.FromRequest(r) - // get context from http handler wrappers - md, ok := metadata.FromContext(r.Context()) - if !ok { - md = make(metadata.Metadata) - } - // fill contex with http headers - md["Host"] = r.Host - md["Method"] = r.Method - // get canonical headers - for k := range r.Header { - // may be need to get all values for key like r.Header.Values() provide in go 1.14 - md[textproto.CanonicalMIMEHeaderKey(k)] = r.Header.Get(k) - } - - // merge context with overwrite - myContext = metadata.MergeContext(myContext, md, true) - - // set merged context to request - *r = *r.Clone(myContext) - // if stream we currently only support json - if isStream(r, service) { - // drop older context as it can have timeouts and create new - // md, _ := metadata.FromContext(cx) - // serveWebsocket(context.TODO(), w, r, service, c) - if err := serveWebsocket(myContext, w, r, service, myClient); err != nil { - logger.Log(log.ErrorLevel, err) - } - - return - } - - // create strategy - mySelector := selector.WithStrategy(strategy(service.Versions)) - - // walk the standard call path - // get payload - br, err := requestPayload(r) - if err != nil { - if werr := writeError(w, r, err); werr != nil { - logger.Log(log.ErrorLevel, werr) - } - - return - } - - var rsp []byte - - switch { - // proto codecs - case hasCodec(contentType, protoCodecs): - request := &proto.Message{} - // if the extracted payload isn't empty lets use it - if len(br) > 0 { - request = proto.NewMessage(br) - } - - // create request/response - response := &proto.Message{} - - req := myClient.NewRequest( - service.Service, - service.Endpoint.Name, - request, - client.WithContentType(contentType), - ) - - // make the call - if err := myClient.Call(myContext, req, response, client.WithSelectOption(mySelector)); err != nil { - if werr := writeError(w, r, err); werr != nil { - logger.Log(log.ErrorLevel, werr) - } - - return - } - - // marshall response - rsp, err = response.Marshal() - if err != nil { - if werr := writeError(w, r, err); werr != nil { - logger.Log(log.ErrorLevel, werr) - } - - return - } - - default: - // if json codec is not present set to json - if !hasCodec(contentType, jsonCodecs) { - contentType = "application/json" - } - - // default to trying json - var request json.RawMessage - // if the extracted payload isn't empty lets use it - if len(br) > 0 { - request = json.RawMessage(br) - } - - // create request/response - var response json.RawMessage - - req := myClient.NewRequest( - service.Service, - service.Endpoint.Name, - &request, - client.WithContentType(contentType), - ) - // make the call - if err := myClient.Call(myContext, req, &response, client.WithSelectOption(mySelector)); err != nil { - if werr := writeError(w, r, err); werr != nil { - logger.Log(log.ErrorLevel, werr) - } - - return - } - - // marshall response - rsp, err = response.MarshalJSON() - if err != nil { - if werr := writeError(w, r, err); werr != nil { - logger.Log(log.ErrorLevel, werr) - } - - return - } - } - - // write the response - if err := writeResponse(w, r, rsp); err != nil { - logger.Log(log.ErrorLevel, err) - } -} - -func (h *rpcHandler) String() string { - return Handler -} - -func hasCodec(ct string, codecs []string) bool { - for _, codec := range codecs { - if ct == codec { - return true - } - } - - return false -} - -// requestPayload takes a *http.Request. -// If the request is a GET the query string parameters are extracted and marshaled to JSON and the raw bytes are returned. -// If the request method is a POST the request body is read and returned. -func requestPayload(r *http.Request) ([]byte, error) { - var err error - - // we have to decode json-rpc and proto-rpc because we suck - // well actually because there's no proxy codec right now - - myCt := r.Header.Get("Content-Type") - - switch { - case strings.Contains(myCt, "application/json-rpc"): - msg := codec.Message{ - Type: codec.Request, - Header: make(map[string]string), - } - - c := jsonrpc.NewCodec(&buffer{r.Body}) - if err = c.ReadHeader(&msg, codec.Request); err != nil { - return nil, err - } - - var raw json.RawMessage - if err = c.ReadBody(&raw); err != nil { - return nil, err - } - - return ([]byte)(raw), nil - case strings.Contains(myCt, "application/proto-rpc"), strings.Contains(myCt, "application/octet-stream"): - msg := codec.Message{ - Type: codec.Request, - Header: make(map[string]string), - } - - c := protorpc.NewCodec(&buffer{r.Body}) - if err = c.ReadHeader(&msg, codec.Request); err != nil { - return nil, err - } - - var raw proto.Message - if err = c.ReadBody(&raw); err != nil { - return nil, err - } - - return raw.Marshal() - case strings.Contains(myCt, "application/www-x-form-urlencoded"), strings.Contains(myCt, "application/x-www-form-urlencoded"): - if err := r.ParseForm(); err != nil { - return nil, err - } - - // generate a new set of values from the form - vals := make(map[string]string) - for k, v := range r.Form { - vals[k] = strings.Join(v, ",") - } - - // marshal - return json.Marshal(vals) - // TODO: application/grpc - } - - // otherwise as per usual - ctx := r.Context() - - // dont user meadata.FromContext as it mangles names - md, ok := metadata.FromContext(ctx) - if !ok { - md = make(map[string]string) - } - - // allocate maximum - matches := make(map[string]interface{}, len(md)) - bodydst := "" - - // get fields from url path - for k, v := range md { - k = strings.ToLower(k) - // filter own keys - if strings.HasPrefix(k, "x-api-field-") { - matches[strings.TrimPrefix(k, "x-api-field-")] = v - - delete(md, k) - } else if k == "x-api-body" { - bodydst = v - - delete(md, k) - } - } - - // map of all fields - req := make(map[string]interface{}, len(md)) - - // get fields from url values - if len(r.URL.RawQuery) > 0 { - umd := make(map[string]interface{}) - - err = qson.Unmarshal(&umd, r.URL.RawQuery) - if err != nil { - return nil, err - } - - for k, v := range umd { - matches[k] = v - } - } - - // restore context without fields - *r = *r.Clone(metadata.NewContext(ctx, md)) - - for k, v := range matches { - ps := strings.Split(k, ".") - if len(ps) == 1 { - req[k] = v - continue - } - - em := make(map[string]interface{}) - em[ps[len(ps)-1]] = v - - for i := len(ps) - 2; i > 0; i-- { - nm := make(map[string]interface{}) - nm[ps[i]] = em - em = nm - } - - if vm, ok := req[ps[0]]; ok { - // nested map - nm := vm.(map[string]interface{}) - for vk, vv := range em { - nm[vk] = vv - } - - req[ps[0]] = nm - } else { - req[ps[0]] = em - } - } - - pathbuf := []byte("{}") - if len(req) > 0 { - pathbuf, err = json.Marshal(req) - if err != nil { - return nil, err - } - } - - urlbuf := []byte("{}") - - out, err := jsonpatch.MergeMergePatches(urlbuf, pathbuf) - if err != nil { - return nil, err - } - - switch r.Method { - case http.MethodGet: - // empty response - if strings.Contains(myCt, "application/json") && string(out) == "{}" { - return out, nil - } else if string(out) == "{}" && !strings.Contains(myCt, "application/json") { - return []byte{}, nil - } - - return out, nil - case http.MethodPatch, http.MethodPost, http.MethodPut, http.MethodDelete: - bodybuf := []byte("{}") - buf := bufferPool.Get() - - defer bufferPool.Put(buf) - if _, err := buf.ReadFrom(r.Body); err != nil { - return nil, err - } - - if b := buf.Bytes(); len(b) > 0 { - bodybuf = b - } - - if bodydst == "" || bodydst == "*" { - if out, err = jsonpatch.MergeMergePatches(out, bodybuf); err == nil { - return out, nil - } - } - - var jsonbody map[string]interface{} - if json.Valid(bodybuf) { - if err = json.Unmarshal(bodybuf, &jsonbody); err != nil { - return nil, err - } - } - - dstmap := make(map[string]interface{}) - ps := strings.Split(bodydst, ".") - if len(ps) == 1 { - if jsonbody != nil { - dstmap[ps[0]] = jsonbody - } else { - // old unexpected behavior - dstmap[ps[0]] = bodybuf - } - } else { - em := make(map[string]interface{}) - if jsonbody != nil { - em[ps[len(ps)-1]] = jsonbody - } else { - // old unexpected behavior - em[ps[len(ps)-1]] = bodybuf - } - for i := len(ps) - 2; i > 0; i-- { - nm := make(map[string]interface{}) - nm[ps[i]] = em - em = nm - } - dstmap[ps[0]] = em - } - - bodyout, err := json.Marshal(dstmap) - if err != nil { - return nil, err - } - - if out, err = jsonpatch.MergeMergePatches(out, bodyout); err == nil { - return out, nil - } - - return bodybuf, nil - } - - return []byte{}, nil -} - -func writeError(rsp http.ResponseWriter, req *http.Request, err error) error { - ce := errors.Parse(err.Error()) - - switch ce.Code { - case 0: - // assuming it's totally screwed - ce.Code = http.StatusInternalServerError - ce.Id = packageID - ce.Status = http.StatusText(http.StatusInternalServerError) - ce.Detail = "error during request: " + ce.Detail - - rsp.WriteHeader(http.StatusInternalServerError) - default: - rsp.WriteHeader(int(ce.Code)) - } - - // response content type - rsp.Header().Set("Content-Type", "application/json") - - // Set trailers - if strings.Contains(req.Header.Get("Content-Type"), "application/grpc") { - rsp.Header().Set("Trailer", "grpc-status") - rsp.Header().Set("Trailer", "grpc-message") - rsp.Header().Set("grpc-status", "13") - rsp.Header().Set("grpc-message", ce.Detail) - } - - _, werr := rsp.Write([]byte(ce.Error())) - - return werr -} - -func writeResponse(w http.ResponseWriter, r *http.Request, rsp []byte) error { - w.Header().Set("Content-Type", r.Header.Get("Content-Type")) - w.Header().Set("Content-Length", strconv.Itoa(len(rsp))) - - // Set trailers - if strings.Contains(r.Header.Get("Content-Type"), "application/grpc") { - w.Header().Set("Trailer", "grpc-status") - w.Header().Set("Trailer", "grpc-message") - w.Header().Set("grpc-status", "0") - w.Header().Set("grpc-message", "") - } - - // write 204 status if rsp is nil - if len(rsp) == 0 { - w.WriteHeader(http.StatusNoContent) - } - - // write response - _, err := w.Write(rsp) - - return err -} - -// NewHandler returns a new RPC handler. -func NewHandler(opts ...handler.Option) handler.Handler { - options := handler.NewOptions(opts...) - - return &rpcHandler{ - opts: options, - } -} diff --git a/api/handler/rpc/rpc_test.go b/api/handler/rpc/rpc_test.go deleted file mode 100644 index f6f489a792..0000000000 --- a/api/handler/rpc/rpc_test.go +++ /dev/null @@ -1,119 +0,0 @@ -package rpc - -import ( - "bytes" - "encoding/json" - "net/http" - "reflect" - "testing" - - "github.com/golang/protobuf/proto" - go_api "go-micro.dev/v5/api/proto" -) - -func TestRequestPayloadFromRequest(t *testing.T) { - // our test event so that we can validate serializing / deserializing of true protos works - protoEvent := go_api.Event{ - Name: "Test", - } - - protoBytes, err := proto.Marshal(&protoEvent) - if err != nil { - t.Fatal("Failed to marshal proto", err) - } - - jsonBytes, err := json.Marshal(protoEvent) - if err != nil { - t.Fatal("Failed to marshal proto to JSON ", err) - } - - type jsonUrl struct { - Key1 string `json:"key1"` - Key2 string `json:"key2"` - Name string `json:"name"` - } - jUrl := &jsonUrl{Key1: "val1", Key2: "val2", Name: "Test"} - - t.Run("extracting a json from a POST request with url params", func(t *testing.T) { - r, err := http.NewRequest("POST", "http://localhost/my/path?key1=val1&key2=val2", bytes.NewReader(jsonBytes)) - if err != nil { - t.Fatalf("Failed to created http.Request: %v", err) - } - - extByte, err := requestPayload(r) - if err != nil { - t.Fatalf("Failed to extract payload from request: %v", err) - } - extJUrl := &jsonUrl{} - if err := json.Unmarshal(extByte, extJUrl); err != nil { - t.Fatalf("Failed to unmarshal payload from request: %v", err) - } - if !reflect.DeepEqual(extJUrl, jUrl) { - t.Fatalf("Expected %v and %v to match", extJUrl, jUrl) - } - }) - - t.Run("extracting a proto from a POST request", func(t *testing.T) { - r, err := http.NewRequest("POST", "http://localhost/my/path", bytes.NewReader(protoBytes)) - if err != nil { - t.Fatalf("Failed to created http.Request: %v", err) - } - - extByte, err := requestPayload(r) - if err != nil { - t.Fatalf("Failed to extract payload from request: %v", err) - } - if string(extByte) != string(protoBytes) { - t.Fatalf("Expected %v and %v to match", string(extByte), string(protoBytes)) - } - }) - - t.Run("extracting JSON from a POST request", func(t *testing.T) { - r, err := http.NewRequest("POST", "http://localhost/my/path", bytes.NewReader(jsonBytes)) - if err != nil { - t.Fatalf("Failed to created http.Request: %v", err) - } - - extByte, err := requestPayload(r) - if err != nil { - t.Fatalf("Failed to extract payload from request: %v", err) - } - if string(extByte) != string(jsonBytes) { - t.Fatalf("Expected %v and %v to match", string(extByte), string(jsonBytes)) - } - }) - - t.Run("extracting params from a GET request", func(t *testing.T) { - r, err := http.NewRequest("GET", "http://localhost/my/path", nil) - if err != nil { - t.Fatalf("Failed to created http.Request: %v", err) - } - - q := r.URL.Query() - q.Add("name", "Test") - r.URL.RawQuery = q.Encode() - - extByte, err := requestPayload(r) - if err != nil { - t.Fatalf("Failed to extract payload from request: %v", err) - } - if string(extByte) != string(jsonBytes) { - t.Fatalf("Expected %v and %v to match", string(extByte), string(jsonBytes)) - } - }) - - t.Run("GET request with no params", func(t *testing.T) { - r, err := http.NewRequest("GET", "http://localhost/my/path", nil) - if err != nil { - t.Fatalf("Failed to created http.Request: %v", err) - } - - extByte, err := requestPayload(r) - if err != nil { - t.Fatalf("Failed to extract payload from request: %v", err) - } - if string(extByte) != "" { - t.Fatalf("Expected %v and %v to match", string(extByte), "") - } - }) -} diff --git a/api/handler/rpc/stream.go b/api/handler/rpc/stream.go deleted file mode 100644 index 74e2391617..0000000000 --- a/api/handler/rpc/stream.go +++ /dev/null @@ -1,245 +0,0 @@ -package rpc - -import ( - "bytes" - "context" - "encoding/json" - "io" - "net/http" - "strings" - "time" - - "github.com/gobwas/httphead" - "github.com/gobwas/ws" - "github.com/gobwas/ws/wsutil" - "go-micro.dev/v5/api/router" - "go-micro.dev/v5/client" - raw "go-micro.dev/v5/codec/bytes" - "go-micro.dev/v5/selector" -) - -// serveWebsocket will stream rpc back over websockets assuming json. -func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request, service *router.Route, c client.Client) (err error) { - var opCode ws.OpCode - - myCt := r.Header.Get("Content-Type") - // Strip charset from Content-Type (like `application/json; charset=UTF-8`) - if idx := strings.IndexRune(myCt, ';'); idx >= 0 { - myCt = myCt[:idx] - } - - // check proto from request - switch myCt { - case "application/json": - opCode = ws.OpText - default: - opCode = ws.OpBinary - } - - hdr := make(http.Header) - - if proto, ok := r.Header["Sec-Websocket-Protocol"]; ok { - for _, p := range proto { - if p == "binary" { - hdr["Sec-WebSocket-Protocol"] = []string{"binary"} - opCode = ws.OpBinary - } - } - } - - payload, err := requestPayload(r) - if err != nil { - return - } - - upgrader := ws.HTTPUpgrader{Timeout: 5 * time.Second, - Protocol: func(proto string) bool { - if strings.Contains(proto, "binary") { - return true - } - // fallback to support all protocols now - return true - }, - Extension: func(httphead.Option) bool { - // disable extensions for compatibility - return false - }, - Header: hdr, - } - - conn, uRw, _, err := upgrader.Upgrade(r, w) - if err != nil { - return - } - - defer func() { - if cErr := conn.Close(); cErr != nil && err == nil { - err = cErr - } - }() - - var request interface{} - - if !bytes.Equal(payload, []byte(`{}`)) { - switch myCt { - case "application/json", "": - m := json.RawMessage(payload) - request = &m - default: - request = &raw.Frame{Data: payload} - } - } - - // we always need to set content type for message - if myCt == "" { - myCt = "application/json" - } - - req := c.NewRequest( - service.Service, - service.Endpoint.Name, - request, - client.WithContentType(myCt), - client.StreamingRequest(), - ) - - cCtx, cancel := context.WithCancel(ctx) - defer cancel() - - so := selector.WithStrategy(strategy(service.Versions)) - - // create a new stream - stream, err := c.Stream(cCtx, req, client.WithSelectOption(so)) - if err != nil { - return - } - - if request != nil { - if err = stream.Send(request); err != nil { - return - } - } - - go func() { - if wErr := writeLoop(uRw, stream); wErr != nil && err == nil { - err = wErr - } - }() - - rsp := stream.Response() - - // receive from stream and send to client - for { - select { - case <-ctx.Done(): - return nil - case <-stream.Context().Done(): - return nil - default: - // read backend response body - buf, err := rsp.Read() - if err != nil { - // wants to avoid import grpc/status.Status - if strings.Contains(err.Error(), "context canceled") { - return nil - } - - return err - } - - // write the response - if err = wsutil.WriteServerMessage(uRw, opCode, buf); err != nil { - return err - } - - if err = uRw.Flush(); err != nil { - return err - } - } - } -} - -// writeLoop. -func writeLoop(rw io.ReadWriter, stream client.Stream) error { - // close stream when done - defer stream.Close() - - for { - select { - case <-stream.Context().Done(): - return nil - default: - buf, op, err := wsutil.ReadClientData(rw) - if err != nil { - if wserr, ok := err.(wsutil.ClosedError); ok { - switch wserr.Code { - case ws.StatusGoingAway: - // this happens when user leave the page - return nil - case ws.StatusNormalClosure, ws.StatusNoStatusRcvd: - // this happens when user close ws connection, or we don't get any status - return nil - default: - return err - } - } - } - - switch op { - default: - // not relevant - continue - case ws.OpText, ws.OpBinary: - break - } - // send to backend - // default to trying json - // if the extracted payload isn't empty lets use it - request := &raw.Frame{Data: buf} - if err := stream.Send(request); err != nil { - return err - } - } - } -} - -func isStream(r *http.Request, srv *router.Route) bool { - // check if it's a web socket - if !isWebSocket(r) { - return false - } - // check if the endpoint supports streaming - for _, service := range srv.Versions { - for _, ep := range service.Endpoints { - // skip if it doesn't match the name - if ep.Name != srv.Endpoint.Name { - continue - } - // matched if the name - if v := ep.Metadata["stream"]; v == "true" { - return true - } - } - } - - return false -} - -func isWebSocket(r *http.Request) bool { - contains := func(key, val string) bool { - vv := strings.Split(r.Header.Get(key), ",") - for _, v := range vv { - if val == strings.ToLower(strings.TrimSpace(v)) { - return true - } - } - - return false - } - - if contains("Connection", "upgrade") && contains("Upgrade", "websocket") { - return true - } - - return false -} diff --git a/api/handler/web/web.go b/api/handler/web/web.go deleted file mode 100644 index bd1e364dad..0000000000 --- a/api/handler/web/web.go +++ /dev/null @@ -1,169 +0,0 @@ -// Package web contains the web handler including websocket support -package web - -import ( - "errors" - "fmt" - "io" - "net" - "net/http" - "net/http/httputil" - "net/url" - "strings" - - "go-micro.dev/v5/api/handler" - "go-micro.dev/v5/api/router" - "go-micro.dev/v5/selector" -) - -const ( - // Handler is the name of the handler. - Handler = "web" -) - -type webHandler struct { - opts handler.Options -} - -func (wh *webHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - service, err := wh.getService(r) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - if len(service) == 0 { - w.WriteHeader(http.StatusNotFound) - return - } - - rp, err := url.Parse(service) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - return - } - - if isWebSocket(r) { - wh.serveWebSocket(rp.Host, w, r) - return - } - - httputil.NewSingleHostReverseProxy(rp).ServeHTTP(w, r) -} - -// getService returns the service for this request from the selector. -func (wh *webHandler) getService(r *http.Request) (string, error) { - var service *router.Route - - if wh.opts.Router != nil { - // try get service from router - s, err := wh.opts.Router.Route(r) - if err != nil { - return "", err - } - - service = s - } else { - // we have no way of routing the request - return "", errors.New("no route found") - } - - // create a random selector - next := selector.Random(service.Versions) - - // get the next node - s, err := next() - if err != nil { - return "", nil - } - - return fmt.Sprintf("http://%s", s.Address), nil -} - -// serveWebSocket used to serve a web socket proxied connection. -func (wh *webHandler) serveWebSocket(host string, rsp http.ResponseWriter, r *http.Request) { - req := new(http.Request) - *req = *r - - if len(host) == 0 { - http.Error(rsp, "invalid host", http.StatusInternalServerError) - return - } - - // set x-forward-for - if clientIP, _, err := net.SplitHostPort(r.RemoteAddr); err == nil { - if ips, ok := req.Header["X-Forwarded-For"]; ok { - clientIP = strings.Join(ips, ", ") + ", " + clientIP - } - - req.Header.Set("X-Forwarded-For", clientIP) - } - - // connect to the backend host - conn, err := net.Dial("tcp", host) - if err != nil { - http.Error(rsp, err.Error(), http.StatusInternalServerError) - return - } - - // hijack the connection - hj, ok := rsp.(http.Hijacker) - if !ok { - http.Error(rsp, "failed to connect", http.StatusInternalServerError) - return - } - - nc, _, err := hj.Hijack() - if err != nil { - return - } - - defer nc.Close() - defer conn.Close() - - if err = req.Write(conn); err != nil { - return - } - - errCh := make(chan error, 2) - - cp := func(dst io.Writer, src io.Reader) { - _, err := io.Copy(dst, src) - errCh <- err - } - - go cp(conn, nc) - go cp(nc, conn) - - <-errCh -} - -func isWebSocket(r *http.Request) bool { - contains := func(key, val string) bool { - vv := strings.Split(r.Header.Get(key), ",") - for _, v := range vv { - if val == strings.ToLower(strings.TrimSpace(v)) { - return true - } - } - - return false - } - - if contains("Connection", "upgrade") && contains("Upgrade", "websocket") { - return true - } - - return false -} - -func (wh *webHandler) String() string { - return "web" -} - -// NewHandler returns a new web handler. -func NewHandler(opts ...handler.Option) handler.Handler { - return &webHandler{ - opts: handler.NewOptions(opts...), - } -} diff --git a/api/internal/proto/message.pb.go b/api/internal/proto/message.pb.go deleted file mode 100644 index aae2743fd1..0000000000 --- a/api/internal/proto/message.pb.go +++ /dev/null @@ -1,28 +0,0 @@ -package proto - -type Message struct { - data []byte -} - -func (m *Message) ProtoMessage() {} - -func (m *Message) Reset() { - *m = Message{} -} - -func (m *Message) String() string { - return string(m.data) -} - -func (m *Message) Marshal() ([]byte, error) { - return m.data, nil -} - -func (m *Message) Unmarshal(data []byte) error { - m.data = data - return nil -} - -func NewMessage(data []byte) *Message { - return &Message{data} -} diff --git a/api/options.go b/api/options.go deleted file mode 100644 index 952d7c7028..0000000000 --- a/api/options.go +++ /dev/null @@ -1,45 +0,0 @@ -package api - -import ( - "go-micro.dev/v5/api/router" - registry2 "go-micro.dev/v5/api/router/registry" - "go-micro.dev/v5/client" - "go-micro.dev/v5/registry" -) - -func NewOptions(opts ...Option) Options { - options := Options{ - Address: ":8080", - } - - for _, o := range opts { - o(&options) - } - - return options -} - -// WithAddress sets the address to listen -func WithAddress(addr string) Option { - return func(o *Options) error { - o.Address = addr - return nil - } -} - -// WithRouter sets the router to use e.g static or registry. -func WithRouter(r router.Router) Option { - return func(o *Options) error { - o.Router = r - return nil - } -} - -// WithRegistry sets the api's client and router to use registry. -func WithRegistry(r registry.Registry) Option { - return func(o *Options) error { - o.Client = client.NewClient(client.Registry(r)) - o.Router = registry2.NewRouter(router.WithRegistry(r)) - return nil - } -} diff --git a/api/proto/api.pb.go b/api/proto/api.pb.go deleted file mode 100644 index e5d88473cf..0000000000 --- a/api/proto/api.pb.go +++ /dev/null @@ -1,335 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: api/proto/api.proto - -package go_api - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -type Pair struct { - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` - Values []string `protobuf:"bytes,2,rep,name=values,proto3" json:"values,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Pair) Reset() { *m = Pair{} } -func (m *Pair) String() string { return proto.CompactTextString(m) } -func (*Pair) ProtoMessage() {} -func (*Pair) Descriptor() ([]byte, []int) { - return fileDescriptor_2df576b66d12087a, []int{0} -} - -func (m *Pair) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Pair.Unmarshal(m, b) -} -func (m *Pair) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Pair.Marshal(b, m, deterministic) -} -func (m *Pair) XXX_Merge(src proto.Message) { - xxx_messageInfo_Pair.Merge(m, src) -} -func (m *Pair) XXX_Size() int { - return xxx_messageInfo_Pair.Size(m) -} -func (m *Pair) XXX_DiscardUnknown() { - xxx_messageInfo_Pair.DiscardUnknown(m) -} - -var xxx_messageInfo_Pair proto.InternalMessageInfo - -func (m *Pair) GetKey() string { - if m != nil { - return m.Key - } - return "" -} - -func (m *Pair) GetValues() []string { - if m != nil { - return m.Values - } - return nil -} - -// A HTTP request as RPC -// Forward by the api handler -type Request struct { - Method string `protobuf:"bytes,1,opt,name=method,proto3" json:"method,omitempty"` - Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"` - Header map[string]*Pair `protobuf:"bytes,3,rep,name=header,proto3" json:"header,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Get map[string]*Pair `protobuf:"bytes,4,rep,name=get,proto3" json:"get,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Post map[string]*Pair `protobuf:"bytes,5,rep,name=post,proto3" json:"post,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Body string `protobuf:"bytes,6,opt,name=body,proto3" json:"body,omitempty"` - Url string `protobuf:"bytes,7,opt,name=url,proto3" json:"url,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Request) Reset() { *m = Request{} } -func (m *Request) String() string { return proto.CompactTextString(m) } -func (*Request) ProtoMessage() {} -func (*Request) Descriptor() ([]byte, []int) { - return fileDescriptor_2df576b66d12087a, []int{1} -} - -func (m *Request) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Request.Unmarshal(m, b) -} -func (m *Request) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Request.Marshal(b, m, deterministic) -} -func (m *Request) XXX_Merge(src proto.Message) { - xxx_messageInfo_Request.Merge(m, src) -} -func (m *Request) XXX_Size() int { - return xxx_messageInfo_Request.Size(m) -} -func (m *Request) XXX_DiscardUnknown() { - xxx_messageInfo_Request.DiscardUnknown(m) -} - -var xxx_messageInfo_Request proto.InternalMessageInfo - -func (m *Request) GetMethod() string { - if m != nil { - return m.Method - } - return "" -} - -func (m *Request) GetPath() string { - if m != nil { - return m.Path - } - return "" -} - -func (m *Request) GetHeader() map[string]*Pair { - if m != nil { - return m.Header - } - return nil -} - -func (m *Request) GetGet() map[string]*Pair { - if m != nil { - return m.Get - } - return nil -} - -func (m *Request) GetPost() map[string]*Pair { - if m != nil { - return m.Post - } - return nil -} - -func (m *Request) GetBody() string { - if m != nil { - return m.Body - } - return "" -} - -func (m *Request) GetUrl() string { - if m != nil { - return m.Url - } - return "" -} - -// A HTTP response as RPC -// Expected response for the api handler -type Response struct { - StatusCode int32 `protobuf:"varint,1,opt,name=statusCode,proto3" json:"statusCode,omitempty"` - Header map[string]*Pair `protobuf:"bytes,2,rep,name=header,proto3" json:"header,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - Body string `protobuf:"bytes,3,opt,name=body,proto3" json:"body,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Response) Reset() { *m = Response{} } -func (m *Response) String() string { return proto.CompactTextString(m) } -func (*Response) ProtoMessage() {} -func (*Response) Descriptor() ([]byte, []int) { - return fileDescriptor_2df576b66d12087a, []int{2} -} - -func (m *Response) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Response.Unmarshal(m, b) -} -func (m *Response) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Response.Marshal(b, m, deterministic) -} -func (m *Response) XXX_Merge(src proto.Message) { - xxx_messageInfo_Response.Merge(m, src) -} -func (m *Response) XXX_Size() int { - return xxx_messageInfo_Response.Size(m) -} -func (m *Response) XXX_DiscardUnknown() { - xxx_messageInfo_Response.DiscardUnknown(m) -} - -var xxx_messageInfo_Response proto.InternalMessageInfo - -func (m *Response) GetStatusCode() int32 { - if m != nil { - return m.StatusCode - } - return 0 -} - -func (m *Response) GetHeader() map[string]*Pair { - if m != nil { - return m.Header - } - return nil -} - -func (m *Response) GetBody() string { - if m != nil { - return m.Body - } - return "" -} - -// A HTTP event as RPC -// Forwarded by the event handler -type Event struct { - // e.g login - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - // uuid - Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"` - // unix timestamp of event - Timestamp int64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - // event headers - Header map[string]*Pair `protobuf:"bytes,4,rep,name=header,proto3" json:"header,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - // the event data - Data string `protobuf:"bytes,5,opt,name=data,proto3" json:"data,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Event) Reset() { *m = Event{} } -func (m *Event) String() string { return proto.CompactTextString(m) } -func (*Event) ProtoMessage() {} -func (*Event) Descriptor() ([]byte, []int) { - return fileDescriptor_2df576b66d12087a, []int{3} -} - -func (m *Event) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Event.Unmarshal(m, b) -} -func (m *Event) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Event.Marshal(b, m, deterministic) -} -func (m *Event) XXX_Merge(src proto.Message) { - xxx_messageInfo_Event.Merge(m, src) -} -func (m *Event) XXX_Size() int { - return xxx_messageInfo_Event.Size(m) -} -func (m *Event) XXX_DiscardUnknown() { - xxx_messageInfo_Event.DiscardUnknown(m) -} - -var xxx_messageInfo_Event proto.InternalMessageInfo - -func (m *Event) GetName() string { - if m != nil { - return m.Name - } - return "" -} - -func (m *Event) GetId() string { - if m != nil { - return m.Id - } - return "" -} - -func (m *Event) GetTimestamp() int64 { - if m != nil { - return m.Timestamp - } - return 0 -} - -func (m *Event) GetHeader() map[string]*Pair { - if m != nil { - return m.Header - } - return nil -} - -func (m *Event) GetData() string { - if m != nil { - return m.Data - } - return "" -} - -func init() { - proto.RegisterType((*Pair)(nil), "go.api.Pair") - proto.RegisterType((*Request)(nil), "go.api.Request") - proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Request.GetEntry") - proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Request.HeaderEntry") - proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Request.PostEntry") - proto.RegisterType((*Response)(nil), "go.api.Response") - proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Response.HeaderEntry") - proto.RegisterType((*Event)(nil), "go.api.Event") - proto.RegisterMapType((map[string]*Pair)(nil), "go.api.Event.HeaderEntry") -} - -func init() { proto.RegisterFile("api/proto/api.proto", fileDescriptor_2df576b66d12087a) } - -var fileDescriptor_2df576b66d12087a = []byte{ - // 393 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x53, 0xcd, 0xce, 0xd3, 0x30, - 0x10, 0x54, 0xe2, 0x24, 0x6d, 0xb6, 0x08, 0x21, 0x23, 0x21, 0x53, 0x2a, 0x54, 0xe5, 0x54, 0x21, - 0x91, 0x42, 0xcb, 0x01, 0x71, 0x85, 0xaa, 0x1c, 0x2b, 0xbf, 0x81, 0xab, 0x58, 0x6d, 0x44, 0x13, - 0x9b, 0xd8, 0xa9, 0xd4, 0x87, 0xe3, 0xc0, 0x63, 0xf0, 0x36, 0xc8, 0x1b, 0xf7, 0xe7, 0xab, 0xfa, - 0x5d, 0xbe, 0xaf, 0xb7, 0x89, 0x3d, 0x3b, 0x3b, 0x3b, 0xeb, 0xc0, 0x6b, 0xa1, 0xcb, 0xa9, 0x6e, - 0x94, 0x55, 0x53, 0xa1, 0xcb, 0x1c, 0x11, 0x4d, 0x36, 0x2a, 0x17, 0xba, 0xcc, 0x3e, 0x41, 0xb4, - 0x12, 0x65, 0x43, 0x5f, 0x01, 0xf9, 0x25, 0x0f, 0x2c, 0x18, 0x07, 0x93, 0x94, 0x3b, 0x48, 0xdf, - 0x40, 0xb2, 0x17, 0xbb, 0x56, 0x1a, 0x16, 0x8e, 0xc9, 0x24, 0xe5, 0xfe, 0x2b, 0xfb, 0x4b, 0xa0, - 0xc7, 0xe5, 0xef, 0x56, 0x1a, 0xeb, 0x38, 0x95, 0xb4, 0x5b, 0x55, 0xf8, 0x42, 0xff, 0x45, 0x29, - 0x44, 0x5a, 0xd8, 0x2d, 0x0b, 0xf1, 0x14, 0x31, 0x9d, 0x43, 0xb2, 0x95, 0xa2, 0x90, 0x0d, 0x23, - 0x63, 0x32, 0x19, 0xcc, 0xde, 0xe5, 0x9d, 0x85, 0xdc, 0x8b, 0xe5, 0x3f, 0xf1, 0x76, 0x51, 0xdb, - 0xe6, 0xc0, 0x3d, 0x95, 0x7e, 0x00, 0xb2, 0x91, 0x96, 0x45, 0x58, 0xc1, 0xae, 0x2b, 0x96, 0xd2, - 0x76, 0x74, 0x47, 0xa2, 0x1f, 0x21, 0xd2, 0xca, 0x58, 0x16, 0x23, 0xf9, 0xed, 0x35, 0x79, 0xa5, - 0x8c, 0x67, 0x23, 0xcd, 0x79, 0x5c, 0xab, 0xe2, 0xc0, 0x92, 0xce, 0xa3, 0xc3, 0x2e, 0x85, 0xb6, - 0xd9, 0xb1, 0x5e, 0x97, 0x42, 0xdb, 0xec, 0x86, 0x4b, 0x18, 0x5c, 0xf8, 0xba, 0x11, 0x53, 0x06, - 0x31, 0x06, 0x83, 0xb3, 0x0e, 0x66, 0x2f, 0x8e, 0x6d, 0x5d, 0xaa, 0xbc, 0xbb, 0xfa, 0x16, 0x7e, - 0x0d, 0x86, 0x3f, 0xa0, 0x7f, 0xb4, 0xfb, 0x0c, 0x95, 0x05, 0xa4, 0xa7, 0x39, 0x9e, 0x2e, 0x93, - 0xfd, 0x09, 0xa0, 0xcf, 0xa5, 0xd1, 0xaa, 0x36, 0x92, 0xbe, 0x07, 0x30, 0x56, 0xd8, 0xd6, 0x7c, - 0x57, 0x85, 0x44, 0xb5, 0x98, 0x5f, 0x9c, 0xd0, 0x2f, 0xa7, 0xc5, 0x85, 0x98, 0xec, 0xe8, 0x9c, - 0x6c, 0xa7, 0x70, 0x73, 0x73, 0xc7, 0x78, 0xc9, 0x39, 0xde, 0xbb, 0x85, 0x99, 0xfd, 0x0b, 0x20, - 0x5e, 0xec, 0x65, 0x8d, 0x5b, 0xac, 0x45, 0x25, 0xbd, 0x08, 0x62, 0xfa, 0x12, 0xc2, 0xb2, 0xf0, - 0x6f, 0x2f, 0x2c, 0x0b, 0x3a, 0x82, 0xd4, 0x96, 0x95, 0x34, 0x56, 0x54, 0x1a, 0xfd, 0x10, 0x7e, - 0x3e, 0xa0, 0x9f, 0x4f, 0xe3, 0x45, 0x0f, 0x1f, 0x0e, 0x36, 0x78, 0x6c, 0xb6, 0x42, 0x58, 0xc1, - 0xe2, 0xae, 0xa9, 0xc3, 0x77, 0x9b, 0x6d, 0x9d, 0xe0, 0x0f, 0x3a, 0xff, 0x1f, 0x00, 0x00, 0xff, - 0xff, 0xd4, 0x6d, 0x70, 0x51, 0xb7, 0x03, 0x00, 0x00, -} diff --git a/api/proto/api.pb.micro.go b/api/proto/api.pb.micro.go deleted file mode 100644 index 9b91e09d04..0000000000 --- a/api/proto/api.pb.micro.go +++ /dev/null @@ -1,21 +0,0 @@ -// Code generated by protoc-gen-micro. DO NOT EDIT. -// source: api/proto/api.proto - -package go_api - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package diff --git a/api/proto/api.proto b/api/proto/api.proto deleted file mode 100644 index fd0f9fec90..0000000000 --- a/api/proto/api.proto +++ /dev/null @@ -1,43 +0,0 @@ -syntax = "proto3"; - -package go.api; - -message Pair { - string key = 1; - repeated string values = 2; -} - -// A HTTP request as RPC -// Forward by the api handler -message Request { - string method = 1; - string path = 2; - map header = 3; - map get = 4; - map post = 5; - string body = 6; // raw request body; if not application/x-www-form-urlencoded - string url = 7; -} - -// A HTTP response as RPC -// Expected response for the api handler -message Response { - int32 statusCode = 1; - map header = 2; - string body = 3; -} - -// A HTTP event as RPC -// Forwarded by the event handler -message Event { - // e.g login - string name = 1; - // uuid - string id = 2; - // unix timestamp of event - int64 timestamp = 3; - // event headers - map header = 4; - // the event data - string data = 5; -} diff --git a/api/resolver/grpc/grpc.go b/api/resolver/grpc/grpc.go deleted file mode 100644 index 28ab41848f..0000000000 --- a/api/resolver/grpc/grpc.go +++ /dev/null @@ -1,42 +0,0 @@ -// Package grpc resolves a grpc service like /greeter.Say/Hello to greeter service -package grpc - -import ( - "errors" - "net/http" - "strings" - - "go-micro.dev/v5/api/resolver" -) - -// Resolver is the gRPC Resolver. -type Resolver struct{} - -// Resolve resolves a http.Request to an grpc Endpoint. -func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { - // /foo.Bar/Service - if req.URL.Path == "/" { - return nil, errors.New("unknown name") - } - // [foo.Bar, Service] - parts := strings.Split(req.URL.Path[1:], "/") - // [foo, Bar] - name := strings.Split(parts[0], ".") - // foo - return &resolver.Endpoint{ - Name: strings.Join(name[:len(name)-1], "."), - Host: req.Host, - Method: req.Method, - Path: req.URL.Path, - }, nil -} - -// String returns the name of the resolver. -func (r *Resolver) String() string { - return "grpc" -} - -// NewResolver creates a new gRPC resolver. -func NewResolver(opts ...resolver.Option) resolver.Resolver { - return &Resolver{} -} diff --git a/api/resolver/host/host.go b/api/resolver/host/host.go deleted file mode 100644 index ba12f616fe..0000000000 --- a/api/resolver/host/host.go +++ /dev/null @@ -1,33 +0,0 @@ -// Package host resolves using http host -package host - -import ( - "net/http" - - "go-micro.dev/v5/api/resolver" -) - -// Resolver is a host resolver. -type Resolver struct { - opts resolver.Options -} - -// Resolve resolves a http.Request to an grpc Endpoint. -func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { - return &resolver.Endpoint{ - Name: req.Host, - Host: req.Host, - Method: req.Method, - Path: req.URL.Path, - }, nil -} - -// String returns the name of the resolver. -func (r *Resolver) String() string { - return "host" -} - -// NewResolver creates a new host resolver. -func NewResolver(opts ...resolver.Option) resolver.Resolver { - return &Resolver{opts: resolver.NewOptions(opts...)} -} diff --git a/api/resolver/options.go b/api/resolver/options.go deleted file mode 100644 index ed87f2aef8..0000000000 --- a/api/resolver/options.go +++ /dev/null @@ -1,33 +0,0 @@ -package resolver - -import ( - "net/http" -) - -// NewOptions wires options together. -func NewOptions(opts ...Option) Options { - var options Options - for _, o := range opts { - o(&options) - } - - if options.Namespace == nil { - options.Namespace = StaticNamespace("go.micro") - } - - return options -} - -// WithHandler sets the handler being used. -func WithHandler(h string) Option { - return func(o *Options) { - o.Handler = h - } -} - -// WithNamespace sets the function which determines the namespace for a request. -func WithNamespace(n func(*http.Request) string) Option { - return func(o *Options) { - o.Namespace = n - } -} diff --git a/api/resolver/path/path.go b/api/resolver/path/path.go deleted file mode 100644 index 628320a480..0000000000 --- a/api/resolver/path/path.go +++ /dev/null @@ -1,40 +0,0 @@ -// Package path resolves using http path -package path - -import ( - "net/http" - "strings" - - "go-micro.dev/v5/api/resolver" -) - -// Resolver is a path resolver. -type Resolver struct { - opts resolver.Options -} - -// Resolve resolves a http.Request to an grpc Endpoint. -func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { - if req.URL.Path == "/" { - return nil, resolver.ErrNotFound - } - - parts := strings.Split(req.URL.Path[1:], "/") - ns := r.opts.Namespace(req) - - return &resolver.Endpoint{ - Name: ns + "." + parts[0], - Host: req.Host, - Method: req.Method, - Path: req.URL.Path, - }, nil -} - -func (r *Resolver) String() string { - return "path" -} - -// NewResolver returns a new path resolver. -func NewResolver(opts ...resolver.Option) resolver.Resolver { - return &Resolver{opts: resolver.NewOptions(opts...)} -} diff --git a/api/resolver/resolver.go b/api/resolver/resolver.go deleted file mode 100644 index 6842613f45..0000000000 --- a/api/resolver/resolver.go +++ /dev/null @@ -1,46 +0,0 @@ -// Package resolver resolves a http request to an endpoint -package resolver - -import ( - "errors" - "net/http" -) - -var ( - ErrNotFound = errors.New("not found") - ErrInvalidPath = errors.New("invalid path") -) - -// Resolver resolves requests to endpoints. -type Resolver interface { - Resolve(r *http.Request) (*Endpoint, error) - String() string -} - -// Endpoint is the endpoint for a http request. -type Endpoint struct { - // e.g greeter - Name string - // HTTP Host e.g example.com - Host string - // HTTP Methods e.g GET, POST - Method string - // HTTP Path e.g /greeter. - Path string -} - -// Options is a struct of available options. -type Options struct { - Namespace func(*http.Request) string - Handler string -} - -// Option is a helper for a single option. -type Option func(o *Options) - -// StaticNamespace returns the same namespace for each request. -func StaticNamespace(ns string) func(*http.Request) string { - return func(*http.Request) string { - return ns - } -} diff --git a/api/resolver/vpath/vpath.go b/api/resolver/vpath/vpath.go deleted file mode 100644 index bf249ec41b..0000000000 --- a/api/resolver/vpath/vpath.go +++ /dev/null @@ -1,72 +0,0 @@ -// Package vpath resolves using http path and recognized versioned urls -package vpath - -import ( - "errors" - "net/http" - "regexp" - "strings" - - "go-micro.dev/v5/api/resolver" -) - -// NewResolver returns a new vpath resolver. -func NewResolver(opts ...resolver.Option) resolver.Resolver { - return &Resolver{opts: resolver.NewOptions(opts...)} -} - -// Resolver is a vpath resolver. -type Resolver struct { - opts resolver.Options -} - -var ( - re = regexp.MustCompile("^v[0-9]+$") -) - -// Resolve resolves a http.Request to an grpc Endpoint. -func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) { - if req.URL.Path == "/" { - return nil, errors.New("unknown name") - } - - parts := strings.Split(req.URL.Path[1:], "/") - if len(parts) == 1 { - return &resolver.Endpoint{ - Name: r.withNamespace(req, parts...), - Host: req.Host, - Method: req.Method, - Path: req.URL.Path, - }, nil - } - - // /v1/foo - if re.MatchString(parts[0]) { - return &resolver.Endpoint{ - Name: r.withNamespace(req, parts[0:2]...), - Host: req.Host, - Method: req.Method, - Path: req.URL.Path, - }, nil - } - - return &resolver.Endpoint{ - Name: r.withNamespace(req, parts[0]), - Host: req.Host, - Method: req.Method, - Path: req.URL.Path, - }, nil -} - -func (r *Resolver) String() string { - return "path" -} - -func (r *Resolver) withNamespace(req *http.Request, parts ...string) string { - ns := r.opts.Namespace(req) - if len(ns) == 0 { - return strings.Join(parts, ".") - } - - return strings.Join(append([]string{ns}, parts...), ".") -} diff --git a/api/router/endpoint.go b/api/router/endpoint.go deleted file mode 100644 index 2deff1d737..0000000000 --- a/api/router/endpoint.go +++ /dev/null @@ -1,99 +0,0 @@ -package router - -import ( - "errors" - "regexp" - "strings" -) - -func strip(s string) string { - return strings.TrimSpace(s) -} - -func slice(s string) []string { - var sl []string - - for _, p := range strings.Split(s, ",") { - if str := strip(p); len(str) > 0 { - sl = append(sl, strip(p)) - } - } - - return sl -} - -// Encode encodes an endpoint to endpoint metadata. -func Encode(e *Endpoint) map[string]string { - if e == nil { - return nil - } - - // endpoint map - ep := make(map[string]string) - - // set vals only if they exist - set := func(k, v string) { - if len(v) == 0 { - return - } - ep[k] = v - } - - set("endpoint", e.Name) - set("description", e.Description) - set("handler", e.Handler) - set("method", strings.Join(e.Method, ",")) - set("path", strings.Join(e.Path, ",")) - set("host", strings.Join(e.Host, ",")) - - return ep -} - -// Decode decodes endpoint metadata into an endpoint. -func Decode(e map[string]string) *Endpoint { - if e == nil { - return nil - } - - return &Endpoint{ - Name: e["endpoint"], - Description: e["description"], - Method: slice(e["method"]), - Path: slice(e["path"]), - Host: slice(e["host"]), - Handler: e["handler"], - } -} - -// Validate validates an endpoint to guarantee it won't blow up when being served. -func Validate(e *Endpoint) error { - if e == nil { - return errors.New("endpoint is nil") - } - - if len(e.Name) == 0 { - return errors.New("name required") - } - - for _, p := range e.Path { - ps := p[0] - pe := p[len(p)-1] - - if ps == '^' && pe == '$' { - _, err := regexp.CompilePOSIX(p) - if err != nil { - return err - } - } else if ps == '^' && pe != '$' { - return errors.New("invalid path") - } else if ps != '^' && pe == '$' { - return errors.New("invalid path") - } - } - - if len(e.Handler) == 0 { - return errors.New("invalid handler") - } - - return nil -} diff --git a/api/router/options.go b/api/router/options.go deleted file mode 100644 index 91a2f85b85..0000000000 --- a/api/router/options.go +++ /dev/null @@ -1,65 +0,0 @@ -package router - -import ( - "go-micro.dev/v5/api/resolver" - "go-micro.dev/v5/api/resolver/vpath" - "go-micro.dev/v5/logger" - "go-micro.dev/v5/registry" -) - -// Options is a struct of options available. -type Options struct { - Registry registry.Registry - Resolver resolver.Resolver - Logger logger.Logger - Handler string -} - -// Option is a helper for a single options. -type Option func(o *Options) - -// NewOptions wires options together. -func NewOptions(opts ...Option) Options { - options := Options{ - Handler: "meta", - Registry: registry.DefaultRegistry, - Logger: logger.DefaultLogger, - } - - for _, o := range opts { - o(&options) - } - - if options.Resolver == nil { - options.Resolver = vpath.NewResolver( - resolver.WithHandler(options.Handler), - ) - } - - return options -} - -func WithHandler(h string) Option { - return func(o *Options) { - o.Handler = h - } -} - -func WithRegistry(r registry.Registry) Option { - return func(o *Options) { - o.Registry = r - } -} - -func WithResolver(r resolver.Resolver) Option { - return func(o *Options) { - o.Resolver = r - } -} - -// WithLogger sets the underline logger. -func WithLogger(l logger.Logger) Option { - return func(o *Options) { - o.Logger = l - } -} diff --git a/api/router/registry/registry.go b/api/router/registry/registry.go deleted file mode 100644 index f68784ded3..0000000000 --- a/api/router/registry/registry.go +++ /dev/null @@ -1,514 +0,0 @@ -// Package registry provides a dynamic api service router -package registry - -import ( - "errors" - "fmt" - "net/http" - "regexp" - "strings" - "sync" - "time" - - "go-micro.dev/v5/api/router" - "go-micro.dev/v5/api/router/util" - log "go-micro.dev/v5/logger" - "go-micro.dev/v5/metadata" - "go-micro.dev/v5/registry" - "go-micro.dev/v5/registry/cache" -) - -// endpoint struct, that holds compiled pcre. -type endpoint struct { - hostregs []*regexp.Regexp - pathregs []util.Pattern - pcreregs []*regexp.Regexp -} - -// router is the default router. -type registryRouter struct { - opts router.Options - - // registry cache - rc cache.Cache - - exit chan bool - eps map[string]*router.Route - // compiled regexp for host and path - ceps map[string]*endpoint - - sync.RWMutex -} - -func (r *registryRouter) isStopped() bool { - select { - case <-r.exit: - return true - default: - return false - } -} - -// refresh list of api services. -func (r *registryRouter) refresh() { - var attempts int - - logger := r.Options().Logger - - for { - services, err := r.opts.Registry.ListServices() - if err != nil { - attempts++ - - logger.Logf(log.ErrorLevel, "unable to list services: %v", err) - time.Sleep(time.Duration(attempts) * time.Second) - - continue - } - - attempts = 0 - - // for each service, get service and store endpoints - for _, s := range services { - service, err := r.rc.GetService(s.Name) - if err != nil { - logger.Logf(log.ErrorLevel, "unable to get service: %v", err) - continue - } - - r.store(service) - } - - // refresh list in 10 minutes... cruft - // use registry watching - select { - case <-time.After(time.Minute * 10): - case <-r.exit: - return - } - } -} - -// process watch event. -func (r *registryRouter) process(res *registry.Result) { - logger := r.Options().Logger - // skip these things - if res == nil || res.Service == nil { - return - } - - // get entry from cache - service, err := r.rc.GetService(res.Service.Name) - if err != nil { - logger.Logf(log.ErrorLevel, "unable to get service: %v", err) - return - } - - // update our local endpoints - r.store(service) -} - -// store local endpoint cache. -func (r *registryRouter) store(services []*registry.Service) { - logger := r.Options().Logger - // endpoints - eps := map[string]*router.Route{} - - // services - names := map[string]bool{} - - // create a new endpoint mapping - for _, service := range services { - // set names we need later - names[service.Name] = true - - // map per endpoint - for _, sep := range service.Endpoints { - // create a key service:endpoint_name - key := fmt.Sprintf("%s.%s", service.Name, sep.Name) - // decode endpoint - end := router.Decode(sep.Metadata) - - // if we got nothing skip - if err := router.Validate(end); err != nil { - logger.Logf(log.TraceLevel, "endpoint validation failed: %v", err) - continue - } - - // try get endpoint - ep, ok := eps[key] - if !ok { - ep = &router.Route{Service: service.Name} - } - - // overwrite the endpoint - ep.Endpoint = end - // append services - ep.Versions = append(ep.Versions, service) - // store it - eps[key] = ep - } - } - - r.Lock() - defer r.Unlock() - - // delete any existing eps for services we know - for key, route := range r.eps { - // skip what we don't care about - if !names[route.Service] { - continue - } - - // ok we know this thing - // delete delete delete - delete(r.eps, key) - } - - // now set the eps we have - for name, ep := range eps { - r.eps[name] = ep - cep := &endpoint{} - - for _, h := range ep.Endpoint.Host { - if h == "" || h == "*" { - continue - } - - hostreg, err := regexp.CompilePOSIX(h) - if err != nil { - logger.Logf(log.TraceLevel, "endpoint have invalid host regexp: %v", err) - continue - } - - cep.hostregs = append(cep.hostregs, hostreg) - } - - for _, p := range ep.Endpoint.Path { - var pcreok bool - - if p[0] == '^' && p[len(p)-1] == '$' { - pcrereg, err := regexp.CompilePOSIX(p) - if err == nil { - cep.pcreregs = append(cep.pcreregs, pcrereg) - pcreok = true - } - } - - rule, err := util.Parse(p) - if err != nil && !pcreok { - logger.Logf(log.TraceLevel, "endpoint have invalid path pattern: %v", err) - continue - } else if err != nil && pcreok { - continue - } - - tpl := rule.Compile() - - pathreg, err := util.NewPattern(tpl.Version, tpl.OpCodes, tpl.Pool, "", util.PatternLogger(logger)) - if err != nil { - logger.Logf(log.TraceLevel, "endpoint have invalid path pattern: %v", err) - continue - } - - cep.pathregs = append(cep.pathregs, pathreg) - } - - r.ceps[name] = cep - } -} - -// watch for endpoint changes. -func (r *registryRouter) watch() { - var attempts int - - logger := r.Options().Logger - - for { - if r.isStopped() { - return - } - - // watch for changes - w, err := r.opts.Registry.Watch() - if err != nil { - attempts++ - - logger.Logf(log.ErrorLevel, "error watching endpoints: %v", err) - time.Sleep(time.Duration(attempts) * time.Second) - - continue - } - - ch := make(chan bool) - - go func() { - select { - case <-ch: - w.Stop() - case <-r.exit: - w.Stop() - } - }() - - // reset if we get here - attempts = 0 - - for { - // process next event - res, err := w.Next() - if err != nil { - logger.Logf(log.ErrorLevel, "error getting next endoint: %v", err) - close(ch) - - break - } - - r.process(res) - } - } -} - -func (r *registryRouter) Options() router.Options { - return r.opts -} - -func (r *registryRouter) Stop() error { - select { - case <-r.exit: - return nil - default: - close(r.exit) - r.rc.Stop() - } - - return nil -} - -func (r *registryRouter) Register(ep *router.Route) error { - return nil -} - -func (r *registryRouter) Deregister(ep *router.Route) error { - return nil -} - -func (r *registryRouter) Endpoint(req *http.Request) (*router.Route, error) { - logger := r.Options().Logger - - if r.isStopped() { - return nil, errors.New("router closed") - } - - r.RLock() - defer r.RUnlock() - - var idx int - if len(req.URL.Path) > 0 && req.URL.Path != "/" { - idx = 1 - } - - path := strings.Split(req.URL.Path[idx:], "/") - - // use the first match - // TODO: weighted matching - for n, endpoint := range r.eps { - cep, ok := r.ceps[n] - if !ok { - continue - } - - ep := endpoint.Endpoint - - var mMatch, hMatch, pMatch bool - // 1. try method - for _, m := range ep.Method { - if m == req.Method { - mMatch = true - break - } - } - - if !mMatch { - continue - } - - logger.Logf(log.DebugLevel, "api method match %s", req.Method) - - // 2. try host - if len(ep.Host) == 0 { - hMatch = true - } else { - for idx, h := range ep.Host { - if h == "" || h == "*" { - hMatch = true - break - } else if cep.hostregs[idx].MatchString(req.URL.Host) { - hMatch = true - break - } - } - } - - if !hMatch { - continue - } - - logger.Logf(log.DebugLevel, "api host match %s", req.URL.Host) - - // 3. try path via google.api path matching - for _, pathreg := range cep.pathregs { - matches, err := pathreg.Match(path, "") - if err != nil { - logger.Logf(log.DebugLevel, "api gpath not match %s != %v", path, pathreg) - continue - } - - logger.Logf(log.DebugLevel, "api gpath match %s = %v", path, pathreg) - - pMatch = true - ctx := req.Context() - - md, ok := metadata.FromContext(ctx) - if !ok { - md = make(metadata.Metadata) - } - - for k, v := range matches { - md[fmt.Sprintf("x-api-field-%s", k)] = v - } - - *req = *req.Clone(metadata.NewContext(ctx, md)) - - break - } - - if !pMatch { - // 4. try path via pcre path matching - for _, pathreg := range cep.pcreregs { - if !pathreg.MatchString(req.URL.Path) { - logger.Logf(log.DebugLevel, "api pcre path not match %s != %v", path, pathreg) - continue - } - - logger.Logf(log.DebugLevel, "api pcre path match %s != %v", path, pathreg) - - pMatch = true - - break - } - } - - if !pMatch { - continue - } - - // TODO: Percentage traffic - // we got here, so its a match - return endpoint, nil - } - - // no match - return nil, errors.New("not found") -} - -func (r *registryRouter) Route(req *http.Request) (*router.Route, error) { - if r.isStopped() { - return nil, errors.New("router closed") - } - - // try get an endpoint - ep, err := r.Endpoint(req) - if err == nil { - return ep, nil - } - - // error not nil - // ignore that shit - // TODO: don't ignore that shit - - // get the service name - rsp, err := r.opts.Resolver.Resolve(req) - if err != nil { - return nil, err - } - - // service name - name := rsp.Name - - // get service - services, err := r.rc.GetService(name) - if err != nil { - return nil, err - } - - // only use endpoint matching when the meta handler is set aka api.Default - switch r.opts.Handler { - // rpc handlers - case "meta", "api", "rpc": - handler := r.opts.Handler - - // set default handler to api - if r.opts.Handler == "meta" { - handler = "rpc" - } - - // extract endpoint from Path, case-sensitive - // just test it in this case, maybe should put the code somewhere else - ep_name := rsp.Method - comps := strings.Split(rsp.Path, "/") - switch len(comps) { - case 3: - ep_name = comps[1] + "." + comps[2] - case 4: - ep_name = comps[2] + "." + comps[3] - } - - // construct api service - return &router.Route{ - Service: name, - Endpoint: &router.Endpoint{ - Name: ep_name, - Handler: handler, - }, - Versions: services, - }, nil - // http handler - case "http", "proxy", "web": - // construct api service - return &router.Route{ - Service: name, - Endpoint: &router.Endpoint{ - Name: req.URL.String(), - Handler: r.opts.Handler, - Host: []string{req.Host}, - Method: []string{req.Method}, - Path: []string{req.URL.Path}, - }, - Versions: services, - }, nil - } - - return nil, errors.New("unknown handler") -} - -func newRouter(opts ...router.Option) *registryRouter { - options := router.NewOptions(opts...) - r := ®istryRouter{ - exit: make(chan bool), - opts: options, - rc: cache.New(options.Registry), - eps: make(map[string]*router.Route), - ceps: make(map[string]*endpoint), - } - - go r.watch() - go r.refresh() - - return r -} - -// NewRouter returns the default router. -func NewRouter(opts ...router.Option) router.Router { - return newRouter(opts...) -} diff --git a/api/router/registry/registry_test.go b/api/router/registry/registry_test.go deleted file mode 100644 index 5ff1621642..0000000000 --- a/api/router/registry/registry_test.go +++ /dev/null @@ -1,34 +0,0 @@ -package registry - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "go-micro.dev/v5/registry" -) - -func TestStoreRegex(t *testing.T) { - router := newRouter() - router.store([]*registry.Service{ - { - Name: "Foobar", - Version: "latest", - Endpoints: []*registry.Endpoint{ - { - Name: "foo", - Metadata: map[string]string{ - "endpoint": "FooEndpoint", - "description": "Some description", - "method": "POST", - "path": "^/foo/$", - "handler": "rpc", - }, - }, - }, - Metadata: map[string]string{}, - }, - }, - ) - - assert.Len(t, router.ceps["Foobar.foo"].pcreregs, 1) -} diff --git a/api/router/router.go b/api/router/router.go deleted file mode 100644 index d60715f970..0000000000 --- a/api/router/router.go +++ /dev/null @@ -1,49 +0,0 @@ -// Package router provides api service routing -package router - -import ( - "net/http" - - "go-micro.dev/v5/registry" -) - -// Router is used to determine an endpoint for a request. -type Router interface { - // Returns options - Options() Options - // Register endpoint in router - Register(r *Route) error - // Deregister endpoint from router - Deregister(r *Route) error - // Route returns an api.Service route - Route(r *http.Request) (*Route, error) - // Stop the router - Stop() error -} - -type Route struct { - // Name of service - Service string - // The endpoint for this service - Endpoint *Endpoint - // Versions of this service - Versions []*registry.Service -} - -// Endpoint is a mapping between an RPC method and HTTP endpoint. -type Endpoint struct { - // RPC Method e.g. Greeter.Hello - Name string - // What the endpoint is for - Description string - // API Handler e.g rpc, proxy - Handler string - // HTTP Host e.g example.com - Host []string - // HTTP Methods e.g GET, POST - Method []string - // HTTP Path e.g /greeter. Expect POSIX regex - Path []string - // Stream flag - Stream bool -} diff --git a/api/router/static/static.go b/api/router/static/static.go deleted file mode 100644 index 113a76891e..0000000000 --- a/api/router/static/static.go +++ /dev/null @@ -1,369 +0,0 @@ -package static - -import ( - "errors" - "fmt" - "net/http" - "regexp" - "strings" - "sync" - - "go-micro.dev/v5/api/router" - "go-micro.dev/v5/api/router/util" - log "go-micro.dev/v5/logger" - "go-micro.dev/v5/metadata" - "go-micro.dev/v5/registry" - rutil "go-micro.dev/v5/util/registry" -) - -type endpoint struct { - apiep *router.Endpoint - hostregs []*regexp.Regexp - pathregs []util.Pattern - pcreregs []*regexp.Regexp -} - -// Router is the default router. -type Router struct { - opts router.Options - exit chan bool - eps map[string]*endpoint - sync.RWMutex -} - -func (r *Router) isStopd() bool { - select { - case <-r.exit: - return true - default: - return false - } -} - -/* -// watch for endpoint changes -func (r *staticRouter) watch() { - var attempts int - - for { - if r.isStopd() { - return - } - - // watch for changes - w, err := r.opts.Registry.Watch() - if err != nil { - attempts++ - log.Println("Error watching endpoints", err) - time.Sleep(time.Duration(attempts) * time.Second) - continue - } - - ch := make(chan bool) - - go func() { - select { - case <-ch: - w.Stop() - case <-r.exit: - w.Stop() - } - }() - - // reset if we get here - attempts = 0 - - for { - // process next event - res, err := w.Next() - if err != nil { - log.Println("Error getting next endpoint", err) - close(ch) - break - } - r.process(res) - } - } -} -*/ - -func (r *Router) Register(route *router.Route) error { - myEndpoint := route.Endpoint - - if err := router.Validate(myEndpoint); err != nil { - return err - } - - var ( - pathregs []util.Pattern - hostregs []*regexp.Regexp - pcreregs []*regexp.Regexp - ) - - for _, h := range myEndpoint.Host { - if h == "" || h == "*" { - continue - } - hostreg, err := regexp.CompilePOSIX(h) - if err != nil { - return err - } - - hostregs = append(hostregs, hostreg) - } - - for _, p := range myEndpoint.Path { - var pcreok bool - - // pcre only when we have start and end markers - if p[0] == '^' && p[len(p)-1] == '$' { - pcrereg, err := regexp.CompilePOSIX(p) - if err == nil { - pcreregs = append(pcreregs, pcrereg) - pcreok = true - } - } - - rule, err := util.Parse(p) - if err != nil && !pcreok { - return err - } else if err != nil && pcreok { - continue - } - - tpl := rule.Compile() - - pathreg, err := util.NewPattern(tpl.Version, tpl.OpCodes, tpl.Pool, "", util.PatternLogger(r.Options().Logger)) - if err != nil { - return err - } - - pathregs = append(pathregs, pathreg) - } - - r.Lock() - r.eps[myEndpoint.Name] = &endpoint{ - apiep: myEndpoint, - pcreregs: pcreregs, - pathregs: pathregs, - hostregs: hostregs, - } - r.Unlock() - - return nil -} - -func (r *Router) Deregister(route *router.Route) error { - ep := route.Endpoint - if err := router.Validate(ep); err != nil { - return err - } - - r.Lock() - delete(r.eps, ep.Name) - r.Unlock() - - return nil -} - -func (r *Router) Options() router.Options { - return r.opts -} - -func (r *Router) Stop() error { - select { - case <-r.exit: - return nil - default: - close(r.exit) - } - - return nil -} - -func (r *Router) Endpoint(req *http.Request) (*router.Route, error) { - myEndpoint, err := r.endpoint(req) - if err != nil { - return nil, err - } - - epf := strings.Split(myEndpoint.apiep.Name, ".") - - services, err := r.opts.Registry.GetService(epf[0]) - if err != nil { - return nil, err - } - - // hack for stream endpoint - if myEndpoint.apiep.Stream { - svcs := rutil.Copy(services) - for _, svc := range svcs { - if len(svc.Endpoints) == 0 { - e := ®istry.Endpoint{} - e.Name = strings.Join(epf[1:], ".") - e.Metadata = make(map[string]string) - e.Metadata["stream"] = "true" - svc.Endpoints = append(svc.Endpoints, e) - } - - for _, e := range svc.Endpoints { - e.Name = strings.Join(epf[1:], ".") - e.Metadata = make(map[string]string) - e.Metadata["stream"] = "true" - } - } - - services = svcs - } - - svc := &router.Route{ - Service: epf[0], - Endpoint: &router.Endpoint{ - Name: strings.Join(epf[1:], "."), - Handler: "rpc", - Host: myEndpoint.apiep.Host, - Method: myEndpoint.apiep.Method, - Path: myEndpoint.apiep.Path, - Stream: myEndpoint.apiep.Stream, - }, - Versions: services, - } - - return svc, nil -} - -func (r *Router) endpoint(req *http.Request) (*endpoint, error) { - logger := r.Options().Logger - - if r.isStopd() { - return nil, errors.New("router closed") - } - - r.RLock() - defer r.RUnlock() - - var idx int - if len(req.URL.Path) > 0 && req.URL.Path != "/" { - idx = 1 - } - - path := strings.Split(req.URL.Path[idx:], "/") - - // use the first match - // TODO: weighted matching - for _, myEndpoint := range r.eps { - var mMatch, hMatch, pMatch bool - - // 1. try method - for _, m := range myEndpoint.apiep.Method { - if m == req.Method { - mMatch = true - break - } - } - - if !mMatch { - continue - } - logger.Logf(log.DebugLevel, "api method match %s", req.Method) - - // 2. try host - if len(myEndpoint.apiep.Host) == 0 { - hMatch = true - } else { - for idx, h := range myEndpoint.apiep.Host { - if h == "" || h == "*" { - hMatch = true - break - } else if myEndpoint.hostregs[idx].MatchString(req.URL.Host) { - hMatch = true - break - } - } - } - - if !hMatch { - continue - } - - logger.Logf(log.DebugLevel, "api host match %s", req.URL.Host) - - // 3. try google.api path - for _, pathreg := range myEndpoint.pathregs { - matches, err := pathreg.Match(path, "") - if err != nil { - logger.Logf(log.DebugLevel, "api gpath not match %s != %v", path, pathreg) - continue - } - - logger.Logf(log.DebugLevel, "api gpath match %s = %v", path, pathreg) - - pMatch = true - ctx := req.Context() - md, ok := metadata.FromContext(ctx) - - if !ok { - md = make(metadata.Metadata) - } - - for k, v := range matches { - md[fmt.Sprintf("x-api-field-%s", k)] = v - } - - *req = *req.Clone(metadata.NewContext(ctx, md)) - - break - } - - if !pMatch { - // 4. try path via pcre path matching - for _, pathreg := range myEndpoint.pcreregs { - if !pathreg.MatchString(req.URL.Path) { - logger.Logf(log.DebugLevel, "api pcre path not match %s != %v", req.URL.Path, pathreg) - continue - } - - pMatch = true - - break - } - } - - if !pMatch { - continue - } - // TODO: Percentage traffic - - // we got here, so its a match - return myEndpoint, nil - } - - // no match - return nil, fmt.Errorf("endpoint not found for %v", req.URL) -} - -func (r *Router) Route(req *http.Request) (*router.Route, error) { - if r.isStopd() { - return nil, errors.New("router closed") - } - - // try get an endpoint - ep, err := r.Endpoint(req) - if err != nil { - return nil, err - } - - return ep, nil -} - -// NewRouter returns a new static router. -func NewRouter(opts ...router.Option) *Router { - options := router.NewOptions(opts...) - r := &Router{ - exit: make(chan bool), - opts: options, - eps: make(map[string]*endpoint), - } - // go r.watch() - return r -} diff --git a/api/router/util/LICENSE.txt b/api/router/util/LICENSE.txt deleted file mode 100644 index 364516251b..0000000000 --- a/api/router/util/LICENSE.txt +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2015, Gengo, Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - - * Neither the name of Gengo, Inc. nor the names of its - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/api/router/util/compile.go b/api/router/util/compile.go deleted file mode 100644 index 956b269a89..0000000000 --- a/api/router/util/compile.go +++ /dev/null @@ -1,122 +0,0 @@ -package util - -// download from -// https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/protoc-gen-grpc-gateway/httprule/compile.go - -const ( - opcodeVersion = 1 -) - -// Template is a compiled representation of path templates. -type Template struct { - // Verb is a VERB part in the template. - Verb string - // Original template (example: /v1/a_bit_of_everything) - Template string - // OpCodes is a sequence of operations. - OpCodes []int - // Pool is a constant pool - Pool []string - // Fields is a list of field paths bound in this template. - Fields []string - // Version is the version number of the format. - Version int -} - -// Compiler compiles utilities representation of path templates into marshallable operations. -// They can be unmarshalled by runtime.NewPattern. -type Compiler interface { - Compile() Template -} - -type op struct { - - // str is a string operand of the code. - // operand is ignored if str is not empty. - str string - - // code is the opcode of the operation - code OpCode - - // operand is a numeric operand of the code. - operand int -} - -func (w wildcard) compile() []op { - return []op{ - {code: OpPush}, - } -} - -func (w deepWildcard) compile() []op { - return []op{ - {code: OpPushM}, - } -} - -func (l literal) compile() []op { - return []op{ - { - code: OpLitPush, - str: string(l), - }, - } -} - -func (v variable) compile() []op { - var ops []op - for _, s := range v.segments { - ops = append(ops, s.compile()...) - } - - ops = append(ops, op{ - code: OpConcatN, - operand: len(v.segments), - }, op{ - code: OpCapture, - str: v.path, - }) - - return ops -} - -func (t template) Compile() Template { - var rawOps []op - for _, s := range t.segments { - rawOps = append(rawOps, s.compile()...) - } - - var ( - ops []int - pool []string - fields []string - ) - - consts := make(map[string]int) - - for _, op := range rawOps { - ops = append(ops, int(op.code)) - if op.str == "" { - ops = append(ops, op.operand) - } else { - if _, ok := consts[op.str]; !ok { - consts[op.str] = len(pool) - pool = append(pool, op.str) - } - ops = append(ops, consts[op.str]) - } - - if op.code == OpCapture { - fields = append(fields, op.str) - } - } - - return Template{ - Version: opcodeVersion, - OpCodes: ops, - Pool: pool, - Verb: t.verb, - Fields: fields, - Template: t.template, - } -} diff --git a/api/router/util/compile_test.go b/api/router/util/compile_test.go deleted file mode 100644 index 3ed6f43ca0..0000000000 --- a/api/router/util/compile_test.go +++ /dev/null @@ -1,122 +0,0 @@ -package util - -// download from https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/protoc-gen-grpc-gateway/httprule/compile_test.go - -import ( - "reflect" - "testing" -) - -const ( - operandFiller = 0 -) - -func TestCompile(t *testing.T) { - for _, spec := range []struct { - segs []segment - verb string - - ops []int - pool []string - fields []string - }{ - {}, - { - segs: []segment{ - wildcard{}, - }, - ops: []int{int(OpPush), operandFiller}, - }, - { - segs: []segment{ - deepWildcard{}, - }, - ops: []int{int(OpPushM), operandFiller}, - }, - { - segs: []segment{ - literal("v1"), - }, - ops: []int{int(OpLitPush), 0}, - pool: []string{"v1"}, - }, - { - segs: []segment{ - literal("v1"), - }, - verb: "LOCK", - ops: []int{int(OpLitPush), 0}, - pool: []string{"v1"}, - }, - { - segs: []segment{ - variable{ - path: "name.nested", - segments: []segment{ - wildcard{}, - }, - }, - }, - ops: []int{ - int(OpPush), operandFiller, - int(OpConcatN), 1, - int(OpCapture), 0, - }, - pool: []string{"name.nested"}, - fields: []string{"name.nested"}, - }, - { - segs: []segment{ - literal("obj"), - variable{ - path: "name.nested", - segments: []segment{ - literal("a"), - wildcard{}, - literal("b"), - }, - }, - variable{ - path: "obj", - segments: []segment{ - deepWildcard{}, - }, - }, - }, - ops: []int{ - int(OpLitPush), 0, - int(OpLitPush), 1, - int(OpPush), operandFiller, - int(OpLitPush), 2, - int(OpConcatN), 3, - int(OpCapture), 3, - int(OpPushM), operandFiller, - int(OpConcatN), 1, - int(OpCapture), 0, - }, - pool: []string{"obj", "a", "b", "name.nested"}, - fields: []string{"name.nested", "obj"}, - }, - } { - tmpl := template{ - segments: spec.segs, - verb: spec.verb, - } - compiled := tmpl.Compile() - if got, want := compiled.Version, opcodeVersion; got != want { - t.Errorf("tmpl.Compile().Version = %d; want %d; segs=%#v, verb=%q", got, want, spec.segs, spec.verb) - } - if got, want := compiled.OpCodes, spec.ops; !reflect.DeepEqual(got, want) { - t.Errorf("tmpl.Compile().OpCodes = %v; want %v; segs=%#v, verb=%q", got, want, spec.segs, spec.verb) - } - if got, want := compiled.Pool, spec.pool; !reflect.DeepEqual(got, want) { - t.Errorf("tmpl.Compile().Pool = %q; want %q; segs=%#v, verb=%q", got, want, spec.segs, spec.verb) - } - if got, want := compiled.Verb, spec.verb; got != want { - t.Errorf("tmpl.Compile().Verb = %q; want %q; segs=%#v, verb=%q", got, want, spec.segs, spec.verb) - } - if got, want := compiled.Fields, spec.fields; !reflect.DeepEqual(got, want) { - t.Errorf("tmpl.Compile().Fields = %q; want %q; segs=%#v, verb=%q", got, want, spec.segs, spec.verb) - } - } -} diff --git a/api/router/util/parse.go b/api/router/util/parse.go deleted file mode 100644 index e836614f13..0000000000 --- a/api/router/util/parse.go +++ /dev/null @@ -1,396 +0,0 @@ -package util - -// download from -// https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/protoc-gen-grpc-gateway/httprule/parse.go - -import ( - "fmt" - "strings" - - log "go-micro.dev/v5/logger" -) - -// InvalidTemplateError indicates that the path template is not valid. -type InvalidTemplateError struct { - tmpl string - msg string -} - -func (e InvalidTemplateError) Error() string { - return fmt.Sprintf("%s: %s", e.msg, e.tmpl) -} - -// Parse parses the string representation of path template. -func Parse(tmpl string) (Compiler, error) { - if !strings.HasPrefix(tmpl, "/") { - return template{}, InvalidTemplateError{tmpl: tmpl, msg: "no leading /"} - } - - tokens, verb := tokenize(tmpl[1:]) - p := parser{tokens: tokens} - - segs, err := p.topLevelSegments() - if err != nil { - return template{}, InvalidTemplateError{tmpl: tmpl, msg: err.Error()} - } - - return template{ - segments: segs, - verb: verb, - template: tmpl, - }, nil -} - -func tokenize(path string) (tokens []string, verb string) { - if path == "" { - return []string{eof}, "" - } - - const ( - init = iota - field - nested - ) - var ( - st = init - ) - - for path != "" { - var idx int - - switch st { - case init: - idx = strings.IndexAny(path, "/{") - case field: - idx = strings.IndexAny(path, ".=}") - case nested: - idx = strings.IndexAny(path, "/}") - } - - if idx < 0 { - tokens = append(tokens, path) - break - } - - switch r := path[idx]; r { - case '/', '.': - case '{': - st = field - case '=': - st = nested - case '}': - st = init - } - - if idx == 0 { - tokens = append(tokens, path[idx:idx+1]) - } else { - tokens = append(tokens, path[:idx], path[idx:idx+1]) - } - - path = path[idx+1:] - } - - l := len(tokens) - t := tokens[l-1] - - if idx := strings.LastIndex(t, ":"); idx == 0 { - tokens, verb = tokens[:l-1], t[1:] - } else if idx > 0 { - tokens[l-1], verb = t[:idx], t[idx+1:] - } - - tokens = append(tokens, eof) - - return tokens, verb -} - -// parser is a parser of the template syntax defined in github.com/googleapis/googleapis/google/api/http.proto. -type parser struct { - logger log.Logger - tokens []string - accepted []string -} - -// topLevelSegments is the target of this parser. -func (p *parser) topLevelSegments() ([]segment, error) { - logger := log.LoggerOrDefault(p.logger) - - logger.Logf(log.DebugLevel, "Parsing %q", p.tokens) - - segs, err := p.segments() - if err != nil { - return nil, err - } - - logger.Logf(log.DebugLevel, "accept segments: %q; %q", p.accepted, p.tokens) - - if _, err := p.accept(typeEOF); err != nil { - return nil, fmt.Errorf("unexpected token %q after segments %q", p.tokens[0], strings.Join(p.accepted, "")) - } - - logger.Logf(log.DebugLevel, "accept eof: %q; %q", p.accepted, p.tokens) - - return segs, nil -} - -func (p *parser) segments() ([]segment, error) { - logger := log.LoggerOrDefault(p.logger) - s, err := p.segment() - - if err != nil { - return nil, err - } - - logger.Logf(log.DebugLevel, "accept segment: %q; %q", p.accepted, p.tokens) - - segs := []segment{s} - for { - if _, err := p.accept("/"); err != nil { - return segs, nil - } - - s, err := p.segment() - if err != nil { - return segs, err - } - - segs = append(segs, s) - - logger.Logf(log.DebugLevel, "accept segment: %q; %q", p.accepted, p.tokens) - } -} - -func (p *parser) segment() (segment, error) { - if _, err := p.accept("*"); err == nil { - return wildcard{}, nil - } - - if _, err := p.accept("**"); err == nil { - return deepWildcard{}, nil - } - - if l, err := p.literal(); err == nil { - return l, nil - } - - v, err := p.variable() - if err != nil { - return nil, fmt.Errorf("segment neither wildcards, literal or variable: %w", err) - } - - return v, err -} - -func (p *parser) literal() (segment, error) { - lit, err := p.accept(typeLiteral) - if err != nil { - return nil, err - } - - return literal(lit), nil -} - -func (p *parser) variable() (segment, error) { - if _, err := p.accept("{"); err != nil { - return nil, err - } - - path, err := p.fieldPath() - if err != nil { - return nil, err - } - - var segs []segment - if _, err := p.accept("="); err == nil { - segs, err = p.segments() - if err != nil { - return nil, fmt.Errorf("invalid segment in variable %q: %w", path, err) - } - } else { - segs = []segment{wildcard{}} - } - - if _, err := p.accept("}"); err != nil { - return nil, fmt.Errorf("unterminated variable segment: %s", path) - } - - return variable{ - path: path, - segments: segs, - }, nil -} - -func (p *parser) fieldPath() (string, error) { - c, err := p.accept(typeIdent) - if err != nil { - return "", err - } - - components := []string{c} - - for { - if _, err = p.accept("."); err != nil { - return strings.Join(components, "."), nil - } - c, err := p.accept(typeIdent) - if err != nil { - return "", fmt.Errorf("invalid field path component: %v", err) - } - components = append(components, c) - } -} - -// A termType is a type of terminal symbols. -type termType string - -// These constants define some of valid values of termType. -// They improve readability of parse functions. -// -// You can also use "/", "*", "**", "." or "=" as valid values. -const ( - typeIdent = termType("ident") - typeLiteral = termType("literal") - typeEOF = termType("$") -) - -const ( - // eof is the terminal symbol which always appears at the end of token sequence. - eof = "\u0000" -) - -// accept tries to accept a token in "p". -// This function consumes a token and returns it if it matches to the specified "term". -// If it doesn't match, the function does not consume any tokens and return an error. -func (p *parser) accept(term termType) (string, error) { - t := p.tokens[0] - - switch term { - case "/", "*", "**", ".", "=", "{", "}": - if t != string(term) && t != "/" { - return "", fmt.Errorf("expected %q but got %q", term, t) - } - case typeEOF: - if t != eof { - return "", fmt.Errorf("expected EOF but got %q", t) - } - case typeIdent: - if err := expectIdent(t); err != nil { - return "", err - } - case typeLiteral: - if err := expectPChars(t); err != nil { - return "", err - } - default: - return "", fmt.Errorf("unknown termType %q", term) - } - - p.tokens = p.tokens[1:] - p.accepted = append(p.accepted, t) - - return t, nil -} - -// expectPChars determines if "t" consists of only pchars defined in RFC3986. -// -// https://www.ietf.org/rfc/rfc3986.txt, P.49 -// -// pchar = unreserved / pct-encoded / sub-delims / ":" / "@" -// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" -// sub-delims = "!" / "$" / "&" / "'" / "(" / ")" -// / "*" / "+" / "," / ";" / "=" -// pct-encoded = "%" HEXDIG HEXDIG -func expectPChars(t string) error { - const ( - init = iota - pct1 - pct2 - ) - - st := init - for _, r := range t { - if st != init { - if !isHexDigit(r) { - return fmt.Errorf("invalid hexdigit: %c(%U)", r, r) - } - switch st { - case pct1: - st = pct2 - case pct2: - st = init - } - continue - } - - // unreserved - switch { - case 'A' <= r && r <= 'Z': - continue - case 'a' <= r && r <= 'z': - continue - case '0' <= r && r <= '9': - continue - } - switch r { - case '-', '.', '_', '~': - // unreserved - case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=': - // sub-delims - case ':', '@': - // rest of pchar - case '%': - // pct-encoded - st = pct1 - default: - return fmt.Errorf("invalid character in path segment: %q(%U)", r, r) - } - } - - if st != init { - return fmt.Errorf("invalid percent-encoding in %q", t) - } - - return nil -} - -// expectIdent determines if "ident" is a valid identifier in .proto schema ([[:alpha:]_][[:alphanum:]_]*). -func expectIdent(ident string) error { - if ident == "" { - return fmt.Errorf("empty identifier") - } - - for pos, r := range ident { - switch { - case '0' <= r && r <= '9': - if pos == 0 { - return fmt.Errorf("identifier starting with digit: %s", ident) - } - - continue - case 'A' <= r && r <= 'Z': - continue - case 'a' <= r && r <= 'z': - continue - case r == '_': - continue - default: - return fmt.Errorf("invalid character %q(%U) in identifier: %s", r, r, ident) - } - } - - return nil -} - -func isHexDigit(r rune) bool { - switch { - case '0' <= r && r <= '9': - return true - case 'A' <= r && r <= 'F': - return true - case 'a' <= r && r <= 'f': - return true - } - - return false -} diff --git a/api/router/util/parse_test.go b/api/router/util/parse_test.go deleted file mode 100644 index a96799bbd6..0000000000 --- a/api/router/util/parse_test.go +++ /dev/null @@ -1,321 +0,0 @@ -package util - -// download from https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/protoc-gen-grpc-gateway/httprule/parse_test.go - -import ( - "flag" - "fmt" - "reflect" - "testing" - - "go-micro.dev/v5/logger" -) - -func TestTokenize(t *testing.T) { - for _, spec := range []struct { - src string - tokens []string - }{ - { - src: "", - tokens: []string{eof}, - }, - { - src: "v1", - tokens: []string{"v1", eof}, - }, - { - src: "v1/b", - tokens: []string{"v1", "/", "b", eof}, - }, - { - src: "v1/endpoint/*", - tokens: []string{"v1", "/", "endpoint", "/", "*", eof}, - }, - { - src: "v1/endpoint/**", - tokens: []string{"v1", "/", "endpoint", "/", "**", eof}, - }, - { - src: "v1/b/{bucket_name=*}", - tokens: []string{ - "v1", "/", - "b", "/", - "{", "bucket_name", "=", "*", "}", - eof, - }, - }, - { - src: "v1/b/{bucket_name=buckets/*}", - tokens: []string{ - "v1", "/", - "b", "/", - "{", "bucket_name", "=", "buckets", "/", "*", "}", - eof, - }, - }, - { - src: "v1/b/{bucket_name=buckets/*}/o", - tokens: []string{ - "v1", "/", - "b", "/", - "{", "bucket_name", "=", "buckets", "/", "*", "}", "/", - "o", - eof, - }, - }, - { - src: "v1/b/{bucket_name=buckets/*}/o/{name}", - tokens: []string{ - "v1", "/", - "b", "/", - "{", "bucket_name", "=", "buckets", "/", "*", "}", "/", - "o", "/", "{", "name", "}", - eof, - }, - }, - { - src: "v1/a=b&c=d;e=f:g/endpoint.rdf", - tokens: []string{ - "v1", "/", - "a=b&c=d;e=f:g", "/", - "endpoint.rdf", - eof, - }, - }, - } { - tokens, verb := tokenize(spec.src) - if got, want := tokens, spec.tokens; !reflect.DeepEqual(got, want) { - t.Errorf("tokenize(%q) = %q, _; want %q, _", spec.src, got, want) - } - if got, want := verb, ""; got != want { - t.Errorf("tokenize(%q) = _, %q; want _, %q", spec.src, got, want) - } - - src := fmt.Sprintf("%s:%s", spec.src, "LOCK") - tokens, verb = tokenize(src) - if got, want := tokens, spec.tokens; !reflect.DeepEqual(got, want) { - t.Errorf("tokenize(%q) = %q, _; want %q, _", src, got, want) - } - if got, want := verb, "LOCK"; got != want { - t.Errorf("tokenize(%q) = _, %q; want _, %q", src, got, want) - } - } -} - -func TestParseSegments(t *testing.T) { - flag.Set("v", "3") - for _, spec := range []struct { - tokens []string - want []segment - }{ - { - tokens: []string{"v1", eof}, - want: []segment{ - literal("v1"), - }, - }, - { - tokens: []string{"/", eof}, - want: []segment{ - wildcard{}, - }, - }, - { - tokens: []string{"-._~!$&'()*+,;=:@", eof}, - want: []segment{ - literal("-._~!$&'()*+,;=:@"), - }, - }, - { - tokens: []string{"%e7%ac%ac%e4%b8%80%e7%89%88", eof}, - want: []segment{ - literal("%e7%ac%ac%e4%b8%80%e7%89%88"), - }, - }, - { - tokens: []string{"v1", "/", "*", eof}, - want: []segment{ - literal("v1"), - wildcard{}, - }, - }, - { - tokens: []string{"v1", "/", "**", eof}, - want: []segment{ - literal("v1"), - deepWildcard{}, - }, - }, - { - tokens: []string{"{", "name", "}", eof}, - want: []segment{ - variable{ - path: "name", - segments: []segment{ - wildcard{}, - }, - }, - }, - }, - { - tokens: []string{"{", "name", "=", "*", "}", eof}, - want: []segment{ - variable{ - path: "name", - segments: []segment{ - wildcard{}, - }, - }, - }, - }, - { - tokens: []string{"{", "field", ".", "nested", ".", "nested2", "=", "*", "}", eof}, - want: []segment{ - variable{ - path: "field.nested.nested2", - segments: []segment{ - wildcard{}, - }, - }, - }, - }, - { - tokens: []string{"{", "name", "=", "a", "/", "b", "/", "*", "}", eof}, - want: []segment{ - variable{ - path: "name", - segments: []segment{ - literal("a"), - literal("b"), - wildcard{}, - }, - }, - }, - }, - { - tokens: []string{ - "v1", "/", - "{", - "name", ".", "nested", ".", "nested2", - "=", - "a", "/", "b", "/", "*", - "}", "/", - "o", "/", - "{", - "another_name", - "=", - "a", "/", "b", "/", "*", "/", "c", - "}", "/", - "**", - eof}, - want: []segment{ - literal("v1"), - variable{ - path: "name.nested.nested2", - segments: []segment{ - literal("a"), - literal("b"), - wildcard{}, - }, - }, - literal("o"), - variable{ - path: "another_name", - segments: []segment{ - literal("a"), - literal("b"), - wildcard{}, - literal("c"), - }, - }, - deepWildcard{}, - }, - }, - } { - p := parser{tokens: spec.tokens} - segs, err := p.topLevelSegments() - if err != nil { - t.Errorf("parser{%q}.segments() failed with %v; want success", spec.tokens, err) - continue - } - if got, want := segs, spec.want; !reflect.DeepEqual(got, want) { - t.Errorf("parser{%q}.segments() = %#v; want %#v", spec.tokens, got, want) - } - if got := p.tokens; len(got) > 0 { - t.Errorf("p.tokens = %q; want []; spec.tokens=%q", got, spec.tokens) - } - } -} - -func TestParseSegmentsWithErrors(t *testing.T) { - flag.Set("v", "3") - for _, spec := range []struct { - tokens []string - }{ - { - // double slash - tokens: []string{"//", eof}, - }, - { - // invalid literal - tokens: []string{"a?b", eof}, - }, - { - // invalid percent-encoding - tokens: []string{"%", eof}, - }, - { - // invalid percent-encoding - tokens: []string{"%2", eof}, - }, - { - // invalid percent-encoding - tokens: []string{"a%2z", eof}, - }, - { - // empty segments - tokens: []string{eof}, - }, - { - // unterminated variable - tokens: []string{"{", "name", eof}, - }, - { - // unterminated variable - tokens: []string{"{", "name", "=", eof}, - }, - { - // unterminated variable - tokens: []string{"{", "name", "=", "*", eof}, - }, - { - // empty component in field path - tokens: []string{"{", "name", ".", "}", eof}, - }, - { - // empty component in field path - tokens: []string{"{", "name", ".", ".", "nested", "}", eof}, - }, - { - // invalid character in identifier - tokens: []string{"{", "field-name", "}", eof}, - }, - { - // no slash between segments - tokens: []string{"v1", "endpoint", eof}, - }, - { - // no slash between segments - tokens: []string{"v1", "{", "name", "}", eof}, - }, - } { - p := parser{tokens: spec.tokens} - segs, err := p.topLevelSegments() - if err == nil { - t.Errorf("parser{%q}.segments() succeeded; want InvalidTemplateError; accepted %#v", spec.tokens, segs) - continue - } - logger.Info(err) - } -} diff --git a/api/router/util/pattern.go b/api/router/util/pattern.go deleted file mode 100644 index b4bb838ca7..0000000000 --- a/api/router/util/pattern.go +++ /dev/null @@ -1,24 +0,0 @@ -package util - -// download from https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/utilities/pattern.go - -// An OpCode is a opcode of compiled path patterns. -type OpCode int - -// These constants are the valid values of OpCode. -const ( - // OpNop does nothing. - OpNop = OpCode(iota) - // OpPush pushes a component to stack. - OpPush - // OpLitPush pushes a component to stack if it matches to the literal. - OpLitPush - // OpPushM concatenates the remaining components and pushes it to stack. - OpPushM - // OpConcatN pops N items from stack, concatenates them and pushes it back to stack. - OpConcatN - // OpCapture pops an item and binds it to the variable. - OpCapture - // OpEnd is the least positive invalid opcode. - OpEnd -) diff --git a/api/router/util/runtime.go b/api/router/util/runtime.go deleted file mode 100644 index 225222984e..0000000000 --- a/api/router/util/runtime.go +++ /dev/null @@ -1,282 +0,0 @@ -package util - -// download from https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/runtime/pattern.go - -import ( - "errors" - "fmt" - "strings" - - log "go-micro.dev/v5/logger" -) - -var ( - // ErrNotMatch indicates that the given HTTP request path does not match to the pattern. - ErrNotMatch = errors.New("not match to the path pattern") - // ErrInvalidPattern indicates that the given definition of Pattern is not valid. - ErrInvalidPattern = errors.New("invalid pattern") -) - -type rop struct { - code OpCode - operand int -} - -// Pattern is a template pattern of http request paths defined in github.com/googleapis/googleapis/google/api/http.proto. -type Pattern struct { - // verb is the VERB part of the path pattern. It is empty if the pattern does not have VERB part. - verb string - // ops is a list of operations - ops []rop - // pool is a constant pool indexed by the operands or vars. - pool []string - // vars is a list of variables names to be bound by this pattern - vars []string - // stacksize is the max depth of the stack - stacksize int - // tailLen is the length of the fixed-size segments after a deep wildcard - tailLen int - // assumeColonVerb indicates whether a path suffix after a final - // colon may only be interpreted as a verb. - assumeColonVerb bool -} - -type patternOptions struct { - logger log.Logger - assumeColonVerb bool -} - -// PatternOpt is an option for creating Patterns. -type PatternOpt func(*patternOptions) - -// PatternLogger sets the logger. -func PatternLogger(l log.Logger) PatternOpt { - return func(po *patternOptions) { - po.logger = l - } -} - -// NewPattern returns a new Pattern from the given definition values. -// "ops" is a sequence of op codes. "pool" is a constant pool. -// "verb" is the verb part of the pattern. It is empty if the pattern does not have the part. -// "version" must be 1 for now. -// It returns an error if the given definition is invalid. -func NewPattern(version int, ops []int, pool []string, verb string, opts ...PatternOpt) (Pattern, error) { - options := patternOptions{ - assumeColonVerb: true, - } - for _, o := range opts { - o(&options) - } - - logger := log.LoggerOrDefault(options.logger) - - if version != 1 { - logger.Logf(log.DebugLevel, "unsupported version: %d", version) - return Pattern{}, ErrInvalidPattern - } - - l := len(ops) - if l%2 != 0 { - logger.Logf(log.DebugLevel, "odd number of ops codes: %d", l) - return Pattern{}, ErrInvalidPattern - } - - var ( - typedOps []rop - stack, maxstack int - tailLen int - pushMSeen bool - vars []string - ) - - for i := 0; i < l; i += 2 { - op := rop{code: OpCode(ops[i]), operand: ops[i+1]} - - switch op.code { - case OpNop: - continue - case OpPush: - if pushMSeen { - tailLen++ - } - stack++ - case OpPushM: - if pushMSeen { - logger.Logf(log.DebugLevel, "pushM appears twice") - return Pattern{}, ErrInvalidPattern - } - - pushMSeen = true - stack++ - case OpLitPush: - if op.operand < 0 || len(pool) <= op.operand { - logger.Logf(log.DebugLevel, "negative literal index: %d", op.operand) - return Pattern{}, ErrInvalidPattern - } - - if pushMSeen { - tailLen++ - } - stack++ - case OpConcatN: - if op.operand <= 0 { - logger.Logf(log.DebugLevel, "negative concat size: %d", op.operand) - return Pattern{}, ErrInvalidPattern - } - - stack -= op.operand - if stack < 0 { - logger.Logf(log.DebugLevel, "stack underflow") - return Pattern{}, ErrInvalidPattern - } - stack++ - case OpCapture: - if op.operand < 0 || len(pool) <= op.operand { - logger.Logf(log.DebugLevel, "variable name index out of bound: %d", op.operand) - return Pattern{}, ErrInvalidPattern - } - - v := pool[op.operand] - op.operand = len(vars) - vars = append(vars, v) - stack-- - - if stack < 0 { - logger.Logf(log.DebugLevel, "stack underflow") - return Pattern{}, ErrInvalidPattern - } - default: - logger.Logf(log.DebugLevel, "invalid opcode: %d", op.code) - return Pattern{}, ErrInvalidPattern - } - - if maxstack < stack { - maxstack = stack - } - - typedOps = append(typedOps, op) - } - - return Pattern{ - ops: typedOps, - pool: pool, - vars: vars, - stacksize: maxstack, - tailLen: tailLen, - verb: verb, - assumeColonVerb: options.assumeColonVerb, - }, nil -} - -// MustPattern is a helper function which makes it easier to call NewPattern in variable initialization. -func MustPattern(p Pattern, err error) Pattern { - if err != nil { - log.Logf(log.FatalLevel, "Pattern initialization failed: %v", err) - } - return p -} - -// Match examines components if it matches to the Pattern. -// If it matches, the function returns a mapping from field paths to their captured values. -// If otherwise, the function returns an error. -func (p Pattern) Match(components []string, verb string) (map[string]string, error) { - if p.verb != verb { - if p.assumeColonVerb || p.verb != "" { - return nil, ErrNotMatch - } - if len(components) == 0 { - components = []string{":" + verb} - } else { - components = append([]string{}, components...) - components[len(components)-1] += ":" + verb - } - verb = "" - } - - var pos int - stack := make([]string, 0, p.stacksize) - captured := make([]string, len(p.vars)) - l := len(components) - for _, op := range p.ops { - switch op.code { - case OpNop: - continue - case OpPush, OpLitPush: - if pos >= l { - return nil, ErrNotMatch - } - c := components[pos] - if op.code == OpLitPush { - if lit := p.pool[op.operand]; c != lit { - return nil, ErrNotMatch - } - } - stack = append(stack, c) - pos++ - case OpPushM: - end := len(components) - if end < pos+p.tailLen { - return nil, ErrNotMatch - } - end -= p.tailLen - stack = append(stack, strings.Join(components[pos:end], "/")) - pos = end - case OpConcatN: - n := op.operand - l := len(stack) - n - stack = append(stack[:l], strings.Join(stack[l:], "/")) - case OpCapture: - n := len(stack) - 1 - captured[op.operand] = stack[n] - stack = stack[:n] - } - } - if pos < l { - return nil, ErrNotMatch - } - bindings := make(map[string]string) - for i, val := range captured { - bindings[p.vars[i]] = val - } - return bindings, nil -} - -// Verb returns the verb part of the Pattern. -func (p Pattern) Verb() string { return p.verb } - -func (p Pattern) String() string { - var stack []string - for _, op := range p.ops { - switch op.code { - case OpNop: - continue - case OpPush: - stack = append(stack, "*") - case OpLitPush: - stack = append(stack, p.pool[op.operand]) - case OpPushM: - stack = append(stack, "**") - case OpConcatN: - n := op.operand - l := len(stack) - n - stack = append(stack[:l], strings.Join(stack[l:], "/")) - case OpCapture: - n := len(stack) - 1 - stack[n] = fmt.Sprintf("{%s=%s}", p.vars[op.operand], stack[n]) - } - } - segs := strings.Join(stack, "/") - if p.verb != "" { - return fmt.Sprintf("/%s:%s", segs, p.verb) - } - return "/" + segs -} - -// AssumeColonVerbOpt indicates whether a path suffix after a final -// colon may only be interpreted as a verb. -func AssumeColonVerbOpt(val bool) PatternOpt { - return PatternOpt(func(o *patternOptions) { - o.assumeColonVerb = val - }) -} diff --git a/api/router/util/types.go b/api/router/util/types.go deleted file mode 100644 index 04e0e53ef3..0000000000 --- a/api/router/util/types.go +++ /dev/null @@ -1,66 +0,0 @@ -package util - -// download from -// https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/protoc-gen-grpc-gateway/httprule/types.go - -import ( - "fmt" - "strings" -) - -type template struct { - verb string - template string - segments []segment -} - -type segment interface { - fmt.Stringer - compile() (ops []op) -} - -type wildcard struct{} - -type deepWildcard struct{} - -type literal string - -type variable struct { - path string - segments []segment -} - -func (wildcard) String() string { - return "*" -} - -func (deepWildcard) String() string { - return "**" -} - -func (l literal) String() string { - return string(l) -} - -func (v variable) String() string { - var segs []string - for _, s := range v.segments { - segs = append(segs, s.String()) - } - - return fmt.Sprintf("{%s=%s}", v.path, strings.Join(segs, "/")) -} - -func (t template) String() string { - var segs []string - for _, s := range t.segments { - segs = append(segs, s.String()) - } - - str := strings.Join(segs, "/") - if t.verb != "" { - str = fmt.Sprintf("%s:%s", str, t.verb) - } - - return "/" + str -} diff --git a/api/router/util/types_test.go b/api/router/util/types_test.go deleted file mode 100644 index d0e5dc7594..0000000000 --- a/api/router/util/types_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package util - -// download from -// https://raw.githubusercontent.com/grpc-ecosystem/grpc-gateway/master/protoc-gen-grpc-gateway/httprule/types_test.go - -import ( - "fmt" - "testing" -) - -func TestTemplateStringer(t *testing.T) { - for _, spec := range []struct { - segs []segment - want string - }{ - { - segs: []segment{ - literal("v1"), - }, - want: "/v1", - }, - { - segs: []segment{ - wildcard{}, - }, - want: "/*", - }, - { - segs: []segment{ - deepWildcard{}, - }, - want: "/**", - }, - { - segs: []segment{ - variable{ - path: "name", - segments: []segment{ - literal("a"), - }, - }, - }, - want: "/{name=a}", - }, - { - segs: []segment{ - variable{ - path: "name", - segments: []segment{ - literal("a"), - wildcard{}, - literal("b"), - }, - }, - }, - want: "/{name=a/*/b}", - }, - { - segs: []segment{ - literal("v1"), - variable{ - path: "name", - segments: []segment{ - literal("a"), - wildcard{}, - literal("b"), - }, - }, - literal("c"), - variable{ - path: "field.nested", - segments: []segment{ - wildcard{}, - literal("d"), - }, - }, - wildcard{}, - literal("e"), - deepWildcard{}, - }, - want: "/v1/{name=a/*/b}/c/{field.nested=*/d}/*/e/**", - }, - } { - tmpl := template{segments: spec.segs} - if got, want := tmpl.String(), spec.want; got != want { - t.Errorf("%#v.String() = %q; want %q", tmpl, got, want) - } - - tmpl.verb = "LOCK" - if got, want := tmpl.String(), fmt.Sprintf("%s:LOCK", spec.want); got != want { - t.Errorf("%#v.String() = %q; want %q", tmpl, got, want) - } - } -} diff --git a/api/server/acme/acme.go b/api/server/acme/acme.go deleted file mode 100644 index 4d726f70ed..0000000000 --- a/api/server/acme/acme.go +++ /dev/null @@ -1,28 +0,0 @@ -// Package acme abstracts away various ACME libraries -package acme - -import ( - "crypto/tls" - "errors" - "net" -) - -var ( - // ErrProviderNotImplemented can be returned when attempting to - // instantiate an unimplemented provider. - ErrProviderNotImplemented = errors.New("Provider not implemented") -) - -// Provider is a ACME provider interface. -type Provider interface { - // Listen returns a new listener - Listen(...string) (net.Listener, error) - // TLSConfig returns a tls config - TLSConfig(...string) (*tls.Config, error) -} - -// The Let's Encrypt ACME endpoints. -const ( - LetsEncryptStagingCA = "https://acme-staging-v02.api.letsencrypt.org/directory" - LetsEncryptProductionCA = "https://acme-v02.api.letsencrypt.org/directory" -) diff --git a/api/server/acme/autocert/autocert.go b/api/server/acme/autocert/autocert.go deleted file mode 100644 index 5811254d40..0000000000 --- a/api/server/acme/autocert/autocert.go +++ /dev/null @@ -1,47 +0,0 @@ -// Package autocert is the ACME provider from golang.org/x/crypto/acme/autocert -// This provider does not take any config. -package autocert - -import ( - "crypto/tls" - "net" - "os" - - "go-micro.dev/v5/api/server/acme" - log "go-micro.dev/v5/logger" - "golang.org/x/crypto/acme/autocert" -) - -// autoCertACME is the ACME provider from golang.org/x/crypto/acme/autocert. -type autocertProvider struct { - logger log.Logger -} - -// Listen implements acme.Provider. -func (a *autocertProvider) Listen(hosts ...string) (net.Listener, error) { - return autocert.NewListener(hosts...), nil -} - -// TLSConfig returns a new tls config. -func (a *autocertProvider) TLSConfig(hosts ...string) (*tls.Config, error) { - logger := log.LoggerOrDefault(a.logger) - // create a new manager - m := &autocert.Manager{ - Prompt: autocert.AcceptTOS, - } - if len(hosts) > 0 { - m.HostPolicy = autocert.HostWhitelist(hosts...) - } - dir := cacheDir() - if err := os.MkdirAll(dir, 0700); err != nil { - logger.Logf(log.InfoLevel, "warning: autocert not using a cache: %v", err) - } else { - m.Cache = autocert.DirCache(dir) - } - return m.TLSConfig(), nil -} - -// New returns an autocert acme.Provider. -func NewProvider() acme.Provider { - return &autocertProvider{} -} diff --git a/api/server/acme/autocert/autocert_test.go b/api/server/acme/autocert/autocert_test.go deleted file mode 100644 index 8a4aed2039..0000000000 --- a/api/server/acme/autocert/autocert_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package autocert - -import ( - "testing" -) - -func TestAutocert(t *testing.T) { - l := NewProvider() - if _, ok := l.(*autocertProvider); !ok { - t.Error("NewProvider() didn't return an autocertProvider") - } - // TODO: Travis CI doesn't let us bind :443 - // if _, err := l.NewListener(); err != nil { - // t.Error(err.Error()) - // } -} diff --git a/api/server/acme/autocert/cache.go b/api/server/acme/autocert/cache.go deleted file mode 100644 index c898c4495f..0000000000 --- a/api/server/acme/autocert/cache.go +++ /dev/null @@ -1,37 +0,0 @@ -package autocert - -import ( - "os" - "path/filepath" - "runtime" -) - -func homeDir() string { - if runtime.GOOS == "windows" { - return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH") - } - if h := os.Getenv("HOME"); h != "" { - return h - } - return "/" -} - -func cacheDir() string { - const base = "golang-autocert" - switch runtime.GOOS { - case "darwin": - return filepath.Join(homeDir(), "Library", "Caches", base) - case "windows": - for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} { - if v := os.Getenv(ev); v != "" { - return filepath.Join(v, base) - } - } - // Worst case: - return filepath.Join(homeDir(), base) - } - if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" { - return filepath.Join(xdg, base) - } - return filepath.Join(homeDir(), ".cache", base) -} diff --git a/api/server/acme/options.go b/api/server/acme/options.go deleted file mode 100644 index 34ff674f0a..0000000000 --- a/api/server/acme/options.go +++ /dev/null @@ -1,86 +0,0 @@ -package acme - -import ( - "github.com/go-acme/lego/v4/challenge" - "go-micro.dev/v5/logger" -) - -// Option (or Options) are passed to New() to configure providers. -type Option func(o *Options) - -// Options represents various options you can present to ACME providers. -type Options struct { - // ChallengeProvider is a go-acme/lego challenge provider. Set this if you - // want to use DNS Challenges. Otherwise, tls-alpn-01 will be used - ChallengeProvider challenge.Provider - // Cache is a storage interface. Most ACME libraries have an cache, but - // there's no defined interface, so if you consume this option - // sanity check it before using. - Cache interface{} - - // Logger is the underling logging framework - Logger logger.Logger - // CA is the CA to use - CA string - // AcceptTLS must be set to true to indicate that you have read your - // provider's terms of service. - AcceptToS bool - // Issue certificates for domains on demand. Otherwise, certs will be - // retrieved / issued on start-up. - OnDemand bool -} - -// AcceptToS indicates whether you accept your CA's terms of service. -func AcceptToS(b bool) Option { - return func(o *Options) { - o.AcceptToS = b - } -} - -// CA sets the CA of an acme.Options. -func CA(CA string) Option { - return func(o *Options) { - o.CA = CA - } -} - -// ChallengeProvider sets the Challenge provider of an acme.Options -// if set, it enables the DNS challenge, otherwise tls-alpn-01 will be used. -func ChallengeProvider(p challenge.Provider) Option { - return func(o *Options) { - o.ChallengeProvider = p - } -} - -// OnDemand enables on-demand certificate issuance. Not recommended for use -// with the DNS challenge, as the first connection may be very slow. -func OnDemand(b bool) Option { - return func(o *Options) { - o.OnDemand = b - } -} - -// Cache provides a cache / storage interface to the underlying ACME library -// as there is no standard, this needs to be validated by the underlying -// implementation. -func Cache(c interface{}) Option { - return func(o *Options) { - o.Cache = c - } -} - -// Logger sets the underline logger. -func Logger(l logger.Logger) Option { - return func(o *Options) { - o.Logger = l - } -} - -// DefaultOptions uses the Let's Encrypt Production CA, with DNS Challenge disabled. -func DefaultOptions() Options { - return Options{ - AcceptToS: true, - CA: LetsEncryptProductionCA, - OnDemand: true, - } -} diff --git a/api/server/cors/cors.go b/api/server/cors/cors.go deleted file mode 100644 index 9d1e74d565..0000000000 --- a/api/server/cors/cors.go +++ /dev/null @@ -1,57 +0,0 @@ -package cors - -import ( - "net/http" -) - -type Config struct { - AllowOrigin string - AllowMethods string - AllowHeaders string - AllowCredentials bool -} - -// CombinedCORSHandler wraps a server and provides CORS headers. -func CombinedCORSHandler(h http.Handler, config *Config) http.Handler { - return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - if config != nil { - SetHeaders(w, r, config) - } - if r.Method == "OPTIONS" { - return - } - - h.ServeHTTP(w, r) - }) -} - -// SetHeaders sets the CORS headers. -func SetHeaders(w http.ResponseWriter, _ *http.Request, config *Config) { - set := func(w http.ResponseWriter, k, v string) { - if v := w.Header().Get(k); len(v) > 0 { - return - } - w.Header().Set(k, v) - } - // For forward-compatible code, default values may not be provided in the future - if config.AllowCredentials { - set(w, "Access-Control-Allow-Credentials", "true") - } else { - set(w, "Access-Control-Allow-Credentials", "false") - } - if config.AllowOrigin == "" { - set(w, "Access-Control-Allow-Origin", "*") - } else { - set(w, "Access-Control-Allow-Origin", config.AllowOrigin) - } - if config.AllowMethods == "" { - set(w, "Access-Control-Allow-Methods", "POST, PATCH, GET, OPTIONS, PUT, DELETE") - } else { - set(w, "Access-Control-Allow-Methods", config.AllowMethods) - } - if config.AllowHeaders == "" { - set(w, "Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization") - } else { - set(w, "Access-Control-Allow-Headers", config.AllowHeaders) - } -} diff --git a/api/server/http/http.go b/api/server/http/http.go deleted file mode 100644 index 4c47fa7dc5..0000000000 --- a/api/server/http/http.go +++ /dev/null @@ -1,118 +0,0 @@ -// Package http provides a http server with features; acme, cors, etc -package http - -import ( - "crypto/tls" - "net" - "net/http" - "os" - "sync" - - "github.com/gorilla/handlers" - "go-micro.dev/v5/api/server" - "go-micro.dev/v5/api/server/cors" - log "go-micro.dev/v5/logger" -) - -type httpServer struct { - opts server.Options - - mux *http.ServeMux - exit chan chan error - address string - - mtx sync.RWMutex -} - -func NewServer(address string, opts ...server.Option) server.Server { - options := server.NewOptions(opts...) - - return &httpServer{ - opts: options, - mux: http.NewServeMux(), - address: address, - exit: make(chan chan error), - } -} - -func (s *httpServer) Address() string { - s.mtx.RLock() - defer s.mtx.RUnlock() - return s.address -} - -func (s *httpServer) Init(opts ...server.Option) error { - for _, o := range opts { - o(&s.opts) - } - return nil -} - -func (s *httpServer) Handle(path string, handler http.Handler) { - // TODO: move this stuff out to one place with ServeHTTP - - // apply the wrappers, e.g. auth - for _, wrapper := range s.opts.Wrappers { - handler = wrapper(handler) - } - - // wrap with cors - if s.opts.EnableCORS { - handler = cors.CombinedCORSHandler(handler, s.opts.CORSConfig) - } - - // wrap with logger - handler = handlers.CombinedLoggingHandler(os.Stdout, handler) - - s.mux.Handle(path, handler) -} - -func (s *httpServer) Start() error { - logger := s.opts.Logger - var l net.Listener - var err error - - if s.opts.EnableACME && s.opts.ACMEProvider != nil { - // should we check the address to make sure its using :443? - l, err = s.opts.ACMEProvider.Listen(s.opts.ACMEHosts...) - } else if s.opts.EnableTLS && s.opts.TLSConfig != nil { - l, err = tls.Listen("tcp", s.address, s.opts.TLSConfig) - } else { - // otherwise plain listen - l, err = net.Listen("tcp", s.address) - } - if err != nil { - return err - } - - logger.Logf(log.InfoLevel, "HTTP API Listening on %s", l.Addr().String()) - - s.mtx.Lock() - s.address = l.Addr().String() - s.mtx.Unlock() - - go func() { - if err := http.Serve(l, s.mux); err != nil { - // temporary fix - // logger.Log(log.FatalLevel, err) - logger.Log(log.ErrorLevel, err) - } - }() - - go func() { - ch := <-s.exit - ch <- l.Close() - }() - - return nil -} - -func (s *httpServer) Stop() error { - ch := make(chan error) - s.exit <- ch - return <-ch -} - -func (s *httpServer) String() string { - return "http" -} diff --git a/api/server/http/http_test.go b/api/server/http/http_test.go deleted file mode 100644 index 2e0a594242..0000000000 --- a/api/server/http/http_test.go +++ /dev/null @@ -1,115 +0,0 @@ -package http - -import ( - "fmt" - "io" - "net/http" - "testing" - - "go-micro.dev/v5/api/server" - "go-micro.dev/v5/api/server/cors" -) - -func TestHTTPServer(t *testing.T) { - testResponse := "hello world" - - s := NewServer("localhost:0") - - s.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, testResponse) - })) - - if err := s.Start(); err != nil { - t.Fatal(err) - } - - rsp, err := http.Get(fmt.Sprintf("http://%s/", s.Address())) - if err != nil { - t.Fatal(err) - } - defer rsp.Body.Close() - - b, err := io.ReadAll(rsp.Body) - if err != nil { - t.Fatal(err) - } - - if string(b) != testResponse { - t.Fatalf("Unexpected response, got %s, expected %s", string(b), testResponse) - } - - if err := s.Stop(); err != nil { - t.Fatal(err) - } -} - -func TestCORSHTTPServer(t *testing.T) { - testResponse := "hello world" - testAllowOrigin := "*" - testAllowCredentials := true - testAllowMethods := "GET" - testAllowHeaders := "Accept, Content-Type, Content-Length" - - s := NewServer("localhost:0", - server.EnableCORS(true), - server.CORSConfig(&cors.Config{ - AllowCredentials: testAllowCredentials, - AllowOrigin: testAllowOrigin, - AllowMethods: testAllowMethods, - AllowHeaders: testAllowHeaders, - }), - ) - - s.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - fmt.Fprint(w, testResponse) - })) - - if err := s.Start(); err != nil { - t.Fatal(err) - } - - rsp, err := http.Get(fmt.Sprintf("http://%s/", s.Address())) - if err != nil { - t.Fatal(err) - } - defer rsp.Body.Close() - - b, err := io.ReadAll(rsp.Body) - if err != nil { - t.Fatal(err) - } - - if string(b) != testResponse { - t.Fatalf("Unexpected response, got %s, expected %s", string(b), testResponse) - } - - allowCredentials := rsp.Header.Get("Access-Control-Allow-Credentials") - getTestCredentialsStr := func() string { - if testAllowCredentials == true { - return "true" - } else { - return "false" - } - } - if getTestCredentialsStr() != allowCredentials { - t.Fatalf("Unexpected Access-Control-Allow-Credentials, got %s, expected %s", allowCredentials, getTestCredentialsStr()) - } - - allowOrigin := rsp.Header.Get("Access-Control-Allow-Origin") - if testAllowOrigin != allowOrigin { - t.Fatalf("Unexpected Access-Control-Allow-Origins, got %s, expected %s", allowOrigin, testAllowOrigin) - } - - allowMethods := rsp.Header.Get("Access-Control-Allow-Methods") - if testAllowMethods != allowMethods { - t.Fatalf("Unexpected Access-Control-Allow-Methods, got %s, expected %s", allowMethods, testAllowMethods) - } - allowHeaders := rsp.Header.Get("Access-Control-Allow-Headers") - if testAllowHeaders != allowHeaders { - t.Fatalf("Unexpected Access-Control-Allow-Headers, got %s, expected %s", allowHeaders, testAllowHeaders) - } - - if err := s.Stop(); err != nil { - t.Fatal(err) - } -} diff --git a/api/server/options.go b/api/server/options.go deleted file mode 100644 index 3957641642..0000000000 --- a/api/server/options.go +++ /dev/null @@ -1,101 +0,0 @@ -package server - -import ( - "crypto/tls" - "net/http" - - "go-micro.dev/v5/api/resolver" - "go-micro.dev/v5/api/server/acme" - "go-micro.dev/v5/api/server/cors" - "go-micro.dev/v5/logger" -) - -type Option func(o *Options) - -type Options struct { - ACMEProvider acme.Provider - Resolver resolver.Resolver - Logger logger.Logger - CORSConfig *cors.Config - TLSConfig *tls.Config - ACMEHosts []string - Wrappers []Wrapper - EnableACME bool - EnableCORS bool - EnableTLS bool -} - -type Wrapper func(h http.Handler) http.Handler - -func NewOptions(opts ...Option) Options { - options := Options{ - Logger: logger.DefaultLogger, - } - - for _, o := range opts { - o(&options) - } - - return options -} - -func WrapHandler(w Wrapper) Option { - return func(o *Options) { - o.Wrappers = append(o.Wrappers, w) - } -} - -func EnableCORS(b bool) Option { - return func(o *Options) { - o.EnableCORS = b - } -} - -func CORSConfig(c *cors.Config) Option { - return func(o *Options) { - o.CORSConfig = c - } -} - -func EnableACME(b bool) Option { - return func(o *Options) { - o.EnableACME = b - } -} - -func ACMEHosts(hosts ...string) Option { - return func(o *Options) { - o.ACMEHosts = hosts - } -} - -func ACMEProvider(p acme.Provider) Option { - return func(o *Options) { - o.ACMEProvider = p - } -} - -func EnableTLS(b bool) Option { - return func(o *Options) { - o.EnableTLS = b - } -} - -func TLSConfig(t *tls.Config) Option { - return func(o *Options) { - o.TLSConfig = t - } -} - -func Resolver(r resolver.Resolver) Option { - return func(o *Options) { - o.Resolver = r - } -} - -// Logger sets the underline logging framework. -func Logger(l logger.Logger) Option { - return func(o *Options) { - o.Logger = l - } -} diff --git a/api/server/server.go b/api/server/server.go deleted file mode 100644 index be6e40f179..0000000000 --- a/api/server/server.go +++ /dev/null @@ -1,15 +0,0 @@ -// Package server provides an API gateway server which handles inbound requests -package server - -import ( - "net/http" -) - -// Server serves api requests. -type Server interface { - Address() string - Init(opts ...Option) error - Handle(path string, handler http.Handler) - Start() error - Stop() error -} diff --git a/cmd/protoc-gen-micro/examples/greeter/greeter.pb.micro.go b/cmd/protoc-gen-micro/examples/greeter/greeter.pb.micro.go index 1cf67347d4..411782d7f6 100644 --- a/cmd/protoc-gen-micro/examples/greeter/greeter.pb.micro.go +++ b/cmd/protoc-gen-micro/examples/greeter/greeter.pb.micro.go @@ -12,7 +12,6 @@ import ( import ( context "context" - api "go-micro.dev/v5/api" client "go-micro.dev/v5/client" server "go-micro.dev/v5/server" ) @@ -23,31 +22,10 @@ var _ = fmt.Errorf var _ = math.Inf // Reference imports to suppress errors if they are not otherwise used. -var _ api.Endpoint var _ context.Context var _ client.Option var _ server.Option -// Api Endpoints for Greeter service - -func NewGreeterEndpoints() []*api.Endpoint { - return []*api.Endpoint{ - { - Name: "Greeter.Hello", - Path: []string{"/hello"}, - Method: []string{"POST"}, - Handler: "rpc", - }, - { - Name: "Greeter.Stream", - Path: []string{"/stream"}, - Method: []string{"GET"}, - Stream: true, - Handler: "rpc", - }, - } -} - // Client API for Greeter service type GreeterService interface { @@ -144,19 +122,6 @@ func RegisterGreeterHandler(s server.Server, hdlr GreeterHandler, opts ...server greeter } h := &greeterHandler{hdlr} - opts = append(opts, api.WithEndpoint(&api.Endpoint{ - Name: "Greeter.Hello", - Path: []string{"/hello"}, - Method: []string{"POST"}, - Handler: "rpc", - })) - opts = append(opts, api.WithEndpoint(&api.Endpoint{ - Name: "Greeter.Stream", - Path: []string{"/stream"}, - Method: []string{"GET"}, - Stream: true, - Handler: "rpc", - })) return s.Handle(s.NewHandler(&Greeter{h}, opts...)) } diff --git a/cmd/protoc-gen-micro/plugin/micro/micro.go b/cmd/protoc-gen-micro/plugin/micro/micro.go index 4dde590937..5d4447deb1 100644 --- a/cmd/protoc-gen-micro/plugin/micro/micro.go +++ b/cmd/protoc-gen-micro/plugin/micro/micro.go @@ -15,7 +15,6 @@ import ( // Paths for packages used by code generated in this file, // relative to the import_prefix of the generator.Generator. const ( - apiPkgPath = "go-micro.dev/v5/api" contextPkgPath = "context" clientPkgPath = "go-micro.dev/v5/client" serverPkgPath = "go-micro.dev/v5/server" @@ -40,7 +39,6 @@ func (g *micro) Name() string { // They may vary from the final path component of the import path // if the name is used by other packages. var ( - apiPkg string contextPkg string clientPkg string serverPkg string @@ -50,7 +48,6 @@ var ( // Init initializes the plugin. func (g *micro) Init(gen *generator.Generator) { g.gen = gen - apiPkg = generator.RegisterUniquePackageName("api", nil) contextPkg = generator.RegisterUniquePackageName("context", nil) clientPkg = generator.RegisterUniquePackageName("client", nil) serverPkg = generator.RegisterUniquePackageName("server", nil) @@ -77,7 +74,6 @@ func (g *micro) Generate(file *generator.FileDescriptor) { return } g.P("// Reference imports to suppress errors if they are not otherwise used.") - g.P("var _ ", apiPkg, ".Endpoint") g.P("var _ ", contextPkg, ".Context") g.P("var _ ", clientPkg, ".Option") g.P("var _ ", serverPkg, ".Option") @@ -94,7 +90,6 @@ func (g *micro) GenerateImports(file *generator.FileDescriptor, imports map[gene return } g.P("import (") - g.P(apiPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, apiPkgPath))) g.P(contextPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, contextPkgPath))) g.P(clientPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, clientPkgPath))) g.P(serverPkg, " ", strconv.Quote(path.Join(g.gen.ImportPrefix, serverPkgPath))) @@ -143,23 +138,6 @@ func (g *micro) generateService(file *generator.FileDescriptor, service *pb.Serv servAlias = strings.TrimSuffix(servAlias, "Service") } - g.P() - g.P("// Api Endpoints for ", servName, " service") - g.P() - - g.P("func New", servName, "Endpoints () []*", apiPkg, ".Endpoint {") - g.P("return []*", apiPkg, ".Endpoint{") - for _, method := range service.Method { - if method.Options != nil && proto.HasExtension(method.Options, options.E_Http) { - g.P("{") - g.generateEndpoint(servName, method) - g.P("},") - } - } - g.P("}") - g.P("}") - g.P() - g.P() g.P("// Client API for ", servName, " service") g.P() @@ -247,13 +225,6 @@ func (g *micro) generateService(file *generator.FileDescriptor, service *pb.Serv g.P(unexport(servName)) g.P("}") g.P("h := &", unexport(servName), "Handler{hdlr}") - for _, method := range service.Method { - if method.Options != nil && proto.HasExtension(method.Options, options.E_Http) { - g.P("opts = append(opts, ", apiPkg, ".WithEndpoint(&", apiPkg, ".Endpoint{") - g.generateEndpoint(servName, method) - g.P("}))") - } - } g.P("return s.Handle(s.NewHandler(&", servName, "{h}, opts...))") g.P("}") g.P() diff --git a/util/file/client.go b/util/file/client.go deleted file mode 100644 index 522d37184c..0000000000 --- a/util/file/client.go +++ /dev/null @@ -1,190 +0,0 @@ -package file - -import ( - "bufio" - "context" - "fmt" - "io" - "os" - - "go-micro.dev/v5/client" - "go-micro.dev/v5/logger" - proto "go-micro.dev/v5/util/file/proto" -) - -// Client is the client interface to access files. -type File interface { - Open(filename string, truncate bool) (int64, error) - Stat(filename string) (*proto.StatResponse, error) - GetBlock(sessionId, blockId int64) ([]byte, error) - ReadAt(sessionId, offset, size int64) ([]byte, error) - Read(sessionId int64, buf []byte) (int, error) - Write(sessionId, offset int64, data []byte) error - Close(sessionId int64) error - Download(filename, saveFile string) error - Upload(filename, localFile string) error - DownloadAt(filename, saveFile string, blockId int) error -} - -// NewClient returns a new Client which uses a micro Client. -func New(service string, c client.Client) File { - return &fc{proto.NewFileService(service, c)} -} - -const ( - blockSize = 512 * 1024 -) - -type fc struct { - c proto.FileService -} - -func (c *fc) Open(filename string, truncate bool) (int64, error) { - rsp, err := c.c.Open(context.TODO(), &proto.OpenRequest{ - Filename: filename, - Truncate: truncate, - }) - if err != nil { - return 0, err - } - return rsp.Id, nil -} - -func (c *fc) Stat(filename string) (*proto.StatResponse, error) { - return c.c.Stat(context.TODO(), &proto.StatRequest{Filename: filename}) -} - -func (c *fc) GetBlock(sessionId, blockId int64) ([]byte, error) { - return c.ReadAt(sessionId, blockId*blockSize, blockSize) -} - -func (c *fc) ReadAt(sessionId, offset, size int64) ([]byte, error) { - rsp, err := c.c.Read(context.TODO(), &proto.ReadRequest{Id: sessionId, Size: size, Offset: offset}) - if err != nil { - return nil, err - } - - if rsp.Eof { - err = io.EOF - } - - if rsp.Data == nil { - rsp.Data = make([]byte, size) - } - - if size != rsp.Size { - return rsp.Data[:rsp.Size], err - } - - return rsp.Data, nil -} - -func (c *fc) Read(sessionId int64, buf []byte) (int, error) { - b, err := c.ReadAt(sessionId, 0, int64(cap(buf))) - if err != nil { - return 0, err - } - copy(buf, b) - return len(b), nil -} - -func (c *fc) Write(sessionId, offset int64, data []byte) error { - _, err := c.c.Write(context.TODO(), &proto.WriteRequest{ - Id: sessionId, - Offset: offset, - Data: data}) - return err -} - -func (c *fc) Close(sessionId int64) error { - _, err := c.c.Close(context.TODO(), &proto.CloseRequest{Id: sessionId}) - return err -} - -func (c *fc) Download(filename, saveFile string) error { - return c.DownloadAt(filename, saveFile, 0) -} - -func (c *fc) Upload(filename, localFile string) error { - file, err := os.Open(localFile) - if err != nil { - return err - } - defer file.Close() - - offset := 0 - sessionId, err := c.Open(filename, true) - defer c.Close(sessionId) - if err != nil { - return err - } - reader := bufio.NewReader(file) - part := make([]byte, blockSize) - - for { - count, err := reader.Read(part) - if err != nil { - break - } - err = c.Write(sessionId, int64(offset), part) - if err != nil { - return err - } - offset += count - } - if err != nil && err != io.EOF { - return fmt.Errorf("Error reading %v: %v", localFile, err) - } - return nil -} - -func (c *fc) DownloadAt(filename, saveFile string, blockId int) error { - stat, err := c.Stat(filename) - if err != nil { - return err - } - if stat.Type == "Directory" { - return fmt.Errorf("%s is directory", filename) - } - - blocks := int(stat.Size / blockSize) - if stat.Size%blockSize != 0 { - blocks += 1 - } - - logger.Logf(logger.InfoLevel, "Download %s in %d blocks\n", filename, blocks-blockId) - - file, err := os.OpenFile(saveFile, os.O_CREATE|os.O_WRONLY, 0666) - if err != nil { - return err - } - defer file.Close() - - sessionId, err := c.Open(filename, false) - if err != nil { - return err - } - - for i := blockId; i < blocks; i++ { - buf, rerr := c.GetBlock(sessionId, int64(i)) - if rerr != nil && rerr != io.EOF { - return rerr - } - if _, werr := file.WriteAt(buf, int64(i)*blockSize); werr != nil { - return werr - } - - if i%((blocks-blockId)/100+1) == 0 { - logger.Logf(logger.InfoLevel, "Downloading %s [%d/%d] blocks", filename, i-blockId+1, blocks-blockId) - } - - if rerr == io.EOF { - break - } - } - logger.Logf(logger.InfoLevel, "Download %s completed", filename) - - c.Close(sessionId) - - return nil -} diff --git a/util/file/file.go b/util/file/file.go deleted file mode 100644 index 27bf271500..0000000000 --- a/util/file/file.go +++ /dev/null @@ -1,15 +0,0 @@ -package file - -import "os" - -// Exists returns true if the path is existing. -func Exists(path string) (bool, error) { - _, err := os.Stat(path) - if err == nil { - return true, nil - } - if os.IsNotExist(err) { - return false, nil - } - return true, err -} diff --git a/util/file/file_test.go b/util/file/file_test.go deleted file mode 100644 index 4ee3fabc4e..0000000000 --- a/util/file/file_test.go +++ /dev/null @@ -1,17 +0,0 @@ -package file - -import ( - "testing" -) - -func TestExists(t *testing.T) { - ok, err := Exists("/") - - if ok { - return - } - - if !ok || err != nil { - t.Fatalf("Test Exists fail, %s", err) - } -} diff --git a/util/file/handler.go b/util/file/handler.go deleted file mode 100644 index c22fe1af1f..0000000000 --- a/util/file/handler.go +++ /dev/null @@ -1,156 +0,0 @@ -package file - -import ( - "io" - "os" - "path/filepath" - "sync" - - "go-micro.dev/v5/errors" - log "go-micro.dev/v5/logger" - "go-micro.dev/v5/server" - proto "go-micro.dev/v5/util/file/proto" - "golang.org/x/net/context" -) - -// NewHandler is a handler that can be registered with a micro Server. -func NewHandler(readDir string) proto.FileHandler { - return &handler{ - readDir: readDir, - session: &session{ - files: make(map[int64]*os.File), - }, - logger: log.DefaultLogger, - } -} - -// RegisterHandler is a convenience method for registering a handler. -func RegisterHandler(s server.Server, readDir string) { - proto.RegisterFileHandler(s, NewHandler(readDir)) -} - -type handler struct { - logger log.Logger - session *session - readDir string -} - -func (h *handler) Open(ctx context.Context, req *proto.OpenRequest, rsp *proto.OpenResponse) error { - path := filepath.Join(h.readDir, req.Filename) - flags := os.O_CREATE | os.O_RDWR - if req.GetTruncate() { - flags = flags | os.O_TRUNC - } - file, err := os.OpenFile(path, flags, 0666) - if err != nil { - return errors.InternalServerError("go.micro.server", err.Error()) - } - - rsp.Id = h.session.Add(file) - rsp.Result = true - - h.logger.Logf(log.DebugLevel, "Open %s, sessionId=%d", req.Filename, rsp.Id) - - return nil -} - -func (h *handler) Close(ctx context.Context, req *proto.CloseRequest, rsp *proto.CloseResponse) error { - h.session.Delete(req.Id) - h.logger.Logf(log.DebugLevel, "Close sessionId=%d", req.Id) - return nil -} - -func (h *handler) Stat(ctx context.Context, req *proto.StatRequest, rsp *proto.StatResponse) error { - path := filepath.Join(h.readDir, req.Filename) - fi, err := os.Stat(path) - if os.IsNotExist(err) { - return errors.InternalServerError("go.micro.srv.file", err.Error()) - } - - if fi.IsDir() { - rsp.Type = "Directory" - } else { - rsp.Type = "File" - rsp.Size = fi.Size() - } - - rsp.LastModified = fi.ModTime().Unix() - h.logger.Logf(log.DebugLevel, "Stat %s, %#v", req.Filename, rsp) - - return nil -} - -func (h *handler) Read(ctx context.Context, req *proto.ReadRequest, rsp *proto.ReadResponse) error { - file := h.session.Get(req.Id) - if file == nil { - return errors.InternalServerError("go.micro.srv.file", "You must call open first.") - } - - rsp.Data = make([]byte, req.Size) - n, err := file.ReadAt(rsp.Data, req.Offset) - if err != nil && err != io.EOF { - return errors.InternalServerError("go.micro.srv.file", err.Error()) - } - - if err == io.EOF { - rsp.Eof = true - } - - rsp.Size = int64(n) - rsp.Data = rsp.Data[:n] - - h.logger.Logf(log.DebugLevel, "Read sessionId=%d, Offset=%d, n=%d", req.Id, req.Offset, rsp.Size) - - return nil -} - -func (h *handler) Write(ctx context.Context, req *proto.WriteRequest, rsp *proto.WriteResponse) error { - file := h.session.Get(req.Id) - if file == nil { - return errors.InternalServerError("go.micro.srv.file", "You must call open first.") - } - - if _, err := file.WriteAt(req.GetData(), req.GetOffset()); err != nil { - return err - } - - h.logger.Logf(log.DebugLevel, "Write sessionId=%d, Offset=%d, n=%d", req.Id, req.Offset) - - return nil -} - -type session struct { - files map[int64]*os.File - counter int64 - sync.Mutex -} - -func (s *session) Add(file *os.File) int64 { - s.Lock() - defer s.Unlock() - - s.counter += 1 - s.files[s.counter] = file - - return s.counter -} - -func (s *session) Get(id int64) *os.File { - s.Lock() - defer s.Unlock() - return s.files[id] -} - -func (s *session) Delete(id int64) { - s.Lock() - defer s.Unlock() - - if file, exist := s.files[id]; exist { - file.Close() - delete(s.files, id) - } -} - -func (s *session) Len() int { - return len(s.files) -} diff --git a/util/file/proto/file.pb.go b/util/file/proto/file.pb.go deleted file mode 100644 index 616525247e..0000000000 --- a/util/file/proto/file.pb.go +++ /dev/null @@ -1,626 +0,0 @@ -// Code generated by protoc-gen-go. DO NOT EDIT. -// source: file.proto - -package go_micro_server - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -type OpenRequest struct { - Filename string `protobuf:"bytes,1,opt,name=filename,proto3" json:"filename,omitempty"` - Truncate bool `protobuf:"varint,2,opt,name=truncate,proto3" json:"truncate,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *OpenRequest) Reset() { *m = OpenRequest{} } -func (m *OpenRequest) String() string { return proto.CompactTextString(m) } -func (*OpenRequest) ProtoMessage() {} -func (*OpenRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9188e3b7e55e1162, []int{0} -} - -func (m *OpenRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_OpenRequest.Unmarshal(m, b) -} -func (m *OpenRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_OpenRequest.Marshal(b, m, deterministic) -} -func (m *OpenRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_OpenRequest.Merge(m, src) -} -func (m *OpenRequest) XXX_Size() int { - return xxx_messageInfo_OpenRequest.Size(m) -} -func (m *OpenRequest) XXX_DiscardUnknown() { - xxx_messageInfo_OpenRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_OpenRequest proto.InternalMessageInfo - -func (m *OpenRequest) GetFilename() string { - if m != nil { - return m.Filename - } - return "" -} - -func (m *OpenRequest) GetTruncate() bool { - if m != nil { - return m.Truncate - } - return false -} - -type OpenResponse struct { - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Result bool `protobuf:"varint,2,opt,name=result,proto3" json:"result,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *OpenResponse) Reset() { *m = OpenResponse{} } -func (m *OpenResponse) String() string { return proto.CompactTextString(m) } -func (*OpenResponse) ProtoMessage() {} -func (*OpenResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9188e3b7e55e1162, []int{1} -} - -func (m *OpenResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_OpenResponse.Unmarshal(m, b) -} -func (m *OpenResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_OpenResponse.Marshal(b, m, deterministic) -} -func (m *OpenResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_OpenResponse.Merge(m, src) -} -func (m *OpenResponse) XXX_Size() int { - return xxx_messageInfo_OpenResponse.Size(m) -} -func (m *OpenResponse) XXX_DiscardUnknown() { - xxx_messageInfo_OpenResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_OpenResponse proto.InternalMessageInfo - -func (m *OpenResponse) GetId() int64 { - if m != nil { - return m.Id - } - return 0 -} - -func (m *OpenResponse) GetResult() bool { - if m != nil { - return m.Result - } - return false -} - -type CloseRequest struct { - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *CloseRequest) Reset() { *m = CloseRequest{} } -func (m *CloseRequest) String() string { return proto.CompactTextString(m) } -func (*CloseRequest) ProtoMessage() {} -func (*CloseRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9188e3b7e55e1162, []int{2} -} - -func (m *CloseRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_CloseRequest.Unmarshal(m, b) -} -func (m *CloseRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_CloseRequest.Marshal(b, m, deterministic) -} -func (m *CloseRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_CloseRequest.Merge(m, src) -} -func (m *CloseRequest) XXX_Size() int { - return xxx_messageInfo_CloseRequest.Size(m) -} -func (m *CloseRequest) XXX_DiscardUnknown() { - xxx_messageInfo_CloseRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_CloseRequest proto.InternalMessageInfo - -func (m *CloseRequest) GetId() int64 { - if m != nil { - return m.Id - } - return 0 -} - -type CloseResponse struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *CloseResponse) Reset() { *m = CloseResponse{} } -func (m *CloseResponse) String() string { return proto.CompactTextString(m) } -func (*CloseResponse) ProtoMessage() {} -func (*CloseResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9188e3b7e55e1162, []int{3} -} - -func (m *CloseResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_CloseResponse.Unmarshal(m, b) -} -func (m *CloseResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_CloseResponse.Marshal(b, m, deterministic) -} -func (m *CloseResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_CloseResponse.Merge(m, src) -} -func (m *CloseResponse) XXX_Size() int { - return xxx_messageInfo_CloseResponse.Size(m) -} -func (m *CloseResponse) XXX_DiscardUnknown() { - xxx_messageInfo_CloseResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_CloseResponse proto.InternalMessageInfo - -type StatRequest struct { - Filename string `protobuf:"bytes,1,opt,name=filename,proto3" json:"filename,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *StatRequest) Reset() { *m = StatRequest{} } -func (m *StatRequest) String() string { return proto.CompactTextString(m) } -func (*StatRequest) ProtoMessage() {} -func (*StatRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9188e3b7e55e1162, []int{4} -} - -func (m *StatRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_StatRequest.Unmarshal(m, b) -} -func (m *StatRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_StatRequest.Marshal(b, m, deterministic) -} -func (m *StatRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_StatRequest.Merge(m, src) -} -func (m *StatRequest) XXX_Size() int { - return xxx_messageInfo_StatRequest.Size(m) -} -func (m *StatRequest) XXX_DiscardUnknown() { - xxx_messageInfo_StatRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_StatRequest proto.InternalMessageInfo - -func (m *StatRequest) GetFilename() string { - if m != nil { - return m.Filename - } - return "" -} - -type StatResponse struct { - Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"` - Size int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` - LastModified int64 `protobuf:"varint,3,opt,name=last_modified,json=lastModified,proto3" json:"last_modified,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *StatResponse) Reset() { *m = StatResponse{} } -func (m *StatResponse) String() string { return proto.CompactTextString(m) } -func (*StatResponse) ProtoMessage() {} -func (*StatResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9188e3b7e55e1162, []int{5} -} - -func (m *StatResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_StatResponse.Unmarshal(m, b) -} -func (m *StatResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_StatResponse.Marshal(b, m, deterministic) -} -func (m *StatResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_StatResponse.Merge(m, src) -} -func (m *StatResponse) XXX_Size() int { - return xxx_messageInfo_StatResponse.Size(m) -} -func (m *StatResponse) XXX_DiscardUnknown() { - xxx_messageInfo_StatResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_StatResponse proto.InternalMessageInfo - -func (m *StatResponse) GetType() string { - if m != nil { - return m.Type - } - return "" -} - -func (m *StatResponse) GetSize() int64 { - if m != nil { - return m.Size - } - return 0 -} - -func (m *StatResponse) GetLastModified() int64 { - if m != nil { - return m.LastModified - } - return 0 -} - -type ReadRequest struct { - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Offset int64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` - Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ReadRequest) Reset() { *m = ReadRequest{} } -func (m *ReadRequest) String() string { return proto.CompactTextString(m) } -func (*ReadRequest) ProtoMessage() {} -func (*ReadRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9188e3b7e55e1162, []int{6} -} - -func (m *ReadRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ReadRequest.Unmarshal(m, b) -} -func (m *ReadRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ReadRequest.Marshal(b, m, deterministic) -} -func (m *ReadRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_ReadRequest.Merge(m, src) -} -func (m *ReadRequest) XXX_Size() int { - return xxx_messageInfo_ReadRequest.Size(m) -} -func (m *ReadRequest) XXX_DiscardUnknown() { - xxx_messageInfo_ReadRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_ReadRequest proto.InternalMessageInfo - -func (m *ReadRequest) GetId() int64 { - if m != nil { - return m.Id - } - return 0 -} - -func (m *ReadRequest) GetOffset() int64 { - if m != nil { - return m.Offset - } - return 0 -} - -func (m *ReadRequest) GetSize() int64 { - if m != nil { - return m.Size - } - return 0 -} - -type ReadResponse struct { - Size int64 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"` - Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` - Eof bool `protobuf:"varint,3,opt,name=eof,proto3" json:"eof,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *ReadResponse) Reset() { *m = ReadResponse{} } -func (m *ReadResponse) String() string { return proto.CompactTextString(m) } -func (*ReadResponse) ProtoMessage() {} -func (*ReadResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9188e3b7e55e1162, []int{7} -} - -func (m *ReadResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_ReadResponse.Unmarshal(m, b) -} -func (m *ReadResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_ReadResponse.Marshal(b, m, deterministic) -} -func (m *ReadResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_ReadResponse.Merge(m, src) -} -func (m *ReadResponse) XXX_Size() int { - return xxx_messageInfo_ReadResponse.Size(m) -} -func (m *ReadResponse) XXX_DiscardUnknown() { - xxx_messageInfo_ReadResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_ReadResponse proto.InternalMessageInfo - -func (m *ReadResponse) GetSize() int64 { - if m != nil { - return m.Size - } - return 0 -} - -func (m *ReadResponse) GetData() []byte { - if m != nil { - return m.Data - } - return nil -} - -func (m *ReadResponse) GetEof() bool { - if m != nil { - return m.Eof - } - return false -} - -type GetRequest struct { - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - BlockId int64 `protobuf:"varint,2,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetRequest) Reset() { *m = GetRequest{} } -func (m *GetRequest) String() string { return proto.CompactTextString(m) } -func (*GetRequest) ProtoMessage() {} -func (*GetRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9188e3b7e55e1162, []int{8} -} - -func (m *GetRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetRequest.Unmarshal(m, b) -} -func (m *GetRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetRequest.Marshal(b, m, deterministic) -} -func (m *GetRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetRequest.Merge(m, src) -} -func (m *GetRequest) XXX_Size() int { - return xxx_messageInfo_GetRequest.Size(m) -} -func (m *GetRequest) XXX_DiscardUnknown() { - xxx_messageInfo_GetRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_GetRequest proto.InternalMessageInfo - -func (m *GetRequest) GetId() int64 { - if m != nil { - return m.Id - } - return 0 -} - -func (m *GetRequest) GetBlockId() int64 { - if m != nil { - return m.BlockId - } - return 0 -} - -type GetResponse struct { - BlockId int64 `protobuf:"varint,1,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"` - Size int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"` - Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *GetResponse) Reset() { *m = GetResponse{} } -func (m *GetResponse) String() string { return proto.CompactTextString(m) } -func (*GetResponse) ProtoMessage() {} -func (*GetResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9188e3b7e55e1162, []int{9} -} - -func (m *GetResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_GetResponse.Unmarshal(m, b) -} -func (m *GetResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_GetResponse.Marshal(b, m, deterministic) -} -func (m *GetResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_GetResponse.Merge(m, src) -} -func (m *GetResponse) XXX_Size() int { - return xxx_messageInfo_GetResponse.Size(m) -} -func (m *GetResponse) XXX_DiscardUnknown() { - xxx_messageInfo_GetResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_GetResponse proto.InternalMessageInfo - -func (m *GetResponse) GetBlockId() int64 { - if m != nil { - return m.BlockId - } - return 0 -} - -func (m *GetResponse) GetSize() int64 { - if m != nil { - return m.Size - } - return 0 -} - -func (m *GetResponse) GetData() []byte { - if m != nil { - return m.Data - } - return nil -} - -type WriteRequest struct { - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - Offset int64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"` - Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *WriteRequest) Reset() { *m = WriteRequest{} } -func (m *WriteRequest) String() string { return proto.CompactTextString(m) } -func (*WriteRequest) ProtoMessage() {} -func (*WriteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9188e3b7e55e1162, []int{10} -} - -func (m *WriteRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_WriteRequest.Unmarshal(m, b) -} -func (m *WriteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_WriteRequest.Marshal(b, m, deterministic) -} -func (m *WriteRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_WriteRequest.Merge(m, src) -} -func (m *WriteRequest) XXX_Size() int { - return xxx_messageInfo_WriteRequest.Size(m) -} -func (m *WriteRequest) XXX_DiscardUnknown() { - xxx_messageInfo_WriteRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_WriteRequest proto.InternalMessageInfo - -func (m *WriteRequest) GetId() int64 { - if m != nil { - return m.Id - } - return 0 -} - -func (m *WriteRequest) GetOffset() int64 { - if m != nil { - return m.Offset - } - return 0 -} - -func (m *WriteRequest) GetData() []byte { - if m != nil { - return m.Data - } - return nil -} - -type WriteResponse struct { - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *WriteResponse) Reset() { *m = WriteResponse{} } -func (m *WriteResponse) String() string { return proto.CompactTextString(m) } -func (*WriteResponse) ProtoMessage() {} -func (*WriteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9188e3b7e55e1162, []int{11} -} - -func (m *WriteResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_WriteResponse.Unmarshal(m, b) -} -func (m *WriteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_WriteResponse.Marshal(b, m, deterministic) -} -func (m *WriteResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_WriteResponse.Merge(m, src) -} -func (m *WriteResponse) XXX_Size() int { - return xxx_messageInfo_WriteResponse.Size(m) -} -func (m *WriteResponse) XXX_DiscardUnknown() { - xxx_messageInfo_WriteResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_WriteResponse proto.InternalMessageInfo - -func init() { - proto.RegisterType((*OpenRequest)(nil), "go.micro.server.OpenRequest") - proto.RegisterType((*OpenResponse)(nil), "go.micro.server.OpenResponse") - proto.RegisterType((*CloseRequest)(nil), "go.micro.server.CloseRequest") - proto.RegisterType((*CloseResponse)(nil), "go.micro.server.CloseResponse") - proto.RegisterType((*StatRequest)(nil), "go.micro.server.StatRequest") - proto.RegisterType((*StatResponse)(nil), "go.micro.server.StatResponse") - proto.RegisterType((*ReadRequest)(nil), "go.micro.server.ReadRequest") - proto.RegisterType((*ReadResponse)(nil), "go.micro.server.ReadResponse") - proto.RegisterType((*GetRequest)(nil), "go.micro.server.GetRequest") - proto.RegisterType((*GetResponse)(nil), "go.micro.server.GetResponse") - proto.RegisterType((*WriteRequest)(nil), "go.micro.server.WriteRequest") - proto.RegisterType((*WriteResponse)(nil), "go.micro.server.WriteResponse") -} - -func init() { proto.RegisterFile("file.proto", fileDescriptor_9188e3b7e55e1162) } - -var fileDescriptor_9188e3b7e55e1162 = []byte{ - // 437 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xcd, 0x8e, 0xd3, 0x30, - 0x14, 0x85, 0x9b, 0x1f, 0x86, 0x70, 0x93, 0x52, 0xe4, 0x05, 0x2a, 0x15, 0x8c, 0x46, 0x66, 0x33, - 0x6c, 0xb2, 0x00, 0x09, 0x1e, 0x00, 0x15, 0x5a, 0x24, 0x04, 0x32, 0x0b, 0x16, 0x2c, 0xaa, 0xb4, - 0xbe, 0x41, 0x16, 0x69, 0x1c, 0x62, 0x17, 0x09, 0x5e, 0x9a, 0x57, 0x40, 0x76, 0xdc, 0xd6, 0x6d, - 0x13, 0x09, 0xcd, 0xce, 0xd7, 0xf7, 0xf8, 0xf3, 0xb1, 0x73, 0x1c, 0x80, 0x52, 0x54, 0x98, 0x37, - 0xad, 0xd4, 0x92, 0x4c, 0xbe, 0xcb, 0x7c, 0x2b, 0x36, 0xad, 0xcc, 0x15, 0xb6, 0xbf, 0xb0, 0xa5, - 0x73, 0x48, 0x3f, 0x35, 0x58, 0x33, 0xfc, 0xb9, 0x43, 0xa5, 0xc9, 0x0c, 0x12, 0xa3, 0xae, 0x8b, - 0x2d, 0x4e, 0x83, 0x9b, 0xe0, 0xf6, 0x01, 0x3b, 0xd4, 0xa6, 0xa7, 0xdb, 0x5d, 0xbd, 0x29, 0x34, - 0x4e, 0xc3, 0x9b, 0xe0, 0x36, 0x61, 0x87, 0x9a, 0xbe, 0x86, 0xac, 0xc3, 0xa8, 0x46, 0xd6, 0x0a, - 0xc9, 0x43, 0x08, 0x05, 0xb7, 0x84, 0x88, 0x85, 0x82, 0x93, 0xc7, 0x70, 0xd5, 0xa2, 0xda, 0x55, - 0xda, 0xad, 0x74, 0x15, 0xbd, 0x86, 0xec, 0x6d, 0x25, 0x15, 0xee, 0xf7, 0x3f, 0x5b, 0x47, 0x27, - 0x30, 0x76, 0xfd, 0x0e, 0x4c, 0x5f, 0x40, 0xfa, 0x45, 0x17, 0xfa, 0x3f, 0xfc, 0xd2, 0x6f, 0x90, - 0x75, 0x52, 0xe7, 0x89, 0x40, 0xac, 0x7f, 0x37, 0x7b, 0x9d, 0x1d, 0x9b, 0x39, 0x25, 0xfe, 0x74, - 0xe7, 0x89, 0x98, 0x1d, 0x93, 0xe7, 0x30, 0xae, 0x0a, 0xa5, 0x57, 0x5b, 0xc9, 0x45, 0x29, 0x90, - 0x4f, 0x23, 0xdb, 0xcc, 0xcc, 0xe4, 0x47, 0x37, 0x47, 0x97, 0x90, 0x32, 0x2c, 0xf8, 0x80, 0x6f, - 0x73, 0x5e, 0x59, 0x96, 0x0a, 0xb5, 0x23, 0xbb, 0xea, 0xb0, 0x5f, 0x74, 0xdc, 0x8f, 0x2e, 0x20, - 0xeb, 0x50, 0x47, 0x9f, 0x56, 0x13, 0x78, 0x9e, 0x08, 0xc4, 0xbc, 0xd0, 0x85, 0xa5, 0x65, 0xcc, - 0x8e, 0xc9, 0x23, 0x88, 0x50, 0x96, 0x16, 0x95, 0x30, 0x33, 0xa4, 0x6f, 0x00, 0xde, 0xa3, 0x1e, - 0xf2, 0xf4, 0x04, 0x92, 0x75, 0x25, 0x37, 0x3f, 0x56, 0x82, 0x3b, 0x57, 0xf7, 0x6d, 0xbd, 0xe4, - 0xf4, 0x33, 0xa4, 0x76, 0xa1, 0x73, 0xe0, 0x2b, 0x83, 0x13, 0x65, 0xef, 0x85, 0xed, 0xcd, 0x45, - 0x47, 0x73, 0xf4, 0x03, 0x64, 0x5f, 0x5b, 0xa1, 0xf1, 0x0e, 0x17, 0x74, 0xc1, 0x9a, 0xc0, 0xd8, - 0xb1, 0x3a, 0x7f, 0x2f, 0xff, 0x86, 0x10, 0xbf, 0x13, 0x15, 0x92, 0x39, 0xc4, 0x26, 0x76, 0xe4, - 0x69, 0x7e, 0x96, 0xeb, 0xdc, 0x0b, 0xf5, 0xec, 0xd9, 0x40, 0xd7, 0x45, 0x6a, 0x64, 0x30, 0x26, - 0x29, 0x3d, 0x18, 0x2f, 0x6b, 0x3d, 0x18, 0x3f, 0x5e, 0x1d, 0xc6, 0x7c, 0xc8, 0x1e, 0x8c, 0x17, - 0x95, 0x1e, 0x8c, 0xff, 0xf5, 0xe9, 0x88, 0x2c, 0xe0, 0x9e, 0x3d, 0x2e, 0xb9, 0x54, 0xfa, 0x57, - 0x3a, 0xbb, 0x1e, 0x6a, 0xfb, 0x24, 0xfb, 0x7a, 0x7a, 0x48, 0xfe, 0xab, 0xeb, 0x21, 0x9d, 0x3e, - 0xba, 0xd1, 0xfa, 0xca, 0xfe, 0x3e, 0x5e, 0xfd, 0x0b, 0x00, 0x00, 0xff, 0xff, 0x5c, 0xf0, 0x71, - 0xa2, 0x4c, 0x04, 0x00, 0x00, -} diff --git a/util/file/proto/file.pb.micro.go b/util/file/proto/file.pb.micro.go deleted file mode 100644 index 2b243c9430..0000000000 --- a/util/file/proto/file.pb.micro.go +++ /dev/null @@ -1,161 +0,0 @@ -// Code generated by protoc-gen-micro. DO NOT EDIT. -// source: file.proto - -package go_micro_server - -import ( - fmt "fmt" - proto "github.com/golang/protobuf/proto" - math "math" -) - -import ( - context "context" - api "go-micro.dev/v5/api" - client "go-micro.dev/v5/client" - server "go-micro.dev/v5/server" -) - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package - -// Reference imports to suppress errors if they are not otherwise used. -var _ api.Endpoint -var _ context.Context -var _ client.Option -var _ server.Option - -// Api Endpoints for File service - -func NewFileEndpoints() []*api.Endpoint { - return []*api.Endpoint{} -} - -// Client API for File service - -type FileService interface { - Open(ctx context.Context, in *OpenRequest, opts ...client.CallOption) (*OpenResponse, error) - Stat(ctx context.Context, in *StatRequest, opts ...client.CallOption) (*StatResponse, error) - Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error) - Write(ctx context.Context, in *WriteRequest, opts ...client.CallOption) (*WriteResponse, error) - Close(ctx context.Context, in *CloseRequest, opts ...client.CallOption) (*CloseResponse, error) -} - -type fileService struct { - c client.Client - name string -} - -func NewFileService(name string, c client.Client) FileService { - return &fileService{ - c: c, - name: name, - } -} - -func (c *fileService) Open(ctx context.Context, in *OpenRequest, opts ...client.CallOption) (*OpenResponse, error) { - req := c.c.NewRequest(c.name, "File.Open", in) - out := new(OpenResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *fileService) Stat(ctx context.Context, in *StatRequest, opts ...client.CallOption) (*StatResponse, error) { - req := c.c.NewRequest(c.name, "File.Stat", in) - out := new(StatResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *fileService) Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error) { - req := c.c.NewRequest(c.name, "File.Read", in) - out := new(ReadResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *fileService) Write(ctx context.Context, in *WriteRequest, opts ...client.CallOption) (*WriteResponse, error) { - req := c.c.NewRequest(c.name, "File.Write", in) - out := new(WriteResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *fileService) Close(ctx context.Context, in *CloseRequest, opts ...client.CallOption) (*CloseResponse, error) { - req := c.c.NewRequest(c.name, "File.Close", in) - out := new(CloseResponse) - err := c.c.Call(ctx, req, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -// Server API for File service - -type FileHandler interface { - Open(context.Context, *OpenRequest, *OpenResponse) error - Stat(context.Context, *StatRequest, *StatResponse) error - Read(context.Context, *ReadRequest, *ReadResponse) error - Write(context.Context, *WriteRequest, *WriteResponse) error - Close(context.Context, *CloseRequest, *CloseResponse) error -} - -func RegisterFileHandler(s server.Server, hdlr FileHandler, opts ...server.HandlerOption) error { - type file interface { - Open(ctx context.Context, in *OpenRequest, out *OpenResponse) error - Stat(ctx context.Context, in *StatRequest, out *StatResponse) error - Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error - Write(ctx context.Context, in *WriteRequest, out *WriteResponse) error - Close(ctx context.Context, in *CloseRequest, out *CloseResponse) error - } - type File struct { - file - } - h := &fileHandler{hdlr} - return s.Handle(s.NewHandler(&File{h}, opts...)) -} - -type fileHandler struct { - FileHandler -} - -func (h *fileHandler) Open(ctx context.Context, in *OpenRequest, out *OpenResponse) error { - return h.FileHandler.Open(ctx, in, out) -} - -func (h *fileHandler) Stat(ctx context.Context, in *StatRequest, out *StatResponse) error { - return h.FileHandler.Stat(ctx, in, out) -} - -func (h *fileHandler) Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error { - return h.FileHandler.Read(ctx, in, out) -} - -func (h *fileHandler) Write(ctx context.Context, in *WriteRequest, out *WriteResponse) error { - return h.FileHandler.Write(ctx, in, out) -} - -func (h *fileHandler) Close(ctx context.Context, in *CloseRequest, out *CloseResponse) error { - return h.FileHandler.Close(ctx, in, out) -} diff --git a/util/file/proto/file.proto b/util/file/proto/file.proto deleted file mode 100644 index 01395f2ce3..0000000000 --- a/util/file/proto/file.proto +++ /dev/null @@ -1,69 +0,0 @@ -syntax = "proto3"; - -package go.micro.server; - -service File { - rpc Open(OpenRequest) returns(OpenResponse) {}; - rpc Stat(StatRequest) returns(StatResponse) {}; - rpc Read(ReadRequest) returns(ReadResponse) {}; - rpc Write(WriteRequest) returns(WriteResponse) {}; - rpc Close(CloseRequest) returns(CloseResponse) {}; -} - -message OpenRequest { - string filename = 1; - bool truncate = 2; -} - -message OpenResponse { - int64 id = 1; - bool result = 2; -} - -message CloseRequest { - int64 id = 1; -} - -message CloseResponse { -} - -message StatRequest { - string filename = 1; -} - -message StatResponse { - string type = 1; - int64 size = 2; - int64 last_modified = 3; -} - -message ReadRequest { - int64 id = 1; - int64 offset = 2; - int64 size = 3; -} - -message ReadResponse { - int64 size = 1; - bytes data = 2; - bool eof = 3; -} - -message GetRequest { - int64 id = 1; - int64 block_id = 2; -} - -message GetResponse { - int64 block_id = 1; - int64 size = 2; - bytes data = 3; -} - -message WriteRequest { - int64 id = 1; - int64 offset = 2; - bytes data = 3; -} - -message WriteResponse {} \ No newline at end of file