mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-06 04:09:40 -06:00
switch to go vendoring
This commit is contained in:
191
vendor/github.com/go-micro/plugins/v4/client/grpc/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/client/grpc/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
25
vendor/github.com/go-micro/plugins/v4/client/grpc/README.md
generated
vendored
Normal file
25
vendor/github.com/go-micro/plugins/v4/client/grpc/README.md
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# GRPC Client
|
||||
|
||||
The grpc client is a [micro.Client](https://godoc.org/github.com/micro/go-micro/client#Client) compatible client.
|
||||
|
||||
## Overview
|
||||
|
||||
The client makes use of the [google.golang.org/grpc](google.golang.org/grpc) framework for the underlying communication mechanism.
|
||||
|
||||
## Usage
|
||||
|
||||
Specify the client to your micro service
|
||||
|
||||
```go
|
||||
import (
|
||||
"github.com/micro/go-micro"
|
||||
"github.com/micro/go-plugins/client/grpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
service := micro.NewService(
|
||||
micro.Name("greeter"),
|
||||
micro.Client(grpc.NewClient()),
|
||||
)
|
||||
}
|
||||
```
|
||||
209
vendor/github.com/go-micro/plugins/v4/client/grpc/codec.go
generated
vendored
Normal file
209
vendor/github.com/go-micro/plugins/v4/client/grpc/codec.go
generated
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
b "bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"go-micro.dev/v4/codec"
|
||||
"go-micro.dev/v4/codec/bytes"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/runtime/protoiface"
|
||||
"google.golang.org/protobuf/runtime/protoimpl"
|
||||
)
|
||||
|
||||
type jsonCodec struct{}
|
||||
type protoCodec struct{}
|
||||
type bytesCodec struct{}
|
||||
type wrapCodec struct{ encoding.Codec }
|
||||
|
||||
var useNumber bool
|
||||
|
||||
var (
|
||||
defaultGRPCCodecs = map[string]encoding.Codec{
|
||||
"application/json": jsonCodec{},
|
||||
"application/proto": protoCodec{},
|
||||
"application/protobuf": protoCodec{},
|
||||
"application/octet-stream": protoCodec{},
|
||||
"application/grpc": protoCodec{},
|
||||
"application/grpc+json": jsonCodec{},
|
||||
"application/grpc+proto": protoCodec{},
|
||||
"application/grpc+bytes": bytesCodec{},
|
||||
}
|
||||
)
|
||||
|
||||
// UseNumber fix unmarshal Number(8234567890123456789) to interface(8.234567890123457e+18).
|
||||
func UseNumber() {
|
||||
useNumber = true
|
||||
}
|
||||
|
||||
func (w wrapCodec) String() string {
|
||||
return w.Codec.Name()
|
||||
}
|
||||
|
||||
func (w wrapCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
b, ok := v.(*bytes.Frame)
|
||||
if ok {
|
||||
return b.Data, nil
|
||||
}
|
||||
return w.Codec.Marshal(v)
|
||||
}
|
||||
|
||||
func (w wrapCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
b, ok := v.(*bytes.Frame)
|
||||
if ok {
|
||||
b.Data = data
|
||||
return nil
|
||||
}
|
||||
return w.Codec.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
func (protoCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
switch m := v.(type) {
|
||||
case *bytes.Frame:
|
||||
return m.Data, nil
|
||||
case proto.Message:
|
||||
return proto.Marshal(m)
|
||||
case protoiface.MessageV1:
|
||||
// #2333 compatible with etcd legacy proto.Message
|
||||
m2 := protoimpl.X.ProtoMessageV2Of(m)
|
||||
return proto.Marshal(m2)
|
||||
}
|
||||
return nil, fmt.Errorf("failed to marshal: %v is not type of *bytes.Frame or proto.Message", v)
|
||||
}
|
||||
|
||||
func (protoCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
switch m := v.(type) {
|
||||
case proto.Message:
|
||||
return proto.Unmarshal(data, m)
|
||||
case protoiface.MessageV1:
|
||||
// #2333 compatible with etcd legacy proto.Message
|
||||
m2 := protoimpl.X.ProtoMessageV2Of(m)
|
||||
return proto.Unmarshal(data, m2)
|
||||
}
|
||||
return fmt.Errorf("failed to unmarshal: %v is not type of proto.Message", v)
|
||||
}
|
||||
|
||||
func (protoCodec) Name() string {
|
||||
return "proto"
|
||||
}
|
||||
|
||||
func (bytesCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
b, ok := v.(*[]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to marshal: %v is not type of *[]byte", v)
|
||||
}
|
||||
return *b, nil
|
||||
}
|
||||
|
||||
func (bytesCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
b, ok := v.(*[]byte)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to unmarshal: %v is not type of *[]byte", v)
|
||||
}
|
||||
*b = data
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bytesCodec) Name() string {
|
||||
return "bytes"
|
||||
}
|
||||
|
||||
func (jsonCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
if b, ok := v.(*bytes.Frame); ok {
|
||||
return b.Data, nil
|
||||
}
|
||||
|
||||
if pb, ok := v.(proto.Message); ok {
|
||||
bytes, err := protojson.Marshal(pb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bytes, nil
|
||||
}
|
||||
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
func (jsonCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
if b, ok := v.(*bytes.Frame); ok {
|
||||
b.Data = data
|
||||
return nil
|
||||
}
|
||||
if pb, ok := v.(proto.Message); ok {
|
||||
return protojson.Unmarshal(data, pb)
|
||||
}
|
||||
|
||||
dec := json.NewDecoder(b.NewReader(data))
|
||||
if useNumber {
|
||||
dec.UseNumber()
|
||||
}
|
||||
return dec.Decode(v)
|
||||
}
|
||||
|
||||
func (jsonCodec) Name() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
type grpcCodec struct {
|
||||
// headers
|
||||
id string
|
||||
target string
|
||||
method string
|
||||
endpoint string
|
||||
|
||||
s grpc.ClientStream
|
||||
c encoding.Codec
|
||||
}
|
||||
|
||||
func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error {
|
||||
md, err := g.s.Header()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if m == nil {
|
||||
m = new(codec.Message)
|
||||
}
|
||||
if m.Header == nil {
|
||||
m.Header = make(map[string]string, len(md))
|
||||
}
|
||||
for k, v := range md {
|
||||
m.Header[k] = strings.Join(v, ",")
|
||||
}
|
||||
m.Id = g.id
|
||||
m.Target = g.target
|
||||
m.Method = g.method
|
||||
m.Endpoint = g.endpoint
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcCodec) ReadBody(v interface{}) error {
|
||||
if f, ok := v.(*bytes.Frame); ok {
|
||||
return g.s.RecvMsg(f)
|
||||
}
|
||||
return g.s.RecvMsg(v)
|
||||
}
|
||||
|
||||
func (g *grpcCodec) Write(m *codec.Message, v interface{}) error {
|
||||
// if we don't have a body
|
||||
if v != nil {
|
||||
return g.s.SendMsg(v)
|
||||
}
|
||||
// write the body using the framing codec
|
||||
return g.s.SendMsg(&bytes.Frame{Data: m.Body})
|
||||
}
|
||||
|
||||
func (g *grpcCodec) Close() error {
|
||||
return g.s.CloseSend()
|
||||
}
|
||||
|
||||
func (g *grpcCodec) String() string {
|
||||
return g.c.Name()
|
||||
}
|
||||
69
vendor/github.com/go-micro/plugins/v4/client/grpc/error.go
generated
vendored
Normal file
69
vendor/github.com/go-micro/plugins/v4/client/grpc/error.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"go-micro.dev/v4/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func microError(err error) error {
|
||||
// no error
|
||||
switch err {
|
||||
case nil:
|
||||
return nil
|
||||
}
|
||||
|
||||
if verr, ok := err.(*errors.Error); ok {
|
||||
return verr
|
||||
}
|
||||
|
||||
// grpc error
|
||||
s, ok := status.FromError(err)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
// return first error from details
|
||||
if details := s.Details(); len(details) > 0 {
|
||||
return microError(details[0].(error))
|
||||
}
|
||||
|
||||
// try to decode micro *errors.Error
|
||||
if e := errors.Parse(s.Message()); e.Code > 0 {
|
||||
return e // actually a micro error
|
||||
}
|
||||
|
||||
// fallback
|
||||
return errors.New("go.micro.client", s.Message(), microStatusFromGrpcCode(s.Code()))
|
||||
}
|
||||
|
||||
func microStatusFromGrpcCode(code codes.Code) int32 {
|
||||
switch code {
|
||||
case codes.OK:
|
||||
return http.StatusOK
|
||||
case codes.InvalidArgument:
|
||||
return http.StatusBadRequest
|
||||
case codes.DeadlineExceeded:
|
||||
return http.StatusRequestTimeout
|
||||
case codes.NotFound:
|
||||
return http.StatusNotFound
|
||||
case codes.AlreadyExists:
|
||||
return http.StatusConflict
|
||||
case codes.PermissionDenied:
|
||||
return http.StatusForbidden
|
||||
case codes.Unauthenticated:
|
||||
return http.StatusUnauthorized
|
||||
case codes.FailedPrecondition:
|
||||
return http.StatusPreconditionFailed
|
||||
case codes.Unimplemented:
|
||||
return http.StatusNotImplemented
|
||||
case codes.Internal:
|
||||
return http.StatusInternalServerError
|
||||
case codes.Unavailable:
|
||||
return http.StatusServiceUnavailable
|
||||
}
|
||||
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
704
vendor/github.com/go-micro/plugins/v4/client/grpc/grpc.go
generated
vendored
Normal file
704
vendor/github.com/go-micro/plugins/v4/client/grpc/grpc.go
generated
vendored
Normal file
@@ -0,0 +1,704 @@
|
||||
// Package grpc provides a gRPC client
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"go-micro.dev/v4/broker"
|
||||
"go-micro.dev/v4/client"
|
||||
raw "go-micro.dev/v4/codec/bytes"
|
||||
"go-micro.dev/v4/errors"
|
||||
"go-micro.dev/v4/metadata"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/selector"
|
||||
"go-micro.dev/v4/util/cmd"
|
||||
pnet "go-micro.dev/v4/util/net"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/encoding"
|
||||
gmetadata "google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
type grpcClient struct {
|
||||
opts client.Options
|
||||
pool *pool
|
||||
once atomic.Value
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmd.DefaultClients["grpc"] = NewClient
|
||||
|
||||
encoding.RegisterCodec(wrapCodec{jsonCodec{}})
|
||||
encoding.RegisterCodec(wrapCodec{protoCodec{}})
|
||||
encoding.RegisterCodec(wrapCodec{bytesCodec{}})
|
||||
}
|
||||
|
||||
// secure returns the dial option for whether its a secure or insecure connection.
|
||||
func (g *grpcClient) secure(addr string) grpc.DialOption {
|
||||
// first we check if theres'a tls config
|
||||
if g.opts.Context != nil {
|
||||
if v := g.opts.Context.Value(tlsAuth{}); v != nil {
|
||||
tls := v.(*tls.Config)
|
||||
creds := credentials.NewTLS(tls)
|
||||
// return tls config if it exists
|
||||
return grpc.WithTransportCredentials(creds)
|
||||
}
|
||||
}
|
||||
|
||||
// default config
|
||||
tlsConfig := &tls.Config{}
|
||||
defaultCreds := grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))
|
||||
|
||||
// check if the address is prepended with https
|
||||
if strings.HasPrefix(addr, "https://") {
|
||||
return defaultCreds
|
||||
}
|
||||
|
||||
// if no port is specified or port is 443 default to tls
|
||||
_, port, err := net.SplitHostPort(addr)
|
||||
// assuming with no port its going to be secured
|
||||
if port == "443" {
|
||||
return defaultCreds
|
||||
} else if err != nil && strings.Contains(err.Error(), "missing port in address") {
|
||||
return defaultCreds
|
||||
}
|
||||
|
||||
// other fallback to insecure
|
||||
return grpc.WithInsecure()
|
||||
}
|
||||
|
||||
func (g *grpcClient) next(request client.Request, opts client.CallOptions) (selector.Next, error) {
|
||||
service, address, _ := pnet.Proxy(request.Service(), opts.Address)
|
||||
|
||||
// return remote address
|
||||
if len(address) > 0 {
|
||||
return func() (*registry.Node, error) {
|
||||
return ®istry.Node{
|
||||
Address: address[0],
|
||||
}, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
// get next nodes from the selector
|
||||
next, err := g.opts.Selector.Select(service, opts.SelectOptions...)
|
||||
if err != nil {
|
||||
if err == selector.ErrNotFound {
|
||||
return nil, errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error())
|
||||
}
|
||||
return nil, errors.InternalServerError("go.micro.client", "error selecting %s node: %s", service, err.Error())
|
||||
}
|
||||
|
||||
return next, nil
|
||||
}
|
||||
|
||||
func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error {
|
||||
var header map[string]string
|
||||
|
||||
address := node.Address
|
||||
|
||||
if md, ok := metadata.FromContext(ctx); ok {
|
||||
header = make(map[string]string, len(md))
|
||||
for k, v := range md {
|
||||
header[strings.ToLower(k)] = v
|
||||
}
|
||||
} else {
|
||||
header = make(map[string]string)
|
||||
}
|
||||
|
||||
// set timeout in nanoseconds
|
||||
header["timeout"] = fmt.Sprintf("%d", opts.RequestTimeout)
|
||||
// set the content type for the request
|
||||
header["x-content-type"] = req.ContentType()
|
||||
|
||||
md := gmetadata.New(header)
|
||||
ctx = gmetadata.NewOutgoingContext(ctx, md)
|
||||
|
||||
cf, err := g.newGRPCCodec(req.ContentType())
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.client", err.Error())
|
||||
}
|
||||
|
||||
maxRecvMsgSize := g.maxRecvMsgSizeValue()
|
||||
maxSendMsgSize := g.maxSendMsgSizeValue()
|
||||
|
||||
var grr error
|
||||
|
||||
var dialCtx context.Context
|
||||
var cancel context.CancelFunc
|
||||
if opts.DialTimeout > 0 {
|
||||
dialCtx, cancel = context.WithTimeout(ctx, opts.DialTimeout)
|
||||
} else {
|
||||
dialCtx, cancel = context.WithCancel(ctx)
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
grpcDialOptions := []grpc.DialOption{
|
||||
g.secure(address),
|
||||
grpc.WithDefaultCallOptions(
|
||||
grpc.MaxCallRecvMsgSize(maxRecvMsgSize),
|
||||
grpc.MaxCallSendMsgSize(maxSendMsgSize),
|
||||
),
|
||||
}
|
||||
|
||||
if opts := g.getGrpcDialOptions(); opts != nil {
|
||||
grpcDialOptions = append(grpcDialOptions, opts...)
|
||||
}
|
||||
|
||||
cc, err := g.pool.getConn(dialCtx, address, grpcDialOptions...)
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
|
||||
}
|
||||
defer func() {
|
||||
// defer execution of release
|
||||
g.pool.release(address, cc, grr)
|
||||
}()
|
||||
|
||||
ch := make(chan error, 1)
|
||||
|
||||
go func() {
|
||||
grpcCallOptions := []grpc.CallOption{
|
||||
grpc.ForceCodec(cf),
|
||||
grpc.CallContentSubtype(cf.Name())}
|
||||
if opts := callOpts(opts); opts != nil {
|
||||
grpcCallOptions = append(grpcCallOptions, opts...)
|
||||
}
|
||||
err := cc.Invoke(ctx, methodToGRPC(req.Service(), req.Endpoint()), req.Body(), rsp, grpcCallOptions...)
|
||||
ch <- microError(err)
|
||||
}()
|
||||
|
||||
select {
|
||||
case err := <-ch:
|
||||
grr = err
|
||||
case <-ctx.Done():
|
||||
grr = errors.Timeout("go.micro.client", "%v", ctx.Err())
|
||||
}
|
||||
|
||||
return grr
|
||||
}
|
||||
|
||||
func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error {
|
||||
var header map[string]string
|
||||
|
||||
address := node.Address
|
||||
|
||||
if md, ok := metadata.FromContext(ctx); ok {
|
||||
header = make(map[string]string, len(md))
|
||||
for k, v := range md {
|
||||
header[k] = v
|
||||
}
|
||||
} else {
|
||||
header = make(map[string]string)
|
||||
}
|
||||
|
||||
// set timeout in nanoseconds
|
||||
if opts.StreamTimeout > time.Duration(0) {
|
||||
header["timeout"] = fmt.Sprintf("%d", opts.StreamTimeout)
|
||||
}
|
||||
// set the content type for the request
|
||||
header["x-content-type"] = req.ContentType()
|
||||
|
||||
md := gmetadata.New(header)
|
||||
ctx = gmetadata.NewOutgoingContext(ctx, md)
|
||||
|
||||
cf, err := g.newGRPCCodec(req.ContentType())
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.client", err.Error())
|
||||
}
|
||||
|
||||
var dialCtx context.Context
|
||||
var cancel context.CancelFunc
|
||||
if opts.DialTimeout > 0 {
|
||||
dialCtx, cancel = context.WithTimeout(ctx, opts.DialTimeout)
|
||||
} else {
|
||||
dialCtx, cancel = context.WithCancel(ctx)
|
||||
}
|
||||
defer cancel()
|
||||
|
||||
wc := wrapCodec{cf}
|
||||
|
||||
grpcDialOptions := []grpc.DialOption{
|
||||
g.secure(address),
|
||||
}
|
||||
|
||||
if opts := g.getGrpcDialOptions(); opts != nil {
|
||||
grpcDialOptions = append(grpcDialOptions, opts...)
|
||||
}
|
||||
|
||||
cc, err := g.pool.getConn(dialCtx, address, grpcDialOptions...)
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
|
||||
}
|
||||
|
||||
desc := &grpc.StreamDesc{
|
||||
StreamName: req.Service() + req.Endpoint(),
|
||||
ClientStreams: true,
|
||||
ServerStreams: true,
|
||||
}
|
||||
|
||||
grpcCallOptions := []grpc.CallOption{
|
||||
grpc.ForceCodec(wc),
|
||||
grpc.CallContentSubtype(cf.Name()),
|
||||
}
|
||||
if opts := callOpts(opts); opts != nil {
|
||||
grpcCallOptions = append(grpcCallOptions, opts...)
|
||||
}
|
||||
|
||||
// create a new canceling context
|
||||
newCtx, cancel := context.WithCancel(ctx)
|
||||
|
||||
st, err := cc.NewStream(newCtx, desc, methodToGRPC(req.Service(), req.Endpoint()), grpcCallOptions...)
|
||||
if err != nil {
|
||||
// we need to cleanup as we dialed and created a context
|
||||
// cancel the context
|
||||
cancel()
|
||||
// close the connection
|
||||
cc.Close()
|
||||
// now return the error
|
||||
return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err))
|
||||
}
|
||||
|
||||
codec := &grpcCodec{
|
||||
s: st,
|
||||
c: wc,
|
||||
}
|
||||
|
||||
// set request codec
|
||||
if r, ok := req.(*grpcRequest); ok {
|
||||
r.codec = codec
|
||||
}
|
||||
|
||||
// setup the stream response
|
||||
stream := &grpcStream{
|
||||
context: ctx,
|
||||
request: req,
|
||||
response: &response{
|
||||
conn: cc.ClientConn,
|
||||
stream: st,
|
||||
codec: cf,
|
||||
gcodec: codec,
|
||||
},
|
||||
stream: st,
|
||||
cancel: cancel,
|
||||
release: func(err error) {
|
||||
g.pool.release(address, cc, err)
|
||||
},
|
||||
}
|
||||
|
||||
// set the stream as the response
|
||||
val := reflect.ValueOf(rsp).Elem()
|
||||
val.Set(reflect.ValueOf(stream).Elem())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcClient) poolMaxStreams() int {
|
||||
if g.opts.Context == nil {
|
||||
return DefaultPoolMaxStreams
|
||||
}
|
||||
v := g.opts.Context.Value(poolMaxStreams{})
|
||||
if v == nil {
|
||||
return DefaultPoolMaxStreams
|
||||
}
|
||||
return v.(int)
|
||||
}
|
||||
|
||||
func (g *grpcClient) poolMaxIdle() int {
|
||||
if g.opts.Context == nil {
|
||||
return DefaultPoolMaxIdle
|
||||
}
|
||||
v := g.opts.Context.Value(poolMaxIdle{})
|
||||
if v == nil {
|
||||
return DefaultPoolMaxIdle
|
||||
}
|
||||
return v.(int)
|
||||
}
|
||||
|
||||
func (g *grpcClient) maxRecvMsgSizeValue() int {
|
||||
if g.opts.Context == nil {
|
||||
return DefaultMaxRecvMsgSize
|
||||
}
|
||||
v := g.opts.Context.Value(maxRecvMsgSizeKey{})
|
||||
if v == nil {
|
||||
return DefaultMaxRecvMsgSize
|
||||
}
|
||||
return v.(int)
|
||||
}
|
||||
|
||||
func (g *grpcClient) maxSendMsgSizeValue() int {
|
||||
if g.opts.Context == nil {
|
||||
return DefaultMaxSendMsgSize
|
||||
}
|
||||
v := g.opts.Context.Value(maxSendMsgSizeKey{})
|
||||
if v == nil {
|
||||
return DefaultMaxSendMsgSize
|
||||
}
|
||||
return v.(int)
|
||||
}
|
||||
|
||||
func (g *grpcClient) newGRPCCodec(contentType string) (encoding.Codec, error) {
|
||||
codecs := make(map[string]encoding.Codec)
|
||||
if g.opts.Context != nil {
|
||||
if v := g.opts.Context.Value(codecsKey{}); v != nil {
|
||||
codecs = v.(map[string]encoding.Codec)
|
||||
}
|
||||
}
|
||||
if c, ok := codecs[contentType]; ok {
|
||||
return wrapCodec{c}, nil
|
||||
}
|
||||
if c, ok := defaultGRPCCodecs[contentType]; ok {
|
||||
return wrapCodec{c}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("unsupported Content-Type: %s", contentType)
|
||||
}
|
||||
|
||||
func (g *grpcClient) Init(opts ...client.Option) error {
|
||||
size := g.opts.PoolSize
|
||||
ttl := g.opts.PoolTTL
|
||||
|
||||
for _, o := range opts {
|
||||
o(&g.opts)
|
||||
}
|
||||
|
||||
// update pool configuration if the options changed
|
||||
if size != g.opts.PoolSize || ttl != g.opts.PoolTTL {
|
||||
g.pool.Lock()
|
||||
g.pool.size = g.opts.PoolSize
|
||||
g.pool.ttl = int64(g.opts.PoolTTL.Seconds())
|
||||
g.pool.Unlock()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcClient) Options() client.Options {
|
||||
return g.opts
|
||||
}
|
||||
|
||||
func (g *grpcClient) NewMessage(topic string, msg interface{}, opts ...client.MessageOption) client.Message {
|
||||
return newGRPCEvent(topic, msg, g.opts.ContentType, opts...)
|
||||
}
|
||||
|
||||
func (g *grpcClient) NewRequest(service, method string, req interface{}, reqOpts ...client.RequestOption) client.Request {
|
||||
return newGRPCRequest(service, method, req, g.opts.ContentType, reqOpts...)
|
||||
}
|
||||
|
||||
func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
||||
if req == nil {
|
||||
return errors.InternalServerError("go.micro.client", "req is nil")
|
||||
} else if rsp == nil {
|
||||
return errors.InternalServerError("go.micro.client", "rsp is nil")
|
||||
}
|
||||
// make a copy of call opts
|
||||
callOpts := g.opts.CallOptions
|
||||
for _, opt := range opts {
|
||||
opt(&callOpts)
|
||||
}
|
||||
|
||||
next, err := g.next(req, callOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if we already have a deadline
|
||||
d, ok := ctx.Deadline()
|
||||
if !ok {
|
||||
// no deadline so we create a new one
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithTimeout(ctx, callOpts.RequestTimeout)
|
||||
defer cancel()
|
||||
} else {
|
||||
// got a deadline so no need to setup context
|
||||
// but we need to set the timeout we pass along
|
||||
opt := client.WithRequestTimeout(time.Until(d))
|
||||
opt(&callOpts)
|
||||
}
|
||||
|
||||
// should we noop right here?
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return errors.New("go.micro.client", fmt.Sprintf("%v", ctx.Err()), 408)
|
||||
default:
|
||||
}
|
||||
|
||||
// make copy of call method
|
||||
gcall := g.call
|
||||
|
||||
// wrap the call in reverse
|
||||
for i := len(callOpts.CallWrappers); i > 0; i-- {
|
||||
gcall = callOpts.CallWrappers[i-1](gcall)
|
||||
}
|
||||
|
||||
// return errors.New("go.micro.client", "request timeout", 408)
|
||||
call := func(i int) error {
|
||||
// call backoff first. Someone may want an initial start delay
|
||||
t, err := callOpts.Backoff(ctx, req, i)
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.client", err.Error())
|
||||
}
|
||||
|
||||
// only sleep if greater than 0
|
||||
if t.Seconds() > 0 {
|
||||
time.Sleep(t)
|
||||
}
|
||||
|
||||
// select next node
|
||||
node, err := next()
|
||||
service := req.Service()
|
||||
if err != nil {
|
||||
if err == selector.ErrNotFound {
|
||||
return errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error())
|
||||
}
|
||||
return errors.InternalServerError("go.micro.client", "error selecting %s node: %s", service, err.Error())
|
||||
}
|
||||
|
||||
// make the call
|
||||
err = gcall(ctx, node, req, rsp, callOpts)
|
||||
g.opts.Selector.Mark(service, node, err)
|
||||
if verr, ok := err.(*errors.Error); ok {
|
||||
return verr
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
ch := make(chan error, callOpts.Retries+1)
|
||||
var gerr error
|
||||
|
||||
for i := 0; i <= callOpts.Retries; i++ {
|
||||
go func(i int) {
|
||||
ch <- call(i)
|
||||
}(i)
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return errors.New("go.micro.client", fmt.Sprintf("%v", ctx.Err()), 408)
|
||||
case err := <-ch:
|
||||
// if the call succeeded lets bail early
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
retry, rerr := callOpts.Retry(ctx, req, i, err)
|
||||
if rerr != nil {
|
||||
return rerr
|
||||
}
|
||||
|
||||
if !retry {
|
||||
return err
|
||||
}
|
||||
|
||||
gerr = err
|
||||
}
|
||||
}
|
||||
|
||||
return gerr
|
||||
}
|
||||
|
||||
func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
|
||||
// make a copy of call opts
|
||||
callOpts := g.opts.CallOptions
|
||||
for _, opt := range opts {
|
||||
opt(&callOpts)
|
||||
}
|
||||
|
||||
next, err := g.next(req, callOpts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// #200 - streams shouldn't have a request timeout set on the context
|
||||
|
||||
// should we noop right here?
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, errors.New("go.micro.client", fmt.Sprintf("%v", ctx.Err()), 408)
|
||||
default:
|
||||
}
|
||||
|
||||
// make a copy of stream
|
||||
gstream := g.stream
|
||||
|
||||
// wrap the call in reverse
|
||||
for i := len(callOpts.CallWrappers); i > 0; i-- {
|
||||
gstream = callOpts.CallWrappers[i-1](gstream)
|
||||
}
|
||||
|
||||
call := func(i int) (client.Stream, error) {
|
||||
// call backoff first. Someone may want an initial start delay
|
||||
t, err := callOpts.Backoff(ctx, req, i)
|
||||
if err != nil {
|
||||
return nil, errors.InternalServerError("go.micro.client", err.Error())
|
||||
}
|
||||
|
||||
// only sleep if greater than 0
|
||||
if t.Seconds() > 0 {
|
||||
time.Sleep(t)
|
||||
}
|
||||
|
||||
node, err := next()
|
||||
service := req.Service()
|
||||
if err != nil {
|
||||
if err == selector.ErrNotFound {
|
||||
return nil, errors.InternalServerError("go.micro.client", "service %s: %s", service, err.Error())
|
||||
}
|
||||
return nil, errors.InternalServerError("go.micro.client", "error selecting %s node: %s", service, err.Error())
|
||||
}
|
||||
|
||||
// make the call
|
||||
stream := &grpcStream{}
|
||||
err = g.stream(ctx, node, req, stream, callOpts)
|
||||
|
||||
g.opts.Selector.Mark(service, node, err)
|
||||
return stream, err
|
||||
}
|
||||
|
||||
type response struct {
|
||||
stream client.Stream
|
||||
err error
|
||||
}
|
||||
|
||||
ch := make(chan response, callOpts.Retries+1)
|
||||
var grr error
|
||||
|
||||
for i := 0; i <= callOpts.Retries; i++ {
|
||||
go func(i int) {
|
||||
s, err := call(i)
|
||||
ch <- response{s, err}
|
||||
}(i)
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, errors.New("go.micro.client", fmt.Sprintf("%v", ctx.Err()), 408)
|
||||
case rsp := <-ch:
|
||||
// if the call succeeded lets bail early
|
||||
if rsp.err == nil {
|
||||
return rsp.stream, nil
|
||||
}
|
||||
|
||||
retry, rerr := callOpts.Retry(ctx, req, i, err)
|
||||
if rerr != nil {
|
||||
return nil, rerr
|
||||
}
|
||||
|
||||
if !retry {
|
||||
return nil, rsp.err
|
||||
}
|
||||
|
||||
grr = rsp.err
|
||||
}
|
||||
}
|
||||
|
||||
return nil, grr
|
||||
}
|
||||
|
||||
func (g *grpcClient) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error {
|
||||
var options client.PublishOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
md, ok := metadata.FromContext(ctx)
|
||||
if !ok {
|
||||
md = make(map[string]string)
|
||||
}
|
||||
md["Content-Type"] = p.ContentType()
|
||||
md["Micro-Topic"] = p.Topic()
|
||||
|
||||
cf, err := g.newGRPCCodec(p.ContentType())
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.client", err.Error())
|
||||
}
|
||||
|
||||
var body []byte
|
||||
|
||||
// passed in raw data
|
||||
if d, ok := p.Payload().(*raw.Frame); ok {
|
||||
body = d.Data
|
||||
} else {
|
||||
// set the body
|
||||
b, err := cf.Marshal(p.Payload())
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.client", err.Error())
|
||||
}
|
||||
body = b
|
||||
}
|
||||
|
||||
if !g.once.Load().(bool) {
|
||||
if err = g.opts.Broker.Connect(); err != nil {
|
||||
return errors.InternalServerError("go.micro.client", err.Error())
|
||||
}
|
||||
g.once.Store(true)
|
||||
}
|
||||
|
||||
topic := p.Topic()
|
||||
|
||||
// get the exchange
|
||||
if len(options.Exchange) > 0 {
|
||||
topic = options.Exchange
|
||||
}
|
||||
|
||||
return g.opts.Broker.Publish(topic, &broker.Message{
|
||||
Header: md,
|
||||
Body: body,
|
||||
}, broker.PublishContext(options.Context))
|
||||
}
|
||||
|
||||
func (g *grpcClient) String() string {
|
||||
return "grpc"
|
||||
}
|
||||
|
||||
func (g *grpcClient) getGrpcDialOptions() []grpc.DialOption {
|
||||
if g.opts.CallOptions.Context == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
v := g.opts.CallOptions.Context.Value(grpcDialOptions{})
|
||||
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
opts, ok := v.([]grpc.DialOption)
|
||||
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
func newClient(opts ...client.Option) client.Client {
|
||||
options := client.NewOptions()
|
||||
// default content type for grpc
|
||||
options.ContentType = "application/grpc+proto"
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
rc := &grpcClient{
|
||||
opts: options,
|
||||
}
|
||||
rc.once.Store(false)
|
||||
|
||||
rc.pool = newPool(options.PoolSize, options.PoolTTL, rc.poolMaxIdle(), rc.poolMaxStreams())
|
||||
|
||||
c := client.Client(rc)
|
||||
|
||||
// wrap in reverse
|
||||
for i := len(options.Wrappers); i > 0; i-- {
|
||||
c = options.Wrappers[i-1](c)
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
func NewClient(opts ...client.Option) client.Client {
|
||||
return newClient(opts...)
|
||||
}
|
||||
218
vendor/github.com/go-micro/plugins/v4/client/grpc/grpc_pool.go
generated
vendored
Normal file
218
vendor/github.com/go-micro/plugins/v4/client/grpc/grpc_pool.go
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/connectivity"
|
||||
)
|
||||
|
||||
type pool struct {
|
||||
size int
|
||||
ttl int64
|
||||
|
||||
// max streams on a *poolConn
|
||||
maxStreams int
|
||||
// max idle conns
|
||||
maxIdle int
|
||||
|
||||
sync.Mutex
|
||||
conns map[string]*streamsPool
|
||||
}
|
||||
|
||||
type streamsPool struct {
|
||||
// head of list
|
||||
head *poolConn
|
||||
// busy conns list
|
||||
busy *poolConn
|
||||
// the size of list
|
||||
count int
|
||||
// idle conn
|
||||
idle int
|
||||
}
|
||||
|
||||
type poolConn struct {
|
||||
// grpc conn
|
||||
*grpc.ClientConn
|
||||
err error
|
||||
addr string
|
||||
|
||||
// pool and streams pool
|
||||
pool *pool
|
||||
sp *streamsPool
|
||||
streams int
|
||||
created int64
|
||||
|
||||
// list
|
||||
pre *poolConn
|
||||
next *poolConn
|
||||
in bool
|
||||
}
|
||||
|
||||
func newPool(size int, ttl time.Duration, idle int, ms int) *pool {
|
||||
if ms <= 0 {
|
||||
ms = 1
|
||||
}
|
||||
if idle < 0 {
|
||||
idle = 0
|
||||
}
|
||||
return &pool{
|
||||
size: size,
|
||||
ttl: int64(ttl.Seconds()),
|
||||
maxStreams: ms,
|
||||
maxIdle: idle,
|
||||
conns: make(map[string]*streamsPool),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *pool) getConn(dialCtx context.Context, addr string, opts ...grpc.DialOption) (*poolConn, error) {
|
||||
now := time.Now().Unix()
|
||||
p.Lock()
|
||||
sp, ok := p.conns[addr]
|
||||
if !ok {
|
||||
sp = &streamsPool{head: &poolConn{}, busy: &poolConn{}, count: 0, idle: 0}
|
||||
p.conns[addr] = sp
|
||||
}
|
||||
// while we have conns check streams and then return one
|
||||
// otherwise we'll create a new conn
|
||||
conn := sp.head.next
|
||||
for conn != nil {
|
||||
// check conn state
|
||||
// https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md
|
||||
switch conn.GetState() {
|
||||
case connectivity.Connecting:
|
||||
conn = conn.next
|
||||
continue
|
||||
case connectivity.Shutdown:
|
||||
next := conn.next
|
||||
if conn.streams == 0 {
|
||||
removeConn(conn)
|
||||
sp.idle--
|
||||
}
|
||||
conn = next
|
||||
continue
|
||||
case connectivity.TransientFailure:
|
||||
next := conn.next
|
||||
if conn.streams == 0 {
|
||||
removeConn(conn)
|
||||
conn.ClientConn.Close()
|
||||
sp.idle--
|
||||
}
|
||||
conn = next
|
||||
continue
|
||||
case connectivity.Ready:
|
||||
case connectivity.Idle:
|
||||
}
|
||||
// a old conn
|
||||
if now-conn.created > p.ttl {
|
||||
next := conn.next
|
||||
if conn.streams == 0 {
|
||||
removeConn(conn)
|
||||
conn.ClientConn.Close()
|
||||
sp.idle--
|
||||
}
|
||||
conn = next
|
||||
continue
|
||||
}
|
||||
// a busy conn
|
||||
if conn.streams >= p.maxStreams {
|
||||
next := conn.next
|
||||
removeConn(conn)
|
||||
addConnAfter(conn, sp.busy)
|
||||
conn = next
|
||||
continue
|
||||
}
|
||||
// a idle conn
|
||||
if conn.streams == 0 {
|
||||
sp.idle--
|
||||
}
|
||||
// a good conn
|
||||
conn.streams++
|
||||
p.Unlock()
|
||||
return conn, nil
|
||||
}
|
||||
p.Unlock()
|
||||
|
||||
// create new conn
|
||||
cc, err := grpc.DialContext(dialCtx, addr, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
conn = &poolConn{cc, nil, addr, p, sp, 1, time.Now().Unix(), nil, nil, false}
|
||||
|
||||
// add conn to streams pool
|
||||
p.Lock()
|
||||
if sp.count < p.size {
|
||||
addConnAfter(conn, sp.head)
|
||||
}
|
||||
p.Unlock()
|
||||
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
func (p *pool) release(addr string, conn *poolConn, err error) {
|
||||
p.Lock()
|
||||
p, sp, created := conn.pool, conn.sp, conn.created
|
||||
// try to add conn
|
||||
if !conn.in && sp.count < p.size {
|
||||
addConnAfter(conn, sp.head)
|
||||
}
|
||||
if !conn.in {
|
||||
p.Unlock()
|
||||
conn.ClientConn.Close()
|
||||
return
|
||||
}
|
||||
// a busy conn
|
||||
if conn.streams >= p.maxStreams {
|
||||
removeConn(conn)
|
||||
addConnAfter(conn, sp.head)
|
||||
}
|
||||
conn.streams--
|
||||
// if streams == 0, we can do something
|
||||
if conn.streams == 0 {
|
||||
// 1. it has errored
|
||||
// 2. too many idle conn or
|
||||
// 3. conn is too old
|
||||
now := time.Now().Unix()
|
||||
if err != nil || sp.idle >= p.maxIdle || now-created > p.ttl {
|
||||
removeConn(conn)
|
||||
p.Unlock()
|
||||
conn.ClientConn.Close()
|
||||
return
|
||||
}
|
||||
sp.idle++
|
||||
}
|
||||
p.Unlock()
|
||||
}
|
||||
|
||||
func (conn *poolConn) Close() {
|
||||
conn.pool.release(conn.addr, conn, conn.err)
|
||||
}
|
||||
|
||||
func removeConn(conn *poolConn) {
|
||||
if conn.pre != nil {
|
||||
conn.pre.next = conn.next
|
||||
}
|
||||
if conn.next != nil {
|
||||
conn.next.pre = conn.pre
|
||||
}
|
||||
conn.pre = nil
|
||||
conn.next = nil
|
||||
conn.in = false
|
||||
conn.sp.count--
|
||||
return
|
||||
}
|
||||
|
||||
func addConnAfter(conn *poolConn, after *poolConn) {
|
||||
conn.next = after.next
|
||||
conn.pre = after
|
||||
if after.next != nil {
|
||||
after.next.pre = conn
|
||||
}
|
||||
after.next = conn
|
||||
conn.in = true
|
||||
conn.sp.count++
|
||||
return
|
||||
}
|
||||
40
vendor/github.com/go-micro/plugins/v4/client/grpc/message.go
generated
vendored
Normal file
40
vendor/github.com/go-micro/plugins/v4/client/grpc/message.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"go-micro.dev/v4/client"
|
||||
)
|
||||
|
||||
type grpcEvent struct {
|
||||
topic string
|
||||
contentType string
|
||||
payload interface{}
|
||||
}
|
||||
|
||||
func newGRPCEvent(topic string, payload interface{}, contentType string, opts ...client.MessageOption) client.Message {
|
||||
var options client.MessageOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
if len(options.ContentType) > 0 {
|
||||
contentType = options.ContentType
|
||||
}
|
||||
|
||||
return &grpcEvent{
|
||||
payload: payload,
|
||||
topic: topic,
|
||||
contentType: contentType,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *grpcEvent) ContentType() string {
|
||||
return g.contentType
|
||||
}
|
||||
|
||||
func (g *grpcEvent) Topic() string {
|
||||
return g.topic
|
||||
}
|
||||
|
||||
func (g *grpcEvent) Payload() interface{} {
|
||||
return g.payload
|
||||
}
|
||||
143
vendor/github.com/go-micro/plugins/v4/client/grpc/options.go
generated
vendored
Normal file
143
vendor/github.com/go-micro/plugins/v4/client/grpc/options.go
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
// Package grpc provides a gRPC options
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
|
||||
"go-micro.dev/v4/client"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultPoolMaxStreams maximum streams on a connectioin
|
||||
// (20).
|
||||
DefaultPoolMaxStreams = 20
|
||||
|
||||
// DefaultPoolMaxIdle maximum idle conns of a pool
|
||||
// (50).
|
||||
DefaultPoolMaxIdle = 50
|
||||
|
||||
// DefaultMaxRecvMsgSize maximum message that client can receive
|
||||
// (4 MB).
|
||||
DefaultMaxRecvMsgSize = 1024 * 1024 * 4
|
||||
|
||||
// DefaultMaxSendMsgSize maximum message that client can send
|
||||
// (4 MB).
|
||||
DefaultMaxSendMsgSize = 1024 * 1024 * 4
|
||||
)
|
||||
|
||||
type poolMaxStreams struct{}
|
||||
type poolMaxIdle struct{}
|
||||
type codecsKey struct{}
|
||||
type tlsAuth struct{}
|
||||
type maxRecvMsgSizeKey struct{}
|
||||
type maxSendMsgSizeKey struct{}
|
||||
type grpcDialOptions struct{}
|
||||
type grpcCallOptions struct{}
|
||||
|
||||
// maximum streams on a connectioin.
|
||||
func PoolMaxStreams(n int) client.Option {
|
||||
return func(o *client.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, poolMaxStreams{}, n)
|
||||
}
|
||||
}
|
||||
|
||||
// maximum idle conns of a pool.
|
||||
func PoolMaxIdle(d int) client.Option {
|
||||
return func(o *client.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, poolMaxIdle{}, d)
|
||||
}
|
||||
}
|
||||
|
||||
// gRPC Codec to be used to encode/decode requests for a given content type.
|
||||
func Codec(contentType string, c encoding.Codec) client.Option {
|
||||
return func(o *client.Options) {
|
||||
codecs := make(map[string]encoding.Codec)
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
if v := o.Context.Value(codecsKey{}); v != nil {
|
||||
codecs = v.(map[string]encoding.Codec)
|
||||
}
|
||||
codecs[contentType] = c
|
||||
o.Context = context.WithValue(o.Context, codecsKey{}, codecs)
|
||||
}
|
||||
}
|
||||
|
||||
// AuthTLS should be used to setup a secure authentication using TLS.
|
||||
func AuthTLS(t *tls.Config) client.Option {
|
||||
return func(o *client.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, tlsAuth{}, t)
|
||||
}
|
||||
}
|
||||
|
||||
// MaxRecvMsgSize set the maximum size of message that client can receive.
|
||||
func MaxRecvMsgSize(s int) client.Option {
|
||||
return func(o *client.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, maxRecvMsgSizeKey{}, s)
|
||||
}
|
||||
}
|
||||
|
||||
// MaxSendMsgSize set the maximum size of message that client can send.
|
||||
func MaxSendMsgSize(s int) client.Option {
|
||||
return func(o *client.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, maxSendMsgSizeKey{}, s)
|
||||
}
|
||||
}
|
||||
|
||||
// DialOptions to be used to configure gRPC dial options.
|
||||
func DialOptions(opts ...grpc.DialOption) client.CallOption {
|
||||
return func(o *client.CallOptions) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, grpcDialOptions{}, opts)
|
||||
}
|
||||
}
|
||||
|
||||
// CallOptions to be used to configure gRPC call options.
|
||||
func CallOptions(opts ...grpc.CallOption) client.CallOption {
|
||||
return func(o *client.CallOptions) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, grpcCallOptions{}, opts)
|
||||
}
|
||||
}
|
||||
|
||||
func callOpts(opts client.CallOptions) []grpc.CallOption {
|
||||
if opts.Context == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
v := opts.Context.Value(grpcCallOptions{})
|
||||
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
options, ok := v.([]grpc.CallOption)
|
||||
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
87
vendor/github.com/go-micro/plugins/v4/client/grpc/request.go
generated
vendored
Normal file
87
vendor/github.com/go-micro/plugins/v4/client/grpc/request.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"go-micro.dev/v4/client"
|
||||
"go-micro.dev/v4/codec"
|
||||
)
|
||||
|
||||
type grpcRequest struct {
|
||||
service string
|
||||
method string
|
||||
contentType string
|
||||
request interface{}
|
||||
opts client.RequestOptions
|
||||
codec codec.Codec
|
||||
}
|
||||
|
||||
// service Struct.Method /service.Struct/Method.
|
||||
func methodToGRPC(service, method string) string {
|
||||
// no method or already grpc method
|
||||
if len(method) == 0 || method[0] == '/' {
|
||||
return method
|
||||
}
|
||||
|
||||
// assume method is Foo.Bar
|
||||
mParts := strings.Split(method, ".")
|
||||
if len(mParts) != 2 {
|
||||
return method
|
||||
}
|
||||
|
||||
if len(service) == 0 {
|
||||
return fmt.Sprintf("/%s/%s", mParts[0], mParts[1])
|
||||
}
|
||||
|
||||
// return /pkg.Foo/Bar
|
||||
return fmt.Sprintf("/%s.%s/%s", service, mParts[0], mParts[1])
|
||||
}
|
||||
|
||||
func newGRPCRequest(service, method string, request interface{}, contentType string, reqOpts ...client.RequestOption) client.Request {
|
||||
var opts client.RequestOptions
|
||||
for _, o := range reqOpts {
|
||||
o(&opts)
|
||||
}
|
||||
|
||||
// set the content-type specified
|
||||
if len(opts.ContentType) > 0 {
|
||||
contentType = opts.ContentType
|
||||
}
|
||||
|
||||
return &grpcRequest{
|
||||
service: service,
|
||||
method: method,
|
||||
request: request,
|
||||
contentType: contentType,
|
||||
opts: opts,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *grpcRequest) ContentType() string {
|
||||
return g.contentType
|
||||
}
|
||||
|
||||
func (g *grpcRequest) Service() string {
|
||||
return g.service
|
||||
}
|
||||
|
||||
func (g *grpcRequest) Method() string {
|
||||
return g.method
|
||||
}
|
||||
|
||||
func (g *grpcRequest) Endpoint() string {
|
||||
return g.method
|
||||
}
|
||||
|
||||
func (g *grpcRequest) Codec() codec.Writer {
|
||||
return g.codec
|
||||
}
|
||||
|
||||
func (g *grpcRequest) Body() interface{} {
|
||||
return g.request
|
||||
}
|
||||
|
||||
func (g *grpcRequest) Stream() bool {
|
||||
return g.opts.Stream
|
||||
}
|
||||
44
vendor/github.com/go-micro/plugins/v4/client/grpc/response.go
generated
vendored
Normal file
44
vendor/github.com/go-micro/plugins/v4/client/grpc/response.go
generated
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"go-micro.dev/v4/codec"
|
||||
"go-micro.dev/v4/codec/bytes"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding"
|
||||
)
|
||||
|
||||
type response struct {
|
||||
conn *grpc.ClientConn
|
||||
stream grpc.ClientStream
|
||||
codec encoding.Codec
|
||||
gcodec codec.Codec
|
||||
}
|
||||
|
||||
// Read the response.
|
||||
func (r *response) Codec() codec.Reader {
|
||||
return r.gcodec
|
||||
}
|
||||
|
||||
// read the header.
|
||||
func (r *response) Header() map[string]string {
|
||||
md, err := r.stream.Header()
|
||||
if err != nil {
|
||||
return map[string]string{}
|
||||
}
|
||||
hdr := make(map[string]string, len(md))
|
||||
for k, v := range md {
|
||||
hdr[k] = strings.Join(v, ",")
|
||||
}
|
||||
return hdr
|
||||
}
|
||||
|
||||
// Read the undecoded response.
|
||||
func (r *response) Read() ([]byte, error) {
|
||||
f := &bytes.Frame{}
|
||||
if err := r.gcodec.ReadBody(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f.Data, nil
|
||||
}
|
||||
84
vendor/github.com/go-micro/plugins/v4/client/grpc/stream.go
generated
vendored
Normal file
84
vendor/github.com/go-micro/plugins/v4/client/grpc/stream.go
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"go-micro.dev/v4/client"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// Implements the streamer interface.
|
||||
type grpcStream struct {
|
||||
sync.RWMutex
|
||||
closed bool
|
||||
err error
|
||||
stream grpc.ClientStream
|
||||
request client.Request
|
||||
response client.Response
|
||||
context context.Context
|
||||
cancel func()
|
||||
release func(error)
|
||||
}
|
||||
|
||||
func (g *grpcStream) Context() context.Context {
|
||||
return g.context
|
||||
}
|
||||
|
||||
func (g *grpcStream) Request() client.Request {
|
||||
return g.request
|
||||
}
|
||||
|
||||
func (g *grpcStream) Response() client.Response {
|
||||
return g.response
|
||||
}
|
||||
|
||||
func (g *grpcStream) Send(msg interface{}) error {
|
||||
if err := g.stream.SendMsg(msg); err != nil {
|
||||
g.setError(err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcStream) Recv(msg interface{}) (err error) {
|
||||
if err = g.stream.RecvMsg(msg); err != nil {
|
||||
if err != io.EOF {
|
||||
g.setError(err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (g *grpcStream) Error() error {
|
||||
g.RLock()
|
||||
defer g.RUnlock()
|
||||
return g.err
|
||||
}
|
||||
|
||||
func (g *grpcStream) setError(e error) {
|
||||
g.Lock()
|
||||
g.err = e
|
||||
g.Unlock()
|
||||
}
|
||||
|
||||
func (g *grpcStream) CloseSend() error {
|
||||
return g.stream.CloseSend()
|
||||
}
|
||||
|
||||
func (g *grpcStream) Close() error {
|
||||
g.Lock()
|
||||
defer g.Unlock()
|
||||
|
||||
if g.closed {
|
||||
return nil
|
||||
}
|
||||
// cancel the context
|
||||
g.cancel()
|
||||
g.closed = true
|
||||
// release back to pool
|
||||
g.release(g.err)
|
||||
return nil
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/events/natsjs/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/events/natsjs/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
3
vendor/github.com/go-micro/plugins/v4/events/natsjs/README.md
generated
vendored
Normal file
3
vendor/github.com/go-micro/plugins/v4/events/natsjs/README.md
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# NATS JetStream
|
||||
|
||||
This plugin uses NATS with JetStream to send and receive events.
|
||||
220
vendor/github.com/go-micro/plugins/v4/events/natsjs/nats.go
generated
vendored
Normal file
220
vendor/github.com/go-micro/plugins/v4/events/natsjs/nats.go
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
package natsjs
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
nats "github.com/nats-io/nats.go"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"go-micro.dev/v4/events"
|
||||
"go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultClusterID = "micro"
|
||||
)
|
||||
|
||||
// NewStream returns an initialized nats stream or an error if the connection to the nats
|
||||
// server could not be established.
|
||||
func NewStream(opts ...Option) (events.Stream, error) {
|
||||
// parse the options
|
||||
options := Options{
|
||||
ClientID: uuid.New().String(),
|
||||
ClusterID: defaultClusterID,
|
||||
Logger: logger.DefaultLogger,
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
s := &stream{opts: options}
|
||||
natsJetStreamCtx, err := connectToNatsJetStream(options)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error connecting to nats cluster %v: %v", options.ClusterID, err)
|
||||
}
|
||||
s.natsJetStreamCtx = natsJetStreamCtx
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type stream struct {
|
||||
opts Options
|
||||
natsJetStreamCtx nats.JetStreamContext
|
||||
}
|
||||
|
||||
func connectToNatsJetStream(options Options) (nats.JetStreamContext, error) {
|
||||
nopts := nats.GetDefaultOptions()
|
||||
if options.TLSConfig != nil {
|
||||
nopts.Secure = true
|
||||
nopts.TLSConfig = options.TLSConfig
|
||||
}
|
||||
if len(options.Address) > 0 {
|
||||
nopts.Servers = strings.Split(options.Address, ",")
|
||||
}
|
||||
|
||||
conn, err := nopts.Connect()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error connecting to nats at %v with tls enabled (%v): %v", options.Address, nopts.TLSConfig != nil, err)
|
||||
}
|
||||
|
||||
js, err := conn.JetStream()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error while obtaining JetStream context: %v", err)
|
||||
}
|
||||
|
||||
return js, nil
|
||||
}
|
||||
|
||||
// Publish a message to a topic.
|
||||
func (s *stream) Publish(topic string, msg interface{}, opts ...events.PublishOption) error {
|
||||
// validate the topic
|
||||
if len(topic) == 0 {
|
||||
return events.ErrMissingTopic
|
||||
}
|
||||
|
||||
// parse the options
|
||||
options := events.PublishOptions{
|
||||
Timestamp: time.Now(),
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
// encode the message if it's not already encoded
|
||||
var payload []byte
|
||||
if p, ok := msg.([]byte); ok {
|
||||
payload = p
|
||||
} else {
|
||||
p, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
return events.ErrEncodingMessage
|
||||
}
|
||||
payload = p
|
||||
}
|
||||
|
||||
// construct the event
|
||||
event := &events.Event{
|
||||
ID: uuid.New().String(),
|
||||
Topic: topic,
|
||||
Timestamp: options.Timestamp,
|
||||
Metadata: options.Metadata,
|
||||
Payload: payload,
|
||||
}
|
||||
|
||||
// serialize the event to bytes
|
||||
bytes, err := json.Marshal(event)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Error encoding event")
|
||||
}
|
||||
|
||||
// publish the event to the topic's channel
|
||||
if _, err := s.natsJetStreamCtx.PublishAsync(event.Topic, bytes); err != nil {
|
||||
return errors.Wrap(err, "Error publishing message to topic")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Consume from a topic.
|
||||
func (s *stream) Consume(topic string, opts ...events.ConsumeOption) (<-chan events.Event, error) {
|
||||
// validate the topic
|
||||
if len(topic) == 0 {
|
||||
return nil, events.ErrMissingTopic
|
||||
}
|
||||
|
||||
log := s.opts.Logger
|
||||
|
||||
// parse the options
|
||||
options := events.ConsumeOptions{
|
||||
Group: uuid.New().String(),
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
// setup the subscriber
|
||||
c := make(chan events.Event)
|
||||
handleMsg := func(m *nats.Msg) {
|
||||
ctx, cancel := context.WithCancel(context.TODO())
|
||||
defer cancel()
|
||||
|
||||
// decode the message
|
||||
var evt events.Event
|
||||
if err := json.Unmarshal(m.Data, &evt); err != nil {
|
||||
log.Logf(logger.ErrorLevel, "Error decoding message: %v", err)
|
||||
// not acknowledging the message is the way to indicate an error occurred
|
||||
return
|
||||
}
|
||||
|
||||
if !options.AutoAck {
|
||||
// set up the ack funcs
|
||||
evt.SetAckFunc(func() error {
|
||||
return m.Ack()
|
||||
})
|
||||
evt.SetNackFunc(func() error {
|
||||
return m.Nak()
|
||||
})
|
||||
}
|
||||
|
||||
// push onto the channel and wait for the consumer to take the event off before we acknowledge it.
|
||||
c <- evt
|
||||
|
||||
if !options.AutoAck {
|
||||
return
|
||||
}
|
||||
if err := m.Ack(nats.Context(ctx)); err != nil {
|
||||
log.Logf(logger.ErrorLevel, "Error acknowledging message: %v", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ensure that a stream exists for that topic
|
||||
_, err := s.natsJetStreamCtx.StreamInfo(topic)
|
||||
if err != nil {
|
||||
cfg := &nats.StreamConfig{
|
||||
Name: topic,
|
||||
}
|
||||
|
||||
_, err = s.natsJetStreamCtx.AddStream(cfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Stream did not exist and adding a stream failed")
|
||||
}
|
||||
}
|
||||
|
||||
// setup the options
|
||||
subOpts := []nats.SubOpt{
|
||||
nats.Durable(options.Group),
|
||||
}
|
||||
|
||||
if options.CustomRetries {
|
||||
subOpts = append(subOpts, nats.MaxDeliver(options.GetRetryLimit()))
|
||||
}
|
||||
|
||||
if options.AutoAck {
|
||||
subOpts = append(subOpts, nats.AckNone())
|
||||
} else {
|
||||
subOpts = append(subOpts, nats.AckExplicit())
|
||||
}
|
||||
|
||||
if !options.Offset.IsZero() {
|
||||
subOpts = append(subOpts, nats.StartTime(options.Offset))
|
||||
} else {
|
||||
subOpts = append(subOpts, nats.DeliverNew())
|
||||
}
|
||||
|
||||
if options.AckWait > 0 {
|
||||
subOpts = append(subOpts, nats.AckWait(options.AckWait))
|
||||
}
|
||||
|
||||
// connect the subscriber
|
||||
_, err = s.natsJetStreamCtx.QueueSubscribe(topic, options.Group, handleMsg, subOpts...)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Error subscribing to topic")
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
54
vendor/github.com/go-micro/plugins/v4/events/natsjs/options.go
generated
vendored
Normal file
54
vendor/github.com/go-micro/plugins/v4/events/natsjs/options.go
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
package natsjs
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
|
||||
"go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
// Options which are used to configure the nats stream.
|
||||
type Options struct {
|
||||
ClusterID string
|
||||
ClientID string
|
||||
Address string
|
||||
TLSConfig *tls.Config
|
||||
Logger logger.Logger
|
||||
}
|
||||
|
||||
// Option is a function which configures options.
|
||||
type Option func(o *Options)
|
||||
|
||||
// ClusterID sets the cluster id for the nats connection.
|
||||
func ClusterID(id string) Option {
|
||||
return func(o *Options) {
|
||||
o.ClusterID = id
|
||||
}
|
||||
}
|
||||
|
||||
// ClientID sets the client id for the nats connection.
|
||||
func ClientID(id string) Option {
|
||||
return func(o *Options) {
|
||||
o.ClientID = id
|
||||
}
|
||||
}
|
||||
|
||||
// Address of the nats cluster.
|
||||
func Address(addr string) Option {
|
||||
return func(o *Options) {
|
||||
o.Address = addr
|
||||
}
|
||||
}
|
||||
|
||||
// TLSConfig to use when connecting to the cluster.
|
||||
func TLSConfig(t *tls.Config) Option {
|
||||
return func(o *Options) {
|
||||
o.TLSConfig = t
|
||||
}
|
||||
}
|
||||
|
||||
// Logger sets the underlyin logger
|
||||
func Logger(log logger.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.Logger = log
|
||||
}
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/logger/zerolog/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/logger/zerolog/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
16
vendor/github.com/go-micro/plugins/v4/logger/zerolog/README.md
generated
vendored
Normal file
16
vendor/github.com/go-micro/plugins/v4/logger/zerolog/README.md
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
# Zerolog
|
||||
|
||||
[Zerolog](https://github.com/rs/zerolog) logger implementation for __go-micro__ [meta logger](https://github.com/micro/go-micro/tree/master/logger).
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
func ExampleWithOut() {
|
||||
logger.DefaultLogger = zerolog.NewLogger(logger.WithOutput(os.Stdout), logger.WithLevel(logger.DebugLevel))
|
||||
|
||||
logger.Infof(logger.InfoLevel, "testing: %s", "Infof")
|
||||
|
||||
// Output:
|
||||
// {"level":"info","message":"testing: Infof"}
|
||||
}
|
||||
```
|
||||
66
vendor/github.com/go-micro/plugins/v4/logger/zerolog/options.go
generated
vendored
Normal file
66
vendor/github.com/go-micro/plugins/v4/logger/zerolog/options.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package zerolog
|
||||
|
||||
import (
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
"go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
logger.Options
|
||||
|
||||
// Flag for whether to log caller info (off by default)
|
||||
ReportCaller bool
|
||||
// Use this logger as system wide default logger (off by default)
|
||||
UseAsDefault bool
|
||||
// zerolog hooks
|
||||
Hooks []zerolog.Hook
|
||||
// TimeFormat is one of time.RFC3339, time.RFC3339Nano, time.*
|
||||
TimeFormat string
|
||||
// Runtime mode. (Production by default)
|
||||
Mode Mode
|
||||
// Exit Function to call when FatalLevel log
|
||||
ExitFunc func(int)
|
||||
}
|
||||
|
||||
type reportCallerKey struct{}
|
||||
|
||||
func ReportCaller() logger.Option {
|
||||
return logger.SetOption(reportCallerKey{}, true)
|
||||
}
|
||||
|
||||
type useAsDefaultKey struct{}
|
||||
|
||||
func UseAsDefault() logger.Option {
|
||||
return logger.SetOption(useAsDefaultKey{}, true)
|
||||
}
|
||||
|
||||
type developmentModeKey struct{}
|
||||
|
||||
func WithDevelopmentMode() logger.Option {
|
||||
return logger.SetOption(developmentModeKey{}, true)
|
||||
}
|
||||
|
||||
type productionModeKey struct{}
|
||||
|
||||
func WithProductionMode() logger.Option {
|
||||
return logger.SetOption(productionModeKey{}, true)
|
||||
}
|
||||
|
||||
type timeFormatKey struct{}
|
||||
|
||||
func WithTimeFormat(timeFormat string) logger.Option {
|
||||
return logger.SetOption(timeFormatKey{}, timeFormat)
|
||||
}
|
||||
|
||||
type hooksKey struct{}
|
||||
|
||||
func WithHooks(hooks []zerolog.Hook) logger.Option {
|
||||
return logger.SetOption(hooksKey{}, hooks)
|
||||
}
|
||||
|
||||
type exitKey struct{}
|
||||
|
||||
func WithExitFunc(exit func(int)) logger.Option {
|
||||
return logger.SetOption(exitKey{}, exit)
|
||||
}
|
||||
218
vendor/github.com/go-micro/plugins/v4/logger/zerolog/zerolog.go
generated
vendored
Normal file
218
vendor/github.com/go-micro/plugins/v4/logger/zerolog/zerolog.go
generated
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
package zerolog
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
zlog "github.com/rs/zerolog/log"
|
||||
"github.com/rs/zerolog/pkgerrors"
|
||||
|
||||
"go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
type Mode uint8
|
||||
|
||||
const (
|
||||
Production Mode = iota
|
||||
Development
|
||||
)
|
||||
|
||||
type zeroLogger struct {
|
||||
zLog zerolog.Logger
|
||||
opts Options
|
||||
}
|
||||
|
||||
func (l *zeroLogger) Init(opts ...logger.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&l.opts.Options)
|
||||
}
|
||||
|
||||
if hs, ok := l.opts.Context.Value(hooksKey{}).([]zerolog.Hook); ok {
|
||||
l.opts.Hooks = hs
|
||||
}
|
||||
if tf, ok := l.opts.Context.Value(timeFormatKey{}).(string); ok {
|
||||
l.opts.TimeFormat = tf
|
||||
}
|
||||
if exitFunction, ok := l.opts.Context.Value(exitKey{}).(func(int)); ok {
|
||||
l.opts.ExitFunc = exitFunction
|
||||
}
|
||||
if caller, ok := l.opts.Context.Value(reportCallerKey{}).(bool); ok && caller {
|
||||
l.opts.ReportCaller = caller
|
||||
}
|
||||
if useDefault, ok := l.opts.Context.Value(useAsDefaultKey{}).(bool); ok && useDefault {
|
||||
l.opts.UseAsDefault = useDefault
|
||||
}
|
||||
if devMode, ok := l.opts.Context.Value(developmentModeKey{}).(bool); ok && devMode {
|
||||
l.opts.Mode = Development
|
||||
}
|
||||
if prodMode, ok := l.opts.Context.Value(productionModeKey{}).(bool); ok && prodMode {
|
||||
l.opts.Mode = Production
|
||||
}
|
||||
|
||||
skip := 4
|
||||
if l.opts.CallerSkipCount > 0 {
|
||||
skip = l.opts.CallerSkipCount
|
||||
}
|
||||
// RESET
|
||||
zerolog.TimeFieldFormat = time.RFC3339
|
||||
zerolog.ErrorStackMarshaler = nil
|
||||
zerolog.CallerSkipFrameCount = skip
|
||||
|
||||
switch l.opts.Mode {
|
||||
case Development:
|
||||
zerolog.ErrorStackMarshaler = func(err error) interface{} {
|
||||
fmt.Println(string(debug.Stack()))
|
||||
return nil
|
||||
}
|
||||
consOut := zerolog.NewConsoleWriter(
|
||||
func(w *zerolog.ConsoleWriter) {
|
||||
if len(l.opts.TimeFormat) > 0 {
|
||||
w.TimeFormat = l.opts.TimeFormat
|
||||
}
|
||||
w.Out = l.opts.Out
|
||||
w.NoColor = false
|
||||
},
|
||||
)
|
||||
// level = logger.DebugLevel
|
||||
l.zLog = zerolog.New(consOut).
|
||||
Level(zerolog.DebugLevel).
|
||||
With().Timestamp().Stack().Logger()
|
||||
default: // Production
|
||||
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
|
||||
l.zLog = zerolog.New(l.opts.Out).
|
||||
Level(zerolog.InfoLevel).
|
||||
With().Timestamp().Stack().Logger()
|
||||
}
|
||||
|
||||
// Set log Level if not default
|
||||
if l.opts.Level != 100 {
|
||||
zerolog.SetGlobalLevel(loggerToZerologLevel(l.opts.Level))
|
||||
l.zLog = l.zLog.Level(loggerToZerologLevel(l.opts.Level))
|
||||
}
|
||||
|
||||
// Reporting caller
|
||||
if l.opts.ReportCaller {
|
||||
l.zLog = l.zLog.With().Caller().Logger()
|
||||
}
|
||||
|
||||
// Adding hooks if exist
|
||||
for _, hook := range l.opts.Hooks {
|
||||
l.zLog = l.zLog.Hook(hook)
|
||||
}
|
||||
|
||||
// Setting timeFormat
|
||||
if len(l.opts.TimeFormat) > 0 {
|
||||
zerolog.TimeFieldFormat = l.opts.TimeFormat
|
||||
}
|
||||
|
||||
// Adding seed fields if exist
|
||||
if l.opts.Fields != nil {
|
||||
l.zLog = l.zLog.With().Fields(l.opts.Fields).Logger()
|
||||
}
|
||||
|
||||
// Also set it as zerolog's Default logger
|
||||
if l.opts.UseAsDefault {
|
||||
zlog.Logger = l.zLog
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *zeroLogger) Fields(fields map[string]interface{}) logger.Logger {
|
||||
l.zLog = l.zLog.With().Fields(fields).Logger()
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *zeroLogger) Error(err error) logger.Logger {
|
||||
l.zLog = l.zLog.With().Fields(map[string]interface{}{zerolog.ErrorFieldName: err}).Logger()
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *zeroLogger) Log(level logger.Level, args ...interface{}) {
|
||||
msg := fmt.Sprint(args...)
|
||||
l.zLog.WithLevel(loggerToZerologLevel(level)).Msg(msg)
|
||||
// Invoke os.Exit because unlike zerolog.Logger.Fatal zerolog.Logger.WithLevel won't stop the execution.
|
||||
if level == logger.FatalLevel {
|
||||
l.opts.ExitFunc(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *zeroLogger) Logf(level logger.Level, format string, args ...interface{}) {
|
||||
l.zLog.WithLevel(loggerToZerologLevel(level)).Msgf(format, args...)
|
||||
// Invoke os.Exit because unlike zerolog.Logger.Fatal zerolog.Logger.WithLevel won't stop the execution.
|
||||
if level == logger.FatalLevel {
|
||||
l.opts.ExitFunc(1)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *zeroLogger) String() string {
|
||||
return "zerolog"
|
||||
}
|
||||
|
||||
func (l *zeroLogger) Options() logger.Options {
|
||||
// FIXME: How to return full opts?
|
||||
return l.opts.Options
|
||||
}
|
||||
|
||||
// NewLogger builds a new logger based on options.
|
||||
func NewLogger(opts ...logger.Option) logger.Logger {
|
||||
// Default options
|
||||
options := Options{
|
||||
Options: logger.Options{
|
||||
Level: 100,
|
||||
Fields: make(map[string]interface{}),
|
||||
Out: os.Stderr,
|
||||
Context: context.Background(),
|
||||
},
|
||||
ReportCaller: false,
|
||||
UseAsDefault: false,
|
||||
Mode: Production,
|
||||
ExitFunc: os.Exit,
|
||||
}
|
||||
|
||||
l := &zeroLogger{opts: options}
|
||||
_ = l.Init(opts...)
|
||||
return l
|
||||
}
|
||||
|
||||
func loggerToZerologLevel(level logger.Level) zerolog.Level {
|
||||
switch level {
|
||||
case logger.TraceLevel:
|
||||
return zerolog.TraceLevel
|
||||
case logger.DebugLevel:
|
||||
return zerolog.DebugLevel
|
||||
case logger.InfoLevel:
|
||||
return zerolog.InfoLevel
|
||||
case logger.WarnLevel:
|
||||
return zerolog.WarnLevel
|
||||
case logger.ErrorLevel:
|
||||
return zerolog.ErrorLevel
|
||||
case logger.FatalLevel:
|
||||
return zerolog.FatalLevel
|
||||
default:
|
||||
return zerolog.InfoLevel
|
||||
}
|
||||
}
|
||||
|
||||
func ZerologToLoggerLevel(level zerolog.Level) logger.Level {
|
||||
switch level {
|
||||
case zerolog.TraceLevel:
|
||||
return logger.TraceLevel
|
||||
case zerolog.DebugLevel:
|
||||
return logger.DebugLevel
|
||||
case zerolog.InfoLevel:
|
||||
return logger.InfoLevel
|
||||
case zerolog.WarnLevel:
|
||||
return logger.WarnLevel
|
||||
case zerolog.ErrorLevel:
|
||||
return logger.ErrorLevel
|
||||
case zerolog.FatalLevel:
|
||||
return logger.FatalLevel
|
||||
default:
|
||||
return logger.InfoLevel
|
||||
}
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/registry/consul/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/registry/consul/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
465
vendor/github.com/go-micro/plugins/v4/registry/consul/consul.go
generated
vendored
Normal file
465
vendor/github.com/go-micro/plugins/v4/registry/consul/consul.go
generated
vendored
Normal file
@@ -0,0 +1,465 @@
|
||||
package consul
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
consul "github.com/hashicorp/consul/api"
|
||||
hash "github.com/mitchellh/hashstructure"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/util/cmd"
|
||||
mnet "go-micro.dev/v4/util/net"
|
||||
)
|
||||
|
||||
type consulRegistry struct {
|
||||
Address []string
|
||||
opts registry.Options
|
||||
|
||||
client *consul.Client
|
||||
config *consul.Config
|
||||
|
||||
// connect enabled
|
||||
connect bool
|
||||
|
||||
queryOptions *consul.QueryOptions
|
||||
|
||||
sync.Mutex
|
||||
register map[string]uint64
|
||||
// lastChecked tracks when a node was last checked as existing in Consul
|
||||
lastChecked map[string]time.Time
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmd.DefaultRegistries["consul"] = NewRegistry
|
||||
}
|
||||
|
||||
func getDeregisterTTL(t time.Duration) time.Duration {
|
||||
// splay slightly for the watcher?
|
||||
splay := time.Second * 5
|
||||
deregTTL := t + splay
|
||||
|
||||
// consul has a minimum timeout on deregistration of 1 minute.
|
||||
if t < time.Minute {
|
||||
deregTTL = time.Minute + splay
|
||||
}
|
||||
|
||||
return deregTTL
|
||||
}
|
||||
|
||||
func newTransport(config *tls.Config) *http.Transport {
|
||||
if config == nil {
|
||||
config = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
}
|
||||
|
||||
t := &http.Transport{
|
||||
Proxy: http.ProxyFromEnvironment,
|
||||
Dial: (&net.Dialer{
|
||||
Timeout: 30 * time.Second,
|
||||
KeepAlive: 30 * time.Second,
|
||||
}).Dial,
|
||||
TLSHandshakeTimeout: 10 * time.Second,
|
||||
TLSClientConfig: config,
|
||||
}
|
||||
runtime.SetFinalizer(&t, func(tr **http.Transport) {
|
||||
(*tr).CloseIdleConnections()
|
||||
})
|
||||
return t
|
||||
}
|
||||
|
||||
func configure(c *consulRegistry, opts ...registry.Option) {
|
||||
// set opts
|
||||
for _, o := range opts {
|
||||
o(&c.opts)
|
||||
}
|
||||
|
||||
// use default non pooled config
|
||||
config := consul.DefaultNonPooledConfig()
|
||||
|
||||
if c.opts.Context != nil {
|
||||
// Use the consul config passed in the options, if available
|
||||
if co, ok := c.opts.Context.Value("consul_config").(*consul.Config); ok {
|
||||
config = co
|
||||
}
|
||||
if cn, ok := c.opts.Context.Value("consul_connect").(bool); ok {
|
||||
c.connect = cn
|
||||
}
|
||||
|
||||
// Use the consul query options passed in the options, if available
|
||||
if qo, ok := c.opts.Context.Value("consul_query_options").(*consul.QueryOptions); ok && qo != nil {
|
||||
c.queryOptions = qo
|
||||
}
|
||||
if as, ok := c.opts.Context.Value("consul_allow_stale").(bool); ok {
|
||||
c.queryOptions.AllowStale = as
|
||||
}
|
||||
}
|
||||
|
||||
// check if there are any addrs
|
||||
var addrs []string
|
||||
|
||||
// iterate the options addresses
|
||||
for _, address := range c.opts.Addrs {
|
||||
// check we have a port
|
||||
addr, port, err := net.SplitHostPort(address)
|
||||
if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
|
||||
port = "8500"
|
||||
addr = address
|
||||
addrs = append(addrs, net.JoinHostPort(addr, port))
|
||||
} else if err == nil {
|
||||
addrs = append(addrs, net.JoinHostPort(addr, port))
|
||||
}
|
||||
}
|
||||
|
||||
// set the addrs
|
||||
if len(addrs) > 0 {
|
||||
c.Address = addrs
|
||||
config.Address = c.Address[0]
|
||||
}
|
||||
|
||||
if config.HttpClient == nil {
|
||||
config.HttpClient = new(http.Client)
|
||||
}
|
||||
|
||||
// requires secure connection?
|
||||
if c.opts.Secure || c.opts.TLSConfig != nil {
|
||||
config.Scheme = "https"
|
||||
// We're going to support InsecureSkipVerify
|
||||
config.HttpClient.Transport = newTransport(c.opts.TLSConfig)
|
||||
}
|
||||
|
||||
// set timeout
|
||||
if c.opts.Timeout > 0 {
|
||||
config.HttpClient.Timeout = c.opts.Timeout
|
||||
}
|
||||
|
||||
// set the config
|
||||
c.config = config
|
||||
|
||||
// remove client
|
||||
c.client = nil
|
||||
|
||||
// setup the client
|
||||
c.Client()
|
||||
}
|
||||
|
||||
func (c *consulRegistry) Init(opts ...registry.Option) error {
|
||||
configure(c, opts...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *consulRegistry) Deregister(s *registry.Service, opts ...registry.DeregisterOption) error {
|
||||
if len(s.Nodes) == 0 {
|
||||
return errors.New("Require at least one node")
|
||||
}
|
||||
|
||||
// delete our hash and time check of the service
|
||||
c.Lock()
|
||||
delete(c.register, s.Name)
|
||||
delete(c.lastChecked, s.Name)
|
||||
c.Unlock()
|
||||
|
||||
node := s.Nodes[0]
|
||||
return c.Client().Agent().ServiceDeregister(node.Id)
|
||||
}
|
||||
|
||||
func (c *consulRegistry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
|
||||
if len(s.Nodes) == 0 {
|
||||
return errors.New("Require at least one node")
|
||||
}
|
||||
|
||||
var regTCPCheck bool
|
||||
var regInterval time.Duration
|
||||
var regHTTPCheck bool
|
||||
var httpCheckConfig consul.AgentServiceCheck
|
||||
|
||||
var options registry.RegisterOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
if c.opts.Context != nil {
|
||||
if tcpCheckInterval, ok := c.opts.Context.Value("consul_tcp_check").(time.Duration); ok {
|
||||
regTCPCheck = true
|
||||
regInterval = tcpCheckInterval
|
||||
}
|
||||
var ok bool
|
||||
if httpCheckConfig, ok = c.opts.Context.Value("consul_http_check_config").(consul.AgentServiceCheck); ok {
|
||||
regHTTPCheck = true
|
||||
}
|
||||
}
|
||||
|
||||
// create hash of service; uint64
|
||||
h, err := hash.Hash(s, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// use first node
|
||||
node := s.Nodes[0]
|
||||
|
||||
// get existing hash and last checked time
|
||||
c.Lock()
|
||||
v, ok := c.register[s.Name]
|
||||
lastChecked := c.lastChecked[s.Name]
|
||||
c.Unlock()
|
||||
|
||||
// if it's already registered and matches then just pass the check
|
||||
if ok && v == h {
|
||||
if options.TTL == time.Duration(0) {
|
||||
// ensure that our service hasn't been deregistered by Consul
|
||||
if time.Since(lastChecked) <= getDeregisterTTL(regInterval) {
|
||||
return nil
|
||||
}
|
||||
services, _, err := c.Client().Health().Checks(s.Name, c.queryOptions)
|
||||
if err == nil {
|
||||
for _, v := range services {
|
||||
if v.ServiceID == node.Id {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if the err is nil we're all good, bail out
|
||||
// if not, we don't know what the state is, so full re-register
|
||||
if err := c.Client().Agent().PassTTL("service:"+node.Id, ""); err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// encode the tags
|
||||
tags := encodeMetadata(node.Metadata)
|
||||
tags = append(tags, encodeEndpoints(s.Endpoints)...)
|
||||
tags = append(tags, encodeVersion(s.Version)...)
|
||||
|
||||
var check *consul.AgentServiceCheck
|
||||
|
||||
if regTCPCheck {
|
||||
deregTTL := getDeregisterTTL(regInterval)
|
||||
|
||||
check = &consul.AgentServiceCheck{
|
||||
TCP: node.Address,
|
||||
Interval: fmt.Sprintf("%v", regInterval),
|
||||
DeregisterCriticalServiceAfter: fmt.Sprintf("%v", deregTTL),
|
||||
}
|
||||
|
||||
} else if regHTTPCheck {
|
||||
interval, _ := time.ParseDuration(httpCheckConfig.Interval)
|
||||
deregTTL := getDeregisterTTL(interval)
|
||||
|
||||
host, _, _ := net.SplitHostPort(node.Address)
|
||||
healthCheckURI := strings.Replace(httpCheckConfig.HTTP, "{host}", host, 1)
|
||||
|
||||
check = &consul.AgentServiceCheck{
|
||||
HTTP: healthCheckURI,
|
||||
Interval: httpCheckConfig.Interval,
|
||||
Timeout: httpCheckConfig.Timeout,
|
||||
DeregisterCriticalServiceAfter: fmt.Sprintf("%v", deregTTL),
|
||||
}
|
||||
|
||||
// if the TTL is greater than 0 create an associated check
|
||||
} else if options.TTL > time.Duration(0) {
|
||||
deregTTL := getDeregisterTTL(options.TTL)
|
||||
|
||||
check = &consul.AgentServiceCheck{
|
||||
TTL: fmt.Sprintf("%v", options.TTL),
|
||||
DeregisterCriticalServiceAfter: fmt.Sprintf("%v", deregTTL),
|
||||
}
|
||||
}
|
||||
|
||||
host, pt, _ := net.SplitHostPort(node.Address)
|
||||
if host == "" {
|
||||
host = node.Address
|
||||
}
|
||||
port, _ := strconv.Atoi(pt)
|
||||
|
||||
// register the service
|
||||
asr := &consul.AgentServiceRegistration{
|
||||
ID: node.Id,
|
||||
Name: s.Name,
|
||||
Tags: tags,
|
||||
Port: port,
|
||||
Address: host,
|
||||
Meta: node.Metadata,
|
||||
Check: check,
|
||||
}
|
||||
|
||||
// Specify consul connect
|
||||
if c.connect {
|
||||
asr.Connect = &consul.AgentServiceConnect{
|
||||
Native: true,
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.Client().Agent().ServiceRegister(asr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// save our hash and time check of the service
|
||||
c.Lock()
|
||||
c.register[s.Name] = h
|
||||
c.lastChecked[s.Name] = time.Now()
|
||||
c.Unlock()
|
||||
|
||||
// if the TTL is 0 we don't mess with the checks
|
||||
if options.TTL == time.Duration(0) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// pass the healthcheck
|
||||
return c.Client().Agent().PassTTL("service:"+node.Id, "")
|
||||
}
|
||||
|
||||
func (c *consulRegistry) GetService(name string, opts ...registry.GetOption) ([]*registry.Service, error) {
|
||||
var rsp []*consul.ServiceEntry
|
||||
var err error
|
||||
|
||||
// if we're connect enabled only get connect services
|
||||
if c.connect {
|
||||
rsp, _, err = c.Client().Health().Connect(name, "", false, c.queryOptions)
|
||||
} else {
|
||||
rsp, _, err = c.Client().Health().Service(name, "", false, c.queryOptions)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serviceMap := map[string]*registry.Service{}
|
||||
|
||||
for _, s := range rsp {
|
||||
if s.Service.Service != name {
|
||||
continue
|
||||
}
|
||||
|
||||
// version is now a tag
|
||||
version, _ := decodeVersion(s.Service.Tags)
|
||||
// service ID is now the node id
|
||||
id := s.Service.ID
|
||||
// key is always the version
|
||||
key := version
|
||||
|
||||
// address is service address
|
||||
address := s.Service.Address
|
||||
|
||||
// use node address
|
||||
if len(address) == 0 {
|
||||
address = s.Node.Address
|
||||
}
|
||||
|
||||
svc, ok := serviceMap[key]
|
||||
if !ok {
|
||||
svc = ®istry.Service{
|
||||
Endpoints: decodeEndpoints(s.Service.Tags),
|
||||
Name: s.Service.Service,
|
||||
Version: version,
|
||||
}
|
||||
serviceMap[key] = svc
|
||||
}
|
||||
|
||||
var del bool
|
||||
|
||||
for _, check := range s.Checks {
|
||||
// delete the node if the status is critical
|
||||
if check.Status == "critical" {
|
||||
del = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// if delete then skip the node
|
||||
if del {
|
||||
continue
|
||||
}
|
||||
|
||||
svc.Nodes = append(svc.Nodes, ®istry.Node{
|
||||
Id: id,
|
||||
Address: mnet.HostPort(address, s.Service.Port),
|
||||
Metadata: decodeMetadata(s.Service.Tags),
|
||||
})
|
||||
}
|
||||
|
||||
var services []*registry.Service
|
||||
for _, service := range serviceMap {
|
||||
services = append(services, service)
|
||||
}
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (c *consulRegistry) ListServices(opts ...registry.ListOption) ([]*registry.Service, error) {
|
||||
rsp, _, err := c.Client().Catalog().Services(c.queryOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var services []*registry.Service
|
||||
|
||||
for service := range rsp {
|
||||
services = append(services, ®istry.Service{Name: service})
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (c *consulRegistry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) {
|
||||
return newConsulWatcher(c, opts...)
|
||||
}
|
||||
|
||||
func (c *consulRegistry) String() string {
|
||||
return "consul"
|
||||
}
|
||||
|
||||
func (c *consulRegistry) Options() registry.Options {
|
||||
return c.opts
|
||||
}
|
||||
|
||||
func (c *consulRegistry) Client() *consul.Client {
|
||||
if c.client != nil {
|
||||
return c.client
|
||||
}
|
||||
|
||||
for _, addr := range c.Address {
|
||||
// set the address
|
||||
c.config.Address = addr
|
||||
|
||||
// create a new client
|
||||
tmpClient, _ := consul.NewClient(c.config)
|
||||
|
||||
// test the client
|
||||
_, err := tmpClient.Agent().Host()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// set the client
|
||||
c.client = tmpClient
|
||||
return c.client
|
||||
}
|
||||
|
||||
// set the default
|
||||
c.client, _ = consul.NewClient(c.config)
|
||||
|
||||
// return the client
|
||||
return c.client
|
||||
}
|
||||
|
||||
func NewRegistry(opts ...registry.Option) registry.Registry {
|
||||
cr := &consulRegistry{
|
||||
opts: registry.Options{},
|
||||
register: make(map[string]uint64),
|
||||
lastChecked: make(map[string]time.Time),
|
||||
queryOptions: &consul.QueryOptions{
|
||||
AllowStale: true,
|
||||
},
|
||||
}
|
||||
configure(cr, opts...)
|
||||
return cr
|
||||
}
|
||||
171
vendor/github.com/go-micro/plugins/v4/registry/consul/encoding.go
generated
vendored
Normal file
171
vendor/github.com/go-micro/plugins/v4/registry/consul/encoding.go
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
package consul
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/zlib"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"io"
|
||||
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
func encode(buf []byte) string {
|
||||
var b bytes.Buffer
|
||||
defer b.Reset()
|
||||
|
||||
w := zlib.NewWriter(&b)
|
||||
if _, err := w.Write(buf); err != nil {
|
||||
return ""
|
||||
}
|
||||
w.Close()
|
||||
|
||||
return hex.EncodeToString(b.Bytes())
|
||||
}
|
||||
|
||||
func decode(d string) []byte {
|
||||
hr, err := hex.DecodeString(d)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
br := bytes.NewReader(hr)
|
||||
zr, err := zlib.NewReader(br)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
rbuf, err := io.ReadAll(zr)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
zr.Close()
|
||||
|
||||
return rbuf
|
||||
}
|
||||
|
||||
func encodeEndpoints(en []*registry.Endpoint) []string {
|
||||
var tags []string
|
||||
for _, e := range en {
|
||||
if b, err := json.Marshal(e); err == nil {
|
||||
tags = append(tags, "e-"+encode(b))
|
||||
}
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
func decodeEndpoints(tags []string) []*registry.Endpoint {
|
||||
var en []*registry.Endpoint
|
||||
|
||||
// use the first format you find
|
||||
var ver byte
|
||||
|
||||
for _, tag := range tags {
|
||||
if len(tag) == 0 || tag[0] != 'e' {
|
||||
continue
|
||||
}
|
||||
|
||||
// check version
|
||||
if ver > 0 && tag[1] != ver {
|
||||
continue
|
||||
}
|
||||
|
||||
var e *registry.Endpoint
|
||||
var buf []byte
|
||||
|
||||
// Old encoding was plain
|
||||
if tag[1] == '=' {
|
||||
buf = []byte(tag[2:])
|
||||
}
|
||||
|
||||
// New encoding is hex
|
||||
if tag[1] == '-' {
|
||||
buf = decode(tag[2:])
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(buf, &e); err == nil {
|
||||
en = append(en, e)
|
||||
}
|
||||
|
||||
// set version
|
||||
ver = tag[1]
|
||||
}
|
||||
return en
|
||||
}
|
||||
|
||||
func encodeMetadata(md map[string]string) []string {
|
||||
var tags []string
|
||||
for k, v := range md {
|
||||
if b, err := json.Marshal(map[string]string{
|
||||
k: v,
|
||||
}); err == nil {
|
||||
// new encoding
|
||||
tags = append(tags, "t-"+encode(b))
|
||||
}
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
func decodeMetadata(tags []string) map[string]string {
|
||||
md := make(map[string]string)
|
||||
|
||||
var ver byte
|
||||
|
||||
for _, tag := range tags {
|
||||
if len(tag) == 0 || tag[0] != 't' {
|
||||
continue
|
||||
}
|
||||
|
||||
// check version
|
||||
if ver > 0 && tag[1] != ver {
|
||||
continue
|
||||
}
|
||||
|
||||
var kv map[string]string
|
||||
var buf []byte
|
||||
|
||||
// Old encoding was plain
|
||||
if tag[1] == '=' {
|
||||
buf = []byte(tag[2:])
|
||||
}
|
||||
|
||||
// New encoding is hex
|
||||
if tag[1] == '-' {
|
||||
buf = decode(tag[2:])
|
||||
}
|
||||
|
||||
// Now unmarshal
|
||||
if err := json.Unmarshal(buf, &kv); err == nil {
|
||||
for k, v := range kv {
|
||||
md[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
// set version
|
||||
ver = tag[1]
|
||||
}
|
||||
return md
|
||||
}
|
||||
|
||||
func encodeVersion(v string) []string {
|
||||
return []string{"v-" + encode([]byte(v))}
|
||||
}
|
||||
|
||||
func decodeVersion(tags []string) (string, bool) {
|
||||
for _, tag := range tags {
|
||||
if len(tag) < 2 || tag[0] != 'v' {
|
||||
continue
|
||||
}
|
||||
|
||||
// Old encoding was plain
|
||||
if tag[1] == '=' {
|
||||
return tag[2:], true
|
||||
}
|
||||
|
||||
// New encoding is hex
|
||||
if tag[1] == '-' {
|
||||
return string(decode(tag[2:])), true
|
||||
}
|
||||
}
|
||||
return "", false
|
||||
}
|
||||
101
vendor/github.com/go-micro/plugins/v4/registry/consul/options.go
generated
vendored
Normal file
101
vendor/github.com/go-micro/plugins/v4/registry/consul/options.go
generated
vendored
Normal file
@@ -0,0 +1,101 @@
|
||||
package consul
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
consul "github.com/hashicorp/consul/api"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
// Connect specifies services should be registered as Consul Connect services.
|
||||
func Connect() registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, "consul_connect", true)
|
||||
}
|
||||
}
|
||||
|
||||
func Config(c *consul.Config) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, "consul_config", c)
|
||||
}
|
||||
}
|
||||
|
||||
// AllowStale sets whether any Consul server (non-leader) can service
|
||||
// a read. This allows for lower latency and higher throughput
|
||||
// at the cost of potentially stale data.
|
||||
// Works similar to Consul DNS Config option [1].
|
||||
// Defaults to true.
|
||||
//
|
||||
// [1] https://www.consul.io/docs/agent/options.html#allow_stale
|
||||
func AllowStale(v bool) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, "consul_allow_stale", v)
|
||||
}
|
||||
}
|
||||
|
||||
// QueryOptions specifies the QueryOptions to be used when calling
|
||||
// Consul. See `Consul API` for more information [1].
|
||||
//
|
||||
// [1] https://godoc.org/github.com/hashicorp/consul/api#QueryOptions
|
||||
func QueryOptions(q *consul.QueryOptions) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if q == nil {
|
||||
return
|
||||
}
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, "consul_query_options", q)
|
||||
}
|
||||
}
|
||||
|
||||
// TCPCheck will tell the service provider to check the service address
|
||||
// and port every `t` interval. It will enabled only if `t` is greater than 0.
|
||||
// See `TCP + Interval` for more information [1].
|
||||
//
|
||||
// [1] https://www.consul.io/docs/agent/checks.html
|
||||
func TCPCheck(t time.Duration) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if t <= time.Duration(0) {
|
||||
return
|
||||
}
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, "consul_tcp_check", t)
|
||||
}
|
||||
}
|
||||
|
||||
// HTTPCheck will tell the service provider to invoke the health check endpoint
|
||||
// with an interval and timeout. It will be enabled only if interval and
|
||||
// timeout are greater than 0.
|
||||
// See `HTTP + Interval` for more information [1].
|
||||
//
|
||||
// [1] https://www.consul.io/docs/agent/checks.html
|
||||
func HTTPCheck(protocol, port, httpEndpoint string, interval, timeout time.Duration) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if interval <= time.Duration(0) || timeout <= time.Duration(0) {
|
||||
return
|
||||
}
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
check := consul.AgentServiceCheck{
|
||||
HTTP: fmt.Sprintf("%s://{host}:%s%s", protocol, port, httpEndpoint),
|
||||
Interval: fmt.Sprintf("%v", interval),
|
||||
Timeout: fmt.Sprintf("%v", timeout),
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, "consul_http_check_config", check)
|
||||
}
|
||||
}
|
||||
290
vendor/github.com/go-micro/plugins/v4/registry/consul/watcher.go
generated
vendored
Normal file
290
vendor/github.com/go-micro/plugins/v4/registry/consul/watcher.go
generated
vendored
Normal file
@@ -0,0 +1,290 @@
|
||||
package consul
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"sync"
|
||||
|
||||
"github.com/hashicorp/consul/api"
|
||||
"github.com/hashicorp/consul/api/watch"
|
||||
"go-micro.dev/v4/registry"
|
||||
regutil "go-micro.dev/v4/util/registry"
|
||||
)
|
||||
|
||||
type consulWatcher struct {
|
||||
r *consulRegistry
|
||||
wo registry.WatchOptions
|
||||
wp *watch.Plan
|
||||
watchers map[string]*watch.Plan
|
||||
|
||||
next chan *registry.Result
|
||||
exit chan bool
|
||||
|
||||
sync.RWMutex
|
||||
services map[string][]*registry.Service
|
||||
}
|
||||
|
||||
func newConsulWatcher(cr *consulRegistry, opts ...registry.WatchOption) (registry.Watcher, error) {
|
||||
var wo registry.WatchOptions
|
||||
for _, o := range opts {
|
||||
o(&wo)
|
||||
}
|
||||
|
||||
cw := &consulWatcher{
|
||||
r: cr,
|
||||
wo: wo,
|
||||
exit: make(chan bool),
|
||||
next: make(chan *registry.Result, 10),
|
||||
watchers: make(map[string]*watch.Plan),
|
||||
services: make(map[string][]*registry.Service),
|
||||
}
|
||||
|
||||
wp, err := watch.Parse(map[string]interface{}{
|
||||
"service": wo.Service,
|
||||
"type": "service",
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
wp.Handler = cw.handle
|
||||
go wp.RunWithClientAndHclog(cr.Client(), wp.Logger)
|
||||
cw.wp = wp
|
||||
|
||||
return cw, nil
|
||||
}
|
||||
|
||||
func (cw *consulWatcher) serviceHandler(idx uint64, data interface{}) {
|
||||
entries, ok := data.([]*api.ServiceEntry)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
serviceMap := map[string]*registry.Service{}
|
||||
serviceName := ""
|
||||
|
||||
for _, e := range entries {
|
||||
serviceName = e.Service.Service
|
||||
// version is now a tag
|
||||
version, _ := decodeVersion(e.Service.Tags)
|
||||
// service ID is now the node id
|
||||
id := e.Service.ID
|
||||
// key is always the version
|
||||
key := version
|
||||
// address is service address
|
||||
address := e.Service.Address
|
||||
|
||||
// use node address
|
||||
if len(address) == 0 {
|
||||
address = e.Node.Address
|
||||
}
|
||||
|
||||
svc, ok := serviceMap[key]
|
||||
if !ok {
|
||||
svc = ®istry.Service{
|
||||
Endpoints: decodeEndpoints(e.Service.Tags),
|
||||
Name: e.Service.Service,
|
||||
Version: version,
|
||||
}
|
||||
serviceMap[key] = svc
|
||||
}
|
||||
|
||||
var del bool
|
||||
|
||||
for _, check := range e.Checks {
|
||||
// delete the node if the status is critical
|
||||
if check.Status == "critical" {
|
||||
del = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// if delete then skip the node
|
||||
if del {
|
||||
continue
|
||||
}
|
||||
|
||||
svc.Nodes = append(svc.Nodes, ®istry.Node{
|
||||
Id: id,
|
||||
Address: net.JoinHostPort(address, fmt.Sprint(e.Service.Port)),
|
||||
Metadata: decodeMetadata(e.Service.Tags),
|
||||
})
|
||||
}
|
||||
|
||||
cw.RLock()
|
||||
// make a copy
|
||||
rservices := make(map[string][]*registry.Service)
|
||||
for k, v := range cw.services {
|
||||
rservices[k] = v
|
||||
}
|
||||
cw.RUnlock()
|
||||
|
||||
var newServices []*registry.Service
|
||||
|
||||
// serviceMap is the new set of services keyed by name+version
|
||||
for _, newService := range serviceMap {
|
||||
// append to the new set of cached services
|
||||
newServices = append(newServices, newService)
|
||||
|
||||
// check if the service exists in the existing cache
|
||||
oldServices, ok := rservices[serviceName]
|
||||
if !ok {
|
||||
// does not exist? then we're creating brand new entries
|
||||
cw.next <- ®istry.Result{Action: "create", Service: newService}
|
||||
continue
|
||||
}
|
||||
|
||||
// service exists. ok let's figure out what to update and delete version wise
|
||||
action := "create"
|
||||
|
||||
for _, oldService := range oldServices {
|
||||
// does this version exist?
|
||||
// no? then default to create
|
||||
if oldService.Version != newService.Version {
|
||||
continue
|
||||
}
|
||||
|
||||
// yes? then it's an update
|
||||
action = "update"
|
||||
|
||||
var nodes []*registry.Node
|
||||
// check the old nodes to see if they've been deleted
|
||||
for _, oldNode := range oldService.Nodes {
|
||||
var seen bool
|
||||
for _, newNode := range newService.Nodes {
|
||||
if newNode.Id == oldNode.Id {
|
||||
seen = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// does the old node exist in the new set of nodes
|
||||
// no? then delete that shit
|
||||
if !seen {
|
||||
nodes = append(nodes, oldNode)
|
||||
}
|
||||
}
|
||||
|
||||
// it's an update rather than creation
|
||||
if len(nodes) > 0 {
|
||||
delService := regutil.CopyService(oldService)
|
||||
delService.Nodes = nodes
|
||||
cw.next <- ®istry.Result{Action: "delete", Service: delService}
|
||||
}
|
||||
}
|
||||
|
||||
cw.next <- ®istry.Result{Action: action, Service: newService}
|
||||
}
|
||||
|
||||
// Now check old versions that may not be in new services map
|
||||
for _, old := range rservices[serviceName] {
|
||||
// old version does not exist in new version map
|
||||
// kill it with fire!
|
||||
if _, ok := serviceMap[old.Version]; !ok {
|
||||
cw.next <- ®istry.Result{Action: "delete", Service: old}
|
||||
}
|
||||
}
|
||||
|
||||
cw.Lock()
|
||||
cw.services[serviceName] = newServices
|
||||
cw.Unlock()
|
||||
}
|
||||
|
||||
func (cw *consulWatcher) handle(idx uint64, data interface{}) {
|
||||
services, ok := data.(map[string][]string)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// add new watchers
|
||||
for service := range services {
|
||||
// Filter on watch options
|
||||
// wo.Service: Only watch services we care about
|
||||
if len(cw.wo.Service) > 0 && service != cw.wo.Service {
|
||||
continue
|
||||
}
|
||||
|
||||
if _, ok := cw.watchers[service]; ok {
|
||||
continue
|
||||
}
|
||||
wp, err := watch.Parse(map[string]interface{}{
|
||||
"type": "service",
|
||||
"service": service,
|
||||
})
|
||||
if err == nil {
|
||||
wp.Handler = cw.serviceHandler
|
||||
go wp.RunWithClientAndHclog(cw.r.Client(), wp.Logger)
|
||||
cw.watchers[service] = wp
|
||||
cw.next <- ®istry.Result{Action: "create", Service: ®istry.Service{Name: service}}
|
||||
}
|
||||
}
|
||||
|
||||
cw.RLock()
|
||||
// make a copy
|
||||
rservices := make(map[string][]*registry.Service)
|
||||
for k, v := range cw.services {
|
||||
rservices[k] = v
|
||||
}
|
||||
cw.RUnlock()
|
||||
|
||||
// remove unknown services from registry
|
||||
// save the things we want to delete
|
||||
deleted := make(map[string][]*registry.Service)
|
||||
|
||||
for service := range rservices {
|
||||
if _, ok := services[service]; !ok {
|
||||
cw.Lock()
|
||||
// save this before deleting
|
||||
deleted[service] = cw.services[service]
|
||||
delete(cw.services, service)
|
||||
cw.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// remove unknown services from watchers
|
||||
for service, w := range cw.watchers {
|
||||
if _, ok := services[service]; !ok {
|
||||
w.Stop()
|
||||
delete(cw.watchers, service)
|
||||
for _, oldService := range deleted[service] {
|
||||
// send a delete for the service nodes that we're removing
|
||||
cw.next <- ®istry.Result{Action: "delete", Service: oldService}
|
||||
}
|
||||
// sent the empty list as the last resort to indicate to delete the entire service
|
||||
cw.next <- ®istry.Result{Action: "delete", Service: ®istry.Service{Name: service}}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (cw *consulWatcher) Next() (*registry.Result, error) {
|
||||
select {
|
||||
case <-cw.exit:
|
||||
return nil, registry.ErrWatcherStopped
|
||||
case r, ok := <-cw.next:
|
||||
if !ok {
|
||||
return nil, registry.ErrWatcherStopped
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (cw *consulWatcher) Stop() {
|
||||
select {
|
||||
case <-cw.exit:
|
||||
return
|
||||
default:
|
||||
close(cw.exit)
|
||||
if cw.wp == nil {
|
||||
return
|
||||
}
|
||||
cw.wp.Stop()
|
||||
|
||||
// drain results
|
||||
for {
|
||||
select {
|
||||
case <-cw.next:
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/registry/etcd/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/registry/etcd/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
423
vendor/github.com/go-micro/plugins/v4/registry/etcd/etcd.go
generated
vendored
Normal file
423
vendor/github.com/go-micro/plugins/v4/registry/etcd/etcd.go
generated
vendored
Normal file
@@ -0,0 +1,423 @@
|
||||
// Package etcd provides an etcd service registry
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
hash "github.com/mitchellh/hashstructure"
|
||||
"go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/util/cmd"
|
||||
"go.etcd.io/etcd/api/v3/v3rpc/rpctypes"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
prefix = "/micro/registry/"
|
||||
)
|
||||
|
||||
type etcdRegistry struct {
|
||||
client *clientv3.Client
|
||||
options registry.Options
|
||||
|
||||
sync.RWMutex
|
||||
register map[string]uint64
|
||||
leases map[string]clientv3.LeaseID
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmd.DefaultRegistries["etcd"] = NewRegistry
|
||||
}
|
||||
|
||||
func NewRegistry(opts ...registry.Option) registry.Registry {
|
||||
e := &etcdRegistry{
|
||||
options: registry.Options{},
|
||||
register: make(map[string]uint64),
|
||||
leases: make(map[string]clientv3.LeaseID),
|
||||
}
|
||||
username, password := os.Getenv("ETCD_USERNAME"), os.Getenv("ETCD_PASSWORD")
|
||||
if len(username) > 0 && len(password) > 0 {
|
||||
opts = append(opts, Auth(username, password))
|
||||
}
|
||||
address := os.Getenv("MICRO_REGISTRY_ADDRESS")
|
||||
if len(address) > 0 {
|
||||
opts = append(opts, registry.Addrs(address))
|
||||
}
|
||||
configure(e, opts...)
|
||||
return e
|
||||
}
|
||||
|
||||
func configure(e *etcdRegistry, opts ...registry.Option) error {
|
||||
config := clientv3.Config{
|
||||
Endpoints: []string{"127.0.0.1:2379"},
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&e.options)
|
||||
}
|
||||
|
||||
if e.options.Timeout == 0 {
|
||||
e.options.Timeout = 5 * time.Second
|
||||
}
|
||||
|
||||
if e.options.Logger == nil {
|
||||
e.options.Logger = logger.DefaultLogger
|
||||
}
|
||||
|
||||
config.DialTimeout = e.options.Timeout
|
||||
|
||||
if e.options.Secure || e.options.TLSConfig != nil {
|
||||
tlsConfig := e.options.TLSConfig
|
||||
if tlsConfig == nil {
|
||||
tlsConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
}
|
||||
|
||||
config.TLS = tlsConfig
|
||||
}
|
||||
|
||||
if e.options.Context != nil {
|
||||
u, ok := e.options.Context.Value(authKey{}).(*authCreds)
|
||||
if ok {
|
||||
config.Username = u.Username
|
||||
config.Password = u.Password
|
||||
}
|
||||
cfg, ok := e.options.Context.Value(logConfigKey{}).(*zap.Config)
|
||||
if ok && cfg != nil {
|
||||
config.LogConfig = cfg
|
||||
}
|
||||
}
|
||||
|
||||
var cAddrs []string
|
||||
|
||||
for _, address := range e.options.Addrs {
|
||||
if len(address) == 0 {
|
||||
continue
|
||||
}
|
||||
addr, port, err := net.SplitHostPort(address)
|
||||
if ae, ok := err.(*net.AddrError); ok && ae.Err == "missing port in address" {
|
||||
port = "2379"
|
||||
addr = address
|
||||
cAddrs = append(cAddrs, net.JoinHostPort(addr, port))
|
||||
} else if err == nil {
|
||||
cAddrs = append(cAddrs, net.JoinHostPort(addr, port))
|
||||
}
|
||||
}
|
||||
|
||||
// if we got addrs then we'll update
|
||||
if len(cAddrs) > 0 {
|
||||
config.Endpoints = cAddrs
|
||||
}
|
||||
|
||||
cli, err := clientv3.New(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.client = cli
|
||||
return nil
|
||||
}
|
||||
|
||||
func encode(s *registry.Service) string {
|
||||
b, _ := json.Marshal(s)
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func decode(ds []byte) *registry.Service {
|
||||
var s *registry.Service
|
||||
json.Unmarshal(ds, &s)
|
||||
return s
|
||||
}
|
||||
|
||||
func nodePath(s, id string) string {
|
||||
service := strings.Replace(s, "/", "-", -1)
|
||||
node := strings.Replace(id, "/", "-", -1)
|
||||
return path.Join(prefix, service, node)
|
||||
}
|
||||
|
||||
func servicePath(s string) string {
|
||||
return path.Join(prefix, strings.Replace(s, "/", "-", -1))
|
||||
}
|
||||
|
||||
func (e *etcdRegistry) Init(opts ...registry.Option) error {
|
||||
return configure(e, opts...)
|
||||
}
|
||||
|
||||
func (e *etcdRegistry) Options() registry.Options {
|
||||
return e.options
|
||||
}
|
||||
|
||||
func (e *etcdRegistry) registerNode(s *registry.Service, node *registry.Node, opts ...registry.RegisterOption) error {
|
||||
if len(s.Nodes) == 0 {
|
||||
return errors.New("Require at least one node")
|
||||
}
|
||||
|
||||
// check existing lease cache
|
||||
e.RLock()
|
||||
leaseID, ok := e.leases[s.Name+node.Id]
|
||||
e.RUnlock()
|
||||
|
||||
log := e.options.Logger
|
||||
|
||||
if !ok {
|
||||
// missing lease, check if the key exists
|
||||
ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout)
|
||||
defer cancel()
|
||||
|
||||
// look for the existing key
|
||||
rsp, err := e.client.Get(ctx, nodePath(s.Name, node.Id), clientv3.WithSerializable())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get the existing lease
|
||||
for _, kv := range rsp.Kvs {
|
||||
if kv.Lease > 0 {
|
||||
leaseID = clientv3.LeaseID(kv.Lease)
|
||||
|
||||
// decode the existing node
|
||||
srv := decode(kv.Value)
|
||||
if srv == nil || len(srv.Nodes) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// create hash of service; uint64
|
||||
h, err := hash.Hash(srv.Nodes[0], nil)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// save the info
|
||||
e.Lock()
|
||||
e.leases[s.Name+node.Id] = leaseID
|
||||
e.register[s.Name+node.Id] = h
|
||||
e.Unlock()
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var leaseNotFound bool
|
||||
|
||||
// renew the lease if it exists
|
||||
if leaseID > 0 {
|
||||
log.Logf(logger.TraceLevel, "Renewing existing lease for %s %d", s.Name, leaseID)
|
||||
if _, err := e.client.KeepAliveOnce(context.TODO(), leaseID); err != nil {
|
||||
if err != rpctypes.ErrLeaseNotFound {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Logf(logger.TraceLevel, "Lease not found for %s %d", s.Name, leaseID)
|
||||
// lease not found do register
|
||||
leaseNotFound = true
|
||||
}
|
||||
}
|
||||
|
||||
// create hash of service; uint64
|
||||
h, err := hash.Hash(node, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get existing hash for the service node
|
||||
e.Lock()
|
||||
v, ok := e.register[s.Name+node.Id]
|
||||
e.Unlock()
|
||||
|
||||
// the service is unchanged, skip registering
|
||||
if ok && v == h && !leaseNotFound {
|
||||
log.Logf(logger.TraceLevel, "Service %s node %s unchanged skipping registration", s.Name, node.Id)
|
||||
return nil
|
||||
}
|
||||
|
||||
service := ®istry.Service{
|
||||
Name: s.Name,
|
||||
Version: s.Version,
|
||||
Metadata: s.Metadata,
|
||||
Endpoints: s.Endpoints,
|
||||
Nodes: []*registry.Node{node},
|
||||
}
|
||||
|
||||
var options registry.RegisterOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout)
|
||||
defer cancel()
|
||||
|
||||
var lgr *clientv3.LeaseGrantResponse
|
||||
if options.TTL.Seconds() > 0 {
|
||||
// get a lease used to expire keys since we have a ttl
|
||||
lgr, err = e.client.Grant(ctx, int64(options.TTL.Seconds()))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
log.Logf(logger.TraceLevel, "Registering %s id %s with lease %v and leaseID %v and ttl %v", service.Name, node.Id, lgr, lgr.ID, options.TTL)
|
||||
// create an entry for the node
|
||||
if lgr != nil {
|
||||
_, err = e.client.Put(ctx, nodePath(service.Name, node.Id), encode(service), clientv3.WithLease(lgr.ID))
|
||||
} else {
|
||||
_, err = e.client.Put(ctx, nodePath(service.Name, node.Id), encode(service))
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
e.Lock()
|
||||
// save our hash of the service
|
||||
e.register[s.Name+node.Id] = h
|
||||
// save our leaseID of the service
|
||||
if lgr != nil {
|
||||
e.leases[s.Name+node.Id] = lgr.ID
|
||||
}
|
||||
e.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *etcdRegistry) Deregister(s *registry.Service, opts ...registry.DeregisterOption) error {
|
||||
if len(s.Nodes) == 0 {
|
||||
return errors.New("Require at least one node")
|
||||
}
|
||||
|
||||
for _, node := range s.Nodes {
|
||||
e.Lock()
|
||||
// delete our hash of the service
|
||||
delete(e.register, s.Name+node.Id)
|
||||
// delete our lease of the service
|
||||
delete(e.leases, s.Name+node.Id)
|
||||
e.Unlock()
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout)
|
||||
defer cancel()
|
||||
|
||||
e.options.Logger.Logf(logger.TraceLevel, "Deregistering %s id %s", s.Name, node.Id)
|
||||
_, err := e.client.Delete(ctx, nodePath(s.Name, node.Id))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *etcdRegistry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
|
||||
if len(s.Nodes) == 0 {
|
||||
return errors.New("Require at least one node")
|
||||
}
|
||||
|
||||
var gerr error
|
||||
|
||||
// register each node individually
|
||||
for _, node := range s.Nodes {
|
||||
err := e.registerNode(s, node, opts...)
|
||||
if err != nil {
|
||||
gerr = err
|
||||
}
|
||||
}
|
||||
|
||||
return gerr
|
||||
}
|
||||
|
||||
func (e *etcdRegistry) GetService(name string, opts ...registry.GetOption) ([]*registry.Service, error) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout)
|
||||
defer cancel()
|
||||
|
||||
rsp, err := e.client.Get(ctx, servicePath(name)+"/", clientv3.WithPrefix(), clientv3.WithSerializable())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(rsp.Kvs) == 0 {
|
||||
return nil, registry.ErrNotFound
|
||||
}
|
||||
|
||||
serviceMap := map[string]*registry.Service{}
|
||||
|
||||
for _, n := range rsp.Kvs {
|
||||
if sn := decode(n.Value); sn != nil {
|
||||
s, ok := serviceMap[sn.Version]
|
||||
if !ok {
|
||||
s = ®istry.Service{
|
||||
Name: sn.Name,
|
||||
Version: sn.Version,
|
||||
Metadata: sn.Metadata,
|
||||
Endpoints: sn.Endpoints,
|
||||
}
|
||||
serviceMap[s.Version] = s
|
||||
}
|
||||
|
||||
s.Nodes = append(s.Nodes, sn.Nodes...)
|
||||
}
|
||||
}
|
||||
|
||||
services := make([]*registry.Service, 0, len(serviceMap))
|
||||
for _, service := range serviceMap {
|
||||
services = append(services, service)
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (e *etcdRegistry) ListServices(opts ...registry.ListOption) ([]*registry.Service, error) {
|
||||
versions := make(map[string]*registry.Service)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout)
|
||||
defer cancel()
|
||||
|
||||
rsp, err := e.client.Get(ctx, prefix, clientv3.WithPrefix(), clientv3.WithSerializable())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(rsp.Kvs) == 0 {
|
||||
return []*registry.Service{}, nil
|
||||
}
|
||||
|
||||
for _, n := range rsp.Kvs {
|
||||
sn := decode(n.Value)
|
||||
if sn == nil {
|
||||
continue
|
||||
}
|
||||
v, ok := versions[sn.Name+sn.Version]
|
||||
if !ok {
|
||||
versions[sn.Name+sn.Version] = sn
|
||||
continue
|
||||
}
|
||||
// append to service:version nodes
|
||||
v.Nodes = append(v.Nodes, sn.Nodes...)
|
||||
}
|
||||
|
||||
services := make([]*registry.Service, 0, len(versions))
|
||||
for _, service := range versions {
|
||||
services = append(services, service)
|
||||
}
|
||||
|
||||
// sort the services
|
||||
sort.Slice(services, func(i, j int) bool { return services[i].Name < services[j].Name })
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (e *etcdRegistry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) {
|
||||
return newEtcdWatcher(e, e.options.Timeout, opts...)
|
||||
}
|
||||
|
||||
func (e *etcdRegistry) String() string {
|
||||
return "etcd"
|
||||
}
|
||||
37
vendor/github.com/go-micro/plugins/v4/registry/etcd/options.go
generated
vendored
Normal file
37
vendor/github.com/go-micro/plugins/v4/registry/etcd/options.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go-micro.dev/v4/registry"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type authKey struct{}
|
||||
|
||||
type logConfigKey struct{}
|
||||
|
||||
type authCreds struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
// Auth allows you to specify username/password.
|
||||
func Auth(username, password string) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, authKey{}, &authCreds{Username: username, Password: password})
|
||||
}
|
||||
}
|
||||
|
||||
// LogConfig allows you to set etcd log config.
|
||||
func LogConfig(config *zap.Config) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, logConfigKey{}, config)
|
||||
}
|
||||
}
|
||||
91
vendor/github.com/go-micro/plugins/v4/registry/etcd/watcher.go
generated
vendored
Normal file
91
vendor/github.com/go-micro/plugins/v4/registry/etcd/watcher.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
package etcd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"go-micro.dev/v4/registry"
|
||||
clientv3 "go.etcd.io/etcd/client/v3"
|
||||
)
|
||||
|
||||
type etcdWatcher struct {
|
||||
stop chan bool
|
||||
w clientv3.WatchChan
|
||||
client *clientv3.Client
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func newEtcdWatcher(r *etcdRegistry, timeout time.Duration, opts ...registry.WatchOption) (registry.Watcher, error) {
|
||||
var wo registry.WatchOptions
|
||||
for _, o := range opts {
|
||||
o(&wo)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
stop := make(chan bool, 1)
|
||||
|
||||
go func() {
|
||||
<-stop
|
||||
cancel()
|
||||
}()
|
||||
|
||||
watchPath := prefix
|
||||
if len(wo.Service) > 0 {
|
||||
watchPath = servicePath(wo.Service) + "/"
|
||||
}
|
||||
|
||||
return &etcdWatcher{
|
||||
stop: stop,
|
||||
w: r.client.Watch(ctx, watchPath, clientv3.WithPrefix(), clientv3.WithPrevKV()),
|
||||
client: r.client,
|
||||
timeout: timeout,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (ew *etcdWatcher) Next() (*registry.Result, error) {
|
||||
for wresp := range ew.w {
|
||||
if wresp.Err() != nil {
|
||||
return nil, wresp.Err()
|
||||
}
|
||||
if wresp.Canceled {
|
||||
return nil, errors.New("could not get next")
|
||||
}
|
||||
for _, ev := range wresp.Events {
|
||||
service := decode(ev.Kv.Value)
|
||||
var action string
|
||||
|
||||
switch ev.Type {
|
||||
case clientv3.EventTypePut:
|
||||
if ev.IsCreate() {
|
||||
action = "create"
|
||||
} else if ev.IsModify() {
|
||||
action = "update"
|
||||
}
|
||||
case clientv3.EventTypeDelete:
|
||||
action = "delete"
|
||||
|
||||
// get service from prevKv
|
||||
service = decode(ev.PrevKv.Value)
|
||||
}
|
||||
|
||||
if service == nil {
|
||||
continue
|
||||
}
|
||||
return ®istry.Result{
|
||||
Action: action,
|
||||
Service: service,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("could not get next")
|
||||
}
|
||||
|
||||
func (ew *etcdWatcher) Stop() {
|
||||
select {
|
||||
case <-ew.stop:
|
||||
return
|
||||
default:
|
||||
close(ew.stop)
|
||||
}
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
66
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/README.md
generated
vendored
Normal file
66
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/README.md
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
# Kubernetes Registry Plugin for micro
|
||||
This is a plugin for go-micro that allows you to use Kubernetes as a registry.
|
||||
|
||||
|
||||
## Overview
|
||||
This registry plugin makes use of Annotations and Labels on a Kubernetes pod
|
||||
to build a service discovery mechanism.
|
||||
|
||||
|
||||
## RBAC
|
||||
If your Kubernetes cluster has RBAC enabled, a role and role binding
|
||||
will need to be created to allow this plugin to `list` and `patch` pods.
|
||||
|
||||
A cluster role can be used to specify the `list` and `patch`
|
||||
requirements, while a role binding per namespace can be used to apply
|
||||
the cluster role. The example RBAC configs below assume your Micro-based
|
||||
services are running in the `test` namespace, and the pods that contain
|
||||
the services are using the `micro-services` service account.
|
||||
|
||||
```
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: micro-registry
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
verbs:
|
||||
- list
|
||||
- patch
|
||||
- watch
|
||||
```
|
||||
|
||||
```
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: micro-registry
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: micro-registry
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: micro-services
|
||||
namespace: test
|
||||
```
|
||||
|
||||
|
||||
## Gotchas
|
||||
* Registering/Deregistering relies on the HOSTNAME Environment Variable, which inside a pod
|
||||
is the place where it can be retrieved from. (This needs improving)
|
||||
|
||||
|
||||
## Connecting to the Kubernetes API
|
||||
### Within a pod
|
||||
If the `--registry_address` flag is omitted, the plugin will securely connect to
|
||||
the Kubernetes API using the pods "Service Account". No extra configuration is necessary.
|
||||
|
||||
Find out more about service accounts here. http://kubernetes.io/docs/user-guide/accessing-the-cluster/
|
||||
|
||||
### Outside of Kubernetes
|
||||
Some functions of the plugin should work, but its not been heavily tested.
|
||||
Currently no TLS support.
|
||||
220
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/api/request.go
generated
vendored
Normal file
220
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/api/request.go
generated
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
// Package api ...
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/go-micro/plugins/v4/registry/kubernetes/client/watch"
|
||||
)
|
||||
|
||||
// Request is used to construct a http request for the k8s API.
|
||||
type Request struct {
|
||||
client *http.Client
|
||||
header http.Header
|
||||
params url.Values
|
||||
method string
|
||||
host string
|
||||
namespace string
|
||||
|
||||
resource string
|
||||
resourceName *string
|
||||
body io.Reader
|
||||
|
||||
err error
|
||||
}
|
||||
|
||||
// Params is the object to pass in to set parameters
|
||||
// on a request.
|
||||
type Params struct {
|
||||
LabelSelector map[string]string
|
||||
Watch bool
|
||||
}
|
||||
|
||||
// Options ...
|
||||
type Options struct {
|
||||
Host string
|
||||
Namespace string
|
||||
BearerToken *string
|
||||
Client *http.Client
|
||||
}
|
||||
|
||||
// NewRequest creates a k8s api request.
|
||||
func NewRequest(opts *Options) *Request {
|
||||
req := Request{
|
||||
header: make(http.Header),
|
||||
params: make(url.Values),
|
||||
client: opts.Client,
|
||||
namespace: opts.Namespace,
|
||||
host: opts.Host,
|
||||
}
|
||||
|
||||
if opts.BearerToken != nil {
|
||||
req.SetHeader("Authorization", "Bearer "+*opts.BearerToken)
|
||||
}
|
||||
|
||||
return &req
|
||||
}
|
||||
|
||||
// verb sets method.
|
||||
func (r *Request) verb(method string) *Request {
|
||||
r.method = method
|
||||
return r
|
||||
}
|
||||
|
||||
// Get request.
|
||||
func (r *Request) Get() *Request {
|
||||
return r.verb("GET")
|
||||
}
|
||||
|
||||
// Post request.
|
||||
func (r *Request) Post() *Request {
|
||||
return r.verb("POST")
|
||||
}
|
||||
|
||||
// Put request.
|
||||
func (r *Request) Put() *Request {
|
||||
return r.verb("PUT")
|
||||
}
|
||||
|
||||
// Patch request
|
||||
// https://github.com/kubernetes/kubernetes/blob/master/docs/devel/api-conventions.md#patch-operations
|
||||
func (r *Request) Patch() *Request {
|
||||
return r.verb("PATCH").SetHeader("Content-Type", "application/strategic-merge-patch+json")
|
||||
}
|
||||
|
||||
// Delete request.
|
||||
func (r *Request) Delete() *Request {
|
||||
return r.verb("DELETE")
|
||||
}
|
||||
|
||||
// Namespace is to set the namespace to operate on.
|
||||
func (r *Request) Namespace(s string) *Request {
|
||||
r.namespace = s
|
||||
return r
|
||||
}
|
||||
|
||||
// Resource is the type of resource the operation is
|
||||
// for, such as "services", "endpoints" or "pods".
|
||||
func (r *Request) Resource(s string) *Request {
|
||||
r.resource = s
|
||||
return r
|
||||
}
|
||||
|
||||
// Name is for targeting a specific resource by id.
|
||||
func (r *Request) Name(s string) *Request {
|
||||
r.resourceName = &s
|
||||
return r
|
||||
}
|
||||
|
||||
// Body pass in a body to set, this is for POST, PUT
|
||||
// and PATCH requests.
|
||||
func (r *Request) Body(in interface{}) *Request {
|
||||
b := new(bytes.Buffer)
|
||||
if err := json.NewEncoder(b).Encode(&in); err != nil {
|
||||
r.err = err
|
||||
return r
|
||||
}
|
||||
|
||||
r.body = b
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// Params isused to set parameters on a request.
|
||||
func (r *Request) Params(p *Params) *Request {
|
||||
for k, v := range p.LabelSelector {
|
||||
// create new key=value pair
|
||||
value := fmt.Sprintf("%s=%s", k, v)
|
||||
// check if there's an existing value
|
||||
if label := r.params.Get("labelSelector"); len(label) > 0 {
|
||||
value = fmt.Sprintf("%s,%s", label, value)
|
||||
}
|
||||
// set and overwrite the value
|
||||
r.params.Set("labelSelector", value)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// SetHeader sets a header on a request with
|
||||
// a `key` and `value`.
|
||||
func (r *Request) SetHeader(key, value string) *Request {
|
||||
r.header.Add(key, value)
|
||||
return r
|
||||
}
|
||||
|
||||
// request builds the http.Request from the options.
|
||||
func (r *Request) request() (*http.Request, error) {
|
||||
url := fmt.Sprintf("%s/api/v1/namespaces/%s/%s/", r.host, r.namespace, r.resource)
|
||||
|
||||
// append resourceName if it is present
|
||||
if r.resourceName != nil {
|
||||
url += *r.resourceName
|
||||
}
|
||||
|
||||
// append any query params
|
||||
if len(r.params) > 0 {
|
||||
url += "?" + r.params.Encode()
|
||||
}
|
||||
|
||||
// build request
|
||||
req, err := http.NewRequest(r.method, url, r.body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// set headers on request
|
||||
req.Header = r.header
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// Do builds and triggers the request.
|
||||
func (r *Request) Do() *Response {
|
||||
if r.err != nil {
|
||||
return &Response{
|
||||
err: r.err,
|
||||
}
|
||||
}
|
||||
|
||||
req, err := r.request()
|
||||
if err != nil {
|
||||
return &Response{
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
res, err := r.client.Do(req)
|
||||
if err != nil {
|
||||
return &Response{
|
||||
err: err,
|
||||
}
|
||||
}
|
||||
|
||||
// return res, err
|
||||
return newResponse(res, err)
|
||||
}
|
||||
|
||||
// Watch builds and triggers the request, but will watch instead of return
|
||||
// an object.
|
||||
func (r *Request) Watch() (watch.Watch, error) {
|
||||
if r.err != nil {
|
||||
return nil, r.err
|
||||
}
|
||||
|
||||
r.params.Set("watch", "true")
|
||||
|
||||
req, err := r.request()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
w, err := watch.NewBodyWatcher(req, r.client)
|
||||
|
||||
return w, err
|
||||
}
|
||||
90
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/api/response.go
generated
vendored
Normal file
90
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/api/response.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
log "go-micro.dev/v4/logger"
|
||||
)
|
||||
|
||||
// Errors ...
|
||||
var (
|
||||
ErrNoPodName = errors.New("no pod name provided")
|
||||
ErrNotFound = errors.New("pod not found")
|
||||
ErrDecode = errors.New("error decoding")
|
||||
ErrOther = errors.New("unspecified error occurred in k8s registry")
|
||||
)
|
||||
|
||||
// Response ...
|
||||
type Response struct {
|
||||
res *http.Response
|
||||
err error
|
||||
}
|
||||
|
||||
// Error returns an error.
|
||||
func (r *Response) Error() error {
|
||||
return r.err
|
||||
}
|
||||
|
||||
// StatusCode returns status code for response.
|
||||
func (r *Response) StatusCode() int {
|
||||
return r.res.StatusCode
|
||||
}
|
||||
|
||||
// Decode decodes body into `data`.
|
||||
func (r *Response) Decode(data interface{}) error {
|
||||
if r.err != nil {
|
||||
return r.err
|
||||
}
|
||||
|
||||
var err error
|
||||
defer func() {
|
||||
nerr := r.res.Body.Close()
|
||||
if err != nil {
|
||||
err = nerr
|
||||
}
|
||||
}()
|
||||
|
||||
decoder := json.NewDecoder(r.res.Body)
|
||||
|
||||
if err := decoder.Decode(&data); err != nil {
|
||||
return errors.Wrap(ErrDecode, err.Error())
|
||||
}
|
||||
|
||||
return r.err
|
||||
}
|
||||
|
||||
func newResponse(r *http.Response, err error) *Response {
|
||||
resp := &Response{
|
||||
res: r,
|
||||
err: err,
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return resp
|
||||
}
|
||||
|
||||
// Check if request is successful.
|
||||
s := resp.res.StatusCode
|
||||
if s == http.StatusOK || s == http.StatusCreated || s == http.StatusNoContent {
|
||||
return resp
|
||||
}
|
||||
|
||||
if resp.res.StatusCode == http.StatusNotFound {
|
||||
resp.err = ErrNotFound
|
||||
return resp
|
||||
}
|
||||
|
||||
log.Errorf("K8s: request failed with code %v", resp.res.StatusCode)
|
||||
|
||||
b, err := io.ReadAll(resp.res.Body)
|
||||
if err == nil {
|
||||
log.Errorf("K8s: request failed with body: %s", string(b))
|
||||
}
|
||||
|
||||
resp.err = ErrOther
|
||||
|
||||
return resp
|
||||
}
|
||||
142
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/client.go
generated
vendored
Normal file
142
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/client.go
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
// Package client is the kubernetes registry client.
|
||||
package client
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"go-micro.dev/v4/logger"
|
||||
|
||||
"github.com/go-micro/plugins/v4/registry/kubernetes/client/api"
|
||||
"github.com/go-micro/plugins/v4/registry/kubernetes/client/watch"
|
||||
)
|
||||
|
||||
var (
|
||||
serviceAccountPath = "/var/run/secrets/kubernetes.io/serviceaccount"
|
||||
|
||||
// ErrReadNamespace error when failed to read namespace.
|
||||
ErrReadNamespace = errors.New("could not read namespace from service account secret")
|
||||
)
|
||||
|
||||
// Client ...
|
||||
type client struct {
|
||||
opts *api.Options
|
||||
}
|
||||
|
||||
// NewClientByHost sets up a client by host.
|
||||
func NewClientByHost(host string) Kubernetes {
|
||||
tr := &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
//nolint:gosec
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
DisableCompression: true,
|
||||
}
|
||||
|
||||
c := &http.Client{
|
||||
Transport: tr,
|
||||
}
|
||||
|
||||
return &client{
|
||||
opts: &api.Options{
|
||||
Client: c,
|
||||
Host: host,
|
||||
Namespace: "default",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewClientInCluster should work similarly to the official api
|
||||
// NewInClient by setting up a client configuration for use within
|
||||
// a k8s pod.
|
||||
func NewClientInCluster() Kubernetes {
|
||||
host := "https://" + os.Getenv("KUBERNETES_SERVICE_HOST") + ":" + os.Getenv("KUBERNETES_SERVICE_PORT")
|
||||
|
||||
s, err := os.Stat(serviceAccountPath)
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
if s == nil || !s.IsDir() {
|
||||
logger.Fatal(errors.New("no k8s service account found"))
|
||||
}
|
||||
|
||||
t, err := os.ReadFile(path.Join(serviceAccountPath, "token"))
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
token := string(t)
|
||||
|
||||
ns, err := detectNamespace()
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
crt, err := CertPoolFromFile(path.Join(serviceAccountPath, "ca.crt"))
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
c := &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
RootCAs: crt,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
},
|
||||
DisableCompression: true,
|
||||
},
|
||||
}
|
||||
|
||||
return &client{
|
||||
opts: &api.Options{
|
||||
Client: c,
|
||||
Host: host,
|
||||
Namespace: ns,
|
||||
BearerToken: &token,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ListPods ...
|
||||
func (c *client) ListPods(labels map[string]string) (*PodList, error) {
|
||||
var pods PodList
|
||||
err := api.NewRequest(c.opts).Get().Resource("pods").Params(&api.Params{LabelSelector: labels}).Do().Decode(&pods)
|
||||
|
||||
return &pods, err
|
||||
}
|
||||
|
||||
// UpdatePod ...
|
||||
func (c *client) UpdatePod(name string, p *Pod) (*Pod, error) {
|
||||
var pod Pod
|
||||
err := api.NewRequest(c.opts).Patch().Resource("pods").Name(name).Body(p).Do().Decode(&pod)
|
||||
|
||||
return &pod, err
|
||||
}
|
||||
|
||||
// WatchPods ...
|
||||
func (c *client) WatchPods(labels map[string]string) (watch.Watch, error) {
|
||||
return api.NewRequest(c.opts).Get().Resource("pods").Params(&api.Params{LabelSelector: labels}).Watch()
|
||||
}
|
||||
|
||||
func detectNamespace() (string, error) {
|
||||
nsPath := path.Join(serviceAccountPath, "namespace")
|
||||
|
||||
// Make sure it's a file and we can read it
|
||||
if s, err := os.Stat(nsPath); err != nil {
|
||||
return "", err
|
||||
} else if s.IsDir() {
|
||||
return "", ErrReadNamespace
|
||||
}
|
||||
|
||||
// Read the file, and cast to a string
|
||||
ns, err := os.ReadFile(path.Clean(nsPath))
|
||||
if err != nil {
|
||||
return string(ns), err
|
||||
}
|
||||
|
||||
return string(ns), nil
|
||||
}
|
||||
35
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/kubernetes.go
generated
vendored
Normal file
35
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/kubernetes.go
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
package client
|
||||
|
||||
import "github.com/go-micro/plugins/v4/registry/kubernetes/client/watch"
|
||||
|
||||
// Kubernetes ...
|
||||
type Kubernetes interface {
|
||||
ListPods(labels map[string]string) (*PodList, error)
|
||||
UpdatePod(podName string, pod *Pod) (*Pod, error)
|
||||
WatchPods(labels map[string]string) (watch.Watch, error)
|
||||
}
|
||||
|
||||
// PodList ...
|
||||
type PodList struct {
|
||||
Items []Pod `json:"items"`
|
||||
}
|
||||
|
||||
// Pod is the top level item for a pod.
|
||||
type Pod struct {
|
||||
Metadata *Meta `json:"metadata"`
|
||||
Status *Status `json:"status"`
|
||||
}
|
||||
|
||||
// Meta ...
|
||||
type Meta struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Labels map[string]*string `json:"labels,omitempty"`
|
||||
Annotations map[string]*string `json:"annotations,omitempty"`
|
||||
DeletionTimestamp string `json:"deletionTimestamp,omitempty"`
|
||||
}
|
||||
|
||||
// Status ...
|
||||
type Status struct {
|
||||
PodIP string `json:"podIP"`
|
||||
Phase string `json:"phase"`
|
||||
}
|
||||
87
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/utils.go
generated
vendored
Normal file
87
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/utils.go
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// COPIED FROM
|
||||
// https://github.com/kubernetes/kubernetes/blob/7a725418af4661067b56506faabc2d44c6d7703a/pkg/util/crypto/crypto.go
|
||||
|
||||
// CertPoolFromFile returns an x509.CertPool containing the certificates in
|
||||
// the given PEM-encoded file. Returns an error if the file could not be read,
|
||||
// a certificate could not be parsed, or if the file does not contain any certificates.
|
||||
func CertPoolFromFile(filename string) (*x509.CertPool, error) {
|
||||
certs, err := certificatesFromFile(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pool := x509.NewCertPool()
|
||||
for _, cert := range certs {
|
||||
pool.AddCert(cert)
|
||||
}
|
||||
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
// certificatesFromFile returns the x509.Certificates contained in the given
|
||||
// PEM-encoded file. Returns an error if the file could not be read, a
|
||||
// certificate could not be parsed, or if the file does not contain any certificates.
|
||||
func certificatesFromFile(file string) ([]*x509.Certificate, error) {
|
||||
if len(file) == 0 {
|
||||
return nil, errors.New("error reading certificates from an empty filename")
|
||||
}
|
||||
|
||||
pemBlock, err := os.ReadFile(filepath.Clean(file))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
certs, err := CertsFromPEM(pemBlock)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "error reading %s", file)
|
||||
}
|
||||
|
||||
return certs, nil
|
||||
}
|
||||
|
||||
// CertsFromPEM returns the x509.Certificates contained in the given PEM-encoded
|
||||
// byte array. Returns an error if a certificate could not be parsed, or if the
|
||||
// data does not contain any certificates.
|
||||
func CertsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) {
|
||||
ok := false
|
||||
certs := []*x509.Certificate{}
|
||||
|
||||
for len(pemCerts) > 0 {
|
||||
var block *pem.Block
|
||||
block, pemCerts = pem.Decode(pemCerts)
|
||||
|
||||
if block == nil {
|
||||
break
|
||||
}
|
||||
|
||||
// Only use PEM "CERTIFICATE" blocks without extra headers
|
||||
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
cert, err := x509.ParseCertificate(block.Bytes)
|
||||
if err != nil {
|
||||
return certs, err
|
||||
}
|
||||
|
||||
certs = append(certs, cert)
|
||||
ok = true
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return certs, errors.New("could not read any certificates")
|
||||
}
|
||||
|
||||
return certs, nil
|
||||
}
|
||||
104
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/watch/body.go
generated
vendored
Normal file
104
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/watch/body.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
package watch
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// bodyWatcher scans the body of a request for chunks.
|
||||
type bodyWatcher struct {
|
||||
ctx context.Context
|
||||
stop context.CancelFunc
|
||||
results chan Event
|
||||
res *http.Response
|
||||
req *http.Request
|
||||
}
|
||||
|
||||
// Changes returns the results channel.
|
||||
func (wr *bodyWatcher) ResultChan() <-chan Event {
|
||||
return wr.results
|
||||
}
|
||||
|
||||
// Stop cancels the request.
|
||||
func (wr *bodyWatcher) Stop() {
|
||||
select {
|
||||
case <-wr.ctx.Done():
|
||||
return
|
||||
default:
|
||||
wr.stop()
|
||||
close(wr.results)
|
||||
}
|
||||
}
|
||||
|
||||
func (wr *bodyWatcher) stream() {
|
||||
reader := bufio.NewReader(wr.res.Body)
|
||||
|
||||
// ignore first few messages from stream,
|
||||
// as they are usually old.
|
||||
var ignore atomic.Bool
|
||||
|
||||
go func() {
|
||||
<-time.After(time.Second)
|
||||
ignore.Store(false)
|
||||
}()
|
||||
|
||||
go func() {
|
||||
//nolint:errcheck
|
||||
defer wr.res.Body.Close()
|
||||
|
||||
for {
|
||||
// Read a line
|
||||
b, err := reader.ReadBytes('\n')
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
|
||||
// Ignore for the first second
|
||||
if ignore.Load() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Send the event
|
||||
var event Event
|
||||
if err := json.Unmarshal(b, &event); err != nil {
|
||||
continue
|
||||
}
|
||||
wr.results <- event
|
||||
}
|
||||
|
||||
// stop the watcher
|
||||
wr.Stop()
|
||||
}()
|
||||
}
|
||||
|
||||
// NewBodyWatcher creates a k8s body watcher for a given http request.
|
||||
func NewBodyWatcher(req *http.Request, client *http.Client) (Watch, error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
req = req.WithContext(ctx)
|
||||
|
||||
//nolint:bodyclose
|
||||
res, err := client.Do(req)
|
||||
if err != nil {
|
||||
cancel()
|
||||
return nil, errors.Wrap(err, "body watcher failed to make http request")
|
||||
}
|
||||
|
||||
wr := &bodyWatcher{
|
||||
ctx: ctx,
|
||||
results: make(chan Event),
|
||||
stop: cancel,
|
||||
req: req,
|
||||
res: res,
|
||||
}
|
||||
|
||||
go wr.stream()
|
||||
|
||||
return wr, nil
|
||||
}
|
||||
27
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/watch/watch.go
generated
vendored
Normal file
27
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/client/watch/watch.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
// Package watch implements the k8s watcher.
|
||||
package watch
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// Watch ...
|
||||
type Watch interface {
|
||||
Stop()
|
||||
ResultChan() <-chan Event
|
||||
}
|
||||
|
||||
// EventType defines the possible types of events.
|
||||
type EventType string
|
||||
|
||||
// EventTypes used.
|
||||
const (
|
||||
Added EventType = "ADDED"
|
||||
Modified EventType = "MODIFIED"
|
||||
Deleted EventType = "DELETED"
|
||||
Error EventType = "ERROR"
|
||||
)
|
||||
|
||||
// Event represents a single event to a watched resource.
|
||||
type Event struct {
|
||||
Type EventType `json:"type"`
|
||||
Object json.RawMessage `json:"object"`
|
||||
}
|
||||
321
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/kubernetes.go
generated
vendored
Normal file
321
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/kubernetes.go
generated
vendored
Normal file
@@ -0,0 +1,321 @@
|
||||
// Package kubernetes provides a kubernetes registry
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/util/cmd"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/go-micro/plugins/v4/registry/kubernetes/client"
|
||||
)
|
||||
|
||||
type kregistry struct {
|
||||
client client.Kubernetes
|
||||
timeout time.Duration
|
||||
options registry.Options
|
||||
}
|
||||
|
||||
var (
|
||||
// used on pods as labels & services to select
|
||||
// eg: svcSelectorPrefix+"svc.name"
|
||||
svcSelectorPrefix = "micro.mu/selector-"
|
||||
svcSelectorValue = "service"
|
||||
|
||||
labelTypeKey = "micro.mu/type"
|
||||
labelTypeValueService = "service"
|
||||
|
||||
// used on k8s services to scope a serialized
|
||||
// micro service by pod name.
|
||||
annotationServiceKeyPrefix = "micro.mu/service-"
|
||||
|
||||
// Pod status.
|
||||
podRunning = "Running"
|
||||
|
||||
// label name regex.
|
||||
labelRe = regexp.MustCompilePOSIX("[-A-Za-z0-9_.]")
|
||||
)
|
||||
|
||||
// Err are all package errors.
|
||||
var (
|
||||
ErrNoHostname = errors.New("failed to get podname from HOSTNAME variable")
|
||||
ErrNoNodesFound = errors.New("you must provide at least one node")
|
||||
)
|
||||
|
||||
// podSelector.
|
||||
var podSelector = map[string]string{
|
||||
labelTypeKey: labelTypeValueService,
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmd.DefaultRegistries["kubernetes"] = NewRegistry
|
||||
}
|
||||
|
||||
func configure(k *kregistry, opts ...registry.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&k.options)
|
||||
}
|
||||
|
||||
// get first host
|
||||
var host string
|
||||
if len(k.options.Addrs) > 0 && len(k.options.Addrs[0]) > 0 {
|
||||
host = k.options.Addrs[0]
|
||||
}
|
||||
|
||||
if k.options.Timeout == 0 {
|
||||
k.options.Timeout = time.Second * 1
|
||||
}
|
||||
|
||||
// if no hosts setup, assume InCluster
|
||||
var c client.Kubernetes
|
||||
if len(host) == 0 {
|
||||
c = client.NewClientInCluster()
|
||||
} else {
|
||||
c = client.NewClientByHost(host)
|
||||
}
|
||||
|
||||
k.client = c
|
||||
k.timeout = k.options.Timeout
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// serviceName generates a valid service name for k8s labels.
|
||||
func serviceName(name string) string {
|
||||
aname := make([]byte, len(name))
|
||||
|
||||
for i, r := range []byte(name) {
|
||||
if !labelRe.Match([]byte{r}) {
|
||||
aname[i] = '_'
|
||||
continue
|
||||
}
|
||||
|
||||
aname[i] = r
|
||||
}
|
||||
|
||||
return string(aname)
|
||||
}
|
||||
|
||||
// Init allows reconfig of options.
|
||||
func (c *kregistry) Init(opts ...registry.Option) error {
|
||||
return configure(c, opts...)
|
||||
}
|
||||
|
||||
// Options returns the registry Options.
|
||||
func (c *kregistry) Options() registry.Options {
|
||||
return c.options
|
||||
}
|
||||
|
||||
// Register sets a service selector label and an annotation with a
|
||||
// serialized version of the service passed in.
|
||||
func (c *kregistry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
|
||||
if len(s.Nodes) == 0 {
|
||||
return ErrNoNodesFound
|
||||
}
|
||||
|
||||
svcName := s.Name
|
||||
|
||||
// TODO: grab podname from somewhere better than this.
|
||||
podName, err := getPodName()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to register")
|
||||
}
|
||||
|
||||
// encode micro service
|
||||
b, err := json.Marshal(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
svc := string(b)
|
||||
|
||||
pod := &client.Pod{
|
||||
Metadata: &client.Meta{
|
||||
Labels: map[string]*string{
|
||||
labelTypeKey: &labelTypeValueService,
|
||||
svcSelectorPrefix + serviceName(svcName): &svcSelectorValue,
|
||||
},
|
||||
Annotations: map[string]*string{
|
||||
annotationServiceKeyPrefix + serviceName(svcName): &svc,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if _, err := c.client.UpdatePod(podName, pod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deregister nils out any things set in Register.
|
||||
func (c *kregistry) Deregister(s *registry.Service, opts ...registry.DeregisterOption) error {
|
||||
if len(s.Nodes) == 0 {
|
||||
return ErrNoNodesFound
|
||||
}
|
||||
|
||||
svcName := s.Name
|
||||
|
||||
// TODO: grab podname from somewhere better than env var.
|
||||
podName, err := getPodName()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to deregister")
|
||||
}
|
||||
|
||||
pod := &client.Pod{
|
||||
Metadata: &client.Meta{
|
||||
Labels: map[string]*string{
|
||||
svcSelectorPrefix + serviceName(svcName): nil,
|
||||
},
|
||||
Annotations: map[string]*string{
|
||||
annotationServiceKeyPrefix + serviceName(svcName): nil,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
if _, err := c.client.UpdatePod(podName, pod); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetService will get all the pods with the given service selector,
|
||||
// and build services from the annotations.
|
||||
func (c *kregistry) GetService(name string, opts ...registry.GetOption) ([]*registry.Service, error) {
|
||||
pods, err := c.client.ListPods(map[string]string{
|
||||
svcSelectorPrefix + serviceName(name): svcSelectorValue,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(pods.Items) == 0 {
|
||||
return nil, registry.ErrNotFound
|
||||
}
|
||||
|
||||
// svcs mapped by version
|
||||
svcs := make(map[string]*registry.Service)
|
||||
|
||||
// loop through items
|
||||
for _, pod := range pods.Items {
|
||||
if pod.Status.Phase != podRunning || pod.Metadata.DeletionTimestamp != "" {
|
||||
continue
|
||||
}
|
||||
// get serialized service from annotation
|
||||
svcStr, ok := pod.Metadata.Annotations[annotationServiceKeyPrefix+serviceName(name)]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
var svc registry.Service
|
||||
|
||||
// unmarshal service string
|
||||
err := json.Unmarshal([]byte(*svcStr), &svc)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not unmarshal service '%s' from pod annotation", name)
|
||||
}
|
||||
|
||||
// merge up pod service & ip with versioned service.
|
||||
vs, ok := svcs[svc.Version]
|
||||
if !ok {
|
||||
svcs[svc.Version] = &svc
|
||||
continue
|
||||
}
|
||||
|
||||
vs.Nodes = append(vs.Nodes, svc.Nodes...)
|
||||
}
|
||||
|
||||
list := make([]*registry.Service, 0, len(svcs))
|
||||
for _, val := range svcs {
|
||||
list = append(list, val)
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// ListServices will list all the service names.
|
||||
func (c *kregistry) ListServices(opts ...registry.ListOption) ([]*registry.Service, error) {
|
||||
pods, err := c.client.ListPods(podSelector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// svcs mapped by name+version
|
||||
svcs := make(map[string]*registry.Service)
|
||||
|
||||
for _, pod := range pods.Items {
|
||||
if pod.Status.Phase != podRunning || pod.Metadata.DeletionTimestamp != "" {
|
||||
continue
|
||||
}
|
||||
|
||||
for k, v := range pod.Metadata.Annotations {
|
||||
if !strings.HasPrefix(k, annotationServiceKeyPrefix) {
|
||||
continue
|
||||
}
|
||||
|
||||
// we have to unmarshal the annotation itself since the
|
||||
// key is encoded to match the regex restriction.
|
||||
var svc registry.Service
|
||||
if err := json.Unmarshal([]byte(*v), &svc); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
s, ok := svcs[svc.Name+svc.Version]
|
||||
if !ok {
|
||||
svcs[svc.Name+svc.Version] = &svc
|
||||
continue
|
||||
}
|
||||
|
||||
// append to service:version nodes
|
||||
s.Nodes = append(s.Nodes, svc.Nodes...)
|
||||
}
|
||||
}
|
||||
|
||||
i := 0
|
||||
list := make([]*registry.Service, len(svcs))
|
||||
|
||||
for _, s := range svcs {
|
||||
list[i] = s
|
||||
i++
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
// Watch returns a kubernetes watcher.
|
||||
func (c *kregistry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) {
|
||||
return newWatcher(c, opts...)
|
||||
}
|
||||
|
||||
func (c *kregistry) String() string {
|
||||
return "kubernetes"
|
||||
}
|
||||
|
||||
// NewRegistry creates a kubernetes registry.
|
||||
func NewRegistry(opts ...registry.Option) registry.Registry {
|
||||
k := &kregistry{
|
||||
options: registry.Options{},
|
||||
}
|
||||
|
||||
//nolint:errcheck,gosec
|
||||
configure(k, opts...)
|
||||
|
||||
return k
|
||||
}
|
||||
|
||||
func getPodName() (string, error) {
|
||||
podName := os.Getenv("HOSTNAME")
|
||||
if len(podName) == 0 {
|
||||
return "", ErrNoHostname
|
||||
}
|
||||
|
||||
return podName, nil
|
||||
}
|
||||
264
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/watcher.go
generated
vendored
Normal file
264
vendor/github.com/go-micro/plugins/v4/registry/kubernetes/watcher.go
generated
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/registry"
|
||||
|
||||
"github.com/go-micro/plugins/v4/registry/kubernetes/client"
|
||||
"github.com/go-micro/plugins/v4/registry/kubernetes/client/watch"
|
||||
)
|
||||
|
||||
var (
|
||||
deleteAction = "delete"
|
||||
)
|
||||
|
||||
type k8sWatcher struct {
|
||||
registry *kregistry
|
||||
watcher watch.Watch
|
||||
next chan *registry.Result
|
||||
|
||||
sync.RWMutex
|
||||
pods map[string]*client.Pod
|
||||
}
|
||||
|
||||
// build a cache of pods when the watcher starts.
|
||||
func (k *k8sWatcher) updateCache() ([]*registry.Result, error) {
|
||||
podList, err := k.registry.client.ListPods(podSelector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var results []*registry.Result
|
||||
|
||||
for _, p := range podList.Items {
|
||||
// Copy to new var as p gets overwritten by the loop
|
||||
pod := p
|
||||
rslts := k.buildPodResults(&pod, nil)
|
||||
results = append(results, rslts...)
|
||||
|
||||
k.Lock()
|
||||
k.pods[pod.Metadata.Name] = &pod
|
||||
k.Unlock()
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// look through pod annotations, compare against cache if present
|
||||
// and return a list of results to send down the wire.
|
||||
func (k *k8sWatcher) buildPodResults(pod *client.Pod, cache *client.Pod) []*registry.Result {
|
||||
var results []*registry.Result
|
||||
|
||||
ignore := make(map[string]bool)
|
||||
|
||||
if pod.Metadata != nil {
|
||||
results, ignore = podBuildResult(pod, cache)
|
||||
}
|
||||
|
||||
// loop through cache annotations to find services
|
||||
// not accounted for above, and "delete" them.
|
||||
if cache != nil && cache.Metadata != nil {
|
||||
for annKey, annVal := range cache.Metadata.Annotations {
|
||||
if ignore[annKey] {
|
||||
continue
|
||||
}
|
||||
|
||||
// check this annotation kv is a service notation
|
||||
if !strings.HasPrefix(annKey, annotationServiceKeyPrefix) {
|
||||
continue
|
||||
}
|
||||
|
||||
rslt := ®istry.Result{Action: deleteAction}
|
||||
|
||||
// unmarshal service notation from annotation value
|
||||
if err := json.Unmarshal([]byte(*annVal), &rslt.Service); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
results = append(results, rslt)
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
// handleEvent will taken an event from the k8s pods API and do the correct
|
||||
// things with the result, based on the local cache.
|
||||
func (k *k8sWatcher) handleEvent(event watch.Event) {
|
||||
var pod client.Pod
|
||||
if err := json.Unmarshal([]byte(event.Object), &pod); err != nil {
|
||||
logger.Error("K8s Watcher: Couldnt unmarshal event object from pod")
|
||||
return
|
||||
}
|
||||
|
||||
//nolint:exhaustive
|
||||
switch event.Type {
|
||||
// Pod was modified
|
||||
case watch.Modified:
|
||||
k.RLock()
|
||||
cache := k.pods[pod.Metadata.Name]
|
||||
k.RUnlock()
|
||||
|
||||
// service could have been added, edited or removed.
|
||||
var results []*registry.Result
|
||||
|
||||
if pod.Status.Phase == podRunning {
|
||||
results = k.buildPodResults(&pod, cache)
|
||||
} else {
|
||||
// passing in cache might not return all results
|
||||
results = k.buildPodResults(&pod, nil)
|
||||
}
|
||||
|
||||
for _, result := range results {
|
||||
// pod isnt running
|
||||
if pod.Status.Phase != podRunning || pod.Metadata.DeletionTimestamp != "" {
|
||||
result.Action = deleteAction
|
||||
}
|
||||
k.next <- result
|
||||
}
|
||||
|
||||
k.Lock()
|
||||
k.pods[pod.Metadata.Name] = &pod
|
||||
k.Unlock()
|
||||
|
||||
return
|
||||
|
||||
// Pod was deleted
|
||||
// passing in cache might not return all results
|
||||
case watch.Deleted:
|
||||
results := k.buildPodResults(&pod, nil)
|
||||
|
||||
for _, result := range results {
|
||||
result.Action = deleteAction
|
||||
k.next <- result
|
||||
}
|
||||
|
||||
k.Lock()
|
||||
delete(k.pods, pod.Metadata.Name)
|
||||
k.Unlock()
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Next will block until a new result comes in.
|
||||
func (k *k8sWatcher) Next() (*registry.Result, error) {
|
||||
r, ok := <-k.next
|
||||
if !ok {
|
||||
return nil, errors.New("result chan closed")
|
||||
}
|
||||
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// Stop will cancel any requests, and close channels.
|
||||
func (k *k8sWatcher) Stop() {
|
||||
k.watcher.Stop()
|
||||
|
||||
select {
|
||||
case <-k.next:
|
||||
return
|
||||
default:
|
||||
close(k.next)
|
||||
}
|
||||
}
|
||||
|
||||
func newWatcher(kr *kregistry, opts ...registry.WatchOption) (registry.Watcher, error) {
|
||||
var wo registry.WatchOptions
|
||||
for _, o := range opts {
|
||||
o(&wo)
|
||||
}
|
||||
|
||||
selector := podSelector
|
||||
if len(wo.Service) > 0 {
|
||||
selector = map[string]string{
|
||||
svcSelectorPrefix + serviceName(wo.Service): svcSelectorValue,
|
||||
}
|
||||
}
|
||||
|
||||
// Create watch request
|
||||
watcher, err := kr.client.WatchPods(selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
k := &k8sWatcher{
|
||||
registry: kr,
|
||||
watcher: watcher,
|
||||
next: make(chan *registry.Result),
|
||||
pods: make(map[string]*client.Pod),
|
||||
}
|
||||
|
||||
// update cache, but dont emit changes
|
||||
if _, err := k.updateCache(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// range over watch request changes, and invoke
|
||||
// the update event
|
||||
go func() {
|
||||
for event := range watcher.ResultChan() {
|
||||
k.handleEvent(event)
|
||||
}
|
||||
|
||||
k.Stop()
|
||||
}()
|
||||
|
||||
return k, nil
|
||||
}
|
||||
|
||||
func podBuildResult(pod *client.Pod, cache *client.Pod) ([]*registry.Result, map[string]bool) {
|
||||
results := make([]*registry.Result, 0, len(pod.Metadata.Annotations))
|
||||
ignore := make(map[string]bool)
|
||||
|
||||
for annKey, annVal := range pod.Metadata.Annotations {
|
||||
// check this annotation kv is a service notation
|
||||
if !strings.HasPrefix(annKey, annotationServiceKeyPrefix) {
|
||||
continue
|
||||
}
|
||||
|
||||
if annVal == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// ignore when we check the cached annotations
|
||||
// as we take care of it here
|
||||
ignore[annKey] = true
|
||||
|
||||
// compare against cache.
|
||||
var (
|
||||
cacheExists bool
|
||||
cav *string
|
||||
)
|
||||
|
||||
if cache != nil && cache.Metadata != nil {
|
||||
cav, cacheExists = cache.Metadata.Annotations[annKey]
|
||||
if cacheExists && cav != nil && cav == annVal {
|
||||
// service notation exists and is identical -
|
||||
// no change result required.
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
rslt := ®istry.Result{}
|
||||
if cacheExists {
|
||||
rslt.Action = "update"
|
||||
} else {
|
||||
rslt.Action = "create"
|
||||
}
|
||||
|
||||
// unmarshal service notation from annotation value
|
||||
if err := json.Unmarshal([]byte(*annVal), &rslt.Service); err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
results = append(results, rslt)
|
||||
}
|
||||
|
||||
return results, ignore
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/registry/mdns/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/registry/mdns/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
16
vendor/github.com/go-micro/plugins/v4/registry/mdns/mdns.go
generated
vendored
Normal file
16
vendor/github.com/go-micro/plugins/v4/registry/mdns/mdns.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
// Package mdns provides a multicast dns registry
|
||||
package mdns
|
||||
|
||||
import (
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/util/cmd"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd.DefaultRegistries["mdns"] = NewRegistry
|
||||
}
|
||||
|
||||
// NewRegistry returns a new mdns registry.
|
||||
func NewRegistry(opts ...registry.Option) registry.Registry {
|
||||
return registry.NewRegistry(opts...)
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/registry/memory/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/registry/memory/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
288
vendor/github.com/go-micro/plugins/v4/registry/memory/memory.go
generated
vendored
Normal file
288
vendor/github.com/go-micro/plugins/v4/registry/memory/memory.go
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
// Package memory provides an in-memory registry
|
||||
package memory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
var (
|
||||
sendEventTime = 10 * time.Millisecond
|
||||
ttlPruneTime = time.Second
|
||||
)
|
||||
|
||||
type node struct {
|
||||
*registry.Node
|
||||
TTL time.Duration
|
||||
LastSeen time.Time
|
||||
}
|
||||
|
||||
type record struct {
|
||||
Name string
|
||||
Version string
|
||||
Metadata map[string]string
|
||||
Nodes map[string]*node
|
||||
Endpoints []*registry.Endpoint
|
||||
}
|
||||
|
||||
type Registry struct {
|
||||
options registry.Options
|
||||
|
||||
sync.RWMutex
|
||||
records map[string]map[string]*record
|
||||
watchers map[string]*Watcher
|
||||
}
|
||||
|
||||
func NewRegistry(opts ...registry.Option) registry.Registry {
|
||||
options := registry.Options{
|
||||
Context: context.Background(),
|
||||
Logger: logger.DefaultLogger,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
records := getServiceRecords(options.Context)
|
||||
if records == nil {
|
||||
records = make(map[string]map[string]*record)
|
||||
}
|
||||
|
||||
reg := &Registry{
|
||||
options: options,
|
||||
records: records,
|
||||
watchers: make(map[string]*Watcher),
|
||||
}
|
||||
|
||||
go reg.ttlPrune()
|
||||
|
||||
return reg
|
||||
}
|
||||
|
||||
func (m *Registry) ttlPrune() {
|
||||
prune := time.NewTicker(ttlPruneTime)
|
||||
defer prune.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-prune.C:
|
||||
m.Lock()
|
||||
for name, records := range m.records {
|
||||
for version, record := range records {
|
||||
for id, n := range record.Nodes {
|
||||
if n.TTL != 0 && time.Since(n.LastSeen) > n.TTL {
|
||||
m.options.Logger.Logf(logger.DebugLevel, "Registry TTL expired for node %s of service %s", n.Id, name)
|
||||
delete(m.records[name][version].Nodes, id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Registry) sendEvent(r *registry.Result) {
|
||||
m.RLock()
|
||||
watchers := make([]*Watcher, 0, len(m.watchers))
|
||||
for _, w := range m.watchers {
|
||||
watchers = append(watchers, w)
|
||||
}
|
||||
m.RUnlock()
|
||||
|
||||
for _, w := range watchers {
|
||||
select {
|
||||
case <-w.exit:
|
||||
m.Lock()
|
||||
delete(m.watchers, w.id)
|
||||
m.Unlock()
|
||||
default:
|
||||
select {
|
||||
case w.res <- r:
|
||||
case <-time.After(sendEventTime):
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Registry) Init(opts ...registry.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&m.options)
|
||||
}
|
||||
|
||||
// add services
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
records := getServiceRecords(m.options.Context)
|
||||
for name, record := range records {
|
||||
// add a whole new service including all of its versions
|
||||
if _, ok := m.records[name]; !ok {
|
||||
m.records[name] = record
|
||||
continue
|
||||
}
|
||||
// add the versions of the service we dont track yet
|
||||
for version, r := range record {
|
||||
if _, ok := m.records[name][version]; !ok {
|
||||
m.records[name][version] = r
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Registry) Options() registry.Options {
|
||||
return m.options
|
||||
}
|
||||
|
||||
func (m *Registry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
log := m.options.Logger
|
||||
|
||||
var options registry.RegisterOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
r := serviceToRecord(s, options.TTL)
|
||||
|
||||
if _, ok := m.records[s.Name]; !ok {
|
||||
m.records[s.Name] = make(map[string]*record)
|
||||
}
|
||||
|
||||
if _, ok := m.records[s.Name][s.Version]; !ok {
|
||||
m.records[s.Name][s.Version] = r
|
||||
log.Logf(logger.DebugLevel, "Registry added new service: %s, version: %s", s.Name, s.Version)
|
||||
go m.sendEvent(®istry.Result{Action: "update", Service: s})
|
||||
return nil
|
||||
}
|
||||
|
||||
addedNodes := false
|
||||
for _, n := range s.Nodes {
|
||||
if _, ok := m.records[s.Name][s.Version].Nodes[n.Id]; !ok {
|
||||
addedNodes = true
|
||||
metadata := make(map[string]string)
|
||||
for k, v := range n.Metadata {
|
||||
metadata[k] = v
|
||||
m.records[s.Name][s.Version].Nodes[n.Id] = &node{
|
||||
Node: ®istry.Node{
|
||||
Id: n.Id,
|
||||
Address: n.Address,
|
||||
Metadata: metadata,
|
||||
},
|
||||
TTL: options.TTL,
|
||||
LastSeen: time.Now(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if addedNodes {
|
||||
log.Logf(logger.DebugLevel, "Registry added new node to service: %s, version: %s", s.Name, s.Version)
|
||||
go m.sendEvent(®istry.Result{Action: "update", Service: s})
|
||||
return nil
|
||||
}
|
||||
|
||||
// refresh TTL and timestamp
|
||||
for _, n := range s.Nodes {
|
||||
log.Logf(logger.DebugLevel, "Updated registration for service: %s, version: %s", s.Name, s.Version)
|
||||
m.records[s.Name][s.Version].Nodes[n.Id].TTL = options.TTL
|
||||
m.records[s.Name][s.Version].Nodes[n.Id].LastSeen = time.Now()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Registry) Deregister(s *registry.Service, opts ...registry.DeregisterOption) error {
|
||||
m.Lock()
|
||||
defer m.Unlock()
|
||||
|
||||
log := m.options.Logger
|
||||
|
||||
if _, ok := m.records[s.Name]; ok {
|
||||
if _, ok := m.records[s.Name][s.Version]; ok {
|
||||
for _, n := range s.Nodes {
|
||||
if _, ok := m.records[s.Name][s.Version].Nodes[n.Id]; ok {
|
||||
log.Logf(logger.DebugLevel, "Registry removed node from service: %s, version: %s", s.Name, s.Version)
|
||||
delete(m.records[s.Name][s.Version].Nodes, n.Id)
|
||||
}
|
||||
}
|
||||
if len(m.records[s.Name][s.Version].Nodes) == 0 {
|
||||
delete(m.records[s.Name], s.Version)
|
||||
log.Logf(logger.DebugLevel, "Registry removed service: %s, version: %s", s.Name, s.Version)
|
||||
}
|
||||
}
|
||||
if len(m.records[s.Name]) == 0 {
|
||||
delete(m.records, s.Name)
|
||||
log.Logf(logger.DebugLevel, "Registry removed service: %s", s.Name)
|
||||
}
|
||||
go m.sendEvent(®istry.Result{Action: "delete", Service: s})
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Registry) GetService(name string, opts ...registry.GetOption) ([]*registry.Service, error) {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
records, ok := m.records[name]
|
||||
if !ok {
|
||||
return nil, registry.ErrNotFound
|
||||
}
|
||||
|
||||
services := make([]*registry.Service, len(m.records[name]))
|
||||
i := 0
|
||||
for _, record := range records {
|
||||
services[i] = recordToService(record)
|
||||
i++
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (m *Registry) ListServices(opts ...registry.ListOption) ([]*registry.Service, error) {
|
||||
m.RLock()
|
||||
defer m.RUnlock()
|
||||
|
||||
var services []*registry.Service
|
||||
for _, records := range m.records {
|
||||
for _, record := range records {
|
||||
services = append(services, recordToService(record))
|
||||
}
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (m *Registry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) {
|
||||
var wo registry.WatchOptions
|
||||
for _, o := range opts {
|
||||
o(&wo)
|
||||
}
|
||||
|
||||
w := &Watcher{
|
||||
exit: make(chan bool),
|
||||
res: make(chan *registry.Result),
|
||||
id: uuid.New().String(),
|
||||
wo: wo,
|
||||
}
|
||||
|
||||
m.Lock()
|
||||
m.watchers[w.id] = w
|
||||
m.Unlock()
|
||||
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func (m *Registry) String() string {
|
||||
return "memory"
|
||||
}
|
||||
27
vendor/github.com/go-micro/plugins/v4/registry/memory/memory_watcher.go
generated
vendored
Normal file
27
vendor/github.com/go-micro/plugins/v4/registry/memory/memory_watcher.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
type memoryWatcher struct {
|
||||
exit chan bool
|
||||
opts registry.WatchOptions
|
||||
}
|
||||
|
||||
func (m *memoryWatcher) Next() (*registry.Result, error) {
|
||||
// not implement so we just block until exit
|
||||
<-m.exit
|
||||
return nil, errors.New("watcher stopped")
|
||||
}
|
||||
|
||||
func (m *memoryWatcher) Stop() {
|
||||
select {
|
||||
case <-m.exit:
|
||||
return
|
||||
default:
|
||||
close(m.exit)
|
||||
}
|
||||
}
|
||||
40
vendor/github.com/go-micro/plugins/v4/registry/memory/options.go
generated
vendored
Normal file
40
vendor/github.com/go-micro/plugins/v4/registry/memory/options.go
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
type servicesKey struct{}
|
||||
|
||||
func getServiceRecords(ctx context.Context) map[string]map[string]*record {
|
||||
memServices, ok := ctx.Value(servicesKey{}).(map[string][]*registry.Service)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
services := make(map[string]map[string]*record)
|
||||
|
||||
for name, svc := range memServices {
|
||||
if _, ok := services[name]; !ok {
|
||||
services[name] = make(map[string]*record)
|
||||
}
|
||||
// go through every version of the service
|
||||
for _, s := range svc {
|
||||
services[s.Name][s.Version] = serviceToRecord(s, 0)
|
||||
}
|
||||
}
|
||||
|
||||
return services
|
||||
}
|
||||
|
||||
// Services is an option that preloads service data.
|
||||
func Services(s map[string][]*registry.Service) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, servicesKey{}, s)
|
||||
}
|
||||
}
|
||||
91
vendor/github.com/go-micro/plugins/v4/registry/memory/util.go
generated
vendored
Normal file
91
vendor/github.com/go-micro/plugins/v4/registry/memory/util.go
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
func serviceToRecord(s *registry.Service, ttl time.Duration) *record {
|
||||
metadata := make(map[string]string, len(s.Metadata))
|
||||
for k, v := range s.Metadata {
|
||||
metadata[k] = v
|
||||
}
|
||||
|
||||
nodes := make(map[string]*node, len(s.Nodes))
|
||||
for _, n := range s.Nodes {
|
||||
nodes[n.Id] = &node{
|
||||
Node: n,
|
||||
TTL: ttl,
|
||||
LastSeen: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
endpoints := make([]*registry.Endpoint, len(s.Endpoints))
|
||||
for i, e := range s.Endpoints {
|
||||
endpoints[i] = e
|
||||
}
|
||||
|
||||
return &record{
|
||||
Name: s.Name,
|
||||
Version: s.Version,
|
||||
Metadata: metadata,
|
||||
Nodes: nodes,
|
||||
Endpoints: endpoints,
|
||||
}
|
||||
}
|
||||
|
||||
func recordToService(r *record) *registry.Service {
|
||||
metadata := make(map[string]string, len(r.Metadata))
|
||||
for k, v := range r.Metadata {
|
||||
metadata[k] = v
|
||||
}
|
||||
|
||||
endpoints := make([]*registry.Endpoint, len(r.Endpoints))
|
||||
for i, e := range r.Endpoints {
|
||||
request := new(registry.Value)
|
||||
if e.Request != nil {
|
||||
*request = *e.Request
|
||||
}
|
||||
response := new(registry.Value)
|
||||
if e.Response != nil {
|
||||
*response = *e.Response
|
||||
}
|
||||
|
||||
metadata := make(map[string]string, len(e.Metadata))
|
||||
for k, v := range e.Metadata {
|
||||
metadata[k] = v
|
||||
}
|
||||
|
||||
endpoints[i] = ®istry.Endpoint{
|
||||
Name: e.Name,
|
||||
Request: request,
|
||||
Response: response,
|
||||
Metadata: metadata,
|
||||
}
|
||||
}
|
||||
|
||||
nodes := make([]*registry.Node, len(r.Nodes))
|
||||
i := 0
|
||||
for _, n := range r.Nodes {
|
||||
metadata := make(map[string]string, len(n.Metadata))
|
||||
for k, v := range n.Metadata {
|
||||
metadata[k] = v
|
||||
}
|
||||
|
||||
nodes[i] = ®istry.Node{
|
||||
Id: n.Id,
|
||||
Address: n.Address,
|
||||
Metadata: metadata,
|
||||
}
|
||||
i++
|
||||
}
|
||||
|
||||
return ®istry.Service{
|
||||
Name: r.Name,
|
||||
Version: r.Version,
|
||||
Metadata: metadata,
|
||||
Endpoints: endpoints,
|
||||
Nodes: nodes,
|
||||
}
|
||||
}
|
||||
37
vendor/github.com/go-micro/plugins/v4/registry/memory/watcher.go
generated
vendored
Normal file
37
vendor/github.com/go-micro/plugins/v4/registry/memory/watcher.go
generated
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
type Watcher struct {
|
||||
id string
|
||||
wo registry.WatchOptions
|
||||
res chan *registry.Result
|
||||
exit chan bool
|
||||
}
|
||||
|
||||
func (m *Watcher) Next() (*registry.Result, error) {
|
||||
for {
|
||||
select {
|
||||
case r := <-m.res:
|
||||
if len(m.wo.Service) > 0 && m.wo.Service != r.Service.Name {
|
||||
continue
|
||||
}
|
||||
return r, nil
|
||||
case <-m.exit:
|
||||
return nil, errors.New("watcher stopped")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Watcher) Stop() {
|
||||
select {
|
||||
case <-m.exit:
|
||||
return
|
||||
default:
|
||||
close(m.exit)
|
||||
}
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/registry/nats/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/registry/nats/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
414
vendor/github.com/go-micro/plugins/v4/registry/nats/nats.go
generated
vendored
Normal file
414
vendor/github.com/go-micro/plugins/v4/registry/nats/nats.go
generated
vendored
Normal file
@@ -0,0 +1,414 @@
|
||||
// Package nats provides a NATS registry using broadcast queries
|
||||
package nats
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/util/cmd"
|
||||
)
|
||||
|
||||
type natsRegistry struct {
|
||||
addrs []string
|
||||
opts registry.Options
|
||||
nopts nats.Options
|
||||
queryTopic string
|
||||
watchTopic string
|
||||
|
||||
sync.RWMutex
|
||||
conn *nats.Conn
|
||||
services map[string][]*registry.Service
|
||||
listeners map[string]chan bool
|
||||
}
|
||||
|
||||
var (
|
||||
defaultQueryTopic = "micro.registry.nats.query"
|
||||
defaultWatchTopic = "micro.registry.nats.watch"
|
||||
)
|
||||
|
||||
func init() {
|
||||
cmd.DefaultRegistries["nats"] = NewRegistry
|
||||
}
|
||||
|
||||
func configure(n *natsRegistry, opts ...registry.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&n.opts)
|
||||
}
|
||||
|
||||
natsOptions := nats.GetDefaultOptions()
|
||||
if n, ok := n.opts.Context.Value(optionsKey{}).(nats.Options); ok {
|
||||
natsOptions = n
|
||||
}
|
||||
|
||||
queryTopic := defaultQueryTopic
|
||||
if qt, ok := n.opts.Context.Value(queryTopicKey{}).(string); ok {
|
||||
queryTopic = qt
|
||||
}
|
||||
|
||||
watchTopic := defaultWatchTopic
|
||||
if wt, ok := n.opts.Context.Value(watchTopicKey{}).(string); ok {
|
||||
watchTopic = wt
|
||||
}
|
||||
|
||||
// registry.Options have higher priority than nats.Options
|
||||
// only if Addrs, Secure or TLSConfig were not set through a registry.Option
|
||||
// we read them from nats.Option
|
||||
if len(n.opts.Addrs) == 0 {
|
||||
n.opts.Addrs = natsOptions.Servers
|
||||
}
|
||||
|
||||
if !n.opts.Secure {
|
||||
n.opts.Secure = natsOptions.Secure
|
||||
}
|
||||
|
||||
if n.opts.TLSConfig == nil {
|
||||
n.opts.TLSConfig = natsOptions.TLSConfig
|
||||
}
|
||||
|
||||
// check & add nats:// prefix (this makes also sure that the addresses
|
||||
// stored in natsRegistry.addrs and n.opts.Addrs are identical)
|
||||
n.opts.Addrs = setAddrs(n.opts.Addrs)
|
||||
|
||||
n.addrs = n.opts.Addrs
|
||||
n.nopts = natsOptions
|
||||
n.queryTopic = queryTopic
|
||||
n.watchTopic = watchTopic
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func setAddrs(addrs []string) []string {
|
||||
var cAddrs []string
|
||||
for _, addr := range addrs {
|
||||
if len(addr) == 0 {
|
||||
continue
|
||||
}
|
||||
if !strings.HasPrefix(addr, "nats://") {
|
||||
addr = "nats://" + addr
|
||||
}
|
||||
cAddrs = append(cAddrs, addr)
|
||||
}
|
||||
if len(cAddrs) == 0 {
|
||||
cAddrs = []string{nats.DefaultURL}
|
||||
}
|
||||
return cAddrs
|
||||
}
|
||||
|
||||
func (n *natsRegistry) newConn() (*nats.Conn, error) {
|
||||
opts := n.nopts
|
||||
opts.Servers = n.addrs
|
||||
opts.Secure = n.opts.Secure
|
||||
opts.TLSConfig = n.opts.TLSConfig
|
||||
|
||||
// secure might not be set
|
||||
if opts.TLSConfig != nil {
|
||||
opts.Secure = true
|
||||
}
|
||||
|
||||
return opts.Connect()
|
||||
}
|
||||
|
||||
func (n *natsRegistry) getConn() (*nats.Conn, error) {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
if n.conn != nil {
|
||||
return n.conn, nil
|
||||
}
|
||||
|
||||
c, err := n.newConn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
n.conn = c
|
||||
|
||||
return n.conn, nil
|
||||
}
|
||||
|
||||
func (n *natsRegistry) register(s *registry.Service) error {
|
||||
conn, err := n.getConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
// cache service
|
||||
n.services[s.Name] = addServices(n.services[s.Name], cp([]*registry.Service{s}))
|
||||
|
||||
// create query listener
|
||||
if n.listeners[s.Name] == nil {
|
||||
listener := make(chan bool)
|
||||
|
||||
// create a subscriber that responds to queries
|
||||
sub, err := conn.Subscribe(n.queryTopic, func(m *nats.Msg) {
|
||||
var result *registry.Result
|
||||
|
||||
if err := json.Unmarshal(m.Data, &result); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var services []*registry.Service
|
||||
|
||||
switch result.Action {
|
||||
// is this a get query and we own the service?
|
||||
case "get":
|
||||
if result.Service.Name != s.Name {
|
||||
return
|
||||
}
|
||||
n.RLock()
|
||||
services = cp(n.services[s.Name])
|
||||
n.RUnlock()
|
||||
// it's a list request, but we're still only a
|
||||
// subscriber for this service... so just get this service
|
||||
// totally suboptimal
|
||||
case "list":
|
||||
n.RLock()
|
||||
services = cp(n.services[s.Name])
|
||||
n.RUnlock()
|
||||
default:
|
||||
// does not match
|
||||
return
|
||||
}
|
||||
|
||||
// respond to query
|
||||
for _, service := range services {
|
||||
b, err := json.Marshal(service)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
conn.Publish(m.Reply, b)
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Unsubscribe if we're told to do so
|
||||
go func() {
|
||||
<-listener
|
||||
sub.Unsubscribe()
|
||||
}()
|
||||
|
||||
n.listeners[s.Name] = listener
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *natsRegistry) deregister(s *registry.Service) error {
|
||||
n.Lock()
|
||||
defer n.Unlock()
|
||||
|
||||
services := delServices(n.services[s.Name], cp([]*registry.Service{s}))
|
||||
if len(services) > 0 {
|
||||
n.services[s.Name] = services
|
||||
return nil
|
||||
}
|
||||
|
||||
// delete cached service
|
||||
delete(n.services, s.Name)
|
||||
|
||||
// delete query listener
|
||||
if listener, lexists := n.listeners[s.Name]; lexists {
|
||||
close(listener)
|
||||
delete(n.listeners, s.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *natsRegistry) query(s string, quorum int) ([]*registry.Service, error) {
|
||||
conn, err := n.getConn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var action string
|
||||
var service *registry.Service
|
||||
|
||||
if len(s) > 0 {
|
||||
action = "get"
|
||||
service = ®istry.Service{Name: s}
|
||||
} else {
|
||||
action = "list"
|
||||
}
|
||||
|
||||
inbox := nats.NewInbox()
|
||||
|
||||
response := make(chan *registry.Service, 10)
|
||||
|
||||
sub, err := conn.Subscribe(inbox, func(m *nats.Msg) {
|
||||
var service *registry.Service
|
||||
if err := json.Unmarshal(m.Data, &service); err != nil {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case response <- service:
|
||||
case <-time.After(n.opts.Timeout):
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer sub.Unsubscribe()
|
||||
|
||||
b, err := json.Marshal(®istry.Result{Action: action, Service: service})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := conn.PublishMsg(&nats.Msg{
|
||||
Subject: n.queryTopic,
|
||||
Reply: inbox,
|
||||
Data: b,
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
timeoutChan := time.After(n.opts.Timeout)
|
||||
|
||||
serviceMap := make(map[string]*registry.Service)
|
||||
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case service := <-response:
|
||||
key := service.Name + "-" + service.Version
|
||||
srv, ok := serviceMap[key]
|
||||
if ok {
|
||||
srv.Nodes = append(srv.Nodes, service.Nodes...)
|
||||
serviceMap[key] = srv
|
||||
} else {
|
||||
serviceMap[key] = service
|
||||
}
|
||||
|
||||
if quorum > 0 && len(serviceMap[key].Nodes) >= quorum {
|
||||
break loop
|
||||
}
|
||||
case <-timeoutChan:
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
var services []*registry.Service
|
||||
for _, service := range serviceMap {
|
||||
services = append(services, service)
|
||||
}
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (n *natsRegistry) Init(opts ...registry.Option) error {
|
||||
return configure(n, opts...)
|
||||
}
|
||||
|
||||
func (n *natsRegistry) Options() registry.Options {
|
||||
return n.opts
|
||||
}
|
||||
|
||||
func (n *natsRegistry) Register(s *registry.Service, opts ...registry.RegisterOption) error {
|
||||
if err := n.register(s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn, err := n.getConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(®istry.Result{Action: "create", Service: s})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return conn.Publish(n.watchTopic, b)
|
||||
}
|
||||
|
||||
func (n *natsRegistry) Deregister(s *registry.Service, opts ...registry.DeregisterOption) error {
|
||||
if err := n.deregister(s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
conn, err := n.getConn()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
b, err := json.Marshal(®istry.Result{Action: "delete", Service: s})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return conn.Publish(n.watchTopic, b)
|
||||
}
|
||||
|
||||
func (n *natsRegistry) GetService(s string, opts ...registry.GetOption) ([]*registry.Service, error) {
|
||||
services, err := n.query(s, getQuorum(n.opts))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (n *natsRegistry) ListServices(opts ...registry.ListOption) ([]*registry.Service, error) {
|
||||
s, err := n.query("", 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var services []*registry.Service
|
||||
serviceMap := make(map[string]*registry.Service)
|
||||
|
||||
for _, v := range s {
|
||||
serviceMap[v.Name] = ®istry.Service{Name: v.Name, Version: v.Version}
|
||||
}
|
||||
|
||||
for _, v := range serviceMap {
|
||||
services = append(services, v)
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
func (n *natsRegistry) Watch(opts ...registry.WatchOption) (registry.Watcher, error) {
|
||||
conn, err := n.getConn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sub, err := conn.SubscribeSync(n.watchTopic)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var wo registry.WatchOptions
|
||||
for _, o := range opts {
|
||||
o(&wo)
|
||||
}
|
||||
|
||||
return &natsWatcher{sub, wo}, nil
|
||||
}
|
||||
|
||||
func (n *natsRegistry) String() string {
|
||||
return "nats"
|
||||
}
|
||||
|
||||
func NewRegistry(opts ...registry.Option) registry.Registry {
|
||||
options := registry.Options{
|
||||
Timeout: time.Millisecond * 100,
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
n := &natsRegistry{
|
||||
opts: options,
|
||||
services: make(map[string][]*registry.Service),
|
||||
listeners: make(map[string]chan bool),
|
||||
}
|
||||
configure(n, opts...)
|
||||
return n
|
||||
}
|
||||
72
vendor/github.com/go-micro/plugins/v4/registry/nats/options.go
generated
vendored
Normal file
72
vendor/github.com/go-micro/plugins/v4/registry/nats/options.go
generated
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
package nats
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
type contextQuorumKey struct{}
|
||||
type optionsKey struct{}
|
||||
type watchTopicKey struct{}
|
||||
type queryTopicKey struct{}
|
||||
|
||||
var (
|
||||
DefaultQuorum = 0
|
||||
)
|
||||
|
||||
func getQuorum(o registry.Options) int {
|
||||
if o.Context == nil {
|
||||
return DefaultQuorum
|
||||
}
|
||||
|
||||
value := o.Context.Value(contextQuorumKey{})
|
||||
if v, ok := value.(int); ok {
|
||||
return v
|
||||
} else {
|
||||
return DefaultQuorum
|
||||
}
|
||||
}
|
||||
|
||||
func Quorum(n int) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
o.Context = context.WithValue(o.Context, contextQuorumKey{}, n)
|
||||
}
|
||||
}
|
||||
|
||||
// Options allow to inject a nats.Options struct for configuring
|
||||
// the nats connection.
|
||||
func Options(nopts nats.Options) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, optionsKey{}, nopts)
|
||||
}
|
||||
}
|
||||
|
||||
// QueryTopic allows to set a custom nats topic on which service registries
|
||||
// query (survey) other services. All registries listen on this topic and
|
||||
// then respond to the query message.
|
||||
func QueryTopic(s string) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, queryTopicKey{}, s)
|
||||
}
|
||||
}
|
||||
|
||||
// WatchTopic allows to set a custom nats topic on which registries broadcast
|
||||
// changes (e.g. when services are added, updated or removed). Since we don't
|
||||
// have a central registry service, each service typically broadcasts in a
|
||||
// determined frequency on this topic.
|
||||
func WatchTopic(s string) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, watchTopicKey{}, s)
|
||||
}
|
||||
}
|
||||
109
vendor/github.com/go-micro/plugins/v4/registry/nats/util.go
generated
vendored
Normal file
109
vendor/github.com/go-micro/plugins/v4/registry/nats/util.go
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
package nats
|
||||
|
||||
import (
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
func cp(current []*registry.Service) []*registry.Service {
|
||||
var services []*registry.Service
|
||||
|
||||
for _, service := range current {
|
||||
// copy service
|
||||
s := new(registry.Service)
|
||||
*s = *service
|
||||
|
||||
// copy nodes
|
||||
var nodes []*registry.Node
|
||||
for _, node := range service.Nodes {
|
||||
n := new(registry.Node)
|
||||
*n = *node
|
||||
nodes = append(nodes, n)
|
||||
}
|
||||
s.Nodes = nodes
|
||||
|
||||
// copy endpoints
|
||||
var eps []*registry.Endpoint
|
||||
for _, ep := range service.Endpoints {
|
||||
e := new(registry.Endpoint)
|
||||
*e = *ep
|
||||
eps = append(eps, e)
|
||||
}
|
||||
s.Endpoints = eps
|
||||
|
||||
// append service
|
||||
services = append(services, s)
|
||||
}
|
||||
|
||||
return services
|
||||
}
|
||||
|
||||
func addNodes(old, neu []*registry.Node) []*registry.Node {
|
||||
for _, n := range neu {
|
||||
var seen bool
|
||||
for i, o := range old {
|
||||
if o.Id == n.Id {
|
||||
seen = true
|
||||
old[i] = n
|
||||
break
|
||||
}
|
||||
}
|
||||
if !seen {
|
||||
old = append(old, n)
|
||||
}
|
||||
}
|
||||
return old
|
||||
}
|
||||
|
||||
func addServices(old, neu []*registry.Service) []*registry.Service {
|
||||
for _, s := range neu {
|
||||
var seen bool
|
||||
for i, o := range old {
|
||||
if o.Version == s.Version {
|
||||
s.Nodes = addNodes(o.Nodes, s.Nodes)
|
||||
seen = true
|
||||
old[i] = s
|
||||
break
|
||||
}
|
||||
}
|
||||
if !seen {
|
||||
old = append(old, s)
|
||||
}
|
||||
}
|
||||
return old
|
||||
}
|
||||
|
||||
func delNodes(old, del []*registry.Node) []*registry.Node {
|
||||
var nodes []*registry.Node
|
||||
for _, o := range old {
|
||||
var rem bool
|
||||
for _, n := range del {
|
||||
if o.Id == n.Id {
|
||||
rem = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !rem {
|
||||
nodes = append(nodes, o)
|
||||
}
|
||||
}
|
||||
return nodes
|
||||
}
|
||||
|
||||
func delServices(old, del []*registry.Service) []*registry.Service {
|
||||
var services []*registry.Service
|
||||
for i, o := range old {
|
||||
var rem bool
|
||||
for _, s := range del {
|
||||
if o.Version == s.Version {
|
||||
old[i].Nodes = delNodes(o.Nodes, s.Nodes)
|
||||
if len(old[i].Nodes) == 0 {
|
||||
rem = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if !rem {
|
||||
services = append(services, o)
|
||||
}
|
||||
}
|
||||
return services
|
||||
}
|
||||
39
vendor/github.com/go-micro/plugins/v4/registry/nats/watcher.go
generated
vendored
Normal file
39
vendor/github.com/go-micro/plugins/v4/registry/nats/watcher.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package nats
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
type natsWatcher struct {
|
||||
sub *nats.Subscription
|
||||
wo registry.WatchOptions
|
||||
}
|
||||
|
||||
func (n *natsWatcher) Next() (*registry.Result, error) {
|
||||
var result *registry.Result
|
||||
for {
|
||||
m, err := n.sub.NextMsg(time.Minute)
|
||||
if err != nil && err == nats.ErrTimeout {
|
||||
continue
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := json.Unmarshal(m.Data, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(n.wo.Service) > 0 && result.Service.Name != n.wo.Service {
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (n *natsWatcher) Stop() {
|
||||
n.sub.Unsubscribe()
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/server/grpc/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/server/grpc/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
30
vendor/github.com/go-micro/plugins/v4/server/grpc/README.md
generated
vendored
Normal file
30
vendor/github.com/go-micro/plugins/v4/server/grpc/README.md
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
# GRPC Server
|
||||
|
||||
The grpc server is a [micro.Server](https://pkg.go.dev/github.com/asim/go-micro/server#Server) compatible server.
|
||||
|
||||
## Overview
|
||||
|
||||
The server makes use of the [google.golang.org/grpc](google.golang.org/grpc) framework for the underlying server
|
||||
but continues to use micro handler signatures and protoc-gen-micro generated code.
|
||||
|
||||
## Usage
|
||||
|
||||
Specify the server to your micro service
|
||||
|
||||
```go
|
||||
import (
|
||||
"go-micro.dev/v4"
|
||||
"github.com/go-micro/plugins/v4/server/grpc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
service := micro.NewService(
|
||||
// This needs to be first as it replaces the underlying server
|
||||
// which causes any configuration set before it
|
||||
// to be discarded
|
||||
micro.Server(grpc.NewServer()),
|
||||
micro.Name("greeter"),
|
||||
)
|
||||
}
|
||||
```
|
||||
**NOTE**: Setting the gRPC server and/or client causes the underlying the server/client to be replaced which causes any previous configuration set on that server/client to be discarded. It is therefore recommended to set gRPC server/client before any other configuration
|
||||
186
vendor/github.com/go-micro/plugins/v4/server/grpc/codec.go
generated
vendored
Normal file
186
vendor/github.com/go-micro/plugins/v4/server/grpc/codec.go
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
|
||||
b "bytes"
|
||||
|
||||
"github.com/golang/protobuf/jsonpb"
|
||||
"github.com/golang/protobuf/proto"
|
||||
"go-micro.dev/v4/codec"
|
||||
"go-micro.dev/v4/codec/bytes"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding"
|
||||
"google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
type jsonCodec struct{}
|
||||
type bytesCodec struct{}
|
||||
type protoCodec struct{}
|
||||
type wrapCodec struct{ encoding.Codec }
|
||||
|
||||
var jsonpbMarshaler = &jsonpb.Marshaler{
|
||||
EnumsAsInts: false,
|
||||
EmitDefaults: false,
|
||||
OrigName: true,
|
||||
}
|
||||
|
||||
var (
|
||||
defaultGRPCCodecs = map[string]encoding.Codec{
|
||||
"application/json": jsonCodec{},
|
||||
"application/proto": protoCodec{},
|
||||
"application/protobuf": protoCodec{},
|
||||
"application/octet-stream": protoCodec{},
|
||||
"application/grpc": protoCodec{},
|
||||
"application/grpc+json": jsonCodec{},
|
||||
"application/grpc+proto": protoCodec{},
|
||||
"application/grpc+bytes": bytesCodec{},
|
||||
}
|
||||
)
|
||||
|
||||
func (w wrapCodec) String() string {
|
||||
return w.Codec.Name()
|
||||
}
|
||||
|
||||
func (w wrapCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
b, ok := v.(*bytes.Frame)
|
||||
if ok {
|
||||
return b.Data, nil
|
||||
}
|
||||
return w.Codec.Marshal(v)
|
||||
}
|
||||
|
||||
func (w wrapCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
b, ok := v.(*bytes.Frame)
|
||||
if ok {
|
||||
b.Data = data
|
||||
return nil
|
||||
}
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
return w.Codec.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
func (protoCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
m, ok := v.(proto.Message)
|
||||
if !ok {
|
||||
return nil, codec.ErrInvalidMessage
|
||||
}
|
||||
return proto.Marshal(m)
|
||||
}
|
||||
|
||||
func (protoCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
m, ok := v.(proto.Message)
|
||||
if !ok {
|
||||
return codec.ErrInvalidMessage
|
||||
}
|
||||
return proto.Unmarshal(data, m)
|
||||
}
|
||||
|
||||
func (protoCodec) Name() string {
|
||||
return "proto"
|
||||
}
|
||||
|
||||
func (jsonCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
if pb, ok := v.(proto.Message); ok {
|
||||
s, err := jsonpbMarshaler.MarshalToString(pb)
|
||||
return []byte(s), err
|
||||
}
|
||||
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
func (jsonCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
if pb, ok := v.(proto.Message); ok {
|
||||
return jsonpb.Unmarshal(b.NewReader(data), pb)
|
||||
}
|
||||
return json.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
func (jsonCodec) Name() string {
|
||||
return "json"
|
||||
}
|
||||
|
||||
func (bytesCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
b, ok := v.(*[]byte)
|
||||
if !ok {
|
||||
return nil, codec.ErrInvalidMessage
|
||||
}
|
||||
return *b, nil
|
||||
}
|
||||
|
||||
func (bytesCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
b, ok := v.(*[]byte)
|
||||
if !ok {
|
||||
return codec.ErrInvalidMessage
|
||||
}
|
||||
*b = data
|
||||
return nil
|
||||
}
|
||||
|
||||
func (bytesCodec) Name() string {
|
||||
return "bytes"
|
||||
}
|
||||
|
||||
type grpcCodec struct {
|
||||
// headers
|
||||
id string
|
||||
target string
|
||||
method string
|
||||
endpoint string
|
||||
|
||||
s grpc.ServerStream
|
||||
c encoding.Codec
|
||||
}
|
||||
|
||||
func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error {
|
||||
md, _ := metadata.FromIncomingContext(g.s.Context())
|
||||
if m == nil {
|
||||
m = new(codec.Message)
|
||||
}
|
||||
if m.Header == nil {
|
||||
m.Header = make(map[string]string, len(md))
|
||||
}
|
||||
for k, v := range md {
|
||||
m.Header[k] = strings.Join(v, ",")
|
||||
}
|
||||
m.Id = g.id
|
||||
m.Target = g.target
|
||||
m.Method = g.method
|
||||
m.Endpoint = g.endpoint
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcCodec) ReadBody(v interface{}) error {
|
||||
// caller has requested a frame
|
||||
if f, ok := v.(*bytes.Frame); ok {
|
||||
return g.s.RecvMsg(f)
|
||||
}
|
||||
return g.s.RecvMsg(v)
|
||||
}
|
||||
|
||||
func (g *grpcCodec) Write(m *codec.Message, v interface{}) error {
|
||||
// if we don't have a body
|
||||
if v != nil {
|
||||
b, err := g.c.Marshal(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.Body = b
|
||||
}
|
||||
// write the body using the framing codec
|
||||
return g.s.SendMsg(&bytes.Frame{Data: m.Body})
|
||||
}
|
||||
|
||||
func (g *grpcCodec) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcCodec) String() string {
|
||||
return "grpc"
|
||||
}
|
||||
16
vendor/github.com/go-micro/plugins/v4/server/grpc/context.go
generated
vendored
Normal file
16
vendor/github.com/go-micro/plugins/v4/server/grpc/context.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
func setServerOption(k, v interface{}) server.Option {
|
||||
return func(o *server.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
42
vendor/github.com/go-micro/plugins/v4/server/grpc/error.go
generated
vendored
Normal file
42
vendor/github.com/go-micro/plugins/v4/server/grpc/error.go
generated
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"go-micro.dev/v4/errors"
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
func microError(err *errors.Error) codes.Code {
|
||||
switch err {
|
||||
case nil:
|
||||
return codes.OK
|
||||
}
|
||||
|
||||
switch err.Code {
|
||||
case http.StatusOK:
|
||||
return codes.OK
|
||||
case http.StatusBadRequest:
|
||||
return codes.InvalidArgument
|
||||
case http.StatusRequestTimeout:
|
||||
return codes.DeadlineExceeded
|
||||
case http.StatusNotFound:
|
||||
return codes.NotFound
|
||||
case http.StatusConflict:
|
||||
return codes.AlreadyExists
|
||||
case http.StatusForbidden:
|
||||
return codes.PermissionDenied
|
||||
case http.StatusUnauthorized:
|
||||
return codes.Unauthenticated
|
||||
case http.StatusPreconditionFailed:
|
||||
return codes.FailedPrecondition
|
||||
case http.StatusNotImplemented:
|
||||
return codes.Unimplemented
|
||||
case http.StatusInternalServerError:
|
||||
return codes.Internal
|
||||
case http.StatusServiceUnavailable:
|
||||
return codes.Unavailable
|
||||
}
|
||||
|
||||
return codes.Unknown
|
||||
}
|
||||
125
vendor/github.com/go-micro/plugins/v4/server/grpc/extractor.go
generated
vendored
Normal file
125
vendor/github.com/go-micro/plugins/v4/server/grpc/extractor.go
generated
vendored
Normal file
@@ -0,0 +1,125 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"go-micro.dev/v4/registry"
|
||||
)
|
||||
|
||||
func extractValue(v reflect.Type, d int) *registry.Value {
|
||||
if d == 3 {
|
||||
return nil
|
||||
}
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
arg := ®istry.Value{
|
||||
Name: v.Name(),
|
||||
Type: v.Name(),
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
f := v.Field(i)
|
||||
if f.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
val := extractValue(f.Type, d+1)
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// if we can find a json tag use it
|
||||
if tags := f.Tag.Get("json"); len(tags) > 0 {
|
||||
parts := strings.Split(tags, ",")
|
||||
if parts[0] == "-" || parts[0] == "omitempty" {
|
||||
continue
|
||||
}
|
||||
val.Name = parts[0]
|
||||
}
|
||||
|
||||
// if there's no name default it
|
||||
if len(val.Name) == 0 {
|
||||
val.Name = v.Field(i).Name
|
||||
}
|
||||
|
||||
arg.Values = append(arg.Values, val)
|
||||
}
|
||||
case reflect.Slice:
|
||||
p := v.Elem()
|
||||
if p.Kind() == reflect.Ptr {
|
||||
p = p.Elem()
|
||||
}
|
||||
arg.Type = "[]" + p.Name()
|
||||
}
|
||||
|
||||
return arg
|
||||
}
|
||||
|
||||
func extractEndpoint(method reflect.Method) *registry.Endpoint {
|
||||
if method.PkgPath != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var rspType, reqType reflect.Type
|
||||
var stream bool
|
||||
mt := method.Type
|
||||
|
||||
switch mt.NumIn() {
|
||||
case 3:
|
||||
reqType = mt.In(1)
|
||||
rspType = mt.In(2)
|
||||
case 4:
|
||||
reqType = mt.In(2)
|
||||
rspType = mt.In(3)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
// are we dealing with a stream?
|
||||
switch rspType.Kind() {
|
||||
case reflect.Func, reflect.Interface:
|
||||
stream = true
|
||||
}
|
||||
|
||||
request := extractValue(reqType, 0)
|
||||
response := extractValue(rspType, 0)
|
||||
|
||||
ep := ®istry.Endpoint{
|
||||
Name: method.Name,
|
||||
Request: request,
|
||||
Response: response,
|
||||
Metadata: make(map[string]string),
|
||||
}
|
||||
|
||||
if stream {
|
||||
ep.Metadata = map[string]string{
|
||||
"stream": fmt.Sprintf("%v", stream),
|
||||
}
|
||||
}
|
||||
|
||||
return ep
|
||||
}
|
||||
|
||||
func extractSubValue(typ reflect.Type) *registry.Value {
|
||||
var reqType reflect.Type
|
||||
switch typ.NumIn() {
|
||||
case 1:
|
||||
reqType = typ.In(0)
|
||||
case 2:
|
||||
reqType = typ.In(1)
|
||||
case 3:
|
||||
reqType = typ.In(2)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return extractValue(reqType, 0)
|
||||
}
|
||||
1039
vendor/github.com/go-micro/plugins/v4/server/grpc/grpc.go
generated
vendored
Normal file
1039
vendor/github.com/go-micro/plugins/v4/server/grpc/grpc.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
66
vendor/github.com/go-micro/plugins/v4/server/grpc/handler.go
generated
vendored
Normal file
66
vendor/github.com/go-micro/plugins/v4/server/grpc/handler.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
type rpcHandler struct {
|
||||
name string
|
||||
handler interface{}
|
||||
endpoints []*registry.Endpoint
|
||||
opts server.HandlerOptions
|
||||
}
|
||||
|
||||
func newRpcHandler(handler interface{}, opts ...server.HandlerOption) server.Handler {
|
||||
options := server.HandlerOptions{
|
||||
Metadata: make(map[string]map[string]string),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
typ := reflect.TypeOf(handler)
|
||||
hdlr := reflect.ValueOf(handler)
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
var endpoints []*registry.Endpoint
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
if e := extractEndpoint(typ.Method(m)); e != nil {
|
||||
e.Name = name + "." + e.Name
|
||||
|
||||
for k, v := range options.Metadata[e.Name] {
|
||||
e.Metadata[k] = v
|
||||
}
|
||||
|
||||
endpoints = append(endpoints, e)
|
||||
}
|
||||
}
|
||||
|
||||
return &rpcHandler{
|
||||
name: name,
|
||||
handler: handler,
|
||||
endpoints: endpoints,
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Name() string {
|
||||
return r.name
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Handler() interface{} {
|
||||
return r.handler
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Endpoints() []*registry.Endpoint {
|
||||
return r.endpoints
|
||||
}
|
||||
|
||||
func (r *rpcHandler) Options() server.HandlerOptions {
|
||||
return r.opts
|
||||
}
|
||||
95
vendor/github.com/go-micro/plugins/v4/server/grpc/options.go
generated
vendored
Normal file
95
vendor/github.com/go-micro/plugins/v4/server/grpc/options.go
generated
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
|
||||
"go-micro.dev/v4/broker"
|
||||
"go-micro.dev/v4/codec"
|
||||
"go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/server"
|
||||
"go-micro.dev/v4/transport"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding"
|
||||
)
|
||||
|
||||
type codecsKey struct{}
|
||||
type grpcOptions struct{}
|
||||
type netListener struct{}
|
||||
type maxMsgSizeKey struct{}
|
||||
type maxConnKey struct{}
|
||||
type tlsAuth struct{}
|
||||
type grpcServerKey struct{}
|
||||
|
||||
// gRPC Codec to be used to encode/decode requests for a given content type.
|
||||
func Codec(contentType string, c encoding.Codec) server.Option {
|
||||
return func(o *server.Options) {
|
||||
codecs := make(map[string]encoding.Codec)
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
if v, ok := o.Context.Value(codecsKey{}).(map[string]encoding.Codec); ok && v != nil {
|
||||
codecs = v
|
||||
}
|
||||
codecs[contentType] = c
|
||||
o.Context = context.WithValue(o.Context, codecsKey{}, codecs)
|
||||
}
|
||||
}
|
||||
|
||||
// AuthTLS should be used to setup a secure authentication using TLS.
|
||||
func AuthTLS(t *tls.Config) server.Option {
|
||||
return setServerOption(tlsAuth{}, t)
|
||||
}
|
||||
|
||||
// MaxConn specifies maximum number of max simultaneous connections to server.
|
||||
func MaxConn(n int) server.Option {
|
||||
return setServerOption(maxConnKey{}, n)
|
||||
}
|
||||
|
||||
// Listener specifies the net.Listener to use instead of the default.
|
||||
func Listener(l net.Listener) server.Option {
|
||||
return setServerOption(netListener{}, l)
|
||||
}
|
||||
|
||||
// Server specifies a *grpc.Server to use instead of the default
|
||||
// This is for rare use case where user need to expose grpc.Server for
|
||||
// customization. Please NOTE however user injected grpcServer doesn't support
|
||||
// server Handler abstraction.
|
||||
func Server(srv *grpc.Server) server.Option {
|
||||
return setServerOption(grpcServerKey{}, srv)
|
||||
}
|
||||
|
||||
// Options to be used to configure gRPC options.
|
||||
func Options(opts ...grpc.ServerOption) server.Option {
|
||||
return setServerOption(grpcOptions{}, opts)
|
||||
}
|
||||
|
||||
// MaxMsgSize set the maximum message in bytes the server can receive and
|
||||
// send. Default maximum message size is 4 MB.
|
||||
func MaxMsgSize(s int) server.Option {
|
||||
return setServerOption(maxMsgSizeKey{}, s)
|
||||
}
|
||||
|
||||
func newOptions(opt ...server.Option) server.Options {
|
||||
opts := server.Options{
|
||||
Codecs: make(map[string]codec.NewCodec),
|
||||
Metadata: map[string]string{},
|
||||
Broker: broker.DefaultBroker,
|
||||
Registry: registry.DefaultRegistry,
|
||||
RegisterCheck: server.DefaultRegisterCheck,
|
||||
Transport: transport.DefaultTransport,
|
||||
Address: server.DefaultAddress,
|
||||
Name: server.DefaultName,
|
||||
Id: server.DefaultId,
|
||||
Version: server.DefaultVersion,
|
||||
Logger: logger.DefaultLogger,
|
||||
}
|
||||
|
||||
for _, o := range opt {
|
||||
o(&opts)
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
90
vendor/github.com/go-micro/plugins/v4/server/grpc/request.go
generated
vendored
Normal file
90
vendor/github.com/go-micro/plugins/v4/server/grpc/request.go
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"go-micro.dev/v4/codec"
|
||||
"go-micro.dev/v4/codec/bytes"
|
||||
)
|
||||
|
||||
type rpcRequest struct {
|
||||
service string
|
||||
method string
|
||||
contentType string
|
||||
codec codec.Codec
|
||||
header map[string]string
|
||||
body []byte
|
||||
stream bool
|
||||
payload interface{}
|
||||
}
|
||||
|
||||
type rpcMessage struct {
|
||||
topic string
|
||||
contentType string
|
||||
payload interface{}
|
||||
header map[string]string
|
||||
body []byte
|
||||
codec codec.Codec
|
||||
}
|
||||
|
||||
func (r *rpcRequest) ContentType() string {
|
||||
return r.contentType
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Service() string {
|
||||
return r.service
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Method() string {
|
||||
return r.method
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Endpoint() string {
|
||||
return r.method
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Codec() codec.Reader {
|
||||
return r.codec
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Header() map[string]string {
|
||||
return r.header
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Read() ([]byte, error) {
|
||||
f := &bytes.Frame{}
|
||||
if err := r.codec.ReadBody(f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return f.Data, nil
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Stream() bool {
|
||||
return r.stream
|
||||
}
|
||||
|
||||
func (r *rpcRequest) Body() interface{} {
|
||||
return r.payload
|
||||
}
|
||||
|
||||
func (r *rpcMessage) ContentType() string {
|
||||
return r.contentType
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Topic() string {
|
||||
return r.topic
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Payload() interface{} {
|
||||
return r.payload
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Header() map[string]string {
|
||||
return r.header
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Body() []byte {
|
||||
return r.body
|
||||
}
|
||||
|
||||
func (r *rpcMessage) Codec() codec.Reader {
|
||||
return r.codec
|
||||
}
|
||||
27
vendor/github.com/go-micro/plugins/v4/server/grpc/response.go
generated
vendored
Normal file
27
vendor/github.com/go-micro/plugins/v4/server/grpc/response.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"go-micro.dev/v4/codec"
|
||||
)
|
||||
|
||||
type rpcResponse struct {
|
||||
header map[string]string
|
||||
codec codec.Codec
|
||||
}
|
||||
|
||||
func (r *rpcResponse) Codec() codec.Writer {
|
||||
return r.codec
|
||||
}
|
||||
|
||||
func (r *rpcResponse) WriteHeader(hdr map[string]string) {
|
||||
for k, v := range hdr {
|
||||
r.header[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
func (r *rpcResponse) Write(b []byte) error {
|
||||
return r.codec.Write(&codec.Message{
|
||||
Header: r.header,
|
||||
Body: b,
|
||||
}, nil)
|
||||
}
|
||||
182
vendor/github.com/go-micro/plugins/v4/server/grpc/server.go
generated
vendored
Normal file
182
vendor/github.com/go-micro/plugins/v4/server/grpc/server.go
generated
vendored
Normal file
@@ -0,0 +1,182 @@
|
||||
package grpc
|
||||
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
//
|
||||
// Meh, we need to get rid of this shit
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"reflect"
|
||||
"sync"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
var (
|
||||
// Precompute the reflect type for error. Can't use error directly
|
||||
// because Typeof takes an empty interface value. This is annoying.
|
||||
typeOfError = reflect.TypeOf((*error)(nil)).Elem()
|
||||
)
|
||||
|
||||
type methodType struct {
|
||||
method reflect.Method
|
||||
ArgType reflect.Type
|
||||
ReplyType reflect.Type
|
||||
ContextType reflect.Type
|
||||
stream bool
|
||||
}
|
||||
|
||||
type service struct {
|
||||
name string // name of service
|
||||
rcvr reflect.Value // receiver of methods for the service
|
||||
typ reflect.Type // type of the receiver
|
||||
method map[string]*methodType // registered methods
|
||||
}
|
||||
|
||||
// server represents an RPC Server.
|
||||
type rServer struct {
|
||||
mu sync.Mutex // protects the serviceMap
|
||||
serviceMap map[string]*service
|
||||
logger logger.Logger
|
||||
}
|
||||
|
||||
// Is this an exported - upper case - name?
|
||||
func isExported(name string) bool {
|
||||
rune, _ := utf8.DecodeRuneInString(name)
|
||||
return unicode.IsUpper(rune)
|
||||
}
|
||||
|
||||
// Is this type exported or a builtin?
|
||||
func isExportedOrBuiltinType(t reflect.Type) bool {
|
||||
for t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
// PkgPath will be non-empty even for an exported type,
|
||||
// so we need to check the type name as well.
|
||||
return isExported(t.Name()) || t.PkgPath() == ""
|
||||
}
|
||||
|
||||
// prepareEndpoint() returns a methodType for the provided method or nil
|
||||
// in case if the method was unsuitable.
|
||||
func prepareEndpoint(method reflect.Method, log logger.Logger) *methodType {
|
||||
mtype := method.Type
|
||||
mname := method.Name
|
||||
var replyType, argType, contextType reflect.Type
|
||||
var stream bool
|
||||
|
||||
// Endpoint() must be exported.
|
||||
if method.PkgPath != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch mtype.NumIn() {
|
||||
case 3:
|
||||
// assuming streaming
|
||||
argType = mtype.In(2)
|
||||
contextType = mtype.In(1)
|
||||
stream = true
|
||||
case 4:
|
||||
// method that takes a context
|
||||
argType = mtype.In(2)
|
||||
replyType = mtype.In(3)
|
||||
contextType = mtype.In(1)
|
||||
default:
|
||||
log.Logf(logger.ErrorLevel, "method %v of %v has wrong number of ins: %v", mname, mtype, mtype.NumIn())
|
||||
return nil
|
||||
}
|
||||
|
||||
if stream {
|
||||
// check stream type
|
||||
streamType := reflect.TypeOf((*server.Stream)(nil)).Elem()
|
||||
if !argType.Implements(streamType) {
|
||||
log.Logf(logger.ErrorLevel, "%v argument does not implement Streamer interface: %v", mname, argType)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
// if not stream check the replyType
|
||||
|
||||
// First arg need not be a pointer.
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
log.Logf(logger.ErrorLevel, "%v argument type not exported: %v", mname, argType)
|
||||
return nil
|
||||
}
|
||||
|
||||
if replyType.Kind() != reflect.Ptr {
|
||||
log.Logf(logger.ErrorLevel, "method %v reply type not a pointer: %v", mname, replyType)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reply type must be exported.
|
||||
if !isExportedOrBuiltinType(replyType) {
|
||||
log.Logf(logger.ErrorLevel, "method %v reply type not exported: %v", mname, replyType)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Endpoint() needs one out.
|
||||
if mtype.NumOut() != 1 {
|
||||
log.Logf(logger.ErrorLevel, "method %v has wrong number of outs: %v", mname, mtype.NumOut())
|
||||
return nil
|
||||
}
|
||||
// The return type of the method must be error.
|
||||
if returnType := mtype.Out(0); returnType != typeOfError {
|
||||
log.Logf(logger.ErrorLevel, "method %v returns %v not error", mname, returnType.String())
|
||||
return nil
|
||||
}
|
||||
return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream}
|
||||
}
|
||||
|
||||
func (server *rServer) register(rcvr interface{}) error {
|
||||
server.mu.Lock()
|
||||
defer server.mu.Unlock()
|
||||
log := server.logger
|
||||
if server.serviceMap == nil {
|
||||
server.serviceMap = make(map[string]*service)
|
||||
}
|
||||
s := new(service)
|
||||
s.typ = reflect.TypeOf(rcvr)
|
||||
s.rcvr = reflect.ValueOf(rcvr)
|
||||
sname := reflect.Indirect(s.rcvr).Type().Name()
|
||||
if sname == "" {
|
||||
logger.Fatalf("rpc: no service name for type %v", s.typ.String())
|
||||
}
|
||||
if !isExported(sname) {
|
||||
s := "rpc Register: type " + sname + " is not exported"
|
||||
log.Log(logger.ErrorLevel, s)
|
||||
return errors.New(s)
|
||||
}
|
||||
if _, present := server.serviceMap[sname]; present {
|
||||
return errors.New("rpc: service already defined: " + sname)
|
||||
}
|
||||
s.name = sname
|
||||
s.method = make(map[string]*methodType)
|
||||
|
||||
// Install the methods
|
||||
for m := 0; m < s.typ.NumMethod(); m++ {
|
||||
method := s.typ.Method(m)
|
||||
if mt := prepareEndpoint(method, log); mt != nil {
|
||||
s.method[method.Name] = mt
|
||||
}
|
||||
}
|
||||
|
||||
if len(s.method) == 0 {
|
||||
s := "rpc Register: type " + sname + " has no exported methods of suitable type"
|
||||
log.Log(logger.ErrorLevel, s)
|
||||
return errors.New(s)
|
||||
}
|
||||
server.serviceMap[s.name] = s
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *methodType) prepareContext(ctx context.Context) reflect.Value {
|
||||
if contextv := reflect.ValueOf(ctx); contextv.IsValid() {
|
||||
return contextv
|
||||
}
|
||||
return reflect.Zero(m.ContextType)
|
||||
}
|
||||
38
vendor/github.com/go-micro/plugins/v4/server/grpc/stream.go
generated
vendored
Normal file
38
vendor/github.com/go-micro/plugins/v4/server/grpc/stream.go
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go-micro.dev/v4/server"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// rpcStream implements a server side Stream.
|
||||
type rpcStream struct {
|
||||
s grpc.ServerStream
|
||||
request server.Request
|
||||
}
|
||||
|
||||
func (r *rpcStream) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rpcStream) Error() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *rpcStream) Request() server.Request {
|
||||
return r.request
|
||||
}
|
||||
|
||||
func (r *rpcStream) Context() context.Context {
|
||||
return r.s.Context()
|
||||
}
|
||||
|
||||
func (r *rpcStream) Send(m interface{}) error {
|
||||
return r.s.SendMsg(m)
|
||||
}
|
||||
|
||||
func (r *rpcStream) Recv(m interface{}) error {
|
||||
return r.s.RecvMsg(m)
|
||||
}
|
||||
291
vendor/github.com/go-micro/plugins/v4/server/grpc/subscriber.go
generated
vendored
Normal file
291
vendor/github.com/go-micro/plugins/v4/server/grpc/subscriber.go
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
"go-micro.dev/v4/broker"
|
||||
"go-micro.dev/v4/errors"
|
||||
"go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/metadata"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
const (
|
||||
subSig = "func(context.Context, interface{}) error"
|
||||
)
|
||||
|
||||
type handler struct {
|
||||
method reflect.Value
|
||||
reqType reflect.Type
|
||||
ctxType reflect.Type
|
||||
}
|
||||
|
||||
type subscriber struct {
|
||||
topic string
|
||||
rcvr reflect.Value
|
||||
typ reflect.Type
|
||||
subscriber interface{}
|
||||
handlers []*handler
|
||||
endpoints []*registry.Endpoint
|
||||
opts server.SubscriberOptions
|
||||
}
|
||||
|
||||
func newSubscriber(topic string, sub interface{}, opts ...server.SubscriberOption) server.Subscriber {
|
||||
options := server.SubscriberOptions{
|
||||
AutoAck: true,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
var endpoints []*registry.Endpoint
|
||||
var handlers []*handler
|
||||
|
||||
if typ := reflect.TypeOf(sub); typ.Kind() == reflect.Func {
|
||||
h := &handler{
|
||||
method: reflect.ValueOf(sub),
|
||||
}
|
||||
|
||||
switch typ.NumIn() {
|
||||
case 1:
|
||||
h.reqType = typ.In(0)
|
||||
case 2:
|
||||
h.ctxType = typ.In(0)
|
||||
h.reqType = typ.In(1)
|
||||
}
|
||||
|
||||
handlers = append(handlers, h)
|
||||
|
||||
endpoints = append(endpoints, ®istry.Endpoint{
|
||||
Name: "Func",
|
||||
Request: extractSubValue(typ),
|
||||
Metadata: map[string]string{
|
||||
"topic": topic,
|
||||
"subscriber": "true",
|
||||
},
|
||||
})
|
||||
} else {
|
||||
hdlr := reflect.ValueOf(sub)
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
method := typ.Method(m)
|
||||
h := &handler{
|
||||
method: method.Func,
|
||||
}
|
||||
|
||||
switch method.Type.NumIn() {
|
||||
case 2:
|
||||
h.reqType = method.Type.In(1)
|
||||
case 3:
|
||||
h.ctxType = method.Type.In(1)
|
||||
h.reqType = method.Type.In(2)
|
||||
}
|
||||
|
||||
handlers = append(handlers, h)
|
||||
|
||||
endpoints = append(endpoints, ®istry.Endpoint{
|
||||
Name: name + "." + method.Name,
|
||||
Request: extractSubValue(method.Type),
|
||||
Metadata: map[string]string{
|
||||
"topic": topic,
|
||||
"subscriber": "true",
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &subscriber{
|
||||
rcvr: reflect.ValueOf(sub),
|
||||
typ: reflect.TypeOf(sub),
|
||||
topic: topic,
|
||||
subscriber: sub,
|
||||
handlers: handlers,
|
||||
endpoints: endpoints,
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
func validateSubscriber(sub server.Subscriber) error {
|
||||
typ := reflect.TypeOf(sub.Subscriber())
|
||||
var argType reflect.Type
|
||||
|
||||
if typ.Kind() == reflect.Func {
|
||||
name := "Func"
|
||||
switch typ.NumIn() {
|
||||
case 2:
|
||||
argType = typ.In(1)
|
||||
default:
|
||||
return fmt.Errorf("subscriber %v takes wrong number of args: %v required signature %s", name, typ.NumIn(), subSig)
|
||||
}
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
return fmt.Errorf("subscriber %v argument type not exported: %v", name, argType)
|
||||
}
|
||||
if typ.NumOut() != 1 {
|
||||
return fmt.Errorf("subscriber %v has wrong number of outs: %v require signature %s",
|
||||
name, typ.NumOut(), subSig)
|
||||
}
|
||||
if returnType := typ.Out(0); returnType != typeOfError {
|
||||
return fmt.Errorf("subscriber %v returns %v not error", name, returnType.String())
|
||||
}
|
||||
} else {
|
||||
hdlr := reflect.ValueOf(sub.Subscriber())
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
method := typ.Method(m)
|
||||
|
||||
switch method.Type.NumIn() {
|
||||
case 3:
|
||||
argType = method.Type.In(2)
|
||||
default:
|
||||
return fmt.Errorf("subscriber %v.%v takes wrong number of args: %v required signature %s",
|
||||
name, method.Name, method.Type.NumIn(), subSig)
|
||||
}
|
||||
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
return fmt.Errorf("%v argument type not exported: %v", name, argType)
|
||||
}
|
||||
if method.Type.NumOut() != 1 {
|
||||
return fmt.Errorf(
|
||||
"subscriber %v.%v has wrong number of outs: %v require signature %s",
|
||||
name, method.Name, method.Type.NumOut(), subSig)
|
||||
}
|
||||
if returnType := method.Type.Out(0); returnType != typeOfError {
|
||||
return fmt.Errorf("subscriber %v.%v returns %v not error", name, method.Name, returnType.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broker.Handler {
|
||||
return func(p broker.Event) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
g.opts.Logger.Log(logger.ErrorLevel, "panic recovered: ", r)
|
||||
g.opts.Logger.Log(logger.ErrorLevel, string(debug.Stack()))
|
||||
err = errors.InternalServerError("go.micro.server", "panic recovered: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
msg := p.Message()
|
||||
// if we don't have headers, create empty map
|
||||
if msg.Header == nil {
|
||||
msg.Header = make(map[string]string)
|
||||
}
|
||||
|
||||
ct := msg.Header["Content-Type"]
|
||||
if len(ct) == 0 {
|
||||
msg.Header["Content-Type"] = defaultContentType
|
||||
ct = defaultContentType
|
||||
}
|
||||
cf, err := g.newGRPCCodec(ct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hdr := make(map[string]string, len(msg.Header))
|
||||
for k, v := range msg.Header {
|
||||
hdr[k] = v
|
||||
}
|
||||
delete(hdr, "Content-Type")
|
||||
ctx := metadata.NewContext(context.Background(), hdr)
|
||||
|
||||
results := make(chan error, len(sb.handlers))
|
||||
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
handler := sb.handlers[i]
|
||||
|
||||
var isVal bool
|
||||
var req reflect.Value
|
||||
|
||||
if handler.reqType.Kind() == reflect.Ptr {
|
||||
req = reflect.New(handler.reqType.Elem())
|
||||
} else {
|
||||
req = reflect.New(handler.reqType)
|
||||
isVal = true
|
||||
}
|
||||
if isVal {
|
||||
req = req.Elem()
|
||||
}
|
||||
|
||||
if err = cf.Unmarshal(msg.Body, req.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fn := func(ctx context.Context, msg server.Message) error {
|
||||
var vals []reflect.Value
|
||||
if sb.typ.Kind() != reflect.Func {
|
||||
vals = append(vals, sb.rcvr)
|
||||
}
|
||||
if handler.ctxType != nil {
|
||||
vals = append(vals, reflect.ValueOf(ctx))
|
||||
}
|
||||
|
||||
vals = append(vals, reflect.ValueOf(msg.Payload()))
|
||||
|
||||
returnValues := handler.method.Call(vals)
|
||||
if rerr := returnValues[0].Interface(); rerr != nil {
|
||||
return rerr.(error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := len(opts.SubWrappers); i > 0; i-- {
|
||||
fn = opts.SubWrappers[i-1](fn)
|
||||
}
|
||||
|
||||
if g.wg != nil {
|
||||
g.wg.Add(1)
|
||||
}
|
||||
go func() {
|
||||
if g.wg != nil {
|
||||
defer g.wg.Done()
|
||||
}
|
||||
err := fn(ctx, &rpcMessage{
|
||||
topic: sb.topic,
|
||||
contentType: ct,
|
||||
payload: req.Interface(),
|
||||
header: msg.Header,
|
||||
body: msg.Body,
|
||||
})
|
||||
results <- err
|
||||
}()
|
||||
}
|
||||
var errors []string
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
if rerr := <-results; rerr != nil {
|
||||
errors = append(errors, rerr.Error())
|
||||
}
|
||||
}
|
||||
if len(errors) > 0 {
|
||||
err = fmt.Errorf("subscriber error: %s", strings.Join(errors, "\n"))
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func (s *subscriber) Topic() string {
|
||||
return s.topic
|
||||
}
|
||||
|
||||
func (s *subscriber) Subscriber() interface{} {
|
||||
return s.subscriber
|
||||
}
|
||||
|
||||
func (s *subscriber) Endpoints() []*registry.Endpoint {
|
||||
return s.endpoints
|
||||
}
|
||||
|
||||
func (s *subscriber) Options() server.SubscriberOptions {
|
||||
return s.opts
|
||||
}
|
||||
49
vendor/github.com/go-micro/plugins/v4/server/grpc/util.go
generated
vendored
Normal file
49
vendor/github.com/go-micro/plugins/v4/server/grpc/util.go
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
// convertCode converts a standard Go error into its canonical code. Note that
|
||||
// this is only used to translate the error returned by the server applications.
|
||||
func convertCode(err error) codes.Code {
|
||||
switch err {
|
||||
case nil:
|
||||
return codes.OK
|
||||
case io.EOF:
|
||||
return codes.OutOfRange
|
||||
case io.ErrClosedPipe, io.ErrNoProgress, io.ErrShortBuffer, io.ErrShortWrite, io.ErrUnexpectedEOF:
|
||||
return codes.FailedPrecondition
|
||||
case os.ErrInvalid:
|
||||
return codes.InvalidArgument
|
||||
case context.Canceled:
|
||||
return codes.Canceled
|
||||
case context.DeadlineExceeded:
|
||||
return codes.DeadlineExceeded
|
||||
}
|
||||
switch {
|
||||
case os.IsExist(err):
|
||||
return codes.AlreadyExists
|
||||
case os.IsNotExist(err):
|
||||
return codes.NotFound
|
||||
case os.IsPermission(err):
|
||||
return codes.PermissionDenied
|
||||
}
|
||||
return codes.Unknown
|
||||
}
|
||||
|
||||
func wait(ctx context.Context) *sync.WaitGroup {
|
||||
if ctx == nil {
|
||||
return nil
|
||||
}
|
||||
wg, ok := ctx.Value("wait").(*sync.WaitGroup)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return wg
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/server/http/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/server/http/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
65
vendor/github.com/go-micro/plugins/v4/server/http/README.md
generated
vendored
Normal file
65
vendor/github.com/go-micro/plugins/v4/server/http/README.md
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
# HTTP Server
|
||||
|
||||
The HTTP Server is a go-micro.Server. It's a partial implementation which strips out codecs, transports, etc but enables you
|
||||
to create a HTTP Server that could potentially be used for REST based API services.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/micro/go-micro/server"
|
||||
httpServer "github.com/go-micro/plugins/v4/server/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
srv := httpServer.NewServer(
|
||||
server.Name("helloworld"),
|
||||
)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(`hello world`))
|
||||
})
|
||||
|
||||
hd := srv.NewHandler(mux)
|
||||
|
||||
srv.Handle(hd)
|
||||
srv.Start()
|
||||
srv.Register()
|
||||
}
|
||||
```
|
||||
|
||||
Or as part of a service
|
||||
|
||||
```go
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"go-micro.dev/v4"
|
||||
"github.com/micro/go-micro/server"
|
||||
httpServer "github.com/go-micro/plugins/v4/server/http"
|
||||
)
|
||||
|
||||
func main() {
|
||||
srv := httpServer.NewServer(
|
||||
server.Name("helloworld"),
|
||||
)
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(`hello world`))
|
||||
})
|
||||
|
||||
hd := srv.NewHandler(mux)
|
||||
|
||||
srv.Handle(hd)
|
||||
|
||||
service := micro.NewService(
|
||||
micro.Server(srv),
|
||||
)
|
||||
service.Init()
|
||||
service.Run()
|
||||
}
|
||||
```
|
||||
14
vendor/github.com/go-micro/plugins/v4/server/http/buffer.go
generated
vendored
Normal file
14
vendor/github.com/go-micro/plugins/v4/server/http/buffer.go
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
)
|
||||
|
||||
type buffer struct {
|
||||
*bytes.Buffer
|
||||
}
|
||||
|
||||
func (b *buffer) Close() error {
|
||||
b.Buffer.Reset()
|
||||
return nil
|
||||
}
|
||||
16
vendor/github.com/go-micro/plugins/v4/server/http/context.go
generated
vendored
Normal file
16
vendor/github.com/go-micro/plugins/v4/server/http/context.go
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
func setServerOption(k, v interface{}) server.Option {
|
||||
return func(o *server.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
165
vendor/github.com/go-micro/plugins/v4/server/http/extractor.go
generated
vendored
Normal file
165
vendor/github.com/go-micro/plugins/v4/server/http/extractor.go
generated
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/server"
|
||||
"go-micro.dev/v4/util/addr"
|
||||
)
|
||||
|
||||
func serviceDef(opts server.Options) *registry.Service {
|
||||
var advt, host string
|
||||
var port int
|
||||
|
||||
if len(opts.Advertise) > 0 {
|
||||
advt = opts.Advertise
|
||||
} else {
|
||||
advt = opts.Address
|
||||
}
|
||||
|
||||
parts := strings.Split(advt, ":")
|
||||
if len(parts) > 1 {
|
||||
host = strings.Join(parts[:len(parts)-1], ":")
|
||||
port, _ = strconv.Atoi(parts[len(parts)-1])
|
||||
} else {
|
||||
host = parts[0]
|
||||
}
|
||||
|
||||
addr, err := addr.Extract(host)
|
||||
if err != nil {
|
||||
addr = host
|
||||
}
|
||||
|
||||
node := ®istry.Node{
|
||||
Id: opts.Name + "-" + opts.Id,
|
||||
Address: net.JoinHostPort(addr, fmt.Sprint(port)),
|
||||
Metadata: opts.Metadata,
|
||||
}
|
||||
|
||||
node.Metadata["server"] = "http"
|
||||
node.Metadata["broker"] = opts.Broker.String()
|
||||
node.Metadata["registry"] = opts.Registry.String()
|
||||
node.Metadata["protocol"] = "http"
|
||||
|
||||
return ®istry.Service{
|
||||
Name: opts.Name,
|
||||
Version: opts.Version,
|
||||
Nodes: []*registry.Node{node},
|
||||
}
|
||||
}
|
||||
|
||||
func extractValue(v reflect.Type, d int) *registry.Value {
|
||||
if d == 3 {
|
||||
return nil
|
||||
}
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
|
||||
arg := ®istry.Value{
|
||||
Name: v.Name(),
|
||||
Type: v.Name(),
|
||||
}
|
||||
|
||||
switch v.Kind() {
|
||||
case reflect.Struct:
|
||||
for i := 0; i < v.NumField(); i++ {
|
||||
f := v.Field(i)
|
||||
if f.PkgPath != "" {
|
||||
continue
|
||||
}
|
||||
val := extractValue(f.Type, d+1)
|
||||
if val == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// if we can find a json tag use it
|
||||
if tags := f.Tag.Get("json"); len(tags) > 0 {
|
||||
parts := strings.Split(tags, ",")
|
||||
val.Name = parts[0]
|
||||
}
|
||||
|
||||
// if there's no name default it
|
||||
if len(val.Name) == 0 {
|
||||
val.Name = v.Field(i).Name
|
||||
}
|
||||
|
||||
arg.Values = append(arg.Values, val)
|
||||
}
|
||||
case reflect.Slice:
|
||||
p := v.Elem()
|
||||
if p.Kind() == reflect.Ptr {
|
||||
p = p.Elem()
|
||||
}
|
||||
arg.Type = "[]" + p.Name()
|
||||
val := extractValue(v.Elem(), d+1)
|
||||
if val != nil {
|
||||
arg.Values = append(arg.Values, val)
|
||||
}
|
||||
}
|
||||
|
||||
return arg
|
||||
}
|
||||
|
||||
func extractEndpoint(method reflect.Method) *registry.Endpoint {
|
||||
if method.PkgPath != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
var rspType, reqType reflect.Type
|
||||
var stream bool
|
||||
mt := method.Type
|
||||
|
||||
switch mt.NumIn() {
|
||||
case 3:
|
||||
reqType = mt.In(1)
|
||||
rspType = mt.In(2)
|
||||
case 4:
|
||||
reqType = mt.In(2)
|
||||
rspType = mt.In(3)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
// are we dealing with a stream?
|
||||
switch rspType.Kind() {
|
||||
case reflect.Func, reflect.Interface:
|
||||
stream = true
|
||||
}
|
||||
|
||||
request := extractValue(reqType, 0)
|
||||
response := extractValue(rspType, 0)
|
||||
|
||||
return ®istry.Endpoint{
|
||||
Name: method.Name,
|
||||
Request: request,
|
||||
Response: response,
|
||||
Metadata: map[string]string{
|
||||
"stream": fmt.Sprintf("%v", stream),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func extractSubValue(typ reflect.Type) *registry.Value {
|
||||
var reqType reflect.Type
|
||||
switch typ.NumIn() {
|
||||
case 1:
|
||||
reqType = typ.In(0)
|
||||
case 2:
|
||||
reqType = typ.In(1)
|
||||
case 3:
|
||||
reqType = typ.In(2)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
return extractValue(reqType, 0)
|
||||
}
|
||||
28
vendor/github.com/go-micro/plugins/v4/server/http/handler.go
generated
vendored
Normal file
28
vendor/github.com/go-micro/plugins/v4/server/http/handler.go
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
type httpHandler struct {
|
||||
opts server.HandlerOptions
|
||||
eps []*registry.Endpoint
|
||||
hd interface{}
|
||||
}
|
||||
|
||||
func (h *httpHandler) Name() string {
|
||||
return "handler"
|
||||
}
|
||||
|
||||
func (h *httpHandler) Handler() interface{} {
|
||||
return h.hd
|
||||
}
|
||||
|
||||
func (h *httpHandler) Endpoints() []*registry.Endpoint {
|
||||
return h.eps
|
||||
}
|
||||
|
||||
func (h *httpHandler) Options() server.HandlerOptions {
|
||||
return h.opts
|
||||
}
|
||||
364
vendor/github.com/go-micro/plugins/v4/server/http/http.go
generated
vendored
Normal file
364
vendor/github.com/go-micro/plugins/v4/server/http/http.go
generated
vendored
Normal file
@@ -0,0 +1,364 @@
|
||||
// Package http implements a go-micro.Server
|
||||
package http
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"go-micro.dev/v4/broker"
|
||||
"go-micro.dev/v4/codec"
|
||||
"go-micro.dev/v4/codec/jsonrpc"
|
||||
"go-micro.dev/v4/codec/protorpc"
|
||||
log "go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/server"
|
||||
"go-micro.dev/v4/util/cmd"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultCodecs = map[string]codec.NewCodec{
|
||||
"application/json": jsonrpc.NewCodec,
|
||||
"application/json-rpc": jsonrpc.NewCodec,
|
||||
"application/protobuf": protorpc.NewCodec,
|
||||
"application/proto-rpc": protorpc.NewCodec,
|
||||
"application/octet-stream": protorpc.NewCodec,
|
||||
}
|
||||
)
|
||||
|
||||
type httpServer struct {
|
||||
sync.Mutex
|
||||
opts server.Options
|
||||
hd server.Handler
|
||||
exit chan chan error
|
||||
registerOnce sync.Once
|
||||
subscribers map[*httpSubscriber][]broker.Subscriber
|
||||
// used for first registration
|
||||
registered bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmd.DefaultServers["http"] = NewServer
|
||||
}
|
||||
|
||||
func (h *httpServer) newCodec(contentType string) (codec.NewCodec, error) {
|
||||
if cf, ok := h.opts.Codecs[contentType]; ok {
|
||||
return cf, nil
|
||||
}
|
||||
if cf, ok := defaultCodecs[contentType]; ok {
|
||||
return cf, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType)
|
||||
}
|
||||
|
||||
func (h *httpServer) getListener() net.Listener {
|
||||
if h.opts.Context == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if l, ok := h.opts.Context.Value(netListener{}).(net.Listener); ok && l != nil {
|
||||
return l
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpServer) Options() server.Options {
|
||||
h.Lock()
|
||||
opts := h.opts
|
||||
h.Unlock()
|
||||
return opts
|
||||
}
|
||||
|
||||
func (h *httpServer) Init(opts ...server.Option) error {
|
||||
h.Lock()
|
||||
for _, o := range opts {
|
||||
o(&h.opts)
|
||||
}
|
||||
h.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpServer) Handle(handler server.Handler) error {
|
||||
if _, ok := handler.Handler().(http.Handler); !ok {
|
||||
return errors.New("Handle requires http.Handler")
|
||||
}
|
||||
h.Lock()
|
||||
h.hd = handler
|
||||
h.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpServer) NewHandler(handler interface{}, opts ...server.HandlerOption) server.Handler {
|
||||
options := server.HandlerOptions{
|
||||
Metadata: make(map[string]map[string]string),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
var eps []*registry.Endpoint
|
||||
|
||||
if !options.Internal {
|
||||
for name, metadata := range options.Metadata {
|
||||
eps = append(eps, ®istry.Endpoint{
|
||||
Name: name,
|
||||
Metadata: metadata,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &httpHandler{
|
||||
eps: eps,
|
||||
hd: handler,
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
func (h *httpServer) NewSubscriber(topic string, handler interface{}, opts ...server.SubscriberOption) server.Subscriber {
|
||||
return newSubscriber(topic, handler, opts...)
|
||||
}
|
||||
|
||||
func (h *httpServer) Subscribe(sb server.Subscriber) error {
|
||||
sub, ok := sb.(*httpSubscriber)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid subscriber: expected *httpSubscriber")
|
||||
}
|
||||
if len(sub.handlers) == 0 {
|
||||
return fmt.Errorf("invalid subscriber: no handler functions")
|
||||
}
|
||||
|
||||
if err := validateSubscriber(sb); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
_, ok = h.subscribers[sub]
|
||||
if ok {
|
||||
return fmt.Errorf("subscriber %v already exists", h)
|
||||
}
|
||||
h.subscribers[sub] = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpServer) Register() error {
|
||||
h.Lock()
|
||||
opts := h.opts
|
||||
eps := h.hd.Endpoints()
|
||||
h.Unlock()
|
||||
|
||||
service := serviceDef(opts)
|
||||
service.Endpoints = eps
|
||||
|
||||
h.Lock()
|
||||
var subscriberList []*httpSubscriber
|
||||
for e := range h.subscribers {
|
||||
// Only advertise non internal subscribers
|
||||
if !e.Options().Internal {
|
||||
subscriberList = append(subscriberList, e)
|
||||
}
|
||||
}
|
||||
sort.Slice(subscriberList, func(i, j int) bool {
|
||||
return subscriberList[i].topic > subscriberList[j].topic
|
||||
})
|
||||
for _, e := range subscriberList {
|
||||
service.Endpoints = append(service.Endpoints, e.Endpoints()...)
|
||||
}
|
||||
h.Unlock()
|
||||
|
||||
rOpts := []registry.RegisterOption{
|
||||
registry.RegisterTTL(opts.RegisterTTL),
|
||||
}
|
||||
|
||||
h.registerOnce.Do(func() {
|
||||
log.Infof("Registering node: %s", opts.Name+"-"+opts.Id)
|
||||
})
|
||||
|
||||
if err := opts.Registry.Register(service, rOpts...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
|
||||
if h.registered {
|
||||
return nil
|
||||
}
|
||||
h.registered = true
|
||||
|
||||
for sb := range h.subscribers {
|
||||
handler := h.createSubHandler(sb, opts)
|
||||
var subOpts []broker.SubscribeOption
|
||||
if queue := sb.Options().Queue; len(queue) > 0 {
|
||||
subOpts = append(subOpts, broker.Queue(queue))
|
||||
}
|
||||
|
||||
if cx := sb.Options().Context; cx != nil {
|
||||
subOpts = append(subOpts, broker.SubscribeContext(cx))
|
||||
}
|
||||
|
||||
if !sb.Options().AutoAck {
|
||||
subOpts = append(subOpts, broker.DisableAutoAck())
|
||||
}
|
||||
|
||||
sub, err := opts.Broker.Subscribe(sb.Topic(), handler, subOpts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.subscribers[sb] = []broker.Subscriber{sub}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpServer) Deregister() error {
|
||||
h.Lock()
|
||||
opts := h.opts
|
||||
h.Unlock()
|
||||
|
||||
log.Infof("Deregistering node: %s", opts.Name+"-"+opts.Id)
|
||||
|
||||
service := serviceDef(opts)
|
||||
if err := opts.Registry.Deregister(service); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
h.Lock()
|
||||
|
||||
if !h.registered {
|
||||
h.Unlock()
|
||||
return nil
|
||||
}
|
||||
h.registered = false
|
||||
|
||||
wg := sync.WaitGroup{}
|
||||
for sb, subs := range h.subscribers {
|
||||
for _, sub := range subs {
|
||||
wg.Add(1)
|
||||
go func(s broker.Subscriber) {
|
||||
defer wg.Done()
|
||||
log.Infof("Unsubscribing from topic: %s", s.Topic())
|
||||
s.Unsubscribe()
|
||||
}(sub)
|
||||
}
|
||||
h.subscribers[sb] = nil
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
h.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpServer) Start() error {
|
||||
h.Lock()
|
||||
opts := h.opts
|
||||
hd := h.hd
|
||||
h.Unlock()
|
||||
|
||||
var (
|
||||
ln net.Listener
|
||||
err error
|
||||
)
|
||||
|
||||
if l := h.getListener(); l != nil {
|
||||
ln = l
|
||||
} else if opts.TLSConfig != nil {
|
||||
ln, err = tls.Listen("tcp", opts.Address, opts.TLSConfig)
|
||||
} else {
|
||||
ln, err = net.Listen("tcp", opts.Address)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("Listening on %s", ln.Addr().String())
|
||||
|
||||
h.Lock()
|
||||
h.opts.Address = ln.Addr().String()
|
||||
h.Unlock()
|
||||
|
||||
handler, ok := hd.Handler().(http.Handler)
|
||||
if !ok {
|
||||
return errors.New("Server required http.Handler")
|
||||
}
|
||||
|
||||
if err = opts.Broker.Connect(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// register
|
||||
if err = h.Register(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go http.Serve(ln, handler)
|
||||
|
||||
go func() {
|
||||
t := new(time.Ticker)
|
||||
|
||||
// only process if it exists
|
||||
if opts.RegisterInterval > time.Duration(0) {
|
||||
// new ticker
|
||||
t = time.NewTicker(opts.RegisterInterval)
|
||||
}
|
||||
|
||||
// return error chan
|
||||
var ch chan error
|
||||
|
||||
Loop:
|
||||
for {
|
||||
select {
|
||||
// register self on interval
|
||||
case <-t.C:
|
||||
if err := h.Register(); err != nil {
|
||||
log.Error("Server register error: ", err)
|
||||
}
|
||||
// wait for exit
|
||||
case ch = <-h.exit:
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
|
||||
// deregister
|
||||
h.Deregister()
|
||||
|
||||
opts.Broker.Disconnect()
|
||||
|
||||
// Solve the problem of early exit
|
||||
ch <- ln.Close()
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *httpServer) Stop() error {
|
||||
ch := make(chan error)
|
||||
h.exit <- ch
|
||||
return <-ch
|
||||
}
|
||||
|
||||
func (h *httpServer) String() string {
|
||||
if h.opts.TLSConfig != nil {
|
||||
return "https"
|
||||
}
|
||||
return "http"
|
||||
}
|
||||
|
||||
func newServer(opts ...server.Option) server.Server {
|
||||
return &httpServer{
|
||||
opts: newOptions(opts...),
|
||||
exit: make(chan chan error),
|
||||
subscribers: make(map[*httpSubscriber][]broker.Subscriber),
|
||||
}
|
||||
}
|
||||
|
||||
func NewServer(opts ...server.Option) server.Server {
|
||||
return newServer(opts...)
|
||||
}
|
||||
36
vendor/github.com/go-micro/plugins/v4/server/http/message.go
generated
vendored
Normal file
36
vendor/github.com/go-micro/plugins/v4/server/http/message.go
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
package http
|
||||
|
||||
import "go-micro.dev/v4/codec"
|
||||
|
||||
type httpMessage struct {
|
||||
topic string
|
||||
payload interface{}
|
||||
contentType string
|
||||
header map[string]string
|
||||
body []byte
|
||||
codec codec.Reader
|
||||
}
|
||||
|
||||
func (r *httpMessage) Topic() string {
|
||||
return r.topic
|
||||
}
|
||||
|
||||
func (r *httpMessage) Payload() interface{} {
|
||||
return r.payload
|
||||
}
|
||||
|
||||
func (r *httpMessage) ContentType() string {
|
||||
return r.contentType
|
||||
}
|
||||
|
||||
func (r *httpMessage) Header() map[string]string {
|
||||
return r.header
|
||||
}
|
||||
|
||||
func (r *httpMessage) Body() []byte {
|
||||
return r.body
|
||||
}
|
||||
|
||||
func (r *httpMessage) Codec() codec.Reader {
|
||||
return r.codec
|
||||
}
|
||||
56
vendor/github.com/go-micro/plugins/v4/server/http/options.go
generated
vendored
Normal file
56
vendor/github.com/go-micro/plugins/v4/server/http/options.go
generated
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
|
||||
"go-micro.dev/v4/broker"
|
||||
"go-micro.dev/v4/codec"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
type netListener struct{}
|
||||
|
||||
func newOptions(opt ...server.Option) server.Options {
|
||||
opts := server.Options{
|
||||
Codecs: make(map[string]codec.NewCodec),
|
||||
Metadata: map[string]string{},
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
for _, o := range opt {
|
||||
o(&opts)
|
||||
}
|
||||
|
||||
if opts.Broker == nil {
|
||||
opts.Broker = broker.DefaultBroker
|
||||
}
|
||||
|
||||
if opts.Registry == nil {
|
||||
opts.Registry = registry.DefaultRegistry
|
||||
}
|
||||
|
||||
if len(opts.Address) == 0 {
|
||||
opts.Address = server.DefaultAddress
|
||||
}
|
||||
|
||||
if len(opts.Name) == 0 {
|
||||
opts.Name = server.DefaultName
|
||||
}
|
||||
|
||||
if len(opts.Id) == 0 {
|
||||
opts.Id = server.DefaultId
|
||||
}
|
||||
|
||||
if len(opts.Version) == 0 {
|
||||
opts.Version = server.DefaultVersion
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
// Listener specifies the net.Listener to use instead of the default.
|
||||
func Listener(l net.Listener) server.Option {
|
||||
return setServerOption(netListener{}, l)
|
||||
}
|
||||
298
vendor/github.com/go-micro/plugins/v4/server/http/subscriber.go
generated
vendored
Normal file
298
vendor/github.com/go-micro/plugins/v4/server/http/subscriber.go
generated
vendored
Normal file
@@ -0,0 +1,298 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"go-micro.dev/v4/broker"
|
||||
"go-micro.dev/v4/codec"
|
||||
"go-micro.dev/v4/metadata"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
const (
|
||||
subSig = "func(context.Context, interface{}) error"
|
||||
)
|
||||
|
||||
var typeOfError = reflect.TypeOf((*error)(nil)).Elem()
|
||||
|
||||
type handler struct {
|
||||
method reflect.Value
|
||||
reqType reflect.Type
|
||||
ctxType reflect.Type
|
||||
}
|
||||
|
||||
type httpSubscriber struct {
|
||||
topic string
|
||||
rcvr reflect.Value
|
||||
typ reflect.Type
|
||||
subscriber interface{}
|
||||
handlers []*handler
|
||||
endpoints []*registry.Endpoint
|
||||
opts server.SubscriberOptions
|
||||
}
|
||||
|
||||
// Is this an exported - upper case - name?
|
||||
func isExported(name string) bool {
|
||||
rune, _ := utf8.DecodeRuneInString(name)
|
||||
return unicode.IsUpper(rune)
|
||||
}
|
||||
|
||||
// Is this type exported or a builtin?
|
||||
func isExportedOrBuiltinType(t reflect.Type) bool {
|
||||
for t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
// PkgPath will be non-empty even for an exported type,
|
||||
// so we need to check the type name as well.
|
||||
return isExported(t.Name()) || t.PkgPath() == ""
|
||||
}
|
||||
|
||||
func newSubscriber(topic string, sub interface{}, opts ...server.SubscriberOption) server.Subscriber {
|
||||
options := server.SubscriberOptions{
|
||||
AutoAck: true,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
var endpoints []*registry.Endpoint
|
||||
var handlers []*handler
|
||||
|
||||
if typ := reflect.TypeOf(sub); typ.Kind() == reflect.Func {
|
||||
h := &handler{
|
||||
method: reflect.ValueOf(sub),
|
||||
}
|
||||
|
||||
switch typ.NumIn() {
|
||||
case 1:
|
||||
h.reqType = typ.In(0)
|
||||
case 2:
|
||||
h.ctxType = typ.In(0)
|
||||
h.reqType = typ.In(1)
|
||||
}
|
||||
|
||||
handlers = append(handlers, h)
|
||||
|
||||
endpoints = append(endpoints, ®istry.Endpoint{
|
||||
Name: "Func",
|
||||
Request: extractSubValue(typ),
|
||||
Metadata: map[string]string{
|
||||
"topic": topic,
|
||||
"subscriber": "true",
|
||||
},
|
||||
})
|
||||
} else {
|
||||
hdlr := reflect.ValueOf(sub)
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
method := typ.Method(m)
|
||||
h := &handler{
|
||||
method: method.Func,
|
||||
}
|
||||
|
||||
switch method.Type.NumIn() {
|
||||
case 2:
|
||||
h.reqType = method.Type.In(1)
|
||||
case 3:
|
||||
h.ctxType = method.Type.In(1)
|
||||
h.reqType = method.Type.In(2)
|
||||
}
|
||||
|
||||
handlers = append(handlers, h)
|
||||
|
||||
endpoints = append(endpoints, ®istry.Endpoint{
|
||||
Name: name + "." + method.Name,
|
||||
Request: extractSubValue(method.Type),
|
||||
Metadata: map[string]string{
|
||||
"topic": topic,
|
||||
"subscriber": "true",
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return &httpSubscriber{
|
||||
rcvr: reflect.ValueOf(sub),
|
||||
typ: reflect.TypeOf(sub),
|
||||
topic: topic,
|
||||
subscriber: sub,
|
||||
handlers: handlers,
|
||||
endpoints: endpoints,
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
func validateSubscriber(sub server.Subscriber) error {
|
||||
typ := reflect.TypeOf(sub.Subscriber())
|
||||
var argType reflect.Type
|
||||
|
||||
if typ.Kind() == reflect.Func {
|
||||
name := "Func"
|
||||
switch typ.NumIn() {
|
||||
case 2:
|
||||
argType = typ.In(1)
|
||||
default:
|
||||
return fmt.Errorf("subscriber %v takes wrong number of args: %v required signature %s", name, typ.NumIn(), subSig)
|
||||
}
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
return fmt.Errorf("subscriber %v argument type not exported: %v", name, argType)
|
||||
}
|
||||
if typ.NumOut() != 1 {
|
||||
return fmt.Errorf("subscriber %v has wrong number of outs: %v require signature %s",
|
||||
name, typ.NumOut(), subSig)
|
||||
}
|
||||
if returnType := typ.Out(0); returnType != typeOfError {
|
||||
return fmt.Errorf("subscriber %v returns %v not error", name, returnType.String())
|
||||
}
|
||||
} else {
|
||||
hdlr := reflect.ValueOf(sub.Subscriber())
|
||||
name := reflect.Indirect(hdlr).Type().Name()
|
||||
|
||||
for m := 0; m < typ.NumMethod(); m++ {
|
||||
method := typ.Method(m)
|
||||
|
||||
switch method.Type.NumIn() {
|
||||
case 3:
|
||||
argType = method.Type.In(2)
|
||||
default:
|
||||
return fmt.Errorf("subscriber %v.%v takes wrong number of args: %v required signature %s",
|
||||
name, method.Name, method.Type.NumIn(), subSig)
|
||||
}
|
||||
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
return fmt.Errorf("%v argument type not exported: %v", name, argType)
|
||||
}
|
||||
if method.Type.NumOut() != 1 {
|
||||
return fmt.Errorf(
|
||||
"subscriber %v.%v has wrong number of outs: %v require signature %s",
|
||||
name, method.Name, method.Type.NumOut(), subSig)
|
||||
}
|
||||
if returnType := method.Type.Out(0); returnType != typeOfError {
|
||||
return fmt.Errorf("subscriber %v.%v returns %v not error", name, method.Name, returnType.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *httpServer) createSubHandler(sb *httpSubscriber, opts server.Options) broker.Handler {
|
||||
return func(p broker.Event) error {
|
||||
msg := p.Message()
|
||||
ct := msg.Header["Content-Type"]
|
||||
cf, err := s.newCodec(ct)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hdr := make(map[string]string)
|
||||
for k, v := range msg.Header {
|
||||
hdr[k] = v
|
||||
}
|
||||
delete(hdr, "Content-Type")
|
||||
ctx := metadata.NewContext(context.Background(), hdr)
|
||||
|
||||
results := make(chan error, len(sb.handlers))
|
||||
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
handler := sb.handlers[i]
|
||||
|
||||
var isVal bool
|
||||
var req reflect.Value
|
||||
|
||||
if handler.reqType.Kind() == reflect.Ptr {
|
||||
req = reflect.New(handler.reqType.Elem())
|
||||
} else {
|
||||
req = reflect.New(handler.reqType)
|
||||
isVal = true
|
||||
}
|
||||
if isVal {
|
||||
req = req.Elem()
|
||||
}
|
||||
|
||||
b := &buffer{bytes.NewBuffer(msg.Body)}
|
||||
co := cf(b)
|
||||
defer co.Close()
|
||||
|
||||
if err := co.ReadHeader(&codec.Message{}, codec.Event); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := co.ReadBody(req.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fn := func(ctx context.Context, msg server.Message) error {
|
||||
var vals []reflect.Value
|
||||
if sb.typ.Kind() != reflect.Func {
|
||||
vals = append(vals, sb.rcvr)
|
||||
}
|
||||
if handler.ctxType != nil {
|
||||
vals = append(vals, reflect.ValueOf(ctx))
|
||||
}
|
||||
|
||||
vals = append(vals, reflect.ValueOf(msg.Payload()))
|
||||
|
||||
returnValues := handler.method.Call(vals)
|
||||
if err := returnValues[0].Interface(); err != nil {
|
||||
return err.(error)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
for i := len(opts.SubWrappers); i > 0; i-- {
|
||||
fn = opts.SubWrappers[i-1](fn)
|
||||
}
|
||||
|
||||
go func() {
|
||||
results <- fn(ctx, &httpMessage{
|
||||
topic: sb.topic,
|
||||
contentType: ct,
|
||||
payload: req.Interface(),
|
||||
header: msg.Header,
|
||||
body: msg.Body,
|
||||
codec: co,
|
||||
})
|
||||
}()
|
||||
}
|
||||
|
||||
var errors []string
|
||||
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
if err := <-results; err != nil {
|
||||
errors = append(errors, err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if len(errors) > 0 {
|
||||
return fmt.Errorf("subscriber error: %s", strings.Join(errors, "\n"))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *httpSubscriber) Topic() string {
|
||||
return s.topic
|
||||
}
|
||||
|
||||
func (s *httpSubscriber) Subscriber() interface{} {
|
||||
return s.subscriber
|
||||
}
|
||||
|
||||
func (s *httpSubscriber) Endpoints() []*registry.Endpoint {
|
||||
return s.endpoints
|
||||
}
|
||||
|
||||
func (s *httpSubscriber) Options() server.SubscriberOptions {
|
||||
return s.opts
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/store/nats-js/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/store/nats-js/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
79
vendor/github.com/go-micro/plugins/v4/store/nats-js/README.md
generated
vendored
Normal file
79
vendor/github.com/go-micro/plugins/v4/store/nats-js/README.md
generated
vendored
Normal file
@@ -0,0 +1,79 @@
|
||||
# NATS JetStream Store Plugin
|
||||
|
||||
> **WARNING**: NATS Object Storage is still marked as an experimental preview.
|
||||
|
||||
This plugin uses the NATS JetStream [Object Store](https://docs.nats.io/nats-concepts/jetstream/obj_store) to implement the Go-Micro store interface.
|
||||
|
||||
This enables a key/value store with unlimited message size, allowing you to store files or data of any size under a single key.
|
||||
|
||||
You can use this plugin like any other store plugin.
|
||||
To start a local NATS JetStream server run `nats-server -js`.
|
||||
|
||||
To manually create a new storage object call:
|
||||
|
||||
```go
|
||||
natsjs.NewStore(opts ...store.Option)
|
||||
```
|
||||
|
||||
The Go-Micro store interface uses databases and tables to store keys. These translate
|
||||
to buckets (object stores) and key prefixes. If no database (bucket name) is provided, "default" will be used.
|
||||
|
||||
You can call `Write` with any arbitrary database name, and if a bucket with that name does not exist yet,
|
||||
it will be automatically created.
|
||||
|
||||
If a table name is provided, it will use it to prefix the key as `<table>_<key>`.
|
||||
|
||||
To delete a bucket, and all the key/value pairs in it, pass the `DeleteBucket` option to the `Delete`
|
||||
method, then they key name will be interpreted as a bucket name, and the bucket will be deleted.
|
||||
|
||||
Next to the default store options, a few NATS specific options are available:
|
||||
|
||||
|
||||
```go
|
||||
// NatsOptions accepts nats.Options
|
||||
NatsOptions(opts nats.Options)
|
||||
|
||||
// JetStreamOptions accepts multiple nats.JSOpt
|
||||
JetStreamOptions(opts ...nats.JSOpt)
|
||||
|
||||
// ObjectStoreOptions accepts multiple nats.ObjectStoreConfigs
|
||||
// This will create buckets with the provided configs at initialization.
|
||||
//
|
||||
// type ObjectStoreConfig struct {
|
||||
// Bucket string
|
||||
// Description string
|
||||
// TTL time.Duration
|
||||
// MaxBytes int64
|
||||
// Storage StorageType (either memory or file storage)
|
||||
// Replicas int
|
||||
// Placement *Placement
|
||||
// }
|
||||
//
|
||||
ObjectStoreOptions(cfg ...*nats.ObjectStoreConfig)
|
||||
|
||||
// DefaultTTL sets the default TTL to use for new buckets
|
||||
// By default no TTL is set.
|
||||
//
|
||||
// TTL ON INDIVIDUAL WRITE CALLS IS NOT SUPPORTED, only bucket wide TTL.
|
||||
// Either set a default TTL with this option or provide bucket specific options
|
||||
// with ObjectStoreOptions
|
||||
DefaultTTL(ttl time.Duration)
|
||||
|
||||
// DefaultMemory sets the default storage type to memory only.
|
||||
//
|
||||
// The default is file storage, persisting storage between service restarts.
|
||||
// Be aware that the default storage location of NATS the /tmp dir is, and thus
|
||||
// won't persist reboots.
|
||||
DefaultMemory()
|
||||
|
||||
// DefaultDescription sets the default description to use when creating new
|
||||
// buckets. The default is "Store managed by go-micro"
|
||||
DefaultDescription(text string)
|
||||
|
||||
// DeleteBucket will use the key passed to Delete as a bucket (database) name,
|
||||
// and delete the bucket.
|
||||
// This option should not be combined with the store.DeleteFrom option, as
|
||||
// that will overwrite the delete action.
|
||||
DeleteBucket()
|
||||
```
|
||||
|
||||
17
vendor/github.com/go-micro/plugins/v4/store/nats-js/context.go
generated
vendored
Normal file
17
vendor/github.com/go-micro/plugins/v4/store/nats-js/context.go
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package natsjs
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go-micro.dev/v4/store"
|
||||
)
|
||||
|
||||
// setStoreOption returns a function to setup a context with given value.
|
||||
func setStoreOption(k, v interface{}) store.Option {
|
||||
return func(o *store.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
437
vendor/github.com/go-micro/plugins/v4/store/nats-js/nats.go
generated
vendored
Normal file
437
vendor/github.com/go-micro/plugins/v4/store/nats-js/nats.go
generated
vendored
Normal file
@@ -0,0 +1,437 @@
|
||||
package natsjs
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
"github.com/pkg/errors"
|
||||
"go-micro.dev/v4/store"
|
||||
"go-micro.dev/v4/util/cmd"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrBucketNotFound = errors.New("Bucket (database) not found")
|
||||
)
|
||||
|
||||
type natsStore struct {
|
||||
sync.Once
|
||||
sync.RWMutex
|
||||
|
||||
ttl time.Duration
|
||||
storageType nats.StorageType
|
||||
description string
|
||||
|
||||
opts store.Options
|
||||
nopts nats.Options
|
||||
jsopts []nats.JSOpt
|
||||
objStoreConfigs []*nats.ObjectStoreConfig
|
||||
|
||||
conn *nats.Conn
|
||||
js nats.JetStreamContext
|
||||
buckets map[string]nats.ObjectStore
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmd.DefaultStores["natsjs"] = NewStore
|
||||
}
|
||||
|
||||
// NewStore will create a new NATS JetStream Object Store.
|
||||
func NewStore(opts ...store.Option) store.Store {
|
||||
options := store.Options{
|
||||
Nodes: []string{},
|
||||
Database: "default",
|
||||
Table: "",
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
n := &natsStore{
|
||||
description: "Object storage administered by go-micro store plugin",
|
||||
opts: options,
|
||||
jsopts: []nats.JSOpt{},
|
||||
objStoreConfigs: []*nats.ObjectStoreConfig{},
|
||||
buckets: map[string]nats.ObjectStore{},
|
||||
storageType: nats.FileStorage,
|
||||
}
|
||||
|
||||
n.setOption(opts...)
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// Init initializes the store. It must perform any required setup on the
|
||||
// backing storage implementation and check that it is ready for use,
|
||||
// returning any errors.
|
||||
func (n *natsStore) Init(opts ...store.Option) error {
|
||||
n.setOption(opts...)
|
||||
|
||||
// Connect to NATS servers
|
||||
conn, err := n.nopts.Connect()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to connect to NATS Server")
|
||||
}
|
||||
n.conn = conn
|
||||
|
||||
// Create JetStream context
|
||||
js, err := conn.JetStream(n.jsopts...)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to create JetStream context")
|
||||
}
|
||||
n.js = js
|
||||
|
||||
// Create default config if no configs present
|
||||
if len(n.objStoreConfigs) == 0 {
|
||||
n.objStoreConfigs = append(n.objStoreConfigs, &nats.ObjectStoreConfig{
|
||||
Bucket: n.opts.Database,
|
||||
Description: n.description,
|
||||
TTL: n.ttl,
|
||||
Storage: n.storageType,
|
||||
})
|
||||
}
|
||||
|
||||
// Create objest store buckets
|
||||
for _, cfg := range n.objStoreConfigs {
|
||||
store, err := js.CreateObjectStore(cfg)
|
||||
if err == nats.ErrStreamNameAlreadyInUse {
|
||||
store, err = n.js.ObjectStore(cfg.Bucket)
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "Failed to create bucket (%s)", cfg.Bucket)
|
||||
}
|
||||
n.buckets[cfg.Bucket] = store
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *natsStore) setOption(opts ...store.Option) {
|
||||
for _, o := range opts {
|
||||
o(&n.opts)
|
||||
}
|
||||
|
||||
n.Once.Do(func() {
|
||||
n.nopts = nats.GetDefaultOptions()
|
||||
})
|
||||
|
||||
// Extract options from context
|
||||
if nopts, ok := n.opts.Context.Value(natsOptionsKey{}).(nats.Options); ok {
|
||||
n.nopts = nopts
|
||||
}
|
||||
|
||||
if jsopts, ok := n.opts.Context.Value(jsOptionsKey{}).([]nats.JSOpt); ok {
|
||||
n.jsopts = append(n.jsopts, jsopts...)
|
||||
}
|
||||
|
||||
if cfg, ok := n.opts.Context.Value(objOptionsKey{}).([]*nats.ObjectStoreConfig); ok {
|
||||
n.objStoreConfigs = append(n.objStoreConfigs, cfg...)
|
||||
}
|
||||
|
||||
if ttl, ok := n.opts.Context.Value(ttlOptionsKey{}).(time.Duration); ok {
|
||||
n.ttl = ttl
|
||||
}
|
||||
|
||||
if sType, ok := n.opts.Context.Value(memoryOptionsKey{}).(nats.StorageType); ok {
|
||||
n.storageType = sType
|
||||
}
|
||||
|
||||
if text, ok := n.opts.Context.Value(descriptionOptionsKey{}).(string); ok {
|
||||
n.description = text
|
||||
}
|
||||
|
||||
// Assign store option server addresses to nats options
|
||||
if len(n.opts.Nodes) > 0 {
|
||||
n.nopts.Url = ""
|
||||
n.nopts.Servers = n.opts.Nodes
|
||||
}
|
||||
|
||||
if len(n.nopts.Servers) == 0 && n.nopts.Url == "" {
|
||||
n.nopts.Url = nats.DefaultURL
|
||||
}
|
||||
}
|
||||
|
||||
// Options allows you to view the current options.
|
||||
func (n *natsStore) Options() store.Options {
|
||||
return n.opts
|
||||
}
|
||||
|
||||
// Read takes a single key name and optional ReadOptions. It returns matching []*Record or an error.
|
||||
func (n *natsStore) Read(key string, opts ...store.ReadOption) ([]*store.Record, error) {
|
||||
if n.conn == nil {
|
||||
if err := n.Init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
opt := store.ReadOptions{}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
|
||||
if opt.Database == "" {
|
||||
opt.Database = n.opts.Database
|
||||
}
|
||||
if opt.Table == "" {
|
||||
opt.Table = n.opts.Table
|
||||
}
|
||||
|
||||
bucket, ok := n.buckets[opt.Database]
|
||||
if !ok {
|
||||
return nil, ErrBucketNotFound
|
||||
}
|
||||
|
||||
var keys []string
|
||||
objects, err := bucket.List()
|
||||
if err == nats.ErrNoObjectsFound {
|
||||
return []*store.Record{}, nil
|
||||
} else if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to list objects")
|
||||
}
|
||||
|
||||
for _, obj := range objects {
|
||||
name := obj.Name
|
||||
if (!opt.Prefix && !opt.Suffix) && getKey(key, opt.Table) != name {
|
||||
continue
|
||||
}
|
||||
if opt.Prefix && !strings.HasPrefix(name, getKey(key, opt.Table)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if opt.Suffix && !strings.HasSuffix(name, key) {
|
||||
continue
|
||||
}
|
||||
keys = append(keys, name)
|
||||
}
|
||||
|
||||
records := []*store.Record{}
|
||||
for _, key := range keys {
|
||||
obj, err := bucket.Get(key)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to get object from bucket")
|
||||
}
|
||||
|
||||
b, err := io.ReadAll(obj)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to read returned bytes")
|
||||
}
|
||||
|
||||
info, err := obj.Info()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to fetch record info")
|
||||
}
|
||||
|
||||
metadata := map[string]interface{}{}
|
||||
for key, value := range info.Headers {
|
||||
var val interface{}
|
||||
if err := json.Unmarshal([]byte(value[0]), &val); err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to JSON unmarshal metadata")
|
||||
}
|
||||
metadata[key] = val
|
||||
}
|
||||
|
||||
records = append(records, &store.Record{
|
||||
Key: key,
|
||||
Value: b,
|
||||
Metadata: metadata,
|
||||
})
|
||||
|
||||
// Why is there a close method?
|
||||
obj.Close()
|
||||
}
|
||||
|
||||
if opt.Limit > 0 {
|
||||
return records[opt.Offset : opt.Offset+opt.Limit], nil
|
||||
}
|
||||
if opt.Offset > 0 {
|
||||
return records[opt.Offset:], nil
|
||||
}
|
||||
return records, nil
|
||||
}
|
||||
|
||||
// Write writes a record to the store, and returns an error if the record was not written.
|
||||
func (n *natsStore) Write(r *store.Record, opts ...store.WriteOption) error {
|
||||
if n.conn == nil {
|
||||
if err := n.Init(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
opt := store.WriteOptions{}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
|
||||
if opt.Database == "" {
|
||||
opt.Database = n.opts.Database
|
||||
}
|
||||
if opt.Table == "" {
|
||||
opt.Table = n.opts.Table
|
||||
}
|
||||
|
||||
store, ok := n.buckets[opt.Database]
|
||||
|
||||
// Create new bucket if not exists
|
||||
if !ok {
|
||||
var err error
|
||||
store, err = n.createNewBucket(opt.Database)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
header := nats.Header{}
|
||||
for key, value := range r.Metadata {
|
||||
val, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to JSON marshal metadata")
|
||||
}
|
||||
header.Set(key, string(val))
|
||||
}
|
||||
|
||||
_, err := store.Put(&nats.ObjectMeta{
|
||||
Name: getKey(r.Key, opt.Table),
|
||||
Description: "Store managed by go-micro",
|
||||
Headers: header,
|
||||
}, bytes.NewReader(r.Value))
|
||||
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Failed to store data in bucket")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes the record with the corresponding key from the store.
|
||||
func (n *natsStore) Delete(key string, opts ...store.DeleteOption) error {
|
||||
if n.conn == nil {
|
||||
if err := n.Init(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
opt := store.DeleteOptions{}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
|
||||
if opt.Database == "" {
|
||||
opt.Database = n.opts.Database
|
||||
}
|
||||
if opt.Table == "" {
|
||||
opt.Table = n.opts.Table
|
||||
}
|
||||
|
||||
if opt.Table == "DELETE_BUCKET" {
|
||||
delete(n.buckets, key)
|
||||
if err := n.js.DeleteObjectStore(key); err != nil {
|
||||
return errors.Wrap(err, "Failed to delete bucket")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
store, ok := n.buckets[opt.Database]
|
||||
if !ok {
|
||||
return ErrBucketNotFound
|
||||
}
|
||||
|
||||
if err := store.Delete(getKey(key, opt.Table)); err != nil {
|
||||
return errors.Wrap(err, "Failed to delete data")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// List returns any keys that match, or an empty list with no error if none matched.
|
||||
func (n *natsStore) List(opts ...store.ListOption) ([]string, error) {
|
||||
if n.conn == nil {
|
||||
if err := n.Init(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
opt := store.ListOptions{}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&opt)
|
||||
}
|
||||
|
||||
if opt.Database == "" {
|
||||
opt.Database = n.opts.Database
|
||||
}
|
||||
if opt.Table == "" {
|
||||
opt.Table = n.opts.Table
|
||||
}
|
||||
|
||||
store, ok := n.buckets[opt.Database]
|
||||
if !ok {
|
||||
return nil, ErrBucketNotFound
|
||||
}
|
||||
|
||||
objects, err := store.List()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to list keys in bucket")
|
||||
}
|
||||
|
||||
var keys []string
|
||||
for _, obj := range objects {
|
||||
key := obj.Name
|
||||
|
||||
if !strings.HasPrefix(key, getKey(opt.Prefix, opt.Table)) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.HasSuffix(key, opt.Suffix) {
|
||||
continue
|
||||
}
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
if opt.Limit > 0 {
|
||||
return keys[opt.Offset : opt.Offset+opt.Limit], nil
|
||||
}
|
||||
if opt.Offset > 0 {
|
||||
return keys[opt.Offset:], nil
|
||||
}
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
// Close the store.
|
||||
func (n *natsStore) Close() error {
|
||||
n.conn.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
// String returns the name of the implementation.
|
||||
func (n *natsStore) String() string {
|
||||
return "NATS JetStream ObjectStore"
|
||||
}
|
||||
|
||||
func getKey(key, table string) string {
|
||||
if table != "" {
|
||||
key = table + "_" + key
|
||||
}
|
||||
return key
|
||||
}
|
||||
|
||||
func (n *natsStore) createNewBucket(name string) (nats.ObjectStore, error) {
|
||||
store, err := n.js.CreateObjectStore(&nats.ObjectStoreConfig{
|
||||
Bucket: name,
|
||||
Description: n.description,
|
||||
TTL: n.ttl,
|
||||
Storage: n.storageType,
|
||||
})
|
||||
if err == nats.ErrStreamNameAlreadyInUse {
|
||||
store, err = n.js.ObjectStore(name)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "Failed to create new bucket (%s)", name)
|
||||
}
|
||||
n.buckets[name] = store
|
||||
return store, err
|
||||
}
|
||||
78
vendor/github.com/go-micro/plugins/v4/store/nats-js/options.go
generated
vendored
Normal file
78
vendor/github.com/go-micro/plugins/v4/store/nats-js/options.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package natsjs
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/nats-io/nats.go"
|
||||
"go-micro.dev/v4/store"
|
||||
)
|
||||
|
||||
// store.Option.
|
||||
type natsOptionsKey struct{}
|
||||
type jsOptionsKey struct{}
|
||||
type objOptionsKey struct{}
|
||||
type ttlOptionsKey struct{}
|
||||
type memoryOptionsKey struct{}
|
||||
type descriptionOptionsKey struct{}
|
||||
|
||||
// store.DeleteOption.
|
||||
type delBucketOptionsKey struct{}
|
||||
|
||||
// NatsOptions accepts nats.Options.
|
||||
func NatsOptions(opts nats.Options) store.Option {
|
||||
return setStoreOption(natsOptionsKey{}, opts)
|
||||
}
|
||||
|
||||
// JetStreamOptions accepts multiple nats.JSOpt.
|
||||
func JetStreamOptions(opts ...nats.JSOpt) store.Option {
|
||||
return setStoreOption(jsOptionsKey{}, opts)
|
||||
}
|
||||
|
||||
// ObjectStoreOptions accepts multiple nats.ObjectStoreConfigs
|
||||
// This will create buckets with the provided configs at initialization.
|
||||
func ObjectStoreOptions(cfg ...*nats.ObjectStoreConfig) store.Option {
|
||||
return setStoreOption(objOptionsKey{}, cfg)
|
||||
}
|
||||
|
||||
// DefaultTTL sets the default TTL to use for new buckets
|
||||
//
|
||||
// By default no TTL is set.
|
||||
//
|
||||
// TTL ON INDIVIDUAL WRITE CALLS IS NOT SUPPORTED, only bucket wide TTL.
|
||||
// Either set a default TTL with this option or provide bucket specific options
|
||||
//
|
||||
// with ObjectStoreOptions
|
||||
func DefaultTTL(ttl time.Duration) store.Option {
|
||||
return setStoreOption(ttlOptionsKey{}, ttl)
|
||||
}
|
||||
|
||||
// DefaultMemory sets the default storage type to memory only.
|
||||
//
|
||||
// The default is file storage, persisting storage between service restarts.
|
||||
//
|
||||
// Be aware that the default storage location of NATS the /tmp dir is, and thus
|
||||
//
|
||||
// won't persist reboots.
|
||||
func DefaultMemory() store.Option {
|
||||
return setStoreOption(memoryOptionsKey{}, nats.MemoryStorage)
|
||||
}
|
||||
|
||||
// DefaultDescription sets the default description to use when creating new
|
||||
//
|
||||
// buckets. The default is "Store managed by go-micro"
|
||||
func DefaultDescription(text string) store.Option {
|
||||
return setStoreOption(descriptionOptionsKey{}, text)
|
||||
}
|
||||
|
||||
// DeleteBucket will use the key passed to Delete as a bucket (database) name,
|
||||
//
|
||||
// and delete the bucket.
|
||||
//
|
||||
// This option should not be combined with the store.DeleteFrom option, as
|
||||
//
|
||||
// that will overwrite the delete action.
|
||||
func DeleteBucket() store.DeleteOption {
|
||||
return func(d *store.DeleteOptions) {
|
||||
d.Table = "DELETE_BUCKET"
|
||||
}
|
||||
}
|
||||
132
vendor/github.com/go-micro/plugins/v4/store/nats-js/test_data.go
generated
vendored
Normal file
132
vendor/github.com/go-micro/plugins/v4/store/nats-js/test_data.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
package natsjs
|
||||
|
||||
import "go-micro.dev/v4/store"
|
||||
|
||||
type test struct {
|
||||
Record *store.Record
|
||||
Database string
|
||||
Table string
|
||||
}
|
||||
|
||||
var (
|
||||
table = []test{
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "One",
|
||||
Value: []byte("First value"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "Two",
|
||||
Value: []byte("Second value"),
|
||||
},
|
||||
Table: "prefix_test",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "Third",
|
||||
Value: []byte("Third value"),
|
||||
},
|
||||
Database: "new-bucket",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "Four",
|
||||
Value: []byte("Fourth value"),
|
||||
},
|
||||
Database: "new-bucket",
|
||||
Table: "prefix_test",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "empty-value",
|
||||
Value: []byte{},
|
||||
},
|
||||
Database: "new-bucket",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "Alex",
|
||||
Value: []byte("Some value"),
|
||||
},
|
||||
Database: "prefix-test",
|
||||
Table: "names",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "Jones",
|
||||
Value: []byte("Some value"),
|
||||
},
|
||||
Database: "prefix-test",
|
||||
Table: "names",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "Adrianna",
|
||||
Value: []byte("Some value"),
|
||||
},
|
||||
Database: "prefix-test",
|
||||
Table: "names",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "MexicoCity",
|
||||
Value: []byte("Some value"),
|
||||
},
|
||||
Database: "prefix-test",
|
||||
Table: "cities",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "HoustonCity",
|
||||
Value: []byte("Some value"),
|
||||
},
|
||||
Database: "prefix-test",
|
||||
Table: "cities",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "ZurichCity",
|
||||
Value: []byte("Some value"),
|
||||
},
|
||||
Database: "prefix-test",
|
||||
Table: "cities",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "Helsinki",
|
||||
Value: []byte("Some value"),
|
||||
},
|
||||
Database: "prefix-test",
|
||||
Table: "cities",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "testKeytest",
|
||||
Value: []byte("Some value"),
|
||||
},
|
||||
Table: "some_table",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "testSecondtest",
|
||||
Value: []byte("Some value"),
|
||||
},
|
||||
Table: "some_table",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "lalala",
|
||||
Value: []byte("Some value"),
|
||||
},
|
||||
Table: "some_table",
|
||||
},
|
||||
{
|
||||
Record: &store.Record{
|
||||
Key: "testAnothertest",
|
||||
Value: []byte("Some value"),
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
191
vendor/github.com/go-micro/plugins/v4/store/redis/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/store/redis/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
48
vendor/github.com/go-micro/plugins/v4/store/redis/options.go
generated
vendored
Normal file
48
vendor/github.com/go-micro/plugins/v4/store/redis/options.go
generated
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
"go-micro.dev/v4/store"
|
||||
)
|
||||
|
||||
type redisOptionsContextKey struct{}
|
||||
|
||||
// WithRedisOptions sets advanced options for redis.
|
||||
func WithRedisOptions(options redis.UniversalOptions) store.Option {
|
||||
return func(o *store.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
|
||||
o.Context = context.WithValue(o.Context, redisOptionsContextKey{}, options)
|
||||
}
|
||||
}
|
||||
|
||||
func newUniversalClient(o store.Options) redis.UniversalClient {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
|
||||
opts, ok := o.Context.Value(redisOptionsContextKey{}).(redis.UniversalOptions)
|
||||
if !ok && len(o.Nodes) <= 1 {
|
||||
addr := "redis://127.0.0.1:6379"
|
||||
if len(o.Nodes) > 0 {
|
||||
addr = o.Nodes[0]
|
||||
}
|
||||
|
||||
redisOptions, err := redis.ParseURL(addr)
|
||||
if err != nil {
|
||||
redisOptions = &redis.Options{Addr: addr}
|
||||
}
|
||||
|
||||
return redis.NewClient(redisOptions)
|
||||
}
|
||||
|
||||
if len(opts.Addrs) == 0 && len(o.Nodes) > 0 {
|
||||
opts.Addrs = o.Nodes
|
||||
}
|
||||
|
||||
return redis.NewUniversalClient(&opts)
|
||||
}
|
||||
164
vendor/github.com/go-micro/plugins/v4/store/redis/redis.go
generated
vendored
Normal file
164
vendor/github.com/go-micro/plugins/v4/store/redis/redis.go
generated
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
package redis
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/go-redis/redis/v8"
|
||||
log "go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/store"
|
||||
"go-micro.dev/v4/util/cmd"
|
||||
)
|
||||
|
||||
type rkv struct {
|
||||
ctx context.Context
|
||||
options store.Options
|
||||
Client redis.UniversalClient
|
||||
}
|
||||
|
||||
func init() {
|
||||
cmd.DefaultStores["redis"] = NewStore
|
||||
}
|
||||
|
||||
func (r *rkv) Init(opts ...store.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&r.options)
|
||||
}
|
||||
|
||||
return r.configure()
|
||||
}
|
||||
|
||||
func (r *rkv) Close() error {
|
||||
return r.Client.Close()
|
||||
}
|
||||
|
||||
func (r *rkv) Read(key string, opts ...store.ReadOption) ([]*store.Record, error) {
|
||||
options := store.ReadOptions{}
|
||||
options.Table = r.options.Table
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
var keys []string
|
||||
|
||||
rkey := fmt.Sprintf("%s%s", options.Table, key)
|
||||
// Handle Prefix
|
||||
// TODO suffix
|
||||
if options.Prefix {
|
||||
prefixKey := fmt.Sprintf("%s*", rkey)
|
||||
fkeys, err := r.Client.Keys(r.ctx, prefixKey).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO Limit Offset
|
||||
|
||||
keys = append(keys, fkeys...)
|
||||
} else {
|
||||
keys = []string{rkey}
|
||||
}
|
||||
|
||||
records := make([]*store.Record, 0, len(keys))
|
||||
|
||||
for _, rkey = range keys {
|
||||
val, err := r.Client.Get(r.ctx, rkey).Bytes()
|
||||
|
||||
if err != nil && err == redis.Nil {
|
||||
return nil, store.ErrNotFound
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if val == nil {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
|
||||
d, err := r.Client.TTL(r.ctx, rkey).Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
records = append(records, &store.Record{
|
||||
Key: key,
|
||||
Value: val,
|
||||
Expiry: d,
|
||||
})
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (r *rkv) Delete(key string, opts ...store.DeleteOption) error {
|
||||
options := store.DeleteOptions{}
|
||||
options.Table = r.options.Table
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
rkey := fmt.Sprintf("%s%s", options.Table, key)
|
||||
return r.Client.Del(r.ctx, rkey).Err()
|
||||
}
|
||||
|
||||
func (r *rkv) Write(record *store.Record, opts ...store.WriteOption) error {
|
||||
options := store.WriteOptions{}
|
||||
options.Table = r.options.Table
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
rkey := fmt.Sprintf("%s%s", options.Table, record.Key)
|
||||
return r.Client.Set(r.ctx, rkey, record.Value, record.Expiry).Err()
|
||||
}
|
||||
|
||||
func (r *rkv) List(opts ...store.ListOption) ([]string, error) {
|
||||
options := store.ListOptions{}
|
||||
options.Table = r.options.Table
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
keys, err := r.Client.Keys(r.ctx, "*").Result()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (r *rkv) Options() store.Options {
|
||||
return r.options
|
||||
}
|
||||
|
||||
func (r *rkv) String() string {
|
||||
return "redis"
|
||||
}
|
||||
|
||||
func NewStore(opts ...store.Option) store.Store {
|
||||
var options store.Options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
s := &rkv{
|
||||
ctx: context.Background(),
|
||||
options: options,
|
||||
}
|
||||
|
||||
if err := s.configure(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (r *rkv) configure() error {
|
||||
if r.Client != nil {
|
||||
r.Client.Close()
|
||||
}
|
||||
r.Client = newUniversalClient(r.options)
|
||||
|
||||
return nil
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/wrapper/breaker/gobreaker/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/wrapper/breaker/gobreaker/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
93
vendor/github.com/go-micro/plugins/v4/wrapper/breaker/gobreaker/gobreaker.go
generated
vendored
Normal file
93
vendor/github.com/go-micro/plugins/v4/wrapper/breaker/gobreaker/gobreaker.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
package gobreaker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/sony/gobreaker"
|
||||
"go-micro.dev/v4/client"
|
||||
"go-micro.dev/v4/errors"
|
||||
)
|
||||
|
||||
type BreakerMethod int
|
||||
|
||||
const (
|
||||
BreakService BreakerMethod = iota
|
||||
BreakServiceEndpoint
|
||||
)
|
||||
|
||||
type clientWrapper struct {
|
||||
bs gobreaker.Settings
|
||||
bm BreakerMethod
|
||||
cbs map[string]*gobreaker.TwoStepCircuitBreaker
|
||||
mu sync.Mutex
|
||||
client.Client
|
||||
}
|
||||
|
||||
func (c *clientWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
||||
var svc string
|
||||
|
||||
switch c.bm {
|
||||
case BreakService:
|
||||
svc = req.Service()
|
||||
case BreakServiceEndpoint:
|
||||
svc = req.Service() + "." + req.Endpoint()
|
||||
}
|
||||
|
||||
c.mu.Lock()
|
||||
cb, ok := c.cbs[svc]
|
||||
if !ok {
|
||||
cb = gobreaker.NewTwoStepCircuitBreaker(c.bs)
|
||||
c.cbs[svc] = cb
|
||||
}
|
||||
c.mu.Unlock()
|
||||
|
||||
cbAllow, err := cb.Allow()
|
||||
if err != nil {
|
||||
return errors.New(req.Service(), err.Error(), 502)
|
||||
}
|
||||
|
||||
if err = c.Client.Call(ctx, req, rsp, opts...); err == nil {
|
||||
cbAllow(true)
|
||||
return nil
|
||||
}
|
||||
|
||||
merr := errors.Parse(err.Error())
|
||||
switch {
|
||||
case merr.Code == 0:
|
||||
merr.Code = 503
|
||||
case len(merr.Id) == 0:
|
||||
merr.Id = req.Service()
|
||||
}
|
||||
|
||||
if merr.Code >= 500 {
|
||||
cbAllow(false)
|
||||
} else {
|
||||
cbAllow(true)
|
||||
}
|
||||
|
||||
return merr
|
||||
}
|
||||
|
||||
// NewClientWrapper returns a client Wrapper.
|
||||
func NewClientWrapper() client.Wrapper {
|
||||
return func(c client.Client) client.Client {
|
||||
w := &clientWrapper{}
|
||||
w.bs = gobreaker.Settings{}
|
||||
w.cbs = make(map[string]*gobreaker.TwoStepCircuitBreaker)
|
||||
w.Client = c
|
||||
return w
|
||||
}
|
||||
}
|
||||
|
||||
// NewCustomClientWrapper takes a gobreaker.Settings and BreakerMethod. Returns a client Wrapper.
|
||||
func NewCustomClientWrapper(bs gobreaker.Settings, bm BreakerMethod) client.Wrapper {
|
||||
return func(c client.Client) client.Client {
|
||||
w := &clientWrapper{}
|
||||
w.bm = bm
|
||||
w.bs = bs
|
||||
w.cbs = make(map[string]*gobreaker.TwoStepCircuitBreaker)
|
||||
w.Client = c
|
||||
return w
|
||||
}
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/wrapper/monitoring/prometheus/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/wrapper/monitoring/prometheus/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
24
vendor/github.com/go-micro/plugins/v4/wrapper/monitoring/prometheus/README.md
generated
vendored
Normal file
24
vendor/github.com/go-micro/plugins/v4/wrapper/monitoring/prometheus/README.md
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Prometheus
|
||||
|
||||
Wrappers are a form of middleware that can be used with go-micro services. They can wrap both the Client and Server handlers.
|
||||
This plugin implements the HandlerWrapper interface to provide automatic prometheus metric handling
|
||||
for each microservice method execution time and operation count for success and failed cases.
|
||||
|
||||
This handler will export two metrics to prometheus:
|
||||
* **micro_request_total**. How many go-micro requests processed, partitioned by method and status.
|
||||
* **micro_request_duration_microseconds**. Service method request latencies in microseconds, partitioned by method.
|
||||
|
||||
# Usage
|
||||
|
||||
When creating your service, add the wrapper like so.
|
||||
|
||||
```go
|
||||
service := micro.NewService(
|
||||
micro.Name("service name"),
|
||||
micro.Version("latest"),
|
||||
micro.WrapHandler(prometheus.NewHandlerWrapper()),
|
||||
)
|
||||
|
||||
service.Init()
|
||||
```
|
||||
|
||||
294
vendor/github.com/go-micro/plugins/v4/wrapper/monitoring/prometheus/prometheus.go
generated
vendored
Normal file
294
vendor/github.com/go-micro/plugins/v4/wrapper/monitoring/prometheus/prometheus.go
generated
vendored
Normal file
@@ -0,0 +1,294 @@
|
||||
package prometheus
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go-micro.dev/v4/client"
|
||||
"go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/registry"
|
||||
"go-micro.dev/v4/server"
|
||||
)
|
||||
|
||||
var (
|
||||
// default metric prefix.
|
||||
DefaultMetricPrefix = "micro_"
|
||||
// default label prefix.
|
||||
DefaultLabelPrefix = "micro_"
|
||||
|
||||
opsCounter *prometheus.CounterVec
|
||||
timeCounterSummary *prometheus.SummaryVec
|
||||
timeCounterHistogram *prometheus.HistogramVec
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Name string
|
||||
Version string
|
||||
ID string
|
||||
}
|
||||
|
||||
type Option func(*Options)
|
||||
|
||||
func ServiceName(name string) Option {
|
||||
return func(opts *Options) {
|
||||
opts.Name = name
|
||||
}
|
||||
}
|
||||
|
||||
func ServiceVersion(version string) Option {
|
||||
return func(opts *Options) {
|
||||
opts.Version = version
|
||||
}
|
||||
}
|
||||
|
||||
func ServiceID(id string) Option {
|
||||
return func(opts *Options) {
|
||||
opts.ID = id
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
if opsCounter == nil {
|
||||
opsCounter = prometheus.NewCounterVec(
|
||||
prometheus.CounterOpts{
|
||||
Name: fmt.Sprintf("%srequest_total", DefaultMetricPrefix),
|
||||
Help: "Requests processed, partitioned by endpoint and status",
|
||||
},
|
||||
[]string{
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "name"),
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "version"),
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "id"),
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "endpoint"),
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "status"),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if timeCounterSummary == nil {
|
||||
timeCounterSummary = prometheus.NewSummaryVec(
|
||||
prometheus.SummaryOpts{
|
||||
Name: fmt.Sprintf("%slatency_microseconds", DefaultMetricPrefix),
|
||||
Help: "Request latencies in microseconds, partitioned by endpoint",
|
||||
},
|
||||
[]string{
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "name"),
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "version"),
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "id"),
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "endpoint"),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if timeCounterHistogram == nil {
|
||||
timeCounterHistogram = prometheus.NewHistogramVec(
|
||||
prometheus.HistogramOpts{
|
||||
Name: fmt.Sprintf("%srequest_duration_seconds", DefaultMetricPrefix),
|
||||
Help: "Request time in seconds, partitioned by endpoint",
|
||||
},
|
||||
[]string{
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "name"),
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "version"),
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "id"),
|
||||
fmt.Sprintf("%s%s", DefaultLabelPrefix, "endpoint"),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
for _, collector := range []prometheus.Collector{opsCounter, timeCounterSummary, timeCounterHistogram} {
|
||||
if err := prometheus.DefaultRegisterer.Register(collector); err != nil {
|
||||
// if already registered, skip fatal
|
||||
if _, ok := err.(prometheus.AlreadyRegisteredError); !ok {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type wrapper struct {
|
||||
options Options
|
||||
callFunc client.CallFunc
|
||||
client.Client
|
||||
}
|
||||
|
||||
func NewClientWrapper(opts ...Option) client.Wrapper {
|
||||
options := Options{}
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
return func(c client.Client) client.Client {
|
||||
handler := &wrapper{
|
||||
options: options,
|
||||
Client: c,
|
||||
}
|
||||
|
||||
return handler
|
||||
}
|
||||
}
|
||||
|
||||
func NewCallWrapper(opts ...Option) client.CallWrapper {
|
||||
options := Options{}
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
return func(fn client.CallFunc) client.CallFunc {
|
||||
handler := &wrapper{
|
||||
options: options,
|
||||
callFunc: fn,
|
||||
}
|
||||
|
||||
return handler.CallFunc
|
||||
}
|
||||
}
|
||||
|
||||
func (w *wrapper) CallFunc(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error {
|
||||
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
|
||||
|
||||
timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) {
|
||||
us := v * 1000000 // make microseconds
|
||||
timeCounterSummary.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint).Observe(us)
|
||||
timeCounterHistogram.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint).Observe(v)
|
||||
}))
|
||||
defer timer.ObserveDuration()
|
||||
|
||||
err := w.callFunc(ctx, node, req, rsp, opts)
|
||||
if err == nil {
|
||||
opsCounter.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint, "success").Inc()
|
||||
} else {
|
||||
opsCounter.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint, "failure").Inc()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *wrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
||||
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
|
||||
|
||||
timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) {
|
||||
us := v * 1000000 // make microseconds
|
||||
timeCounterSummary.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint).Observe(us)
|
||||
timeCounterHistogram.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint).Observe(v)
|
||||
}))
|
||||
defer timer.ObserveDuration()
|
||||
|
||||
err := w.Client.Call(ctx, req, rsp, opts...)
|
||||
if err == nil {
|
||||
opsCounter.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint, "success").Inc()
|
||||
} else {
|
||||
opsCounter.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint, "failure").Inc()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (w *wrapper) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
|
||||
endpoint := fmt.Sprintf("%s.%s", req.Service(), req.Endpoint())
|
||||
|
||||
timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) {
|
||||
us := v * 1000000 // make microseconds
|
||||
timeCounterSummary.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint).Observe(us)
|
||||
timeCounterHistogram.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint).Observe(v)
|
||||
}))
|
||||
defer timer.ObserveDuration()
|
||||
|
||||
stream, err := w.Client.Stream(ctx, req, opts...)
|
||||
if err == nil {
|
||||
opsCounter.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint, "success").Inc()
|
||||
} else {
|
||||
opsCounter.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint, "failure").Inc()
|
||||
}
|
||||
|
||||
return stream, err
|
||||
}
|
||||
|
||||
func (w *wrapper) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) error {
|
||||
endpoint := p.Topic()
|
||||
|
||||
timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) {
|
||||
us := v * 1000000 // make microseconds
|
||||
timeCounterSummary.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint).Observe(us)
|
||||
timeCounterHistogram.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint).Observe(v)
|
||||
}))
|
||||
defer timer.ObserveDuration()
|
||||
|
||||
err := w.Client.Publish(ctx, p, opts...)
|
||||
if err == nil {
|
||||
opsCounter.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint, "success").Inc()
|
||||
} else {
|
||||
opsCounter.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint, "failure").Inc()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func NewHandlerWrapper(opts ...Option) server.HandlerWrapper {
|
||||
options := Options{}
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
handler := &wrapper{
|
||||
options: options,
|
||||
}
|
||||
|
||||
return handler.HandlerFunc
|
||||
}
|
||||
|
||||
func (w *wrapper) HandlerFunc(fn server.HandlerFunc) server.HandlerFunc {
|
||||
return func(ctx context.Context, req server.Request, rsp interface{}) error {
|
||||
endpoint := req.Endpoint()
|
||||
|
||||
timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) {
|
||||
us := v * 1000000 // make microseconds
|
||||
timeCounterSummary.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint).Observe(us)
|
||||
timeCounterHistogram.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint).Observe(v)
|
||||
}))
|
||||
defer timer.ObserveDuration()
|
||||
|
||||
err := fn(ctx, req, rsp)
|
||||
if err == nil {
|
||||
opsCounter.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint, "success").Inc()
|
||||
} else {
|
||||
opsCounter.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint, "failure").Inc()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
func NewSubscriberWrapper(opts ...Option) server.SubscriberWrapper {
|
||||
options := Options{}
|
||||
for _, opt := range opts {
|
||||
opt(&options)
|
||||
}
|
||||
|
||||
handler := &wrapper{
|
||||
options: options,
|
||||
}
|
||||
|
||||
return handler.SubscriberFunc
|
||||
}
|
||||
|
||||
func (w *wrapper) SubscriberFunc(fn server.SubscriberFunc) server.SubscriberFunc {
|
||||
return func(ctx context.Context, msg server.Message) error {
|
||||
endpoint := msg.Topic()
|
||||
|
||||
timer := prometheus.NewTimer(prometheus.ObserverFunc(func(v float64) {
|
||||
us := v * 1000000 // make microseconds
|
||||
timeCounterSummary.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint).Observe(us)
|
||||
timeCounterHistogram.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint).Observe(v)
|
||||
}))
|
||||
defer timer.ObserveDuration()
|
||||
|
||||
err := fn(ctx, msg)
|
||||
if err == nil {
|
||||
opsCounter.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint, "success").Inc()
|
||||
} else {
|
||||
opsCounter.WithLabelValues(w.options.Name, w.options.Version, w.options.ID, endpoint, "failure").Inc()
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
}
|
||||
191
vendor/github.com/go-micro/plugins/v4/wrapper/trace/opencensus/LICENSE
generated
vendored
Normal file
191
vendor/github.com/go-micro/plugins/v4/wrapper/trace/opencensus/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015 Asim Aslam.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
31
vendor/github.com/go-micro/plugins/v4/wrapper/trace/opencensus/README.md
generated
vendored
Normal file
31
vendor/github.com/go-micro/plugins/v4/wrapper/trace/opencensus/README.md
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# OpenCensus wrappers
|
||||
|
||||
OpenCensus wrappers propagate traces (spans) accross services.
|
||||
|
||||
## Usage
|
||||
|
||||
```go
|
||||
service := micro.NewService(
|
||||
micro.Name("go.micro.srv.greeter"),
|
||||
micro.WrapClient(opencensus.NewClientWrapper()),
|
||||
micro.WrapHandler(opencensus.NewHandlerWrapper()),
|
||||
micro.WrapSubscriber(opencensus.NewSubscriberWrapper()),
|
||||
)
|
||||
```
|
||||
|
||||
### Views
|
||||
|
||||
The OpenCensus package exposes some convenience views.
|
||||
Don't forget to register these views:
|
||||
|
||||
```go
|
||||
// Register to all RPC server views.
|
||||
if err := view.Register(opencensus.DefaultServerViews...); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Register to all RPC client views.
|
||||
if err := view.Register(opencensus.DefaultClientViews...); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
```
|
||||
150
vendor/github.com/go-micro/plugins/v4/wrapper/trace/opencensus/opencensus.go
generated
vendored
Normal file
150
vendor/github.com/go-micro/plugins/v4/wrapper/trace/opencensus/opencensus.go
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
// Package opencensus provides wrappers for OpenCensus tracing.
|
||||
package opencensus
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
|
||||
"go-micro.dev/v4/client"
|
||||
log "go-micro.dev/v4/logger"
|
||||
"go-micro.dev/v4/metadata"
|
||||
"go-micro.dev/v4/server"
|
||||
"go.opencensus.io/trace"
|
||||
"go.opencensus.io/trace/propagation"
|
||||
)
|
||||
|
||||
const (
|
||||
// TracePropagationField is the key for the tracing context
|
||||
// that will be injected in go-micro's metadata.
|
||||
TracePropagationField = "X-Trace-Context"
|
||||
)
|
||||
|
||||
// clientWrapper wraps an RPC client and adds tracing.
|
||||
type clientWrapper struct {
|
||||
client.Client
|
||||
}
|
||||
|
||||
func injectTraceIntoCtx(ctx context.Context, span *trace.Span) context.Context {
|
||||
spanCtx := propagation.Binary(span.SpanContext())
|
||||
return metadata.Set(ctx, TracePropagationField, base64.RawStdEncoding.EncodeToString(spanCtx))
|
||||
}
|
||||
|
||||
// Call implements client.Client.Call.
|
||||
func (w *clientWrapper) Call(
|
||||
ctx context.Context,
|
||||
req client.Request,
|
||||
rsp interface{},
|
||||
opts ...client.CallOption) (err error) {
|
||||
t := newRequestTracker(req, ClientProfile)
|
||||
ctx = t.start(ctx, true)
|
||||
|
||||
defer func() { t.end(ctx, err) }()
|
||||
|
||||
ctx = injectTraceIntoCtx(ctx, t.span)
|
||||
|
||||
err = w.Client.Call(ctx, req, rsp, opts...)
|
||||
return
|
||||
}
|
||||
|
||||
// Publish implements client.Client.Publish.
|
||||
func (w *clientWrapper) Publish(ctx context.Context, p client.Message, opts ...client.PublishOption) (err error) {
|
||||
t := newEventTracker(p, ClientProfile)
|
||||
ctx = t.start(ctx, true)
|
||||
|
||||
defer func() { t.end(ctx, err) }()
|
||||
|
||||
ctx = injectTraceIntoCtx(ctx, t.span)
|
||||
|
||||
err = w.Client.Publish(ctx, p, opts...)
|
||||
return
|
||||
}
|
||||
|
||||
// NewClientWrapper returns a client.Wrapper
|
||||
// that adds monitoring to outgoing requests.
|
||||
func NewClientWrapper() client.Wrapper {
|
||||
return func(c client.Client) client.Client {
|
||||
return &clientWrapper{c}
|
||||
}
|
||||
}
|
||||
|
||||
func getTraceFromCtx(ctx context.Context) *trace.SpanContext {
|
||||
encodedTraceCtx, ok := metadata.Get(ctx, TracePropagationField)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
traceCtxBytes, err := base64.RawStdEncoding.DecodeString(encodedTraceCtx)
|
||||
if err != nil {
|
||||
log.Errorf("Could not decode trace context: %s", err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
spanCtx, ok := propagation.FromBinary(traceCtxBytes)
|
||||
if !ok {
|
||||
log.Errorf("Could not decode trace context from binary")
|
||||
return nil
|
||||
}
|
||||
|
||||
return &spanCtx
|
||||
}
|
||||
|
||||
// NewHandlerWrapper returns a server.HandlerWrapper
|
||||
// that adds tracing to incoming requests.
|
||||
func NewHandlerWrapper() server.HandlerWrapper {
|
||||
return func(fn server.HandlerFunc) server.HandlerFunc {
|
||||
return func(ctx context.Context, req server.Request, rsp interface{}) (err error) {
|
||||
t := newRequestTracker(req, ServerProfile)
|
||||
ctx = t.start(ctx, false)
|
||||
|
||||
defer func() { t.end(ctx, err) }()
|
||||
|
||||
spanCtx := getTraceFromCtx(ctx)
|
||||
if spanCtx != nil {
|
||||
ctx, t.span = trace.StartSpanWithRemoteParent(
|
||||
ctx,
|
||||
fmt.Sprintf("rpc/%s/%s/%s", ServerProfile.Role, req.Service(), req.Endpoint()),
|
||||
*spanCtx,
|
||||
)
|
||||
} else {
|
||||
ctx, t.span = trace.StartSpan(
|
||||
ctx,
|
||||
fmt.Sprintf("rpc/%s/%s/%s", ServerProfile.Role, req.Service(), req.Endpoint()),
|
||||
)
|
||||
}
|
||||
|
||||
err = fn(ctx, req, rsp)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NewSubscriberWrapper returns a server.SubscriberWrapper
|
||||
// that adds tracing to subscription requests.
|
||||
func NewSubscriberWrapper() server.SubscriberWrapper {
|
||||
return func(fn server.SubscriberFunc) server.SubscriberFunc {
|
||||
return func(ctx context.Context, p server.Message) (err error) {
|
||||
t := newEventTracker(p, ServerProfile)
|
||||
ctx = t.start(ctx, false)
|
||||
|
||||
defer func() { t.end(ctx, err) }()
|
||||
|
||||
spanCtx := getTraceFromCtx(ctx)
|
||||
if spanCtx != nil {
|
||||
ctx, t.span = trace.StartSpanWithRemoteParent(
|
||||
ctx,
|
||||
fmt.Sprintf("rpc/%s/pubsub/%s", ServerProfile.Role, p.Topic()),
|
||||
*spanCtx,
|
||||
)
|
||||
} else {
|
||||
ctx, t.span = trace.StartSpan(
|
||||
ctx,
|
||||
fmt.Sprintf("rpc/%s/pubsub/%s", ServerProfile.Role, p.Topic()),
|
||||
)
|
||||
}
|
||||
|
||||
err = fn(ctx, p)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
142
vendor/github.com/go-micro/plugins/v4/wrapper/trace/opencensus/stats.go
generated
vendored
Normal file
142
vendor/github.com/go-micro/plugins/v4/wrapper/trace/opencensus/stats.go
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
package opencensus
|
||||
|
||||
import (
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/stats/view"
|
||||
"go.opencensus.io/tag"
|
||||
)
|
||||
|
||||
// The following client RPC measures are supported for use in custom views.
|
||||
var (
|
||||
ClientRequestCount = stats.Int64("opencensus.io/rpc/client/request_count", "Number of RPC requests started", stats.UnitNone)
|
||||
ClientLatency = stats.Float64("opencensus.io/rpc/client/latency", "End-to-end latency", stats.UnitMilliseconds)
|
||||
)
|
||||
|
||||
// The following server RPC measures are supported for use in custom views.
|
||||
var (
|
||||
ServerRequestCount = stats.Int64("opencensus.io/rpc/server/request_count", "Number of RPC requests received", stats.UnitNone)
|
||||
ServerLatency = stats.Float64("opencensus.io/rpc/server/latency", "End-to-end latency", stats.UnitMilliseconds)
|
||||
)
|
||||
|
||||
// The following tags are applied to stats recorded by this package.
|
||||
// Service and Method are applied to all measures.
|
||||
// StatusCode is not applied to ClientRequestCount or ServerRequestCount,
|
||||
// since it is recorded before the status is known.
|
||||
var (
|
||||
// StatusCode is the RPC status code.
|
||||
StatusCode, _ = tag.NewKey("rpc.status")
|
||||
|
||||
// Service is the name of the micro-service.
|
||||
Service, _ = tag.NewKey("rpc.service")
|
||||
|
||||
// Method is the service method called.
|
||||
Endpoint, _ = tag.NewKey("rpc.endpoint")
|
||||
)
|
||||
|
||||
// Default distributions used by views in this package.
|
||||
var (
|
||||
DefaultLatencyDistribution = view.Distribution(0, 1, 2, 3, 4, 5, 6, 8, 10, 13, 16, 20, 25, 30, 40, 50, 65, 80, 100, 130, 160, 200, 250, 300, 400, 500, 650, 800, 1000, 2000, 5000, 10000, 20000, 50000, 100000)
|
||||
)
|
||||
|
||||
// This package provides some convenience views.
|
||||
// You need to subscribe to the views for data to actually be collected.
|
||||
var (
|
||||
ClientRequestCountView = &view.View{
|
||||
Name: "opencensus.io/rpc/client/request_count",
|
||||
Description: "Count of RPC requests started",
|
||||
Measure: ClientRequestCount,
|
||||
Aggregation: view.Count(),
|
||||
}
|
||||
|
||||
ClientLatencyView = &view.View{
|
||||
Name: "opencensus.io/rpc/client/latency",
|
||||
Description: "Latency distribution of RPC requests",
|
||||
Measure: ClientLatency,
|
||||
Aggregation: DefaultLatencyDistribution,
|
||||
}
|
||||
|
||||
ClientRequestCountByMethod = &view.View{
|
||||
Name: "opencensus.io/rpc/client/request_count_by_method",
|
||||
Description: "Client request count by RPC method",
|
||||
TagKeys: []tag.Key{Endpoint},
|
||||
Measure: ClientRequestCount,
|
||||
Aggregation: view.Count(),
|
||||
}
|
||||
|
||||
ClientResponseCountByStatusCode = &view.View{
|
||||
Name: "opencensus.io/rpc/client/response_count_by_status_code",
|
||||
Description: "Client response count by RPC status code",
|
||||
TagKeys: []tag.Key{StatusCode},
|
||||
Measure: ClientLatency,
|
||||
Aggregation: view.Count(),
|
||||
}
|
||||
|
||||
ServerRequestCountView = &view.View{
|
||||
Name: "opencensus.io/rpc/server/request_count",
|
||||
Description: "Count of RPC requests received",
|
||||
Measure: ServerRequestCount,
|
||||
Aggregation: view.Count(),
|
||||
}
|
||||
|
||||
ServerLatencyView = &view.View{
|
||||
Name: "opencensus.io/rpc/server/latency",
|
||||
Description: "Latency distribution of RPC requests",
|
||||
Measure: ServerLatency,
|
||||
Aggregation: DefaultLatencyDistribution,
|
||||
}
|
||||
|
||||
ServerRequestCountByMethod = &view.View{
|
||||
Name: "opencensus.io/rpc/server/request_count_by_method",
|
||||
Description: "Server request count by RPC method",
|
||||
TagKeys: []tag.Key{Endpoint},
|
||||
Measure: ServerRequestCount,
|
||||
Aggregation: view.Count(),
|
||||
}
|
||||
|
||||
ServerResponseCountByStatusCode = &view.View{
|
||||
Name: "opencensus.io/rpc/server/response_count_by_status_code",
|
||||
Description: "Server response count by RPC status code",
|
||||
TagKeys: []tag.Key{StatusCode},
|
||||
Measure: ServerLatency,
|
||||
Aggregation: view.Count(),
|
||||
}
|
||||
)
|
||||
|
||||
// DefaultClientViews are the default client views provided by this package.
|
||||
var DefaultClientViews = []*view.View{
|
||||
ClientRequestCountView,
|
||||
ClientLatencyView,
|
||||
ClientRequestCountByMethod,
|
||||
ClientResponseCountByStatusCode,
|
||||
}
|
||||
|
||||
// DefaultServerViews are the default server views provided by this package.
|
||||
var DefaultServerViews = []*view.View{
|
||||
ServerRequestCountView,
|
||||
ServerLatencyView,
|
||||
ServerRequestCountByMethod,
|
||||
ServerResponseCountByStatusCode,
|
||||
}
|
||||
|
||||
// StatsProfile groups metrics-related data.
|
||||
type StatsProfile struct {
|
||||
Role string
|
||||
CountMeasure *stats.Int64Measure
|
||||
LatencyMeasure *stats.Float64Measure
|
||||
}
|
||||
|
||||
var (
|
||||
// ClientProfile is used for RPC clients.
|
||||
ClientProfile = &StatsProfile{
|
||||
Role: "client",
|
||||
CountMeasure: ClientRequestCount,
|
||||
LatencyMeasure: ClientLatency,
|
||||
}
|
||||
|
||||
// ServerProfile is used for RPC servers.
|
||||
ServerProfile = &StatsProfile{
|
||||
Role: "server",
|
||||
CountMeasure: ServerRequestCount,
|
||||
LatencyMeasure: ServerLatency,
|
||||
}
|
||||
)
|
||||
45
vendor/github.com/go-micro/plugins/v4/wrapper/trace/opencensus/status.go
generated
vendored
Normal file
45
vendor/github.com/go-micro/plugins/v4/wrapper/trace/opencensus/status.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
package opencensus
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
microerr "go-micro.dev/v4/errors"
|
||||
|
||||
"go.opencensus.io/trace"
|
||||
|
||||
"google.golang.org/genproto/googleapis/rpc/code"
|
||||
)
|
||||
|
||||
var microCodeToStatusCode = map[int32]code.Code{
|
||||
400: code.Code_INVALID_ARGUMENT,
|
||||
401: code.Code_UNAUTHENTICATED,
|
||||
403: code.Code_PERMISSION_DENIED,
|
||||
404: code.Code_NOT_FOUND,
|
||||
409: code.Code_ABORTED,
|
||||
500: code.Code_INTERNAL,
|
||||
}
|
||||
|
||||
func getResponseStatus(err error) trace.Status {
|
||||
if err != nil {
|
||||
microErr, ok := err.(*microerr.Error)
|
||||
if ok {
|
||||
statusCode := microErr.Code
|
||||
code, ok := microCodeToStatusCode[microErr.Code]
|
||||
if ok {
|
||||
statusCode = int32(code)
|
||||
}
|
||||
|
||||
return trace.Status{
|
||||
Code: statusCode,
|
||||
Message: fmt.Sprintf("%s: %s", microErr.Id, microErr.Detail),
|
||||
}
|
||||
}
|
||||
|
||||
return trace.Status{
|
||||
Code: int32(code.Code_UNKNOWN),
|
||||
Message: err.Error(),
|
||||
}
|
||||
}
|
||||
|
||||
return trace.Status{}
|
||||
}
|
||||
81
vendor/github.com/go-micro/plugins/v4/wrapper/trace/opencensus/tracker.go
generated
vendored
Normal file
81
vendor/github.com/go-micro/plugins/v4/wrapper/trace/opencensus/tracker.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
package opencensus
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"go.opencensus.io/stats"
|
||||
"go.opencensus.io/tag"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
type tracker struct {
|
||||
startedAt time.Time
|
||||
|
||||
profile *StatsProfile
|
||||
span *trace.Span
|
||||
|
||||
method string
|
||||
service string
|
||||
}
|
||||
|
||||
type requestDescriptor interface {
|
||||
Service() string
|
||||
Endpoint() string
|
||||
}
|
||||
|
||||
type publicationDescriptor interface {
|
||||
Topic() string
|
||||
}
|
||||
|
||||
// newRequestTracker creates a new tracker for an RPC request (client or server).
|
||||
func newRequestTracker(req requestDescriptor, profile *StatsProfile) *tracker {
|
||||
return &tracker{
|
||||
profile: profile,
|
||||
method: req.Endpoint(),
|
||||
service: req.Service(),
|
||||
}
|
||||
}
|
||||
|
||||
// newEventTracker creates a new tracker for a publication (client or server).
|
||||
func newEventTracker(pub publicationDescriptor, profile *StatsProfile) *tracker {
|
||||
return &tracker{
|
||||
profile: profile,
|
||||
method: pub.Topic(),
|
||||
service: "pubsub",
|
||||
}
|
||||
}
|
||||
|
||||
// start monitoring a request. You can choose to let this method
|
||||
// start a span for the request or attach one later.
|
||||
func (t *tracker) start(ctx context.Context, startSpan bool) context.Context {
|
||||
t.startedAt = time.Now()
|
||||
|
||||
ctx, _ = tag.New(ctx, tag.Upsert(Service, t.service), tag.Upsert(Endpoint, t.method))
|
||||
stats.Record(ctx, t.profile.CountMeasure.M(1))
|
||||
|
||||
if startSpan {
|
||||
ctx, t.span = trace.StartSpan(
|
||||
ctx,
|
||||
fmt.Sprintf("rpc/%s/%s/%s", t.profile.Role, t.service, t.method),
|
||||
)
|
||||
}
|
||||
|
||||
return ctx
|
||||
}
|
||||
|
||||
// end a request's monitoring session. If there is a span ongoing, it will
|
||||
// be ended and metrics will be recorded.
|
||||
func (t *tracker) end(ctx context.Context, err error) {
|
||||
status := getResponseStatus(err)
|
||||
|
||||
ctx, _ = tag.New(ctx, tag.Upsert(StatusCode, strconv.Itoa(int(status.Code))))
|
||||
stats.Record(ctx, t.profile.LatencyMeasure.M(float64(time.Since(t.startedAt))/float64(time.Millisecond)))
|
||||
|
||||
if t.span != nil {
|
||||
t.span.SetStatus(status)
|
||||
t.span.End()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user