Compare commits
74 Commits
Author | SHA1 | Date | |
---|---|---|---|
ab73127063 | |||
|
03031a694d | ||
|
5712aafba9 | ||
ac333d9d47 | |||
|
247707f583 | ||
|
d91c14eb30 | ||
|
ca8684a886 | ||
|
0449138f61 | ||
609f4826b3 | |||
60993e6275 | |||
|
e803fb0855 | ||
3543b275e0 | |||
fbde872e7f | |||
|
078dd4eb9b | ||
62a644ddd8 | |||
|
d8cfa7a295 | ||
|
47f1203e97 | ||
|
1b4e881d74 | ||
|
20ce61da5a | ||
|
eef4825be4 | ||
|
be9c6141f5 | ||
|
1ca4619506 | ||
|
f55493993c | ||
7b385bf163 | |||
|
4125ae8d53 | ||
|
48b2a5c37c | ||
|
ed83c27f0e | ||
241614ff68 | |||
|
1a4f608ed1 | ||
43b0dbb123 | |||
|
b344171c80 | ||
|
e3ce45495a | ||
f01664a551 | |||
8ecbdc1cd6 | |||
55c19afb0b | |||
077063c212 | |||
|
9a7a65f05e | ||
8ee5607254 | |||
11be2c68b9 | |||
a864f812f1 | |||
|
ae60bea8d8 | ||
|
a851b9db7a | ||
d807dac2a7 | |||
ce2ba71002 | |||
|
67c26c71b6 | ||
|
9386f36a13 | ||
|
6d803d9e45 | ||
|
6a9001bdb1 | ||
|
3f0c28a815 | ||
|
49ffc60afb | ||
|
beb5e80e87 | ||
|
eebd69c995 | ||
|
bc71989e2c | ||
89ba602e17 | |||
|
f6102bde70 | ||
|
7cad77bfc0 | ||
|
1f2e067f71 | ||
b555269b1b | |||
|
9200c70202 | ||
|
d8377e09c9 | ||
0754229878 | |||
6b8930a960 | |||
d0a978bd50 | |||
|
afe6861e2f | ||
|
962567ef42 | ||
|
e21ed3a183 | ||
64a5ce9607 | |||
|
d651b16acd | ||
|
1034837f69 | ||
|
80f2bfd5d0 | ||
|
6aaaf54275 | ||
|
603d37b135 | ||
|
53c3bff819 | ||
|
dcf859098b |
@@ -5,7 +5,7 @@ RUN mkdir /user && \
|
||||
echo 'nobody:x:65534:' > /user/group
|
||||
|
||||
ENV GO111MODULE=on
|
||||
RUN apk --no-cache add make git gcc libtool musl-dev ca-certificates && \
|
||||
RUN apk --no-cache add make git gcc libtool musl-dev ca-certificates dumb-init && \
|
||||
rm -rf /var/cache/apk/* /tmp/*
|
||||
|
||||
WORKDIR /
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/micro/go-micro/v2/agent/input"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
type discordConn struct {
|
||||
@@ -74,7 +74,9 @@ func (dc *discordConn) Send(e *input.Event) error {
|
||||
fields := strings.Split(e.To, ":")
|
||||
_, err := dc.master.session.ChannelMessageSend(fields[0], string(e.Data))
|
||||
if err != nil {
|
||||
log.Error("[bot][loop][send]", err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("[bot][loop][send]", err)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/forestgiant/sliceutil"
|
||||
"github.com/micro/go-micro/v2/agent/input"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
tgbotapi "gopkg.in/telegram-bot-api.v4"
|
||||
)
|
||||
|
||||
@@ -104,7 +104,9 @@ func (tc *telegramConn) Send(event *input.Event) error {
|
||||
|
||||
if err != nil {
|
||||
// probably it could be because of nested HTML tags -- telegram doesn't allow nested tags
|
||||
log.Error("[telegram][Send] error:", err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("[telegram][Send] error:", err)
|
||||
}
|
||||
msgConfig.Text = "This bot couldn't send the response (Internal error)"
|
||||
tc.input.api.Send(msgConfig)
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/micro/go-micro/v2/api/handler"
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -136,7 +136,9 @@ func (c *conn) writeLoop() {
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -214,7 +216,9 @@ func (b *brokerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
ws, err := b.u.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
log.Error(err.Error())
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -104,9 +104,20 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// micro client
|
||||
c := h.opts.Service.Client()
|
||||
|
||||
// create context
|
||||
cx := ctx.FromRequest(r)
|
||||
|
||||
// if stream we currently only support json
|
||||
if isStream(r, service) {
|
||||
serveWebsocket(cx, w, r, service, c)
|
||||
return
|
||||
}
|
||||
|
||||
// create strategy
|
||||
so := selector.WithStrategy(strategy(service.Services))
|
||||
|
||||
// walk the standard call path
|
||||
|
||||
// get payload
|
||||
br, err := requestPayload(r)
|
||||
if err != nil {
|
||||
@@ -114,9 +125,6 @@ func (h *rpcHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// create context
|
||||
cx := ctx.FromRequest(r)
|
||||
|
||||
var rsp []byte
|
||||
|
||||
switch {
|
||||
|
150
api/handler/rpc/stream.go
Normal file
150
api/handler/rpc/stream.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package rpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/micro/go-micro/v2/api"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/client/selector"
|
||||
)
|
||||
|
||||
var upgrader = websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
}
|
||||
|
||||
// serveWebsocket will stream rpc back over websockets assuming json
|
||||
func serveWebsocket(ctx context.Context, w http.ResponseWriter, r *http.Request, service *api.Service, c client.Client) {
|
||||
// upgrade the connection
|
||||
conn, err := upgrader.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// close on exit
|
||||
defer conn.Close()
|
||||
|
||||
// wait for the first request so we know
|
||||
_, p, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// send to backend
|
||||
// default to trying json
|
||||
var request json.RawMessage
|
||||
// if the extracted payload isn't empty lets use it
|
||||
if len(p) > 0 {
|
||||
request = json.RawMessage(p)
|
||||
}
|
||||
|
||||
// create a request to the backend
|
||||
req := c.NewRequest(
|
||||
service.Name,
|
||||
service.Endpoint.Name,
|
||||
&request,
|
||||
client.WithContentType("application/json"),
|
||||
)
|
||||
|
||||
so := selector.WithStrategy(strategy(service.Services))
|
||||
|
||||
// create a new stream
|
||||
stream, err := c.Stream(ctx, req, client.WithSelectOption(so))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// send the first request for the client
|
||||
// since
|
||||
if err := stream.Send(request); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
go writeLoop(conn, stream)
|
||||
|
||||
resp := stream.Response()
|
||||
|
||||
// receive from stream and send to client
|
||||
for {
|
||||
// read backend response body
|
||||
body, err := resp.Read()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// write the response
|
||||
if err := conn.WriteMessage(websocket.TextMessage, body); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// writeLoop
|
||||
func writeLoop(conn *websocket.Conn, stream client.Stream) {
|
||||
// close stream when done
|
||||
defer stream.Close()
|
||||
|
||||
for {
|
||||
_, p, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// send to backend
|
||||
// default to trying json
|
||||
var request json.RawMessage
|
||||
// if the extracted payload isn't empty lets use it
|
||||
if len(p) > 0 {
|
||||
request = json.RawMessage(p)
|
||||
}
|
||||
|
||||
if err := stream.Send(request); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isStream(r *http.Request, srv *api.Service) bool {
|
||||
// check if it's a web socket
|
||||
if !isWebSocket(r) {
|
||||
return false
|
||||
}
|
||||
|
||||
// check if the endpoint supports streaming
|
||||
for _, service := range srv.Services {
|
||||
for _, ep := range service.Endpoints {
|
||||
// skip if it doesn't match the name
|
||||
if ep.Name != srv.Endpoint.Name {
|
||||
continue
|
||||
}
|
||||
|
||||
// matched if the name
|
||||
if v := ep.Metadata["stream"]; v == "true" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func isWebSocket(r *http.Request) bool {
|
||||
contains := func(key, val string) bool {
|
||||
vv := strings.Split(r.Header.Get(key), ",")
|
||||
for _, v := range vv {
|
||||
if val == strings.ToLower(strings.TrimSpace(v)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if contains("Connection", "upgrade") && contains("Upgrade", "websocket") {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
@@ -18,6 +18,11 @@ func apiRoute(p string) (string, string) {
|
||||
p = strings.TrimPrefix(p, "/")
|
||||
parts := strings.Split(p, "/")
|
||||
|
||||
// if we have 1 part assume name Name.Call
|
||||
if len(parts) == 1 && len(parts[0]) > 0 {
|
||||
return parts[0], methodName(append(parts, "Call"))
|
||||
}
|
||||
|
||||
// If we've got two or less parts
|
||||
// Use first part as service
|
||||
// Use all parts as method
|
||||
|
@@ -48,7 +48,7 @@ func (c *certmagicProvider) TLSConfig(hosts ...string) (*tls.Config, error) {
|
||||
return certmagic.TLS(hosts)
|
||||
}
|
||||
|
||||
// New returns a certmagic provider
|
||||
// NewProvider returns a certmagic provider
|
||||
func NewProvider(options ...acme.Option) acme.Provider {
|
||||
opts := acme.DefaultOptions()
|
||||
|
||||
|
@@ -88,16 +88,16 @@ func (s *storage) Exists(key string) bool {
|
||||
}
|
||||
|
||||
func (s *storage) List(prefix string, recursive bool) ([]string, error) {
|
||||
records, err := s.store.List()
|
||||
keys, err := s.store.List()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//nolint:prealloc
|
||||
var results []string
|
||||
for _, r := range records {
|
||||
if strings.HasPrefix(r.Key, prefix) {
|
||||
results = append(results, r.Key)
|
||||
for _, k := range keys {
|
||||
if strings.HasPrefix(k, prefix) {
|
||||
results = append(results, k)
|
||||
}
|
||||
}
|
||||
if recursive {
|
||||
|
71
api/server/auth/auth.go
Normal file
71
api/server/auth/auth.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
)
|
||||
|
||||
// CombinedAuthHandler wraps a server and authenticates requests
|
||||
func CombinedAuthHandler(h http.Handler) http.Handler {
|
||||
return authHandler{
|
||||
handler: h,
|
||||
auth: auth.DefaultAuth,
|
||||
}
|
||||
}
|
||||
|
||||
type authHandler struct {
|
||||
handler http.Handler
|
||||
auth auth.Auth
|
||||
}
|
||||
|
||||
const (
|
||||
// BearerScheme is the prefix in the auth header
|
||||
BearerScheme = "Bearer "
|
||||
)
|
||||
|
||||
func (h authHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
loginURL := h.auth.Options().LoginURL
|
||||
|
||||
// Return if the user disabled auth on this endpoint
|
||||
excludes := h.auth.Options().Exclude
|
||||
if len(loginURL) > 0 {
|
||||
excludes = append(excludes, loginURL)
|
||||
}
|
||||
for _, e := range excludes {
|
||||
if e == req.URL.Path {
|
||||
h.handler.ServeHTTP(w, req)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var token string
|
||||
if header := req.Header.Get("Authorization"); len(header) > 0 {
|
||||
// Extract the auth token from the request
|
||||
if strings.HasPrefix(header, BearerScheme) {
|
||||
token = header[len(BearerScheme):]
|
||||
}
|
||||
} else {
|
||||
// Get the token out the cookies if not provided in headers
|
||||
if c, err := req.Cookie("micro-token"); err == nil && c != nil {
|
||||
token = strings.TrimPrefix(c.Value, auth.CookieName+"=")
|
||||
req.Header.Set("Authorization", BearerScheme+token)
|
||||
}
|
||||
}
|
||||
|
||||
// If the token is valid, allow the request
|
||||
if _, err := h.auth.Verify(token); err == nil {
|
||||
h.handler.ServeHTTP(w, req)
|
||||
return
|
||||
}
|
||||
|
||||
// If there is no auth login url set, 401
|
||||
if loginURL == "" {
|
||||
w.WriteHeader(401)
|
||||
return
|
||||
}
|
||||
|
||||
// Redirect to the login path
|
||||
http.Redirect(w, req, loginURL, http.StatusTemporaryRedirect)
|
||||
}
|
44
api/server/cors/cors.go
Normal file
44
api/server/cors/cors.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package cors
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// CombinedCORSHandler wraps a server and provides CORS headers
|
||||
func CombinedCORSHandler(h http.Handler) http.Handler {
|
||||
return corsHandler{h}
|
||||
}
|
||||
|
||||
type corsHandler struct {
|
||||
handler http.Handler
|
||||
}
|
||||
|
||||
func (c corsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
SetHeaders(w, r)
|
||||
|
||||
if r.Method == "OPTIONS" {
|
||||
return
|
||||
}
|
||||
|
||||
c.handler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
// SetHeaders sets the CORS headers
|
||||
func SetHeaders(w http.ResponseWriter, r *http.Request) {
|
||||
set := func(w http.ResponseWriter, k, v string) {
|
||||
if v := w.Header().Get(k); len(v) > 0 {
|
||||
return
|
||||
}
|
||||
w.Header().Set(k, v)
|
||||
}
|
||||
|
||||
if origin := r.Header.Get("Origin"); len(origin) > 0 {
|
||||
set(w, "Access-Control-Allow-Origin", origin)
|
||||
} else {
|
||||
set(w, "Access-Control-Allow-Origin", "*")
|
||||
}
|
||||
|
||||
set(w, "Access-Control-Allow-Credentials", "true")
|
||||
set(w, "Access-Control-Allow-Methods", "POST, PATCH, GET, OPTIONS, PUT, DELETE")
|
||||
set(w, "Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
|
||||
}
|
@@ -8,9 +8,12 @@ import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/micro/go-micro/v2/api/server/auth"
|
||||
|
||||
"github.com/gorilla/handlers"
|
||||
"github.com/micro/go-micro/v2/api/server"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/api/server/cors"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
type httpServer struct {
|
||||
@@ -45,7 +48,14 @@ func (s *httpServer) Init(opts ...server.Option) error {
|
||||
}
|
||||
|
||||
func (s *httpServer) Handle(path string, handler http.Handler) {
|
||||
s.mux.Handle(path, handlers.CombinedLoggingHandler(os.Stdout, handler))
|
||||
h := handlers.CombinedLoggingHandler(os.Stdout, handler)
|
||||
h = auth.CombinedAuthHandler(handler)
|
||||
|
||||
if s.opts.EnableCORS {
|
||||
h = cors.CombinedCORSHandler(h)
|
||||
}
|
||||
|
||||
s.mux.Handle(path, h)
|
||||
}
|
||||
|
||||
func (s *httpServer) Start() error {
|
||||
@@ -65,7 +75,9 @@ func (s *httpServer) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("HTTP API Listening on %s", l.Addr().String())
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Infof("HTTP API Listening on %s", l.Addr().String())
|
||||
}
|
||||
|
||||
s.mtx.Lock()
|
||||
s.address = l.Addr().String()
|
||||
@@ -74,7 +86,7 @@ func (s *httpServer) Start() error {
|
||||
go func() {
|
||||
if err := http.Serve(l, s.mux); err != nil {
|
||||
// temporary fix
|
||||
//log.Fatal(err)
|
||||
//logger.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@@ -10,12 +10,19 @@ type Option func(o *Options)
|
||||
|
||||
type Options struct {
|
||||
EnableACME bool
|
||||
EnableCORS bool
|
||||
ACMEProvider acme.Provider
|
||||
EnableTLS bool
|
||||
ACMEHosts []string
|
||||
TLSConfig *tls.Config
|
||||
}
|
||||
|
||||
func EnableCORS(b bool) Option {
|
||||
return func(o *Options) {
|
||||
o.EnableCORS = b
|
||||
}
|
||||
}
|
||||
|
||||
func EnableACME(b bool) Option {
|
||||
return func(o *Options) {
|
||||
o.EnableACME = b
|
||||
|
56
auth/auth.go
56
auth/auth.go
@@ -2,7 +2,11 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/metadata"
|
||||
)
|
||||
|
||||
// Auth providers authentication and authorization
|
||||
@@ -15,8 +19,8 @@ type Auth interface {
|
||||
Generate(id string, opts ...GenerateOption) (*Account, error)
|
||||
// Revoke an authorization Account
|
||||
Revoke(token string) error
|
||||
// Validate an account token
|
||||
Validate(token string) (*Account, error)
|
||||
// Verify an account token
|
||||
Verify(token string) (*Account, error)
|
||||
// String returns the implementation
|
||||
String() string
|
||||
}
|
||||
@@ -31,13 +35,16 @@ type Resource struct {
|
||||
|
||||
// Role an account has
|
||||
type Role struct {
|
||||
Name string
|
||||
// Name of the role
|
||||
Name string
|
||||
// The resource it has access
|
||||
// TODO: potentially remove
|
||||
Resource *Resource
|
||||
}
|
||||
|
||||
// Account provided by an auth provider
|
||||
type Account struct {
|
||||
// ID of the account (UUID or email)
|
||||
// ID of the account (UUIDV4, email or username)
|
||||
Id string `json:"id"`
|
||||
// Token used to authenticate
|
||||
Token string `json:"token"`
|
||||
@@ -50,3 +57,44 @@ type Account struct {
|
||||
// Any other associated metadata
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
}
|
||||
|
||||
const (
|
||||
// MetadataKey is the key used when storing the account
|
||||
// in metadata
|
||||
MetadataKey = "auth-account"
|
||||
// CookieName is the name of the cookie which stores the
|
||||
// auth token
|
||||
CookieName = "micro-token"
|
||||
)
|
||||
|
||||
// AccountFromContext gets the account from the context, which
|
||||
// is set by the auth wrapper at the start of a call. If the account
|
||||
// is not set, a nil account will be returned. The error is only returned
|
||||
// when there was a problem retrieving an account
|
||||
func AccountFromContext(ctx context.Context) (*Account, error) {
|
||||
str, ok := metadata.Get(ctx, MetadataKey)
|
||||
// there was no account set
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var acc *Account
|
||||
// metadata is stored as a string, so unmarshal to an account
|
||||
if err := json.Unmarshal([]byte(str), &acc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
// ContextWithAccount sets the account in the context
|
||||
func ContextWithAccount(ctx context.Context, account *Account) (context.Context, error) {
|
||||
// metadata is stored as a string, so marshal to bytes
|
||||
bytes, err := json.Marshal(account)
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
}
|
||||
|
||||
// generate a new context with the MetadataKey set
|
||||
return metadata.Set(ctx, MetadataKey, string(bytes)), nil
|
||||
}
|
||||
|
112
auth/default.go
112
auth/default.go
@@ -1,36 +1,122 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/base32"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultAuth = NewAuth()
|
||||
)
|
||||
|
||||
// NewAuth returns a new default registry which is noop
|
||||
func genAccount(id string) *Account {
|
||||
// return a pseudo account
|
||||
return &Account{
|
||||
Id: id,
|
||||
Token: base32.StdEncoding.EncodeToString([]byte(id)),
|
||||
Created: time.Now(),
|
||||
Expiry: time.Now().Add(time.Hour * 24),
|
||||
Metadata: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
// NewAuth returns a new default registry which is memory
|
||||
func NewAuth(opts ...Option) Auth {
|
||||
return noop{}
|
||||
var options Options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return &memory{
|
||||
accounts: make(map[string]*Account),
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
type noop struct{}
|
||||
// TODO: replace with https://github.com/nats-io/nkeys
|
||||
// We'll then register public key in registry to use
|
||||
type memory struct {
|
||||
opts Options
|
||||
// accounts
|
||||
sync.RWMutex
|
||||
accounts map[string]*Account
|
||||
}
|
||||
|
||||
func (noop) Init(opts ...Option) error {
|
||||
func (n *memory) Init(opts ...Option) error {
|
||||
for _, o := range opts {
|
||||
o(&n.opts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (noop) Options() Options {
|
||||
return Options{}
|
||||
func (n *memory) Options() Options {
|
||||
return n.opts
|
||||
}
|
||||
|
||||
func (noop) Generate(id string, opts ...GenerateOption) (*Account, error) {
|
||||
return nil, nil
|
||||
func (n *memory) Generate(id string, opts ...GenerateOption) (*Account, error) {
|
||||
var options GenerateOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
// return a pseudo account
|
||||
acc := genAccount(id)
|
||||
|
||||
// set opts
|
||||
if len(options.Roles) > 0 {
|
||||
acc.Roles = options.Roles
|
||||
}
|
||||
if options.Metadata != nil {
|
||||
acc.Metadata = options.Metadata
|
||||
}
|
||||
|
||||
// TODO: don't overwrite
|
||||
n.Lock()
|
||||
// maybe save by account id?
|
||||
n.accounts[acc.Token] = acc
|
||||
n.Unlock()
|
||||
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
func (noop) Revoke(token string) error {
|
||||
func (n *memory) Revoke(token string) error {
|
||||
n.Lock()
|
||||
delete(n.accounts, token)
|
||||
n.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (noop) Validate(token string) (*Account, error) {
|
||||
return nil, nil
|
||||
func (n *memory) Verify(token string) (*Account, error) {
|
||||
n.RLock()
|
||||
defer n.RUnlock()
|
||||
|
||||
if len(token) == 0 {
|
||||
// pseudo account?
|
||||
return genAccount(""), nil
|
||||
}
|
||||
|
||||
// try get the local account if it exists
|
||||
if acc, ok := n.accounts[token]; ok {
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
// decode the token otherwise
|
||||
b, err := base32.StdEncoding.DecodeString(token)
|
||||
if err != nil {
|
||||
return genAccount(""), nil
|
||||
}
|
||||
|
||||
// return a pseudo account based on token/id
|
||||
return &Account{
|
||||
Id: string(b),
|
||||
Token: token,
|
||||
Created: time.Now(),
|
||||
Expiry: time.Now().Add(time.Hour * 24),
|
||||
Metadata: make(map[string]string),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (noop) String() string {
|
||||
return "noop"
|
||||
func (n *memory) String() string {
|
||||
return "memory"
|
||||
}
|
||||
|
@@ -1,24 +1,26 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/dgrijalva/jwt-go"
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
)
|
||||
|
||||
// ErrInvalidPrivateKey is returned when the service provided an invalid private key
|
||||
var ErrInvalidPrivateKey = errors.New("An invalid private key was provided")
|
||||
var (
|
||||
// ErrInvalidPrivateKey is returned when the service provided an invalid private key
|
||||
ErrInvalidPrivateKey = errors.New("An invalid private key was provided")
|
||||
|
||||
// ErrEncodingToken is returned when the service encounters an error during encoding
|
||||
var ErrEncodingToken = errors.New("An error occured while encoding the JWT")
|
||||
// ErrEncodingToken is returned when the service encounters an error during encoding
|
||||
ErrEncodingToken = errors.New("An error occured while encoding the JWT")
|
||||
|
||||
// ErrInvalidToken is returned when the token provided is not valid
|
||||
var ErrInvalidToken = errors.New("An invalid token was provided")
|
||||
// ErrInvalidToken is returned when the token provided is not valid
|
||||
ErrInvalidToken = errors.New("An invalid token was provided")
|
||||
|
||||
// ErrMissingToken is returned when no token is provided
|
||||
var ErrMissingToken = errors.New("A valid JWT is required")
|
||||
// ErrMissingToken is returned when no token is provided
|
||||
ErrMissingToken = errors.New("A valid JWT is required")
|
||||
)
|
||||
|
||||
// NewAuth returns a new instance of the Auth service
|
||||
func NewAuth(opts ...auth.Option) auth.Auth {
|
||||
@@ -59,7 +61,13 @@ type AuthClaims struct {
|
||||
|
||||
// Generate a new JWT
|
||||
func (s *svc) Generate(id string, ops ...auth.GenerateOption) (*auth.Account, error) {
|
||||
key, err := jwt.ParseRSAPrivateKeyFromPEM(s.options.PrivateKey)
|
||||
// decode the private key
|
||||
priv, err := base64.StdEncoding.DecodeString(s.options.PrivateKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := jwt.ParseRSAPrivateKeyFromPEM(priv)
|
||||
if err != nil {
|
||||
return nil, ErrEncodingToken
|
||||
}
|
||||
@@ -68,7 +76,7 @@ func (s *svc) Generate(id string, ops ...auth.GenerateOption) (*auth.Account, er
|
||||
account := jwt.NewWithClaims(jwt.SigningMethodRS256, AuthClaims{
|
||||
id, options.Roles, options.Metadata, jwt.StandardClaims{
|
||||
Subject: id,
|
||||
ExpiresAt: time.Now().Add(time.Hour * 24).Unix(),
|
||||
ExpiresAt: options.Expiry.Unix(),
|
||||
},
|
||||
})
|
||||
|
||||
@@ -90,14 +98,20 @@ func (s *svc) Revoke(token string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate a JWT
|
||||
func (s *svc) Validate(token string) (*auth.Account, error) {
|
||||
// Verify a JWT
|
||||
func (s *svc) Verify(token string) (*auth.Account, error) {
|
||||
if token == "" {
|
||||
return nil, ErrMissingToken
|
||||
}
|
||||
|
||||
// decode the public key
|
||||
pub, err := base64.StdEncoding.DecodeString(s.options.PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := jwt.ParseWithClaims(token, &AuthClaims{}, func(token *jwt.Token) (interface{}, error) {
|
||||
return jwt.ParseRSAPublicKeyFromPEM(s.options.PublicKey)
|
||||
return jwt.ParseRSAPublicKeyFromPEM(pub)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -1,41 +1,77 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
b64 "encoding/base64"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth/provider"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
PublicKey []byte
|
||||
PrivateKey []byte
|
||||
Excludes []string
|
||||
// Token is an auth token
|
||||
Token string
|
||||
// Public key base64 encoded
|
||||
PublicKey string
|
||||
// Private key base64 encoded
|
||||
PrivateKey string
|
||||
// Endpoints to exclude
|
||||
Exclude []string
|
||||
// Provider is an auth provider
|
||||
Provider provider.Provider
|
||||
// LoginURL is the relative url path where a user can login
|
||||
LoginURL string
|
||||
}
|
||||
|
||||
type Option func(o *Options)
|
||||
|
||||
// Excludes endpoints from auth
|
||||
func Excludes(excludes ...string) Option {
|
||||
// Exclude ecludes a set of endpoints from authorization
|
||||
func Exclude(e ...string) Option {
|
||||
return func(o *Options) {
|
||||
o.Excludes = excludes
|
||||
o.Exclude = e
|
||||
}
|
||||
}
|
||||
|
||||
// PublicKey is the JWT public key
|
||||
func PublicKey(key string) Option {
|
||||
return func(o *Options) {
|
||||
o.PublicKey, _ = b64.StdEncoding.DecodeString(key)
|
||||
o.PublicKey = key
|
||||
}
|
||||
}
|
||||
|
||||
// PrivateKey is the JWT private key
|
||||
func PrivateKey(key string) Option {
|
||||
return func(o *Options) {
|
||||
o.PrivateKey, _ = b64.StdEncoding.DecodeString(key)
|
||||
o.PrivateKey = key
|
||||
}
|
||||
}
|
||||
|
||||
// Token sets an auth token
|
||||
func Token(t string) Option {
|
||||
return func(o *Options) {
|
||||
o.Token = t
|
||||
}
|
||||
}
|
||||
|
||||
// Provider set the auth provider
|
||||
func Provider(p provider.Provider) Option {
|
||||
return func(o *Options) {
|
||||
o.Provider = p
|
||||
}
|
||||
}
|
||||
|
||||
// LoginURL sets the auth LoginURL
|
||||
func LoginURL(url string) Option {
|
||||
return func(o *Options) {
|
||||
o.LoginURL = url
|
||||
}
|
||||
}
|
||||
|
||||
type GenerateOptions struct {
|
||||
// Metadata associated with the account
|
||||
Metadata map[string]string
|
||||
Roles []*Role
|
||||
// Roles/scopes associated with the account
|
||||
Roles []*Role
|
||||
//Expiry of the token
|
||||
Expiry time.Time
|
||||
}
|
||||
|
||||
type GenerateOption func(o *GenerateOptions)
|
||||
@@ -54,12 +90,22 @@ func Roles(rs []*Role) func(o *GenerateOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
// Expiry for the generated account's token expires
|
||||
func Expiry(ex time.Time) func(o *GenerateOptions) {
|
||||
return func(o *GenerateOptions) {
|
||||
o.Expiry = ex
|
||||
}
|
||||
}
|
||||
|
||||
// NewGenerateOptions from a slice of options
|
||||
func NewGenerateOptions(opts ...GenerateOption) GenerateOptions {
|
||||
var options GenerateOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
//set defualt expiry of token
|
||||
if options.Expiry.IsZero() {
|
||||
options.Expiry = time.Now().Add(time.Hour * 24)
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
34
auth/provider/basic/basic.go
Normal file
34
auth/provider/basic/basic.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package basic
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/v2/auth/provider"
|
||||
)
|
||||
|
||||
// NewProvider returns an initialised basic provider
|
||||
func NewProvider(opts ...provider.Option) provider.Provider {
|
||||
var options provider.Options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
return &basic{options}
|
||||
}
|
||||
|
||||
type basic struct {
|
||||
opts provider.Options
|
||||
}
|
||||
|
||||
func (b *basic) String() string {
|
||||
return "basic"
|
||||
}
|
||||
|
||||
func (b *basic) Options() provider.Options {
|
||||
return b.opts
|
||||
}
|
||||
|
||||
func (b *basic) Endpoint() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (b *basic) Redirect() string {
|
||||
return ""
|
||||
}
|
54
auth/provider/oauth/oauth.go
Normal file
54
auth/provider/oauth/oauth.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package oauth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth/provider"
|
||||
)
|
||||
|
||||
// NewProvider returns an initialised oauth provider
|
||||
func NewProvider(opts ...provider.Option) provider.Provider {
|
||||
var options provider.Options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
return &oauth{options}
|
||||
}
|
||||
|
||||
type oauth struct {
|
||||
opts provider.Options
|
||||
}
|
||||
|
||||
func (o *oauth) String() string {
|
||||
return "oauth"
|
||||
}
|
||||
|
||||
func (o *oauth) Options() provider.Options {
|
||||
return o.opts
|
||||
}
|
||||
|
||||
func (o *oauth) Endpoint() string {
|
||||
params := make(url.Values)
|
||||
params.Add("response_type", "code")
|
||||
|
||||
if clientID := o.opts.ClientID; len(clientID) > 0 {
|
||||
params.Add("client_id", clientID)
|
||||
}
|
||||
|
||||
if scope := o.opts.Scope; len(scope) > 0 {
|
||||
// spaces are url encoded since this cannot be passed in env vars
|
||||
params.Add("scope", strings.ReplaceAll(scope, "%20", " "))
|
||||
}
|
||||
|
||||
if redir := o.Redirect(); len(redir) > 0 {
|
||||
params.Add("redirect_uri", redir)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%v?%v", o.opts.Endpoint, params.Encode())
|
||||
}
|
||||
|
||||
func (o *oauth) Redirect() string {
|
||||
return o.opts.Redirect
|
||||
}
|
47
auth/provider/options.go
Normal file
47
auth/provider/options.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package provider
|
||||
|
||||
// Option returns a function which sets an option
|
||||
type Option func(*Options)
|
||||
|
||||
// Options a provider can have
|
||||
type Options struct {
|
||||
// ClientID is the application's ID.
|
||||
ClientID string
|
||||
// ClientSecret is the application's secret.
|
||||
ClientSecret string
|
||||
// Endpoint for the provider
|
||||
Endpoint string
|
||||
// Redirect url incase of UI
|
||||
Redirect string
|
||||
// Scope of the oauth request
|
||||
Scope string
|
||||
}
|
||||
|
||||
// Credentials is an option which sets the client id and secret
|
||||
func Credentials(id, secret string) Option {
|
||||
return func(o *Options) {
|
||||
o.ClientID = id
|
||||
o.ClientSecret = secret
|
||||
}
|
||||
}
|
||||
|
||||
// Endpoint sets the endpoint option
|
||||
func Endpoint(e string) Option {
|
||||
return func(o *Options) {
|
||||
o.Endpoint = e
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect sets the Redirect option
|
||||
func Redirect(r string) Option {
|
||||
return func(o *Options) {
|
||||
o.Redirect = r
|
||||
}
|
||||
}
|
||||
|
||||
// Scope sets the oauth scope
|
||||
func Scope(s string) Option {
|
||||
return func(o *Options) {
|
||||
o.Scope = s
|
||||
}
|
||||
}
|
28
auth/provider/provider.go
Normal file
28
auth/provider/provider.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// Package provider is an external auth provider e.g oauth
|
||||
package provider
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// Provider is an auth provider
|
||||
type Provider interface {
|
||||
// String returns the name of the provider
|
||||
String() string
|
||||
// Options returns the options of a provider
|
||||
Options() Options
|
||||
// Endpoint for the provider
|
||||
Endpoint() string
|
||||
// Redirect url incase of UI
|
||||
Redirect() string
|
||||
}
|
||||
|
||||
// Grant is a granted authorisation
|
||||
type Grant struct {
|
||||
// token for reuse
|
||||
Token string
|
||||
// Expiry of the token
|
||||
Expiry time.Time
|
||||
// Scopes associated with grant
|
||||
Scopes []string
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: auth/service/proto/auth.proto
|
||||
// source: micro/go-micro/auth/service/proto/auth.proto
|
||||
|
||||
package go_micro_auth
|
||||
|
||||
@@ -36,7 +36,7 @@ func (m *Account) Reset() { *m = Account{} }
|
||||
func (m *Account) String() string { return proto.CompactTextString(m) }
|
||||
func (*Account) ProtoMessage() {}
|
||||
func (*Account) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{0}
|
||||
return fileDescriptor_de609d4872dacc78, []int{0}
|
||||
}
|
||||
|
||||
func (m *Account) XXX_Unmarshal(b []byte) error {
|
||||
@@ -111,7 +111,7 @@ func (m *Role) Reset() { *m = Role{} }
|
||||
func (m *Role) String() string { return proto.CompactTextString(m) }
|
||||
func (*Role) ProtoMessage() {}
|
||||
func (*Role) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{1}
|
||||
return fileDescriptor_de609d4872dacc78, []int{1}
|
||||
}
|
||||
|
||||
func (m *Role) XXX_Unmarshal(b []byte) error {
|
||||
@@ -158,7 +158,7 @@ func (m *Resource) Reset() { *m = Resource{} }
|
||||
func (m *Resource) String() string { return proto.CompactTextString(m) }
|
||||
func (*Resource) ProtoMessage() {}
|
||||
func (*Resource) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{2}
|
||||
return fileDescriptor_de609d4872dacc78, []int{2}
|
||||
}
|
||||
|
||||
func (m *Resource) XXX_Unmarshal(b []byte) error {
|
||||
@@ -204,7 +204,7 @@ func (m *GenerateRequest) Reset() { *m = GenerateRequest{} }
|
||||
func (m *GenerateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*GenerateRequest) ProtoMessage() {}
|
||||
func (*GenerateRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{3}
|
||||
return fileDescriptor_de609d4872dacc78, []int{3}
|
||||
}
|
||||
|
||||
func (m *GenerateRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -243,7 +243,7 @@ func (m *GenerateResponse) Reset() { *m = GenerateResponse{} }
|
||||
func (m *GenerateResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*GenerateResponse) ProtoMessage() {}
|
||||
func (*GenerateResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{4}
|
||||
return fileDescriptor_de609d4872dacc78, []int{4}
|
||||
}
|
||||
|
||||
func (m *GenerateResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -271,78 +271,78 @@ func (m *GenerateResponse) GetAccount() *Account {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ValidateRequest struct {
|
||||
type VerifyRequest struct {
|
||||
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ValidateRequest) Reset() { *m = ValidateRequest{} }
|
||||
func (m *ValidateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ValidateRequest) ProtoMessage() {}
|
||||
func (*ValidateRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{5}
|
||||
func (m *VerifyRequest) Reset() { *m = VerifyRequest{} }
|
||||
func (m *VerifyRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*VerifyRequest) ProtoMessage() {}
|
||||
func (*VerifyRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_de609d4872dacc78, []int{5}
|
||||
}
|
||||
|
||||
func (m *ValidateRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ValidateRequest.Unmarshal(m, b)
|
||||
func (m *VerifyRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_VerifyRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ValidateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ValidateRequest.Marshal(b, m, deterministic)
|
||||
func (m *VerifyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_VerifyRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ValidateRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ValidateRequest.Merge(m, src)
|
||||
func (m *VerifyRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_VerifyRequest.Merge(m, src)
|
||||
}
|
||||
func (m *ValidateRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_ValidateRequest.Size(m)
|
||||
func (m *VerifyRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_VerifyRequest.Size(m)
|
||||
}
|
||||
func (m *ValidateRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ValidateRequest.DiscardUnknown(m)
|
||||
func (m *VerifyRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_VerifyRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ValidateRequest proto.InternalMessageInfo
|
||||
var xxx_messageInfo_VerifyRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *ValidateRequest) GetToken() string {
|
||||
func (m *VerifyRequest) GetToken() string {
|
||||
if m != nil {
|
||||
return m.Token
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ValidateResponse struct {
|
||||
type VerifyResponse struct {
|
||||
Account *Account `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ValidateResponse) Reset() { *m = ValidateResponse{} }
|
||||
func (m *ValidateResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ValidateResponse) ProtoMessage() {}
|
||||
func (*ValidateResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{6}
|
||||
func (m *VerifyResponse) Reset() { *m = VerifyResponse{} }
|
||||
func (m *VerifyResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*VerifyResponse) ProtoMessage() {}
|
||||
func (*VerifyResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_de609d4872dacc78, []int{6}
|
||||
}
|
||||
|
||||
func (m *ValidateResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ValidateResponse.Unmarshal(m, b)
|
||||
func (m *VerifyResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_VerifyResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ValidateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ValidateResponse.Marshal(b, m, deterministic)
|
||||
func (m *VerifyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_VerifyResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ValidateResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ValidateResponse.Merge(m, src)
|
||||
func (m *VerifyResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_VerifyResponse.Merge(m, src)
|
||||
}
|
||||
func (m *ValidateResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_ValidateResponse.Size(m)
|
||||
func (m *VerifyResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_VerifyResponse.Size(m)
|
||||
}
|
||||
func (m *ValidateResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ValidateResponse.DiscardUnknown(m)
|
||||
func (m *VerifyResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_VerifyResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ValidateResponse proto.InternalMessageInfo
|
||||
var xxx_messageInfo_VerifyResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *ValidateResponse) GetAccount() *Account {
|
||||
func (m *VerifyResponse) GetAccount() *Account {
|
||||
if m != nil {
|
||||
return m.Account
|
||||
}
|
||||
@@ -360,7 +360,7 @@ func (m *RevokeRequest) Reset() { *m = RevokeRequest{} }
|
||||
func (m *RevokeRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*RevokeRequest) ProtoMessage() {}
|
||||
func (*RevokeRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{7}
|
||||
return fileDescriptor_de609d4872dacc78, []int{7}
|
||||
}
|
||||
|
||||
func (m *RevokeRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -398,7 +398,7 @@ func (m *RevokeResponse) Reset() { *m = RevokeResponse{} }
|
||||
func (m *RevokeResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*RevokeResponse) ProtoMessage() {}
|
||||
func (*RevokeResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{8}
|
||||
return fileDescriptor_de609d4872dacc78, []int{8}
|
||||
}
|
||||
|
||||
func (m *RevokeResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -426,41 +426,43 @@ func init() {
|
||||
proto.RegisterType((*Resource)(nil), "go.micro.auth.Resource")
|
||||
proto.RegisterType((*GenerateRequest)(nil), "go.micro.auth.GenerateRequest")
|
||||
proto.RegisterType((*GenerateResponse)(nil), "go.micro.auth.GenerateResponse")
|
||||
proto.RegisterType((*ValidateRequest)(nil), "go.micro.auth.ValidateRequest")
|
||||
proto.RegisterType((*ValidateResponse)(nil), "go.micro.auth.ValidateResponse")
|
||||
proto.RegisterType((*VerifyRequest)(nil), "go.micro.auth.VerifyRequest")
|
||||
proto.RegisterType((*VerifyResponse)(nil), "go.micro.auth.VerifyResponse")
|
||||
proto.RegisterType((*RevokeRequest)(nil), "go.micro.auth.RevokeRequest")
|
||||
proto.RegisterType((*RevokeResponse)(nil), "go.micro.auth.RevokeResponse")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("auth/service/proto/auth.proto", fileDescriptor_21300bfacc51fc2a) }
|
||||
|
||||
var fileDescriptor_21300bfacc51fc2a = []byte{
|
||||
// 429 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0x4d, 0x6f, 0xd3, 0x40,
|
||||
0x10, 0xad, 0x3f, 0xe2, 0x98, 0x89, 0xd2, 0x46, 0x03, 0x2a, 0x56, 0x44, 0x21, 0xb2, 0x40, 0x84,
|
||||
0x8b, 0x83, 0xdc, 0x0b, 0x82, 0x0b, 0x15, 0xa0, 0x9e, 0x2a, 0xa4, 0x3d, 0x70, 0x5f, 0xec, 0x11,
|
||||
0xb5, 0xe2, 0x78, 0xcd, 0x7a, 0x1d, 0xe1, 0xdf, 0xc0, 0x6f, 0xe5, 0x3f, 0x20, 0xaf, 0xbd, 0x69,
|
||||
0xea, 0xb4, 0xaa, 0xd4, 0xdb, 0x7c, 0xbc, 0x79, 0xf3, 0xde, 0x68, 0x17, 0xce, 0x78, 0xad, 0xae,
|
||||
0x57, 0x15, 0xc9, 0x6d, 0x96, 0xd0, 0xaa, 0x94, 0x42, 0x89, 0x55, 0x5b, 0x8a, 0x74, 0x88, 0xd3,
|
||||
0x5f, 0x22, 0xda, 0x64, 0x89, 0x14, 0x51, 0x5b, 0x0c, 0xff, 0xda, 0x30, 0xbe, 0x48, 0x12, 0x51,
|
||||
0x17, 0x0a, 0x8f, 0xc1, 0xce, 0xd2, 0xc0, 0x5a, 0x58, 0xcb, 0x27, 0xcc, 0xce, 0x52, 0x7c, 0x06,
|
||||
0x23, 0x25, 0xd6, 0x54, 0x04, 0xb6, 0x2e, 0x75, 0x09, 0x06, 0x30, 0x4e, 0x24, 0x71, 0x45, 0x69,
|
||||
0xe0, 0x2c, 0xac, 0xa5, 0xc3, 0x4c, 0x8a, 0xa7, 0xe0, 0xd1, 0x9f, 0x32, 0x93, 0x4d, 0xe0, 0xea,
|
||||
0x46, 0x9f, 0xe1, 0x3b, 0x18, 0x49, 0x91, 0x53, 0x15, 0x8c, 0x16, 0xce, 0x72, 0x12, 0x3f, 0x8d,
|
||||
0x6e, 0x49, 0x88, 0x98, 0xc8, 0x89, 0x75, 0x08, 0xfc, 0x0c, 0xfe, 0x86, 0x14, 0x4f, 0xb9, 0xe2,
|
||||
0x81, 0xa7, 0xd1, 0xaf, 0x07, 0xe8, 0x5e, 0x6c, 0x74, 0xd5, 0xc3, 0xbe, 0x15, 0x4a, 0x36, 0x6c,
|
||||
0x37, 0x35, 0xff, 0x04, 0xd3, 0x5b, 0x2d, 0x9c, 0x81, 0xb3, 0xa6, 0xa6, 0xb7, 0xd5, 0x86, 0xad,
|
||||
0xaf, 0x2d, 0xcf, 0x6b, 0x32, 0xbe, 0x74, 0xf2, 0xd1, 0xfe, 0x60, 0x85, 0xdf, 0xc1, 0x6d, 0xd5,
|
||||
0x20, 0x82, 0x5b, 0xf0, 0x0d, 0xf5, 0x43, 0x3a, 0xc6, 0x73, 0xf0, 0x25, 0x55, 0xa2, 0x96, 0x49,
|
||||
0x37, 0x38, 0x89, 0x9f, 0x0f, 0x8d, 0xf4, 0x6d, 0xb6, 0x03, 0x86, 0x31, 0xf8, 0xa6, 0x7a, 0x27,
|
||||
0x29, 0x82, 0xab, 0x9a, 0xd2, 0x28, 0xd1, 0x71, 0xf8, 0x05, 0x4e, 0x2e, 0xa9, 0x20, 0xc9, 0x15,
|
||||
0x31, 0xfa, 0x5d, 0x53, 0xa5, 0xf0, 0x3d, 0x8c, 0x79, 0xe7, 0x5b, 0x4f, 0x4f, 0xe2, 0xd3, 0xbb,
|
||||
0xaf, 0xc2, 0x0c, 0x2c, 0xfc, 0x0a, 0xb3, 0x1b, 0x92, 0xaa, 0x14, 0x45, 0x45, 0x8f, 0x60, 0x79,
|
||||
0x0b, 0x27, 0x3f, 0x78, 0x9e, 0xa5, 0x7b, 0x52, 0x76, 0x8f, 0xc2, 0xda, 0x7b, 0x14, 0xed, 0xba,
|
||||
0x1b, 0xe0, 0xa3, 0xd7, 0xbd, 0x81, 0x29, 0xa3, 0xad, 0x58, 0x3f, 0xb0, 0x6c, 0x06, 0xc7, 0x06,
|
||||
0xd6, 0xad, 0x8a, 0xff, 0x59, 0xe0, 0x5e, 0xd4, 0xea, 0x1a, 0xaf, 0xc0, 0x37, 0xb6, 0xf1, 0xe5,
|
||||
0x60, 0xdd, 0xe0, 0xa8, 0xf3, 0x57, 0xf7, 0xf6, 0x3b, 0xd6, 0xf0, 0xa8, 0xa5, 0x33, 0xb6, 0x0e,
|
||||
0xe8, 0x06, 0x87, 0x39, 0xa0, 0x1b, 0xde, 0x23, 0x3c, 0xc2, 0x4b, 0xf0, 0x3a, 0xe1, 0xf8, 0xe2,
|
||||
0xe0, 0xe9, 0xec, 0xd9, 0x9e, 0x9f, 0xdd, 0xd3, 0x35, 0x44, 0x3f, 0x3d, 0xfd, 0x97, 0xcf, 0xff,
|
||||
0x07, 0x00, 0x00, 0xff, 0xff, 0x79, 0x35, 0xb2, 0x7e, 0xec, 0x03, 0x00, 0x00,
|
||||
func init() {
|
||||
proto.RegisterFile("micro/go-micro/auth/service/proto/auth.proto", fileDescriptor_de609d4872dacc78)
|
||||
}
|
||||
|
||||
var fileDescriptor_de609d4872dacc78 = []byte{
|
||||
// 432 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x53, 0x4b, 0x6f, 0xd3, 0x40,
|
||||
0x10, 0xae, 0x1d, 0xe7, 0xc1, 0x44, 0x09, 0xd1, 0x80, 0x8a, 0x15, 0xf1, 0x88, 0x56, 0x20, 0x05,
|
||||
0x09, 0x1c, 0xe4, 0x5e, 0x10, 0x5c, 0x28, 0x0f, 0xf5, 0x54, 0x21, 0xed, 0x81, 0xfb, 0xe2, 0x0c,
|
||||
0xad, 0x95, 0xc4, 0x6b, 0xd6, 0xeb, 0x08, 0xff, 0x06, 0x7e, 0x28, 0x7f, 0x03, 0x79, 0xd7, 0x1b,
|
||||
0x6a, 0xb7, 0xe5, 0x00, 0xb7, 0x79, 0x7c, 0xf3, 0xcd, 0xf7, 0x8d, 0x76, 0xe1, 0xc5, 0x2e, 0x4d,
|
||||
0x94, 0x5c, 0x5d, 0xc8, 0x97, 0x36, 0x10, 0xa5, 0xbe, 0x5c, 0x15, 0xa4, 0xf6, 0x69, 0x42, 0xab,
|
||||
0x5c, 0x49, 0x6d, 0x4b, 0x91, 0x09, 0x71, 0x72, 0x21, 0x23, 0x83, 0x8b, 0xea, 0x22, 0xfb, 0xe9,
|
||||
0xc3, 0xf0, 0x34, 0x49, 0x64, 0x99, 0x69, 0x9c, 0x82, 0x9f, 0xae, 0x43, 0x6f, 0xe1, 0x2d, 0xef,
|
||||
0x70, 0x3f, 0x5d, 0xe3, 0x7d, 0xe8, 0x6b, 0xb9, 0xa1, 0x2c, 0xf4, 0x4d, 0xc9, 0x26, 0x18, 0xc2,
|
||||
0x30, 0x51, 0x24, 0x34, 0xad, 0xc3, 0xde, 0xc2, 0x5b, 0xf6, 0xb8, 0x4b, 0xf1, 0x18, 0x06, 0xf4,
|
||||
0x23, 0x4f, 0x55, 0x15, 0x06, 0xa6, 0xd1, 0x64, 0xf8, 0x1c, 0xfa, 0x4a, 0x6e, 0xa9, 0x08, 0xfb,
|
||||
0x8b, 0xde, 0x72, 0x1c, 0xdf, 0x8b, 0x5a, 0x12, 0x22, 0x2e, 0xb7, 0xc4, 0x2d, 0x02, 0xdf, 0xc1,
|
||||
0x68, 0x47, 0x5a, 0xac, 0x85, 0x16, 0xe1, 0xc0, 0xa0, 0x9f, 0x76, 0xd0, 0x8d, 0xd8, 0xe8, 0xbc,
|
||||
0x81, 0x7d, 0xca, 0xb4, 0xaa, 0xf8, 0x61, 0x6a, 0xfe, 0x16, 0x26, 0xad, 0x16, 0xce, 0xa0, 0xb7,
|
||||
0xa1, 0xaa, 0xb1, 0x55, 0x87, 0xb5, 0xaf, 0xbd, 0xd8, 0x96, 0xe4, 0x7c, 0x99, 0xe4, 0x8d, 0xff,
|
||||
0xda, 0x63, 0x9f, 0x21, 0xa8, 0xd5, 0x20, 0x42, 0x90, 0x89, 0x1d, 0x35, 0x43, 0x26, 0xc6, 0x13,
|
||||
0x18, 0x29, 0x2a, 0x64, 0xa9, 0x12, 0x3b, 0x38, 0x8e, 0x1f, 0x74, 0x8d, 0x34, 0x6d, 0x7e, 0x00,
|
||||
0xb2, 0x18, 0x46, 0xae, 0x7a, 0x23, 0x29, 0x42, 0xa0, 0xab, 0xdc, 0x29, 0x31, 0x31, 0xfb, 0x00,
|
||||
0x77, 0xcf, 0x28, 0x23, 0x25, 0x34, 0x71, 0xfa, 0x5e, 0x52, 0xa1, 0xf1, 0x15, 0x0c, 0x85, 0xf5,
|
||||
0x6d, 0xa6, 0xc7, 0xf1, 0xf1, 0xcd, 0x57, 0xe1, 0x0e, 0xc6, 0x3e, 0xc2, 0xec, 0x0f, 0x49, 0x91,
|
||||
0xcb, 0xac, 0xa0, 0x7f, 0x60, 0x79, 0x06, 0x93, 0x2f, 0xa4, 0xd2, 0x6f, 0x95, 0x13, 0x72, 0x78,
|
||||
0x12, 0xde, 0x95, 0x27, 0xc1, 0xde, 0xc3, 0xd4, 0xc1, 0xfe, 0x67, 0x15, 0xa7, 0xbd, 0xdc, 0xd0,
|
||||
0xdf, 0x57, 0xcd, 0x60, 0xea, 0x60, 0x76, 0x55, 0xfc, 0xcb, 0x83, 0xe0, 0xb4, 0xd4, 0x97, 0x78,
|
||||
0x0e, 0x23, 0x67, 0x19, 0x1f, 0x77, 0xd6, 0x75, 0x0e, 0x3a, 0x7f, 0x72, 0x6b, 0xdf, 0xb2, 0xb2,
|
||||
0x23, 0x3c, 0x83, 0x81, 0x35, 0x85, 0x0f, 0x3b, 0xe0, 0xd6, 0x49, 0xe6, 0x8f, 0x6e, 0xe9, 0x5e,
|
||||
0x25, 0xb2, 0x92, 0xaf, 0x11, 0xb5, 0x0c, 0x5f, 0x23, 0x6a, 0xfb, 0x64, 0x47, 0x5f, 0x07, 0xe6,
|
||||
0x07, 0x9f, 0xfc, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x34, 0xce, 0x17, 0xf1, 0x03, 0x00, 0x00,
|
||||
}
|
||||
|
@@ -1,16 +1,16 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: auth/service/proto/auth.proto
|
||||
// source: micro/go-micro/auth/service/proto/auth.proto
|
||||
|
||||
package go_micro_auth
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
math "math"
|
||||
|
||||
context "context"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
math "math"
|
||||
)
|
||||
|
||||
import (
|
||||
context "context"
|
||||
client "github.com/micro/go-micro/v2/client"
|
||||
server "github.com/micro/go-micro/v2/server"
|
||||
)
|
||||
@@ -35,7 +35,7 @@ var _ server.Option
|
||||
|
||||
type AuthService interface {
|
||||
Generate(ctx context.Context, in *GenerateRequest, opts ...client.CallOption) (*GenerateResponse, error)
|
||||
Validate(ctx context.Context, in *ValidateRequest, opts ...client.CallOption) (*ValidateResponse, error)
|
||||
Verify(ctx context.Context, in *VerifyRequest, opts ...client.CallOption) (*VerifyResponse, error)
|
||||
Revoke(ctx context.Context, in *RevokeRequest, opts ...client.CallOption) (*RevokeResponse, error)
|
||||
}
|
||||
|
||||
@@ -45,12 +45,6 @@ type authService struct {
|
||||
}
|
||||
|
||||
func NewAuthService(name string, c client.Client) AuthService {
|
||||
if c == nil {
|
||||
c = client.NewClient()
|
||||
}
|
||||
if len(name) == 0 {
|
||||
name = "go.micro.auth"
|
||||
}
|
||||
return &authService{
|
||||
c: c,
|
||||
name: name,
|
||||
@@ -67,9 +61,9 @@ func (c *authService) Generate(ctx context.Context, in *GenerateRequest, opts ..
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *authService) Validate(ctx context.Context, in *ValidateRequest, opts ...client.CallOption) (*ValidateResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Auth.Validate", in)
|
||||
out := new(ValidateResponse)
|
||||
func (c *authService) Verify(ctx context.Context, in *VerifyRequest, opts ...client.CallOption) (*VerifyResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Auth.Verify", in)
|
||||
out := new(VerifyResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -91,14 +85,14 @@ func (c *authService) Revoke(ctx context.Context, in *RevokeRequest, opts ...cli
|
||||
|
||||
type AuthHandler interface {
|
||||
Generate(context.Context, *GenerateRequest, *GenerateResponse) error
|
||||
Validate(context.Context, *ValidateRequest, *ValidateResponse) error
|
||||
Verify(context.Context, *VerifyRequest, *VerifyResponse) error
|
||||
Revoke(context.Context, *RevokeRequest, *RevokeResponse) error
|
||||
}
|
||||
|
||||
func RegisterAuthHandler(s server.Server, hdlr AuthHandler, opts ...server.HandlerOption) error {
|
||||
type auth interface {
|
||||
Generate(ctx context.Context, in *GenerateRequest, out *GenerateResponse) error
|
||||
Validate(ctx context.Context, in *ValidateRequest, out *ValidateResponse) error
|
||||
Verify(ctx context.Context, in *VerifyRequest, out *VerifyResponse) error
|
||||
Revoke(ctx context.Context, in *RevokeRequest, out *RevokeResponse) error
|
||||
}
|
||||
type Auth struct {
|
||||
@@ -116,8 +110,8 @@ func (h *authHandler) Generate(ctx context.Context, in *GenerateRequest, out *Ge
|
||||
return h.AuthHandler.Generate(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *authHandler) Validate(ctx context.Context, in *ValidateRequest, out *ValidateResponse) error {
|
||||
return h.AuthHandler.Validate(ctx, in, out)
|
||||
func (h *authHandler) Verify(ctx context.Context, in *VerifyRequest, out *VerifyResponse) error {
|
||||
return h.AuthHandler.Verify(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *authHandler) Revoke(ctx context.Context, in *RevokeRequest, out *RevokeResponse) error {
|
||||
|
@@ -4,47 +4,47 @@ package go.micro.auth;
|
||||
|
||||
service Auth {
|
||||
rpc Generate(GenerateRequest) returns (GenerateResponse) {};
|
||||
rpc Validate(ValidateRequest) returns (ValidateResponse) {};
|
||||
rpc Verify(VerifyRequest) returns (VerifyResponse) {};
|
||||
rpc Revoke(RevokeRequest) returns (RevokeResponse) {};
|
||||
}
|
||||
|
||||
message Account{
|
||||
string id = 1;
|
||||
string token = 2;
|
||||
int64 created = 3;
|
||||
int64 expiry = 4;
|
||||
repeated Role roles = 5;
|
||||
string id = 1;
|
||||
string token = 2;
|
||||
int64 created = 3;
|
||||
int64 expiry = 4;
|
||||
repeated Role roles = 5;
|
||||
map<string, string> metadata = 6;
|
||||
}
|
||||
|
||||
message Role {
|
||||
string name = 1;
|
||||
Resource resource = 2;
|
||||
string name = 1;
|
||||
Resource resource = 2;
|
||||
}
|
||||
|
||||
message Resource{
|
||||
string name = 1;
|
||||
string type = 2;
|
||||
string name = 1;
|
||||
string type = 2;
|
||||
}
|
||||
|
||||
message GenerateRequest {
|
||||
Account account = 1;
|
||||
Account account = 1;
|
||||
}
|
||||
|
||||
message GenerateResponse {
|
||||
Account account = 1;
|
||||
Account account = 1;
|
||||
}
|
||||
|
||||
message ValidateRequest {
|
||||
string token = 1;
|
||||
message VerifyRequest {
|
||||
string token = 1;
|
||||
}
|
||||
|
||||
message ValidateResponse {
|
||||
Account account = 1;
|
||||
message VerifyResponse {
|
||||
Account account = 1;
|
||||
}
|
||||
|
||||
message RevokeRequest {
|
||||
string token = 1;
|
||||
string token = 1;
|
||||
}
|
||||
|
||||
message RevokeResponse {}
|
||||
|
@@ -72,9 +72,9 @@ func (s *svc) Revoke(token string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate an account token
|
||||
func (s *svc) Validate(token string) (*auth.Account, error) {
|
||||
resp, err := s.auth.Validate(context.Background(), &pb.ValidateRequest{Token: token})
|
||||
// Verify an account token
|
||||
func (s *svc) Verify(token string) (*auth.Account, error) {
|
||||
resp, err := s.auth.Verify(context.Background(), &pb.VerifyRequest{Token: token})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -7,14 +7,19 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
|
||||
"github.com/micro/go-micro/v2/errors"
|
||||
"github.com/micro/go-micro/v2/store"
|
||||
)
|
||||
|
||||
type Auth struct {
|
||||
store store.Store
|
||||
opts auth.Options
|
||||
}
|
||||
|
||||
// NewAuth returns an instance of store auth
|
||||
func NewAuth(opts ...auth.Option) auth.Auth {
|
||||
options := auth.Options{}
|
||||
var options auth.Options
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
@@ -25,11 +30,6 @@ func NewAuth(opts ...auth.Option) auth.Auth {
|
||||
}
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
store store.Store
|
||||
opts auth.Options
|
||||
}
|
||||
|
||||
// Init the auth package
|
||||
func (a *Auth) Init(opts ...auth.Option) error {
|
||||
for _, o := range opts {
|
||||
@@ -64,6 +64,7 @@ func (a *Auth) Generate(id string, opts ...auth.GenerateOption) (*auth.Account,
|
||||
}
|
||||
|
||||
// encode the data to bytes
|
||||
// TODO: replace with json
|
||||
buf := &bytes.Buffer{}
|
||||
e := gob.NewEncoder(buf)
|
||||
if err := e.Encode(sa); err != nil {
|
||||
@@ -102,8 +103,8 @@ func (a *Auth) Revoke(token string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate an account token
|
||||
func (a *Auth) Validate(token string) (*auth.Account, error) {
|
||||
// Verify an account token
|
||||
func (a *Auth) Verify(token string) (*auth.Account, error) {
|
||||
// lookup the record by token
|
||||
records, err := a.store.Read(token, store.ReadSuffix())
|
||||
if err == store.ErrNotFound || len(records) == 0 {
|
||||
@@ -113,6 +114,7 @@ func (a *Auth) Validate(token string) (*auth.Account, error) {
|
||||
}
|
||||
|
||||
// decode the result
|
||||
// TODO: replace with json
|
||||
b := bytes.NewBuffer(records[0].Value)
|
||||
decoder := gob.NewDecoder(b)
|
||||
var sa auth.Account
|
||||
|
@@ -28,6 +28,7 @@ type Event interface {
|
||||
Topic() string
|
||||
Message() *Message
|
||||
Ack() error
|
||||
Error() error
|
||||
}
|
||||
|
||||
// Subscriber is a convenience return type for the Subscribe method
|
||||
|
@@ -11,7 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/codec/json"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/util/addr"
|
||||
"github.com/nats-io/nats-server/v2/server"
|
||||
@@ -53,8 +53,9 @@ type subscriber struct {
|
||||
}
|
||||
|
||||
type publication struct {
|
||||
t string
|
||||
m *Message
|
||||
t string
|
||||
err error
|
||||
m *Message
|
||||
}
|
||||
|
||||
func (p *publication) Topic() string {
|
||||
@@ -70,6 +71,10 @@ func (p *publication) Ack() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *publication) Error() error {
|
||||
return p.err
|
||||
}
|
||||
|
||||
func (s *subscriber) Options() SubscribeOptions {
|
||||
return s.opts
|
||||
}
|
||||
@@ -167,7 +172,9 @@ func (n *natsBroker) serve(exit chan bool) error {
|
||||
for _, node := range service.Nodes {
|
||||
u, err := url.Parse("nats://" + node.Address)
|
||||
if err != nil {
|
||||
log.Info(err)
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Info(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// append to the cluster routes
|
||||
@@ -242,7 +249,9 @@ func (n *natsBroker) serve(exit chan bool) error {
|
||||
select {
|
||||
case err := <-n.closeCh:
|
||||
if err != nil {
|
||||
log.Info(err)
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Info(err)
|
||||
}
|
||||
}
|
||||
case <-exit:
|
||||
// deregister on exit
|
||||
@@ -390,10 +399,30 @@ func (n *natsBroker) Subscribe(topic string, handler Handler, opts ...SubscribeO
|
||||
|
||||
fn := func(msg *nats.Msg) {
|
||||
var m Message
|
||||
if err := n.opts.Codec.Unmarshal(msg.Data, &m); err != nil {
|
||||
pub := &publication{t: msg.Subject}
|
||||
eh := n.opts.ErrorHandler
|
||||
err := n.opts.Codec.Unmarshal(msg.Data, &m)
|
||||
pub.err = err
|
||||
pub.m = &m
|
||||
if err != nil {
|
||||
m.Body = msg.Data
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(err)
|
||||
}
|
||||
if eh != nil {
|
||||
eh(pub)
|
||||
}
|
||||
return
|
||||
}
|
||||
handler(&publication{m: &m, t: msg.Subject})
|
||||
if err := handler(pub); err != nil {
|
||||
pub.err = err
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(err)
|
||||
}
|
||||
if eh != nil {
|
||||
eh(pub)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sub *nats.Subscription
|
||||
|
@@ -2,6 +2,7 @@
|
||||
package memory
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"sync"
|
||||
@@ -9,6 +10,7 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
maddr "github.com/micro/go-micro/v2/util/addr"
|
||||
mnet "github.com/micro/go-micro/v2/util/net"
|
||||
)
|
||||
@@ -23,8 +25,10 @@ type memoryBroker struct {
|
||||
}
|
||||
|
||||
type memoryEvent struct {
|
||||
opts broker.Options
|
||||
topic string
|
||||
message *broker.Message
|
||||
err error
|
||||
message interface{}
|
||||
}
|
||||
|
||||
type memorySubscriber struct {
|
||||
@@ -85,7 +89,7 @@ func (m *memoryBroker) Init(opts ...broker.Option) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memoryBroker) Publish(topic string, message *broker.Message, opts ...broker.PublishOption) error {
|
||||
func (m *memoryBroker) Publish(topic string, msg *broker.Message, opts ...broker.PublishOption) error {
|
||||
m.RLock()
|
||||
if !m.connected {
|
||||
m.RUnlock()
|
||||
@@ -98,13 +102,30 @@ func (m *memoryBroker) Publish(topic string, message *broker.Message, opts ...br
|
||||
return nil
|
||||
}
|
||||
|
||||
var v interface{}
|
||||
if m.opts.Codec != nil {
|
||||
buf, err := m.opts.Codec.Marshal(msg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
v = buf
|
||||
} else {
|
||||
v = msg
|
||||
}
|
||||
|
||||
p := &memoryEvent{
|
||||
topic: topic,
|
||||
message: message,
|
||||
message: v,
|
||||
opts: m.opts,
|
||||
}
|
||||
|
||||
for _, sub := range subs {
|
||||
if err := sub.handler(p); err != nil {
|
||||
p.err = err
|
||||
if eh := m.opts.ErrorHandler; eh != nil {
|
||||
eh(p)
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -163,13 +184,31 @@ func (m *memoryEvent) Topic() string {
|
||||
}
|
||||
|
||||
func (m *memoryEvent) Message() *broker.Message {
|
||||
return m.message
|
||||
switch v := m.message.(type) {
|
||||
case *broker.Message:
|
||||
return v
|
||||
case []byte:
|
||||
msg := &broker.Message{}
|
||||
if err := m.opts.Codec.Unmarshal(v, msg); err != nil {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("[memory]: failed to unmarshal: %v\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memoryEvent) Ack() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *memoryEvent) Error() error {
|
||||
return m.err
|
||||
}
|
||||
|
||||
func (m *memorySubscriber) Options() broker.SubscribeOptions {
|
||||
return m.opts
|
||||
}
|
||||
@@ -184,7 +223,10 @@ func (m *memorySubscriber) Unsubscribe() error {
|
||||
}
|
||||
|
||||
func NewBroker(opts ...broker.Option) broker.Broker {
|
||||
var options broker.Options
|
||||
options := broker.Options{
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
|
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/codec/json"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/util/addr"
|
||||
"github.com/nats-io/nats-server/v2/server"
|
||||
@@ -50,8 +50,9 @@ type subscriber struct {
|
||||
}
|
||||
|
||||
type publication struct {
|
||||
t string
|
||||
m *broker.Message
|
||||
t string
|
||||
err error
|
||||
m *broker.Message
|
||||
}
|
||||
|
||||
func (p *publication) Topic() string {
|
||||
@@ -67,6 +68,10 @@ func (p *publication) Ack() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *publication) Error() error {
|
||||
return p.err
|
||||
}
|
||||
|
||||
func (s *subscriber) Options() broker.SubscribeOptions {
|
||||
return s.opts
|
||||
}
|
||||
@@ -164,7 +169,9 @@ func (n *natsBroker) serve(exit chan bool) error {
|
||||
for _, node := range service.Nodes {
|
||||
u, err := url.Parse("nats://" + node.Address)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// append to the cluster routes
|
||||
@@ -375,10 +382,30 @@ func (n *natsBroker) Subscribe(topic string, handler broker.Handler, opts ...bro
|
||||
|
||||
fn := func(msg *nats.Msg) {
|
||||
var m broker.Message
|
||||
if err := n.opts.Codec.Unmarshal(msg.Data, &m); err != nil {
|
||||
pub := &publication{t: msg.Subject}
|
||||
eh := n.opts.ErrorHandler
|
||||
err := n.opts.Codec.Unmarshal(msg.Data, &m)
|
||||
pub.err = err
|
||||
pub.m = &m
|
||||
if err != nil {
|
||||
m.Body = msg.Data
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(err)
|
||||
}
|
||||
if eh != nil {
|
||||
eh(pub)
|
||||
}
|
||||
return
|
||||
}
|
||||
handler(&publication{m: &m, t: msg.Subject})
|
||||
if err := handler(pub); err != nil {
|
||||
pub.err = err
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(err)
|
||||
}
|
||||
if eh != nil {
|
||||
eh(pub)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sub *nats.Subscription
|
||||
|
@@ -9,9 +9,14 @@ import (
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
Addrs []string
|
||||
Secure bool
|
||||
Codec codec.Marshaler
|
||||
Addrs []string
|
||||
Secure bool
|
||||
Codec codec.Marshaler
|
||||
|
||||
// Handler executed when error happens in broker mesage
|
||||
// processing
|
||||
ErrorHandler Handler
|
||||
|
||||
TLSConfig *tls.Config
|
||||
// Registry used for clustering
|
||||
Registry registry.Registry
|
||||
@@ -81,6 +86,14 @@ func DisableAutoAck() SubscribeOption {
|
||||
}
|
||||
}
|
||||
|
||||
// ErrorHandler will catch all broker errors that cant be handled
|
||||
// in normal way, for example Codec errors
|
||||
func ErrorHandler(h Handler) Option {
|
||||
return func(o *Options) {
|
||||
o.ErrorHandler = h
|
||||
}
|
||||
}
|
||||
|
||||
// Queue sets the name of the queue to share messages on
|
||||
func Queue(name string) SubscribeOption {
|
||||
return func(o *SubscribeOptions) {
|
||||
|
@@ -8,7 +8,7 @@ import (
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
pb "github.com/micro/go-micro/v2/broker/service/proto"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
type serviceBroker struct {
|
||||
@@ -45,7 +45,9 @@ func (b *serviceBroker) Options() broker.Options {
|
||||
}
|
||||
|
||||
func (b *serviceBroker) Publish(topic string, msg *broker.Message, opts ...broker.PublishOption) error {
|
||||
log.Debugf("Publishing to topic %s broker %v", topic, b.Addrs)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Publishing to topic %s broker %v", topic, b.Addrs)
|
||||
}
|
||||
_, err := b.Client.Publish(context.TODO(), &pb.PublishRequest{
|
||||
Topic: topic,
|
||||
Message: &pb.Message{
|
||||
@@ -61,7 +63,9 @@ func (b *serviceBroker) Subscribe(topic string, handler broker.Handler, opts ...
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
log.Debugf("Subscribing to topic %s queue %s broker %v", topic, options.Queue, b.Addrs)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Subscribing to topic %s queue %s broker %v", topic, options.Queue, b.Addrs)
|
||||
}
|
||||
stream, err := b.Client.Subscribe(context.TODO(), &pb.SubscribeRequest{
|
||||
Topic: topic,
|
||||
Queue: options.Queue,
|
||||
@@ -83,19 +87,27 @@ func (b *serviceBroker) Subscribe(topic string, handler broker.Handler, opts ...
|
||||
for {
|
||||
select {
|
||||
case <-sub.closed:
|
||||
log.Debugf("Unsubscribed from topic %s", topic)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Unsubscribed from topic %s", topic)
|
||||
}
|
||||
return
|
||||
default:
|
||||
// run the subscriber
|
||||
log.Debugf("Streaming from broker %v to topic [%s] queue [%s]", b.Addrs, topic, options.Queue)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
// run the subscriber
|
||||
logger.Debugf("Streaming from broker %v to topic [%s] queue [%s]", b.Addrs, topic, options.Queue)
|
||||
}
|
||||
if err := sub.run(); err != nil {
|
||||
log.Debugf("Resubscribing to topic %s broker %v", topic, b.Addrs)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Resubscribing to topic %s broker %v", topic, b.Addrs)
|
||||
}
|
||||
stream, err := b.Client.Subscribe(context.TODO(), &pb.SubscribeRequest{
|
||||
Topic: topic,
|
||||
Queue: options.Queue,
|
||||
}, client.WithAddress(b.Addrs...), client.WithRequestTimeout(time.Hour))
|
||||
if err != nil {
|
||||
log.Debugf("Failed to resubscribe to topic %s: %v", topic, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Failed to resubscribe to topic %s: %v", topic, err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ package service
|
||||
import (
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
pb "github.com/micro/go-micro/v2/broker/service/proto"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
type serviceSub struct {
|
||||
@@ -17,6 +17,7 @@ type serviceSub struct {
|
||||
|
||||
type serviceEvent struct {
|
||||
topic string
|
||||
err error
|
||||
message *broker.Message
|
||||
}
|
||||
|
||||
@@ -32,6 +33,10 @@ func (s *serviceEvent) Ack() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *serviceEvent) Error() error {
|
||||
return s.err
|
||||
}
|
||||
|
||||
func (s *serviceSub) isClosed() bool {
|
||||
select {
|
||||
case <-s.closed:
|
||||
@@ -57,7 +62,9 @@ func (s *serviceSub) run() error {
|
||||
// TODO: do not fail silently
|
||||
msg, err := s.stream.Recv()
|
||||
if err != nil {
|
||||
log.Debugf("Streaming error for subcription to topic %s: %v", s.Topic(), err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Streaming error for subcription to topic %s: %v", s.Topic(), err)
|
||||
}
|
||||
|
||||
// close the exit channel
|
||||
close(exit)
|
||||
@@ -71,14 +78,14 @@ func (s *serviceSub) run() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: handle error
|
||||
s.handler(&serviceEvent{
|
||||
p := &serviceEvent{
|
||||
topic: s.topic,
|
||||
message: &broker.Message{
|
||||
Header: msg.Header,
|
||||
Body: msg.Body,
|
||||
},
|
||||
})
|
||||
}
|
||||
p.err = s.handler(p)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -117,7 +117,9 @@ func (jsonCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
|
||||
return []byte(s), err
|
||||
}
|
||||
|
||||
if b, ok := v.(*bytes.Frame); ok {
|
||||
return b.Data, nil
|
||||
}
|
||||
return json.Marshal(v)
|
||||
}
|
||||
|
||||
@@ -125,6 +127,10 @@ 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 jsonpb.Unmarshal(b.NewReader(data), pb)
|
||||
}
|
||||
|
@@ -17,18 +17,21 @@ func microError(err error) error {
|
||||
}
|
||||
|
||||
// grpc error
|
||||
if s, ok := status.FromError(err); ok {
|
||||
details := s.Details()
|
||||
if len(details) == 0 {
|
||||
if e := errors.Parse(s.Message()); e.Code > 0 {
|
||||
return e // actually a micro error
|
||||
}
|
||||
return errors.InternalServerError("go.micro.client", s.Message())
|
||||
}
|
||||
// return first error from details
|
||||
return details[0].(error)
|
||||
s, ok := status.FromError(err)
|
||||
if !ok {
|
||||
return err
|
||||
}
|
||||
|
||||
// do nothing
|
||||
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.InternalServerError("go.micro.client", s.Message())
|
||||
}
|
||||
|
@@ -26,6 +26,10 @@ import (
|
||||
gmetadata "google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
var (
|
||||
BearerScheme = "Bearer "
|
||||
)
|
||||
|
||||
type grpcClient struct {
|
||||
opts client.Options
|
||||
pool *pool
|
||||
@@ -119,7 +123,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
|
||||
if md, ok := metadata.FromContext(ctx); ok {
|
||||
header = make(map[string]string, len(md))
|
||||
for k, v := range md {
|
||||
header[k] = v
|
||||
header[strings.ToLower(k)] = v
|
||||
}
|
||||
} else {
|
||||
header = make(map[string]string)
|
||||
@@ -129,9 +133,12 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
|
||||
header["timeout"] = fmt.Sprintf("%d", opts.RequestTimeout)
|
||||
// set the content type for the request
|
||||
header["x-content-type"] = req.ContentType()
|
||||
|
||||
// set the authorization token if one is saved locally
|
||||
if token, err := config.Get("token"); err == nil && len(token) > 0 {
|
||||
header["authorization"] = fmt.Sprintf("Bearer %v", token)
|
||||
if len(header["authorization"]) == 0 {
|
||||
if token, err := config.Get("token"); err == nil && len(token) > 0 {
|
||||
header["authorization"] = BearerScheme + token
|
||||
}
|
||||
}
|
||||
|
||||
md := gmetadata.New(header)
|
||||
@@ -388,6 +395,11 @@ func (g *grpcClient) NewRequest(service, method string, req interface{}, 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 {
|
||||
@@ -454,6 +466,10 @@ func (g *grpcClient) Call(ctx context.Context, req client.Request, rsp interface
|
||||
// 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
|
||||
}
|
||||
|
||||
|
@@ -8,11 +8,17 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
"github.com/micro/go-micro/v2/auth/provider"
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/client/selector"
|
||||
"github.com/micro/go-micro/v2/config"
|
||||
configSrv "github.com/micro/go-micro/v2/config/source/service"
|
||||
"github.com/micro/go-micro/v2/debug/profile"
|
||||
"github.com/micro/go-micro/v2/debug/profile/http"
|
||||
"github.com/micro/go-micro/v2/debug/profile/pprof"
|
||||
"github.com/micro/go-micro/v2/debug/trace"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/runtime"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
@@ -25,6 +31,7 @@ import (
|
||||
|
||||
// servers
|
||||
"github.com/micro/cli/v2"
|
||||
|
||||
sgrpc "github.com/micro/go-micro/v2/server/grpc"
|
||||
smucp "github.com/micro/go-micro/v2/server/mucp"
|
||||
|
||||
@@ -66,6 +73,10 @@ import (
|
||||
jwtAuth "github.com/micro/go-micro/v2/auth/jwt"
|
||||
sAuth "github.com/micro/go-micro/v2/auth/service"
|
||||
storeAuth "github.com/micro/go-micro/v2/auth/store"
|
||||
|
||||
// auth providers
|
||||
"github.com/micro/go-micro/v2/auth/provider/basic"
|
||||
"github.com/micro/go-micro/v2/auth/provider/oauth"
|
||||
)
|
||||
|
||||
type Cmd interface {
|
||||
@@ -245,6 +256,11 @@ var (
|
||||
EnvVars: []string{"MICRO_AUTH"},
|
||||
Usage: "Auth for role based access control, e.g. service",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_token",
|
||||
EnvVars: []string{"MICRO_AUTH_TOKEN"},
|
||||
Usage: "Auth token used for client authentication",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_public_key",
|
||||
EnvVars: []string{"MICRO_AUTH_PUBLIC_KEY"},
|
||||
@@ -260,6 +276,41 @@ var (
|
||||
EnvVars: []string{"MICRO_AUTH_EXCLUDE"},
|
||||
Usage: "Comma-separated list of endpoints excluded from authentication, e.g. Users.ListUsers",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_provider",
|
||||
EnvVars: []string{"MICRO_AUTH_PROVIDER"},
|
||||
Usage: "Auth provider used to login user",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_provider_client_id",
|
||||
EnvVars: []string{"MICRO_AUTH_PROVIDER_CLIENT_ID"},
|
||||
Usage: "The client id to be used for oauth",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_provider_client_secret",
|
||||
EnvVars: []string{"MICRO_AUTH_PROVIDER_CLIENT_SECRET"},
|
||||
Usage: "The client secret to be used for oauth",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_provider_endpoint",
|
||||
EnvVars: []string{"MICRO_AUTH_PROVIDER_ENDPOINT"},
|
||||
Usage: "The enpoint to be used for oauth",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_provider_redirect",
|
||||
EnvVars: []string{"MICRO_AUTH_PROVIDER_REDIRECT"},
|
||||
Usage: "The redirect to be used for oauth",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_provider_scope",
|
||||
EnvVars: []string{"MICRO_AUTH_PROVIDER_SCOPE"},
|
||||
Usage: "The scope to be used for oauth",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "config",
|
||||
EnvVars: []string{"MICRO_CONFIG"},
|
||||
Usage: "The source of the config to be used to get configuration",
|
||||
},
|
||||
}
|
||||
|
||||
DefaultBrokers = map[string]func(...broker.Option) broker.Broker{
|
||||
@@ -318,6 +369,20 @@ var (
|
||||
"store": storeAuth.NewAuth,
|
||||
"jwt": jwtAuth.NewAuth,
|
||||
}
|
||||
|
||||
DefaultAuthProviders = map[string]func(...provider.Option) provider.Provider{
|
||||
"oauth": oauth.NewProvider,
|
||||
"basic": basic.NewProvider,
|
||||
}
|
||||
|
||||
DefaultProfiles = map[string]func(...profile.Option) profile.Profile{
|
||||
"http": http.NewProfile,
|
||||
"pprof": pprof.NewProfile,
|
||||
}
|
||||
|
||||
DefaultConfigs = map[string]func(...config.Option) (config.Config, error){
|
||||
"service": config.NewConfig,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -336,6 +401,8 @@ func newCmd(opts ...Option) Cmd {
|
||||
Runtime: &runtime.DefaultRuntime,
|
||||
Store: &store.DefaultStore,
|
||||
Tracer: &trace.DefaultTracer,
|
||||
Profile: &profile.DefaultProfile,
|
||||
Config: &config.DefaultConfig,
|
||||
|
||||
Brokers: DefaultBrokers,
|
||||
Clients: DefaultClients,
|
||||
@@ -347,6 +414,8 @@ func newCmd(opts ...Option) Cmd {
|
||||
Stores: DefaultStores,
|
||||
Tracers: DefaultTracers,
|
||||
Auths: DefaultAuths,
|
||||
Profiles: DefaultProfiles,
|
||||
Configs: DefaultConfigs,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
@@ -430,6 +499,16 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
*c.opts.Auth = a()
|
||||
}
|
||||
|
||||
// Set the profile
|
||||
if name := ctx.String("profile"); len(name) > 0 {
|
||||
p, ok := c.opts.Profiles[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Unsupported profile: %s", name)
|
||||
}
|
||||
|
||||
*c.opts.Profile = p()
|
||||
}
|
||||
|
||||
// Set the client
|
||||
if name := ctx.String("client"); len(name) > 0 {
|
||||
// only change if we have the client and type differs
|
||||
@@ -470,13 +549,13 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
clientOpts = append(clientOpts, client.Registry(*c.opts.Registry))
|
||||
|
||||
if err := (*c.opts.Selector).Init(selector.Registry(*c.opts.Registry)); err != nil {
|
||||
log.Fatalf("Error configuring registry: %v", err)
|
||||
logger.Fatalf("Error configuring registry: %v", err)
|
||||
}
|
||||
|
||||
clientOpts = append(clientOpts, client.Selector(*c.opts.Selector))
|
||||
|
||||
if err := (*c.opts.Broker).Init(broker.Registry(*c.opts.Registry)); err != nil {
|
||||
log.Fatalf("Error configuring broker: %v", err)
|
||||
logger.Fatalf("Error configuring broker: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -523,31 +602,31 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
|
||||
if len(ctx.String("broker_address")) > 0 {
|
||||
if err := (*c.opts.Broker).Init(broker.Addrs(strings.Split(ctx.String("broker_address"), ",")...)); err != nil {
|
||||
log.Fatalf("Error configuring broker: %v", err)
|
||||
logger.Fatalf("Error configuring broker: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(ctx.String("registry_address")) > 0 {
|
||||
if err := (*c.opts.Registry).Init(registry.Addrs(strings.Split(ctx.String("registry_address"), ",")...)); err != nil {
|
||||
log.Fatalf("Error configuring registry: %v", err)
|
||||
logger.Fatalf("Error configuring registry: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(ctx.String("transport_address")) > 0 {
|
||||
if err := (*c.opts.Transport).Init(transport.Addrs(strings.Split(ctx.String("transport_address"), ",")...)); err != nil {
|
||||
log.Fatalf("Error configuring transport: %v", err)
|
||||
logger.Fatalf("Error configuring transport: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(ctx.String("store_address")) > 0 {
|
||||
if err := (*c.opts.Store).Init(store.Nodes(strings.Split(ctx.String("store_address"), ",")...)); err != nil {
|
||||
log.Fatalf("Error configuring store: %v", err)
|
||||
logger.Fatalf("Error configuring store: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(ctx.String("store_namespace")) > 0 {
|
||||
if err := (*c.opts.Store).Init(store.Namespace(ctx.String("store_address"))); err != nil {
|
||||
log.Fatalf("Error configuring store: %v", err)
|
||||
logger.Fatalf("Error configuring store: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,10 +660,14 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
|
||||
if len(ctx.String("runtime_source")) > 0 {
|
||||
if err := (*c.opts.Runtime).Init(runtime.WithSource(ctx.String("runtime_source"))); err != nil {
|
||||
log.Fatalf("Error configuring runtime: %v", err)
|
||||
logger.Fatalf("Error configuring runtime: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(ctx.String("auth_token")) > 0 {
|
||||
authOpts = append(authOpts, auth.Token(ctx.String("auth_token")))
|
||||
}
|
||||
|
||||
if len(ctx.String("auth_public_key")) > 0 {
|
||||
authOpts = append(authOpts, auth.PublicKey(ctx.String("auth_public_key")))
|
||||
}
|
||||
@@ -594,12 +677,45 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
}
|
||||
|
||||
if len(ctx.StringSlice("auth_exclude")) > 0 {
|
||||
authOpts = append(authOpts, auth.Excludes(ctx.StringSlice("auth_exclude")...))
|
||||
authOpts = append(authOpts, auth.Exclude(ctx.StringSlice("auth_exclude")...))
|
||||
}
|
||||
|
||||
if name := ctx.String("auth_provider"); len(name) > 0 {
|
||||
p, ok := DefaultAuthProviders[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("AuthProvider %s not found", name)
|
||||
}
|
||||
|
||||
var provOpts []provider.Option
|
||||
|
||||
clientID := ctx.String("auth_provider_client_id")
|
||||
clientSecret := ctx.String("auth_provider_client_secret")
|
||||
if len(clientID) > 0 || len(clientSecret) > 0 {
|
||||
provOpts = append(provOpts, provider.Credentials(clientID, clientSecret))
|
||||
}
|
||||
if e := ctx.String("auth_provider_endpoint"); len(e) > 0 {
|
||||
provOpts = append(provOpts, provider.Endpoint(e))
|
||||
}
|
||||
if r := ctx.String("auth_provider_redirect"); len(r) > 0 {
|
||||
provOpts = append(provOpts, provider.Redirect(r))
|
||||
}
|
||||
if s := ctx.String("auth_provider_scope"); len(s) > 0 {
|
||||
provOpts = append(provOpts, provider.Scope(s))
|
||||
}
|
||||
|
||||
authOpts = append(authOpts, auth.Provider(p(provOpts...)))
|
||||
}
|
||||
|
||||
if len(authOpts) > 0 {
|
||||
if err := (*c.opts.Auth).Init(authOpts...); err != nil {
|
||||
log.Fatalf("Error configuring auth: %v", err)
|
||||
logger.Fatalf("Error configuring auth: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if ctx.String("config") == "service" {
|
||||
opt := config.WithSource(configSrv.NewSource())
|
||||
if err := (*c.opts.Config).Init(opt); err != nil {
|
||||
logger.Fatalf("Error configuring config: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -632,14 +748,14 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
// Lets set it up
|
||||
if len(serverOpts) > 0 {
|
||||
if err := (*c.opts.Server).Init(serverOpts...); err != nil {
|
||||
log.Fatalf("Error configuring server: %v", err)
|
||||
logger.Fatalf("Error configuring server: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Use an init option?
|
||||
if len(clientOpts) > 0 {
|
||||
if err := (*c.opts.Client).Init(clientOpts...); err != nil {
|
||||
log.Fatalf("Error configuring client: %v", err)
|
||||
logger.Fatalf("Error configuring client: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -7,6 +7,8 @@ import (
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/client/selector"
|
||||
"github.com/micro/go-micro/v2/config"
|
||||
"github.com/micro/go-micro/v2/debug/profile"
|
||||
"github.com/micro/go-micro/v2/debug/trace"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/runtime"
|
||||
@@ -26,14 +28,17 @@ type Options struct {
|
||||
Registry *registry.Registry
|
||||
Selector *selector.Selector
|
||||
Transport *transport.Transport
|
||||
Config *config.Config
|
||||
Client *client.Client
|
||||
Server *server.Server
|
||||
Runtime *runtime.Runtime
|
||||
Store *store.Store
|
||||
Tracer *trace.Tracer
|
||||
Auth *auth.Auth
|
||||
Profile *profile.Profile
|
||||
|
||||
Brokers map[string]func(...broker.Option) broker.Broker
|
||||
Configs map[string]func(...config.Option) (config.Config, error)
|
||||
Clients map[string]func(...client.Option) client.Client
|
||||
Registries map[string]func(...registry.Option) registry.Registry
|
||||
Selectors map[string]func(...selector.Option) selector.Selector
|
||||
@@ -43,6 +48,7 @@ type Options struct {
|
||||
Stores map[string]func(...store.Option) store.Store
|
||||
Tracers map[string]func(...trace.Option) trace.Tracer
|
||||
Auths map[string]func(...auth.Option) auth.Auth
|
||||
Profiles map[string]func(...profile.Option) profile.Profile
|
||||
|
||||
// Other options for implementations of the interface
|
||||
// can be stored in a context
|
||||
@@ -76,6 +82,12 @@ func Broker(b *broker.Broker) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func Config(c *config.Config) Option {
|
||||
return func(o *Options) {
|
||||
o.Config = c
|
||||
}
|
||||
}
|
||||
|
||||
func Selector(s *selector.Selector) Option {
|
||||
return func(o *Options) {
|
||||
o.Selector = s
|
||||
@@ -118,6 +130,12 @@ func Auth(a *auth.Auth) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func Profile(p *profile.Profile) Option {
|
||||
return func(o *Options) {
|
||||
o.Profile = p
|
||||
}
|
||||
}
|
||||
|
||||
// New broker func
|
||||
func NewBroker(name string, b func(...broker.Option) broker.Broker) Option {
|
||||
return func(o *Options) {
|
||||
|
@@ -14,6 +14,8 @@ import (
|
||||
type Config interface {
|
||||
// provide the reader.Values interface
|
||||
reader.Values
|
||||
// Init the config
|
||||
Init(opts ...Option) error
|
||||
// Stop the config loader/watcher
|
||||
Close() error
|
||||
// Load config sources
|
||||
|
@@ -31,38 +31,40 @@ type watcher struct {
|
||||
}
|
||||
|
||||
func newConfig(opts ...Option) (Config, error) {
|
||||
options := Options{
|
||||
var c config
|
||||
|
||||
c.Init(opts...)
|
||||
go c.run()
|
||||
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func (c *config) Init(opts ...Option) error {
|
||||
c.opts = Options{
|
||||
Loader: memory.NewLoader(),
|
||||
Reader: json.NewReader(),
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
o(&c.opts)
|
||||
}
|
||||
|
||||
if err := options.Loader.Load(options.Source...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
snap, err := options.Loader.Snapshot()
|
||||
err := c.opts.Loader.Load(c.opts.Source...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
vals, err := options.Reader.Values(snap.ChangeSet)
|
||||
|
||||
c.snap, err = c.opts.Loader.Snapshot()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
c := &config{
|
||||
exit: make(chan bool),
|
||||
opts: options,
|
||||
snap: snap,
|
||||
vals: vals,
|
||||
c.vals, err = c.opts.Reader.Values(c.snap.ChangeSet)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
go c.run()
|
||||
|
||||
return c, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *config) run() {
|
||||
|
@@ -12,10 +12,6 @@ import (
|
||||
"github.com/micro/go-micro/v2/config/source/file"
|
||||
)
|
||||
|
||||
var (
|
||||
sep = string(os.PathSeparator)
|
||||
)
|
||||
|
||||
func createFileForIssue18(t *testing.T, content string) *os.File {
|
||||
data := []byte(content)
|
||||
path := filepath.Join(os.TempDir(), fmt.Sprintf("file.%d", time.Now().UnixNano()))
|
||||
|
@@ -1,34 +0,0 @@
|
||||
package options
|
||||
|
||||
type defaultOptions struct {
|
||||
opts *Values
|
||||
}
|
||||
|
||||
type stringKey struct{}
|
||||
|
||||
func (d *defaultOptions) Init(opts ...Option) error {
|
||||
if d.opts == nil {
|
||||
d.opts = new(Values)
|
||||
}
|
||||
for _, o := range opts {
|
||||
if err := d.opts.Option(o); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *defaultOptions) Values() *Values {
|
||||
return d.opts
|
||||
}
|
||||
|
||||
func (d *defaultOptions) String() string {
|
||||
if d.opts == nil {
|
||||
d.opts = new(Values)
|
||||
}
|
||||
n, ok := d.opts.Get(stringKey{})
|
||||
if ok {
|
||||
return n.(string)
|
||||
}
|
||||
return "Values"
|
||||
}
|
@@ -1,76 +0,0 @@
|
||||
// Package options provides a way to initialise options
|
||||
package options
|
||||
|
||||
import (
|
||||
"log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Options is used for initialisation
|
||||
type Options interface {
|
||||
// Initialise options
|
||||
Init(...Option) error
|
||||
// Options returns the current options
|
||||
Values() *Values
|
||||
// The name for who these options exist
|
||||
String() string
|
||||
}
|
||||
|
||||
// Values holds the set of option values and protects them
|
||||
type Values struct {
|
||||
sync.RWMutex
|
||||
values map[interface{}]interface{}
|
||||
}
|
||||
|
||||
// Option gives access to options
|
||||
type Option func(o *Values) error
|
||||
|
||||
// Get a value from options
|
||||
func (o *Values) Get(k interface{}) (interface{}, bool) {
|
||||
o.RLock()
|
||||
defer o.RUnlock()
|
||||
v, ok := o.values[k]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// Set a value in the options
|
||||
func (o *Values) Set(k, v interface{}) error {
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
if o.values == nil {
|
||||
o.values = map[interface{}]interface{}{}
|
||||
}
|
||||
o.values[k] = v
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetOption executes an option
|
||||
func (o *Values) Option(op Option) error {
|
||||
return op(o)
|
||||
}
|
||||
|
||||
// WithValue allows you to set any value within the options
|
||||
func WithValue(k, v interface{}) Option {
|
||||
return func(o *Values) error {
|
||||
return o.Set(k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// WithOption gives you the ability to create an option that accesses values
|
||||
func WithOption(o Option) Option {
|
||||
return o
|
||||
}
|
||||
|
||||
// String sets the string
|
||||
func WithString(s string) Option {
|
||||
return WithValue(stringKey{}, s)
|
||||
}
|
||||
|
||||
// NewOptions returns a new initialiser
|
||||
func NewOptions(opts ...Option) Options {
|
||||
o := new(defaultOptions)
|
||||
if err := o.Init(opts...); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return o
|
||||
}
|
89
config/secrets/box/box.go
Normal file
89
config/secrets/box/box.go
Normal file
@@ -0,0 +1,89 @@
|
||||
// Package box is an asymmetric implementation of config/secrets using nacl/box
|
||||
package box
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/v2/config/secrets"
|
||||
"github.com/pkg/errors"
|
||||
naclbox "golang.org/x/crypto/nacl/box"
|
||||
|
||||
"crypto/rand"
|
||||
)
|
||||
|
||||
const keyLength = 32
|
||||
|
||||
type box struct {
|
||||
options secrets.Options
|
||||
|
||||
publicKey [keyLength]byte
|
||||
privateKey [keyLength]byte
|
||||
}
|
||||
|
||||
// NewCodec returns a nacl-box codec
|
||||
func NewCodec(opts ...secrets.Option) secrets.Codec {
|
||||
b := &box{}
|
||||
for _, o := range opts {
|
||||
o(&b.options)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Init initialises a box
|
||||
func (b *box) Init(opts ...secrets.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&b.options)
|
||||
}
|
||||
if len(b.options.PrivateKey) != keyLength || len(b.options.PublicKey) != keyLength {
|
||||
return errors.Errorf("a public key and a private key of length %d must both be provided", keyLength)
|
||||
}
|
||||
copy(b.privateKey[:], b.options.PrivateKey)
|
||||
copy(b.publicKey[:], b.options.PublicKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Options returns options
|
||||
func (b *box) Options() secrets.Options {
|
||||
return b.options
|
||||
}
|
||||
|
||||
// String returns nacl-box
|
||||
func (*box) String() string {
|
||||
return "nacl-box"
|
||||
}
|
||||
|
||||
// Encrypt encrypts a message with the sender's private key and the receipient's public key
|
||||
func (b *box) Encrypt(in []byte, opts ...secrets.EncryptOption) ([]byte, error) {
|
||||
var options secrets.EncryptOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
if len(options.RecipientPublicKey) != keyLength {
|
||||
return []byte{}, errors.New("recepient's public key must be provided")
|
||||
}
|
||||
var recipientPublicKey [keyLength]byte
|
||||
copy(recipientPublicKey[:], options.RecipientPublicKey)
|
||||
var nonce [24]byte
|
||||
if _, err := rand.Reader.Read(nonce[:]); err != nil {
|
||||
return []byte{}, errors.Wrap(err, "couldn't obtain a random nonce from crypto/rand")
|
||||
}
|
||||
return naclbox.Seal(nonce[:], in, &nonce, &recipientPublicKey, &b.privateKey), nil
|
||||
}
|
||||
|
||||
// Decrypt Decrypts a message with the receiver's private key and the sender's public key
|
||||
func (b *box) Decrypt(in []byte, opts ...secrets.DecryptOption) ([]byte, error) {
|
||||
var options secrets.DecryptOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
if len(options.SenderPublicKey) != keyLength {
|
||||
return []byte{}, errors.New("sender's public key bust be provided")
|
||||
}
|
||||
var nonce [24]byte
|
||||
var senderPublicKey [32]byte
|
||||
copy(nonce[:], in[:24])
|
||||
copy(senderPublicKey[:], options.SenderPublicKey)
|
||||
decrypted, ok := naclbox.Open(nil, in[24:], &nonce, &senderPublicKey, &b.privateKey)
|
||||
if !ok {
|
||||
return []byte{}, errors.New("incoming message couldn't be verified / decrypted")
|
||||
}
|
||||
return decrypted, nil
|
||||
}
|
63
config/secrets/box/box_test.go
Normal file
63
config/secrets/box/box_test.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package box
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/v2/config/secrets"
|
||||
naclbox "golang.org/x/crypto/nacl/box"
|
||||
)
|
||||
|
||||
func TestBox(t *testing.T) {
|
||||
alicePublicKey, alicePrivateKey, err := naclbox.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bobPublicKey, bobPrivateKey, err := naclbox.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
alice, bob := NewCodec(secrets.PublicKey(alicePublicKey[:]), secrets.PrivateKey(alicePrivateKey[:])), NewCodec()
|
||||
if err := alice.Init(); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if err := bob.Init(secrets.PublicKey(bobPublicKey[:]), secrets.PrivateKey(bobPrivateKey[:])); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
if alice.String() != "nacl-box" {
|
||||
t.Error("String() doesn't return nacl-box")
|
||||
}
|
||||
aliceSecret := []byte("Why is a raven like a writing-desk?")
|
||||
if _, err := alice.Encrypt(aliceSecret); err == nil {
|
||||
t.Error("alice.Encrypt succeded without a public key")
|
||||
}
|
||||
enc, err := alice.Encrypt(aliceSecret, secrets.RecipientPublicKey(bob.Options().PublicKey))
|
||||
if err != nil {
|
||||
t.Error("alice.Encrypt failed")
|
||||
}
|
||||
if _, err := bob.Decrypt(enc); err == nil {
|
||||
t.Error("bob.Decrypt succeded without a public key")
|
||||
}
|
||||
if dec, err := bob.Decrypt(enc, secrets.SenderPublicKey(alice.Options().PublicKey)); err == nil {
|
||||
if !reflect.DeepEqual(dec, aliceSecret) {
|
||||
t.Errorf("Bob's decrypted message didn't match Alice's encrypted message: %v != %v", aliceSecret, dec)
|
||||
}
|
||||
} else {
|
||||
t.Errorf("bob.Decrypt failed (%s)", err)
|
||||
}
|
||||
|
||||
bobSecret := []byte("I haven't the slightest idea")
|
||||
enc, err = bob.Encrypt(bobSecret, secrets.RecipientPublicKey(alice.Options().PublicKey))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
dec, err := alice.Decrypt(enc, secrets.SenderPublicKey(bob.Options().PrivateKey))
|
||||
if err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
dec, err = alice.Decrypt(enc, secrets.SenderPublicKey(bob.Options().PublicKey))
|
||||
if !reflect.DeepEqual(dec, bobSecret) {
|
||||
t.Errorf("Alice's decrypted message didn't match Bob's encrypted message %v != %v", bobSecret, dec)
|
||||
}
|
||||
}
|
73
config/secrets/secretbox/secretbox.go
Normal file
73
config/secrets/secretbox/secretbox.go
Normal file
@@ -0,0 +1,73 @@
|
||||
// Package secretbox is a config/secrets implementation that uses nacl/secretbox
|
||||
// to do symmetric encryption / verification
|
||||
package secretbox
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/v2/config/secrets"
|
||||
"github.com/pkg/errors"
|
||||
"golang.org/x/crypto/nacl/secretbox"
|
||||
|
||||
"crypto/rand"
|
||||
)
|
||||
|
||||
const keyLength = 32
|
||||
|
||||
type secretBox struct {
|
||||
options secrets.Options
|
||||
|
||||
secretKey [keyLength]byte
|
||||
}
|
||||
|
||||
// NewCodec returns a secretbox codec
|
||||
func NewCodec(opts ...secrets.Option) secrets.Codec {
|
||||
sb := &secretBox{}
|
||||
for _, o := range opts {
|
||||
o(&sb.options)
|
||||
}
|
||||
return sb
|
||||
}
|
||||
|
||||
func (s *secretBox) Init(opts ...secrets.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&s.options)
|
||||
}
|
||||
if len(s.options.SecretKey) == 0 {
|
||||
return errors.New("no secret key is defined")
|
||||
}
|
||||
if len(s.options.SecretKey) != keyLength {
|
||||
return errors.Errorf("secret key must be %d bytes long", keyLength)
|
||||
}
|
||||
copy(s.secretKey[:], s.options.SecretKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *secretBox) Options() secrets.Options {
|
||||
return s.options
|
||||
}
|
||||
|
||||
func (s *secretBox) String() string {
|
||||
return "nacl-secretbox"
|
||||
}
|
||||
|
||||
func (s *secretBox) Encrypt(in []byte, opts ...secrets.EncryptOption) ([]byte, error) {
|
||||
// no opts are expected, so they are ignored
|
||||
|
||||
// there must be a unique nonce for each message
|
||||
var nonce [24]byte
|
||||
if _, err := rand.Reader.Read(nonce[:]); err != nil {
|
||||
return []byte{}, errors.Wrap(err, "couldn't obtain a random nonce from crypto/rand")
|
||||
}
|
||||
return secretbox.Seal(nonce[:], in, &nonce, &s.secretKey), nil
|
||||
}
|
||||
|
||||
func (s *secretBox) Decrypt(in []byte, opts ...secrets.DecryptOption) ([]byte, error) {
|
||||
// no options are expected, so they are ignored
|
||||
|
||||
var decryptNonce [24]byte
|
||||
copy(decryptNonce[:], in[:24])
|
||||
decrypted, ok := secretbox.Open(nil, in[24:], &decryptNonce, &s.secretKey)
|
||||
if !ok {
|
||||
return []byte{}, errors.New("decryption failed (is the key set correctly?)")
|
||||
}
|
||||
return decrypted, nil
|
||||
}
|
56
config/secrets/secretbox/secretbox_test.go
Normal file
56
config/secrets/secretbox/secretbox_test.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package secretbox
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/v2/config/secrets"
|
||||
)
|
||||
|
||||
func TestSecretBox(t *testing.T) {
|
||||
secretKey, err := base64.StdEncoding.DecodeString("4jbVgq8FsAV7vy+n8WqEZrl7BUtNqh3fYT5RXzXOPFY=")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
s := NewCodec()
|
||||
|
||||
if err := s.Init(); err == nil {
|
||||
t.Error("Secretbox accepted an empty secret key")
|
||||
}
|
||||
if err := s.Init(secrets.SecretKey([]byte("invalid"))); err == nil {
|
||||
t.Error("Secretbox accepted a secret key that is invalid")
|
||||
}
|
||||
|
||||
if err := s.Init(secrets.SecretKey(secretKey)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
o := s.Options()
|
||||
if !reflect.DeepEqual(o.SecretKey, secretKey) {
|
||||
t.Error("Init() didn't set secret key correctly")
|
||||
}
|
||||
if s.String() != "nacl-secretbox" {
|
||||
t.Error(s.String() + " should be nacl-secretbox")
|
||||
}
|
||||
|
||||
// Try 10 times to get different nonces
|
||||
for i := 0; i < 10; i++ {
|
||||
message := []byte(`Can you hear me, Major Tom?`)
|
||||
|
||||
encrypted, err := s.Encrypt(message)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to encrypt message (%s)", err)
|
||||
}
|
||||
|
||||
decrypted, err := s.Decrypt(encrypted)
|
||||
if err != nil {
|
||||
t.Errorf("Failed to decrypt encrypted message (%s)", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(message, decrypted) {
|
||||
t.Errorf("Decrypted Message dod not match encrypted message")
|
||||
}
|
||||
}
|
||||
}
|
82
config/secrets/secrets.go
Normal file
82
config/secrets/secrets.go
Normal file
@@ -0,0 +1,82 @@
|
||||
// Package secrets is an interface for encrypting and decrypting secrets
|
||||
package secrets
|
||||
|
||||
import "context"
|
||||
|
||||
// Codec encrypts or decrypts arbitrary data. The data should be as small as possible
|
||||
type Codec interface {
|
||||
Init(...Option) error
|
||||
Options() Options
|
||||
String() string
|
||||
Decrypt([]byte, ...DecryptOption) ([]byte, error)
|
||||
Encrypt([]byte, ...EncryptOption) ([]byte, error)
|
||||
}
|
||||
|
||||
// Options is a codec's options
|
||||
// SecretKey or both PublicKey and PrivateKey should be set depending on the
|
||||
// underlying implementation
|
||||
type Options struct {
|
||||
SecretKey []byte
|
||||
PrivateKey []byte
|
||||
PublicKey []byte
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// Option sets options
|
||||
type Option func(*Options)
|
||||
|
||||
// SecretKey sets the symmetric secret key
|
||||
func SecretKey(key []byte) Option {
|
||||
return func(o *Options) {
|
||||
o.SecretKey = make([]byte, len(key))
|
||||
copy(o.SecretKey, key)
|
||||
}
|
||||
}
|
||||
|
||||
// PublicKey sets the asymmetric Public Key of this codec
|
||||
func PublicKey(key []byte) Option {
|
||||
return func(o *Options) {
|
||||
o.PublicKey = make([]byte, len(key))
|
||||
copy(o.PublicKey, key)
|
||||
}
|
||||
}
|
||||
|
||||
// PrivateKey sets the asymmetric Private Key of this codec
|
||||
func PrivateKey(key []byte) Option {
|
||||
return func(o *Options) {
|
||||
o.PrivateKey = make([]byte, len(key))
|
||||
copy(o.PrivateKey, key)
|
||||
}
|
||||
}
|
||||
|
||||
// DecryptOptions can be passed to Codec.Decrypt
|
||||
type DecryptOptions struct {
|
||||
SenderPublicKey []byte
|
||||
}
|
||||
|
||||
// DecryptOption sets DecryptOptions
|
||||
type DecryptOption func(*DecryptOptions)
|
||||
|
||||
// SenderPublicKey is the Public Key of the Codec that encrypted this message
|
||||
func SenderPublicKey(key []byte) DecryptOption {
|
||||
return func(d *DecryptOptions) {
|
||||
d.SenderPublicKey = make([]byte, len(key))
|
||||
copy(d.SenderPublicKey, key)
|
||||
}
|
||||
}
|
||||
|
||||
// EncryptOptions can be passed to Codec.Encrypt
|
||||
type EncryptOptions struct {
|
||||
RecipientPublicKey []byte
|
||||
}
|
||||
|
||||
// EncryptOption Sets EncryptOptions
|
||||
type EncryptOption func(*EncryptOptions)
|
||||
|
||||
// RecipientPublicKey is the Public Key of the Codec that will decrypt this message
|
||||
func RecipientPublicKey(key []byte) EncryptOption {
|
||||
return func(e *EncryptOptions) {
|
||||
e.RecipientPublicKey = make([]byte, len(key))
|
||||
copy(e.RecipientPublicKey, key)
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
type serviceNameKey struct{}
|
||||
type keyKey struct{}
|
||||
type namespaceKey struct{}
|
||||
type pathKey struct{}
|
||||
|
||||
func ServiceName(name string) source.Option {
|
||||
@@ -19,12 +19,12 @@ func ServiceName(name string) source.Option {
|
||||
}
|
||||
}
|
||||
|
||||
func Key(key string) source.Option {
|
||||
func Namespace(namespace string) source.Option {
|
||||
return func(o *source.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, keyKey{}, key)
|
||||
o.Context = context.WithValue(o.Context, namespaceKey{}, namespace)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: go-micro/config/source/service/proto/service.proto
|
||||
// source: service.proto
|
||||
|
||||
package service
|
||||
|
||||
@@ -21,7 +21,7 @@ var _ = math.Inf
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type ChangeSet struct {
|
||||
Data []byte `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
|
||||
Data string `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"`
|
||||
Checksum string `protobuf:"bytes,2,opt,name=checksum,proto3" json:"checksum,omitempty"`
|
||||
Format string `protobuf:"bytes,3,opt,name=format,proto3" json:"format,omitempty"`
|
||||
Source string `protobuf:"bytes,4,opt,name=source,proto3" json:"source,omitempty"`
|
||||
@@ -35,7 +35,7 @@ func (m *ChangeSet) Reset() { *m = ChangeSet{} }
|
||||
func (m *ChangeSet) String() string { return proto.CompactTextString(m) }
|
||||
func (*ChangeSet) ProtoMessage() {}
|
||||
func (*ChangeSet) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{0}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{0}
|
||||
}
|
||||
|
||||
func (m *ChangeSet) XXX_Unmarshal(b []byte) error {
|
||||
@@ -56,11 +56,11 @@ func (m *ChangeSet) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_ChangeSet proto.InternalMessageInfo
|
||||
|
||||
func (m *ChangeSet) GetData() []byte {
|
||||
func (m *ChangeSet) GetData() string {
|
||||
if m != nil {
|
||||
return m.Data
|
||||
}
|
||||
return nil
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *ChangeSet) GetChecksum() string {
|
||||
@@ -92,7 +92,7 @@ func (m *ChangeSet) GetTimestamp() int64 {
|
||||
}
|
||||
|
||||
type Change struct {
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
||||
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
|
||||
ChangeSet *ChangeSet `protobuf:"bytes,3,opt,name=changeSet,proto3" json:"changeSet,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
@@ -104,7 +104,7 @@ func (m *Change) Reset() { *m = Change{} }
|
||||
func (m *Change) String() string { return proto.CompactTextString(m) }
|
||||
func (*Change) ProtoMessage() {}
|
||||
func (*Change) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{1}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{1}
|
||||
}
|
||||
|
||||
func (m *Change) XXX_Unmarshal(b []byte) error {
|
||||
@@ -125,9 +125,9 @@ func (m *Change) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_Change proto.InternalMessageInfo
|
||||
|
||||
func (m *Change) GetKey() string {
|
||||
func (m *Change) GetNamespace() string {
|
||||
if m != nil {
|
||||
return m.Key
|
||||
return m.Namespace
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -157,7 +157,7 @@ func (m *CreateRequest) Reset() { *m = CreateRequest{} }
|
||||
func (m *CreateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateRequest) ProtoMessage() {}
|
||||
func (*CreateRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{2}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{2}
|
||||
}
|
||||
|
||||
func (m *CreateRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -195,7 +195,7 @@ func (m *CreateResponse) Reset() { *m = CreateResponse{} }
|
||||
func (m *CreateResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateResponse) ProtoMessage() {}
|
||||
func (*CreateResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{3}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{3}
|
||||
}
|
||||
|
||||
func (m *CreateResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -227,7 +227,7 @@ func (m *UpdateRequest) Reset() { *m = UpdateRequest{} }
|
||||
func (m *UpdateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateRequest) ProtoMessage() {}
|
||||
func (*UpdateRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{4}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{4}
|
||||
}
|
||||
|
||||
func (m *UpdateRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -265,7 +265,7 @@ func (m *UpdateResponse) Reset() { *m = UpdateResponse{} }
|
||||
func (m *UpdateResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateResponse) ProtoMessage() {}
|
||||
func (*UpdateResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{5}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{5}
|
||||
}
|
||||
|
||||
func (m *UpdateResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -297,7 +297,7 @@ func (m *DeleteRequest) Reset() { *m = DeleteRequest{} }
|
||||
func (m *DeleteRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteRequest) ProtoMessage() {}
|
||||
func (*DeleteRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{6}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{6}
|
||||
}
|
||||
|
||||
func (m *DeleteRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -335,7 +335,7 @@ func (m *DeleteResponse) Reset() { *m = DeleteResponse{} }
|
||||
func (m *DeleteResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteResponse) ProtoMessage() {}
|
||||
func (*DeleteResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{7}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{7}
|
||||
}
|
||||
|
||||
func (m *DeleteResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -366,7 +366,7 @@ func (m *ListRequest) Reset() { *m = ListRequest{} }
|
||||
func (m *ListRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListRequest) ProtoMessage() {}
|
||||
func (*ListRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{8}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{8}
|
||||
}
|
||||
|
||||
func (m *ListRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -398,7 +398,7 @@ func (m *ListResponse) Reset() { *m = ListResponse{} }
|
||||
func (m *ListResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListResponse) ProtoMessage() {}
|
||||
func (*ListResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{9}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{9}
|
||||
}
|
||||
|
||||
func (m *ListResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -427,7 +427,7 @@ func (m *ListResponse) GetValues() []*Change {
|
||||
}
|
||||
|
||||
type ReadRequest struct {
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
||||
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
@@ -438,7 +438,7 @@ func (m *ReadRequest) Reset() { *m = ReadRequest{} }
|
||||
func (m *ReadRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ReadRequest) ProtoMessage() {}
|
||||
func (*ReadRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{10}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{10}
|
||||
}
|
||||
|
||||
func (m *ReadRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -459,9 +459,9 @@ func (m *ReadRequest) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_ReadRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *ReadRequest) GetKey() string {
|
||||
func (m *ReadRequest) GetNamespace() string {
|
||||
if m != nil {
|
||||
return m.Key
|
||||
return m.Namespace
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -484,7 +484,7 @@ func (m *ReadResponse) Reset() { *m = ReadResponse{} }
|
||||
func (m *ReadResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ReadResponse) ProtoMessage() {}
|
||||
func (*ReadResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{11}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{11}
|
||||
}
|
||||
|
||||
func (m *ReadResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -513,7 +513,7 @@ func (m *ReadResponse) GetChange() *Change {
|
||||
}
|
||||
|
||||
type WatchRequest struct {
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
||||
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
@@ -524,7 +524,7 @@ func (m *WatchRequest) Reset() { *m = WatchRequest{} }
|
||||
func (m *WatchRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*WatchRequest) ProtoMessage() {}
|
||||
func (*WatchRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{12}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{12}
|
||||
}
|
||||
|
||||
func (m *WatchRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -545,9 +545,9 @@ func (m *WatchRequest) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_WatchRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *WatchRequest) GetKey() string {
|
||||
func (m *WatchRequest) GetNamespace() string {
|
||||
if m != nil {
|
||||
return m.Key
|
||||
return m.Namespace
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -560,7 +560,7 @@ func (m *WatchRequest) GetPath() string {
|
||||
}
|
||||
|
||||
type WatchResponse struct {
|
||||
Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
|
||||
Namespace string `protobuf:"bytes,1,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
||||
ChangeSet *ChangeSet `protobuf:"bytes,2,opt,name=changeSet,proto3" json:"changeSet,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
@@ -571,7 +571,7 @@ func (m *WatchResponse) Reset() { *m = WatchResponse{} }
|
||||
func (m *WatchResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*WatchResponse) ProtoMessage() {}
|
||||
func (*WatchResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_05971a9aaecb0484, []int{13}
|
||||
return fileDescriptor_a0b84a42fa06f626, []int{13}
|
||||
}
|
||||
|
||||
func (m *WatchResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -592,9 +592,9 @@ func (m *WatchResponse) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_WatchResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *WatchResponse) GetKey() string {
|
||||
func (m *WatchResponse) GetNamespace() string {
|
||||
if m != nil {
|
||||
return m.Key
|
||||
return m.Namespace
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -623,38 +623,35 @@ func init() {
|
||||
proto.RegisterType((*WatchResponse)(nil), "WatchResponse")
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("go-micro/config/source/service/proto/service.proto", fileDescriptor_05971a9aaecb0484)
|
||||
}
|
||||
func init() { proto.RegisterFile("service.proto", fileDescriptor_a0b84a42fa06f626) }
|
||||
|
||||
var fileDescriptor_05971a9aaecb0484 = []byte{
|
||||
// 443 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x93, 0xcf, 0x6a, 0xdb, 0x40,
|
||||
0x10, 0xc6, 0x2d, 0xdb, 0x51, 0xab, 0xb1, 0x24, 0x87, 0x39, 0x14, 0x21, 0x0a, 0x35, 0x82, 0x82,
|
||||
0x69, 0xe9, 0x2a, 0x38, 0x7d, 0x03, 0xf7, 0xd6, 0x9e, 0x54, 0x4a, 0x7b, 0xdd, 0xca, 0x13, 0x5b,
|
||||
0x24, 0xf2, 0xaa, 0xda, 0x75, 0xa0, 0x8f, 0x90, 0xb7, 0x2e, 0xfb, 0x47, 0xb1, 0xe4, 0x82, 0x89,
|
||||
0x6f, 0x3b, 0x33, 0x3b, 0xdf, 0x7c, 0x9a, 0x9f, 0x16, 0x56, 0x5b, 0xf1, 0xa9, 0xae, 0xca, 0x56,
|
||||
0xe4, 0xa5, 0xd8, 0xdf, 0x55, 0xdb, 0x5c, 0x8a, 0x43, 0x5b, 0x52, 0x2e, 0xa9, 0x7d, 0xac, 0x4a,
|
||||
0xca, 0x9b, 0x56, 0x28, 0xd1, 0x45, 0xcc, 0x44, 0xd9, 0x93, 0x07, 0xc1, 0x7a, 0xc7, 0xf7, 0x5b,
|
||||
0xfa, 0x4e, 0x0a, 0x11, 0xa6, 0x1b, 0xae, 0x78, 0xe2, 0x2d, 0xbc, 0x65, 0x58, 0x98, 0x33, 0xa6,
|
||||
0xf0, 0xba, 0xdc, 0x51, 0x79, 0x2f, 0x0f, 0x75, 0x32, 0x5e, 0x78, 0xcb, 0xa0, 0x78, 0x8e, 0xf1,
|
||||
0x0d, 0xf8, 0x77, 0xa2, 0xad, 0xb9, 0x4a, 0x26, 0xa6, 0xe2, 0x22, 0x9d, 0xb7, 0xb3, 0x93, 0xa9,
|
||||
0xcd, 0xdb, 0x08, 0xdf, 0x42, 0xa0, 0xaa, 0x9a, 0xa4, 0xe2, 0x75, 0x93, 0x5c, 0x2d, 0xbc, 0xe5,
|
||||
0xa4, 0x38, 0x26, 0xb2, 0x5f, 0xe0, 0x5b, 0x2b, 0x78, 0x0d, 0x93, 0x7b, 0xfa, 0x6b, 0x6c, 0x04,
|
||||
0x85, 0x3e, 0x6a, 0x67, 0x0d, 0x57, 0x3b, 0xe7, 0xc0, 0x9c, 0x71, 0x09, 0x41, 0xd9, 0x59, 0x37,
|
||||
0x06, 0x66, 0x2b, 0x60, 0xcf, 0x1f, 0x53, 0x1c, 0x8b, 0xd9, 0x0d, 0x44, 0xeb, 0x96, 0xb8, 0xa2,
|
||||
0x82, 0xfe, 0x1c, 0x48, 0x2a, 0x7c, 0x07, 0xbe, 0xad, 0x9a, 0x19, 0xb3, 0xd5, 0x2b, 0xd7, 0x57,
|
||||
0xb8, 0x74, 0x76, 0x0d, 0x71, 0xd7, 0x21, 0x1b, 0xb1, 0x97, 0xa4, 0x35, 0x7e, 0x34, 0x9b, 0x0b,
|
||||
0x35, 0xba, 0x8e, 0xa3, 0xc6, 0x17, 0x7a, 0xa0, 0xcb, 0x34, 0xba, 0x0e, 0xa7, 0x11, 0xc1, 0xec,
|
||||
0x5b, 0x25, 0x95, 0x53, 0xc8, 0x72, 0x08, 0x6d, 0x68, 0xcb, 0x5a, 0xf1, 0x91, 0x3f, 0x1c, 0x48,
|
||||
0x26, 0xde, 0x62, 0x32, 0x50, 0xb4, 0xe9, 0xec, 0x16, 0x66, 0x05, 0xf1, 0x4d, 0xe7, 0xe0, 0x45,
|
||||
0xab, 0xd6, 0x53, 0x6c, 0xd3, 0x71, 0xca, 0x79, 0xdf, 0x9f, 0x21, 0xfc, 0xc9, 0x55, 0xb9, 0xbb,
|
||||
0x6c, 0xcc, 0x57, 0x88, 0x5c, 0x97, 0x9b, 0xf3, 0x7f, 0xdb, 0x00, 0xfa, 0xf8, 0x0c, 0xf4, 0xd5,
|
||||
0xd3, 0x18, 0xfc, 0xb5, 0x79, 0x08, 0xf8, 0x11, 0x7c, 0x4b, 0x13, 0x63, 0x36, 0xf8, 0x11, 0xd2,
|
||||
0x39, 0x3b, 0xc1, 0x3c, 0xd2, 0x97, 0x2d, 0x36, 0x8c, 0xd9, 0x80, 0x78, 0x3a, 0x67, 0x27, 0x3c,
|
||||
0xcd, 0x65, 0xcb, 0x07, 0x63, 0x36, 0x40, 0x9b, 0xce, 0xd9, 0x09, 0xb8, 0x11, 0xbe, 0x87, 0xa9,
|
||||
0x66, 0x85, 0x21, 0xeb, 0x11, 0x4c, 0x23, 0xd6, 0x07, 0x68, 0xaf, 0xe9, 0x65, 0x63, 0xc8, 0x7a,
|
||||
0xa0, 0xd2, 0x88, 0xf5, 0x09, 0x64, 0x23, 0xfc, 0x00, 0x57, 0x66, 0x59, 0x18, 0xb1, 0xfe, 0xaa,
|
||||
0xd3, 0x98, 0x0d, 0x76, 0x98, 0x8d, 0x6e, 0xbc, 0xdf, 0xbe, 0x79, 0xed, 0xb7, 0xff, 0x02, 0x00,
|
||||
0x00, 0xff, 0xff, 0xea, 0xa0, 0x1e, 0x8e, 0x23, 0x04, 0x00, 0x00,
|
||||
var fileDescriptor_a0b84a42fa06f626 = []byte{
|
||||
// 424 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xcd, 0x6a, 0xdb, 0x40,
|
||||
0x10, 0xc7, 0x2d, 0xdb, 0x51, 0xeb, 0xb1, 0x24, 0x97, 0x39, 0x14, 0x21, 0x0a, 0x35, 0x0b, 0x05,
|
||||
0xd3, 0xc2, 0x36, 0xb8, 0x0f, 0xd0, 0x82, 0x7b, 0xec, 0x49, 0xa5, 0xe4, 0xbc, 0x95, 0x26, 0x91,
|
||||
0x68, 0xf4, 0x51, 0xed, 0x2a, 0xef, 0x90, 0xb7, 0x2e, 0xfb, 0xa1, 0x48, 0xf2, 0xc1, 0xe0, 0xde,
|
||||
0xb4, 0xff, 0x99, 0xf9, 0xcf, 0xec, 0xfe, 0x06, 0x41, 0x28, 0xa9, 0x7b, 0x2a, 0x33, 0xe2, 0x6d,
|
||||
0xd7, 0xa8, 0x86, 0x3d, 0x7b, 0xb0, 0x39, 0x15, 0xa2, 0x7e, 0xa0, 0x9f, 0xa4, 0x10, 0x61, 0x9d,
|
||||
0x0b, 0x25, 0x62, 0x6f, 0xef, 0x1d, 0x36, 0xa9, 0xf9, 0xc6, 0x04, 0x5e, 0x67, 0x05, 0x65, 0x7f,
|
||||
0x64, 0x5f, 0xc5, 0x4b, 0xa3, 0xbf, 0x9c, 0xf1, 0x2d, 0xf8, 0xf7, 0x4d, 0x57, 0x09, 0x15, 0xaf,
|
||||
0x4c, 0xc4, 0x9d, 0xb4, 0x2e, 0x9b, 0xbe, 0xcb, 0x28, 0x5e, 0x5b, 0xdd, 0x9e, 0xf0, 0x1d, 0x6c,
|
||||
0x54, 0x59, 0x91, 0x54, 0xa2, 0x6a, 0xe3, 0x9b, 0xbd, 0x77, 0x58, 0xa5, 0xa3, 0xc0, 0x72, 0xf0,
|
||||
0xed, 0x28, 0x3a, 0xaf, 0x16, 0x15, 0xc9, 0x56, 0x64, 0xe4, 0x86, 0x19, 0x05, 0x3d, 0x65, 0x2b,
|
||||
0x54, 0xe1, 0xa6, 0x31, 0xdf, 0x78, 0x80, 0x4d, 0x36, 0x5c, 0xc3, 0x0c, 0xb3, 0x3d, 0x02, 0x7f,
|
||||
0xb9, 0x58, 0x3a, 0x06, 0xd9, 0x2d, 0x84, 0xa7, 0x8e, 0x84, 0xa2, 0x94, 0xfe, 0xf6, 0x24, 0x15,
|
||||
0xbe, 0x07, 0xdf, 0x46, 0x4d, 0xa7, 0xed, 0xf1, 0x95, 0xab, 0x4b, 0x9d, 0xcc, 0xde, 0x40, 0x34,
|
||||
0x54, 0xc8, 0xb6, 0xa9, 0x25, 0x69, 0x8f, 0x5f, 0x6d, 0x7e, 0xa5, 0xc7, 0x50, 0x31, 0x7a, 0x7c,
|
||||
0xa7, 0x47, 0xba, 0xce, 0x63, 0xa8, 0x70, 0x1e, 0x21, 0x6c, 0x7f, 0x94, 0x52, 0x39, 0x07, 0xf6,
|
||||
0x19, 0x02, 0x7b, 0xb4, 0x61, 0xed, 0xf8, 0x24, 0x1e, 0x7b, 0x92, 0xb1, 0xb7, 0x5f, 0xcd, 0x1c,
|
||||
0xad, 0xcc, 0xbe, 0xc2, 0x36, 0x25, 0x91, 0x0f, 0x13, 0x5c, 0xfd, 0xec, 0xba, 0xa3, 0x35, 0x18,
|
||||
0x3b, 0x5e, 0xbe, 0xc3, 0x37, 0x08, 0xee, 0x84, 0xca, 0x8a, 0xff, 0x6f, 0x79, 0x07, 0xa1, 0x73,
|
||||
0x70, 0x3d, 0x2f, 0x5b, 0xcc, 0x16, 0x63, 0x79, 0x61, 0x31, 0x8e, 0xcf, 0x4b, 0xf0, 0x4f, 0x4d,
|
||||
0x7d, 0x5f, 0x3e, 0xe0, 0x27, 0xf0, 0x2d, 0x71, 0x8c, 0xf8, 0x6c, 0x59, 0x92, 0x1d, 0x3f, 0x5b,
|
||||
0x85, 0x85, 0x4e, 0xb6, 0x68, 0x31, 0xe2, 0xb3, 0xad, 0x48, 0x76, 0xfc, 0x8c, 0xb9, 0x49, 0xb6,
|
||||
0x0c, 0x31, 0xe2, 0x33, 0xfc, 0xc9, 0x8e, 0x9f, 0xc1, 0x5d, 0xe0, 0x07, 0x58, 0x6b, 0x9e, 0x18,
|
||||
0xf0, 0x09, 0xe5, 0x24, 0xe4, 0x53, 0xc8, 0x36, 0x4d, 0x43, 0xc0, 0x80, 0x4f, 0x60, 0x26, 0x21,
|
||||
0x9f, 0x92, 0x61, 0x0b, 0xfc, 0x08, 0x37, 0xe6, 0xe1, 0x30, 0xe4, 0x53, 0x04, 0x49, 0xc4, 0x67,
|
||||
0xef, 0xc9, 0x16, 0xb7, 0xde, 0x6f, 0xdf, 0xfc, 0x1d, 0xbe, 0xfc, 0x0b, 0x00, 0x00, 0xff, 0xff,
|
||||
0x1c, 0x3e, 0x57, 0xb0, 0x2e, 0x04, 0x00, 0x00,
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: go-micro/config/source/service/proto/service.proto
|
||||
// source: service.proto
|
||||
|
||||
package service
|
||||
|
||||
@@ -48,12 +48,6 @@ type configService struct {
|
||||
}
|
||||
|
||||
func NewConfigService(name string, c client.Client) ConfigService {
|
||||
if c == nil {
|
||||
c = client.NewClient()
|
||||
}
|
||||
if len(name) == 0 {
|
||||
name = "config"
|
||||
}
|
||||
return &configService{
|
||||
c: c,
|
||||
name: name,
|
||||
@@ -123,6 +117,7 @@ func (c *configService) Watch(ctx context.Context, in *WatchRequest, opts ...cli
|
||||
}
|
||||
|
||||
type Config_WatchService interface {
|
||||
Context() context.Context
|
||||
SendMsg(interface{}) error
|
||||
RecvMsg(interface{}) error
|
||||
Close() error
|
||||
@@ -137,6 +132,10 @@ func (x *configServiceWatch) Close() error {
|
||||
return x.stream.Close()
|
||||
}
|
||||
|
||||
func (x *configServiceWatch) Context() context.Context {
|
||||
return x.stream.Context()
|
||||
}
|
||||
|
||||
func (x *configServiceWatch) SendMsg(m interface{}) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
@@ -214,6 +213,7 @@ func (h *configHandler) Watch(ctx context.Context, stream server.Stream) error {
|
||||
}
|
||||
|
||||
type Config_WatchStream interface {
|
||||
Context() context.Context
|
||||
SendMsg(interface{}) error
|
||||
RecvMsg(interface{}) error
|
||||
Close() error
|
||||
@@ -228,6 +228,10 @@ func (x *configWatchStream) Close() error {
|
||||
return x.stream.Close()
|
||||
}
|
||||
|
||||
func (x *configWatchStream) Context() context.Context {
|
||||
return x.stream.Context()
|
||||
}
|
||||
|
||||
func (x *configWatchStream) SendMsg(m interface{}) error {
|
||||
return x.stream.Send(m)
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ service Config {
|
||||
}
|
||||
|
||||
message ChangeSet {
|
||||
bytes data = 1;
|
||||
string data = 1;
|
||||
string checksum = 2;
|
||||
string format = 3;
|
||||
string source = 4;
|
||||
@@ -18,7 +18,7 @@ message ChangeSet {
|
||||
}
|
||||
|
||||
message Change {
|
||||
string key = 1;
|
||||
string namespace = 1;
|
||||
string path = 2;
|
||||
ChangeSet changeSet = 3;
|
||||
}
|
||||
@@ -48,7 +48,7 @@ message ListResponse {
|
||||
}
|
||||
|
||||
message ReadRequest {
|
||||
string key = 1;
|
||||
string namespace = 1;
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
@@ -57,11 +57,11 @@ message ReadResponse {
|
||||
}
|
||||
|
||||
message WatchRequest {
|
||||
string key = 1;
|
||||
string namespace = 1;
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
message WatchResponse {
|
||||
string key = 1;
|
||||
string namespace = 1;
|
||||
ChangeSet changeSet = 2;
|
||||
}
|
||||
|
@@ -6,26 +6,29 @@ import (
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/config/source"
|
||||
proto "github.com/micro/go-micro/v2/config/source/service/proto"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
DefaultName = "go.micro.config"
|
||||
DefaultKey = "NAMESPACE:CONFIG"
|
||||
DefaultPath = ""
|
||||
DefaultClient = client.DefaultClient
|
||||
DefaultName = "go.micro.config"
|
||||
DefaultNamespace = "global"
|
||||
DefaultPath = ""
|
||||
)
|
||||
|
||||
type service struct {
|
||||
serviceName string
|
||||
key string
|
||||
namespace string
|
||||
path string
|
||||
opts source.Options
|
||||
client proto.ConfigService
|
||||
}
|
||||
|
||||
func (m *service) Read() (set *source.ChangeSet, err error) {
|
||||
req, err := m.client.Read(context.Background(), &proto.ReadRequest{Key: m.key, Path: m.path})
|
||||
client := proto.NewConfigService(m.serviceName, client.DefaultClient)
|
||||
req, err := client.Read(context.Background(), &proto.ReadRequest{
|
||||
Namespace: m.namespace,
|
||||
Path: m.path,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -34,9 +37,15 @@ func (m *service) Read() (set *source.ChangeSet, err error) {
|
||||
}
|
||||
|
||||
func (m *service) Watch() (w source.Watcher, err error) {
|
||||
stream, err := m.client.Watch(context.Background(), &proto.WatchRequest{Key: m.key, Path: m.path})
|
||||
client := proto.NewConfigService(m.serviceName, client.DefaultClient)
|
||||
stream, err := client.Watch(context.Background(), &proto.WatchRequest{
|
||||
Namespace: m.namespace,
|
||||
Path: m.path,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("watch err: ", err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("watch err: ", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
return newWatcher(stream)
|
||||
@@ -58,7 +67,7 @@ func NewSource(opts ...source.Option) source.Source {
|
||||
}
|
||||
|
||||
addr := DefaultName
|
||||
key := DefaultKey
|
||||
namespace := DefaultNamespace
|
||||
path := DefaultPath
|
||||
|
||||
if options.Context != nil {
|
||||
@@ -67,9 +76,9 @@ func NewSource(opts ...source.Option) source.Source {
|
||||
addr = a
|
||||
}
|
||||
|
||||
k, ok := options.Context.Value(keyKey{}).(string)
|
||||
k, ok := options.Context.Value(namespaceKey{}).(string)
|
||||
if ok {
|
||||
key = k
|
||||
namespace = k
|
||||
}
|
||||
|
||||
p, ok := options.Context.Value(pathKey{}).(string)
|
||||
@@ -81,9 +90,8 @@ func NewSource(opts ...source.Option) source.Source {
|
||||
s := &service{
|
||||
serviceName: addr,
|
||||
opts: options,
|
||||
key: key,
|
||||
namespace: namespace,
|
||||
path: path,
|
||||
client: proto.NewConfigService(addr, DefaultClient),
|
||||
}
|
||||
|
||||
return s
|
||||
|
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
func toChangeSet(c *proto.ChangeSet) *source.ChangeSet {
|
||||
return &source.ChangeSet{
|
||||
Data: c.Data,
|
||||
Data: []byte(c.Data),
|
||||
Checksum: c.Checksum,
|
||||
Format: c.Format,
|
||||
Timestamp: time.Unix(c.Timestamp, 0),
|
||||
|
@@ -10,6 +10,24 @@ type Profile interface {
|
||||
String() string
|
||||
}
|
||||
|
||||
var (
|
||||
DefaultProfile Profile = new(noop)
|
||||
)
|
||||
|
||||
type noop struct{}
|
||||
|
||||
func (p *noop) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *noop) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *noop) String() string {
|
||||
return "noop"
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
// Name to use for the profile
|
||||
Name string
|
||||
|
@@ -115,3 +115,22 @@ func InternalServerError(id, format string, a ...interface{}) error {
|
||||
Status: http.StatusText(500),
|
||||
}
|
||||
}
|
||||
|
||||
func Equal(err1 error, err2 error) bool {
|
||||
verr1, ok1 := err1.(*Error)
|
||||
verr2, ok2 := err2.(*Error)
|
||||
|
||||
if ok1 != ok2 {
|
||||
return false
|
||||
}
|
||||
|
||||
if !ok1 {
|
||||
return err1 == err2
|
||||
}
|
||||
|
||||
if verr1.Code != verr2.Code {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
@@ -1,10 +1,26 @@
|
||||
package errors
|
||||
|
||||
import (
|
||||
er "errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEqual(t *testing.T) {
|
||||
err1 := NotFound("myid1", "msg1")
|
||||
err2 := NotFound("myid2", "msg2")
|
||||
|
||||
if !Equal(err1, err2) {
|
||||
t.Fatal("errors must be equal")
|
||||
}
|
||||
|
||||
err3 := er.New("my test err")
|
||||
if Equal(err1, err3) {
|
||||
t.Fatal("errors must be not equal")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestErrors(t *testing.T) {
|
||||
testData := []*Error{
|
||||
{
|
||||
|
3
go.mod
3
go.mod
@@ -13,6 +13,7 @@ require (
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f // indirect
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/forestgiant/sliceutil v0.0.0-20160425183142-94783f95db6c
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
@@ -28,6 +29,7 @@ require (
|
||||
github.com/gorilla/websocket v1.4.1
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0
|
||||
github.com/imdario/mergo v0.3.8
|
||||
github.com/jonboulle/clockwork v0.1.0 // indirect
|
||||
@@ -46,6 +48,7 @@ require (
|
||||
github.com/nats-io/nats.go v1.9.1
|
||||
github.com/nlopes/slack v0.6.1-0.20191106133607-d06c2a2b3249
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/soheilhy/cmux v0.1.4 // indirect
|
||||
github.com/stretchr/testify v1.4.0
|
||||
|
7
go.sum
7
go.sum
@@ -101,6 +101,8 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
|
||||
github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMElOWxok=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
@@ -213,6 +215,8 @@ github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92Bcuy
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5 h1:2+KSC78XiO6Qy0hIjfc1OD9H+hsaJdJlb8Kqsd41CTE=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.8.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5 h1:UImYN5qQ8tuGpGE16ZmjvcTtTw24zw1QAp/SlnNrZhI=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-multierror v0.0.0-20161216184304-ed905158d874/go.mod h1:JMRHfdO9jKNzS/+BTlxCjKNQHg/jZAft8U7LloJvN7I=
|
||||
@@ -284,7 +288,6 @@ github.com/mholt/certmagic v0.9.3 h1:RmzuNJ5mpFplDbyS41z+gGgE/py24IX6m0nHZ0yNTQU
|
||||
github.com/mholt/certmagic v0.9.3/go.mod h1:nu8jbsbtwK4205EDH/ZUMTKsfYpJA1Q7MKXHfgTihNw=
|
||||
github.com/micro/cli/v2 v2.1.2 h1:43J1lChg/rZCC1rvdqZNFSQDrGT7qfMrtp6/ztpIkEM=
|
||||
github.com/micro/cli/v2 v2.1.2/go.mod h1:EguNh6DAoWKm9nmk+k/Rg0H3lQnDxqzu5x5srOtGtYg=
|
||||
github.com/micro/go-micro v1.18.0 h1:gP70EZVHpJuUIT0YWth192JmlIci+qMOEByHm83XE9E=
|
||||
github.com/micro/mdns v0.3.0 h1:bYycYe+98AXR3s8Nq5qvt6C573uFTDPIYzJemWON0QE=
|
||||
github.com/micro/mdns v0.3.0/go.mod h1:KJ0dW7KmicXU2BV++qkLlmHYcVv7/hHnbtguSWt9Aoc=
|
||||
github.com/miekg/dns v1.1.3/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
@@ -348,6 +351,8 @@ github.com/oracle/oci-go-sdk v7.0.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukw
|
||||
github.com/ovh/go-ovh v0.0.0-20181109152953-ba5adb4cf014/go.mod h1:joRatxRJaZBsY3JAOEMcoOp05CnZzsx4scTxi95DHyQ=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -13,7 +14,6 @@ import (
|
||||
type defaultLogger struct {
|
||||
sync.RWMutex
|
||||
opts Options
|
||||
err error
|
||||
}
|
||||
|
||||
// Init(opts...) should only overwrite provided options
|
||||
@@ -35,13 +35,6 @@ func (l *defaultLogger) Fields(fields map[string]interface{}) Logger {
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *defaultLogger) Error(err error) Logger {
|
||||
l.Lock()
|
||||
l.err = err
|
||||
l.Unlock()
|
||||
return l
|
||||
}
|
||||
|
||||
func copyFields(src map[string]interface{}) map[string]interface{} {
|
||||
dst := make(map[string]interface{}, len(src))
|
||||
for k, v := range src {
|
||||
@@ -58,9 +51,6 @@ func (l *defaultLogger) Log(level Level, v ...interface{}) {
|
||||
|
||||
l.RLock()
|
||||
fields := copyFields(l.opts.Fields)
|
||||
if l.err != nil {
|
||||
fields["error"] = l.err.Error()
|
||||
}
|
||||
l.RUnlock()
|
||||
|
||||
fields["level"] = level.String()
|
||||
@@ -70,14 +60,24 @@ func (l *defaultLogger) Log(level Level, v ...interface{}) {
|
||||
Message: fmt.Sprint(v...),
|
||||
Metadata: make(map[string]string, len(fields)),
|
||||
}
|
||||
|
||||
keys := make([]string, 0, len(fields))
|
||||
for k, v := range fields {
|
||||
keys = append(keys, k)
|
||||
rec.Metadata[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
metadata := ""
|
||||
|
||||
for _, k := range keys {
|
||||
metadata += fmt.Sprintf(" %s=%v", k, fields[k])
|
||||
}
|
||||
|
||||
dlog.DefaultLog.Write(rec)
|
||||
|
||||
t := rec.Timestamp.Format("2006-01-02 15:04:05")
|
||||
fmt.Printf("%s %v\n", t, rec.Message)
|
||||
fmt.Printf("%s %s %v\n", t, metadata, rec.Message)
|
||||
}
|
||||
|
||||
func (l *defaultLogger) Logf(level Level, format string, v ...interface{}) {
|
||||
@@ -88,9 +88,6 @@ func (l *defaultLogger) Logf(level Level, format string, v ...interface{}) {
|
||||
|
||||
l.RLock()
|
||||
fields := copyFields(l.opts.Fields)
|
||||
if l.err != nil {
|
||||
fields["error"] = l.err.Error()
|
||||
}
|
||||
l.RUnlock()
|
||||
|
||||
fields["level"] = level.String()
|
||||
@@ -100,14 +97,24 @@ func (l *defaultLogger) Logf(level Level, format string, v ...interface{}) {
|
||||
Message: fmt.Sprintf(format, v...),
|
||||
Metadata: make(map[string]string, len(fields)),
|
||||
}
|
||||
|
||||
keys := make([]string, 0, len(fields))
|
||||
for k, v := range fields {
|
||||
keys = append(keys, k)
|
||||
rec.Metadata[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
sort.Strings(keys)
|
||||
metadata := ""
|
||||
|
||||
for _, k := range keys {
|
||||
metadata += fmt.Sprintf(" %s=%v", k, fields[k])
|
||||
}
|
||||
|
||||
dlog.DefaultLog.Write(rec)
|
||||
|
||||
t := rec.Timestamp.Format("2006-01-02 15:04:05")
|
||||
fmt.Printf("%s %v\n", t, rec.Message)
|
||||
fmt.Printf("%s %s %v\n", t, metadata, rec.Message)
|
||||
}
|
||||
|
||||
func (n *defaultLogger) Options() Options {
|
||||
|
114
logger/helper.go
Normal file
114
logger/helper.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
type Helper struct {
|
||||
Logger
|
||||
fields map[string]interface{}
|
||||
}
|
||||
|
||||
func NewHelper(log Logger) *Helper {
|
||||
return &Helper{Logger: log}
|
||||
}
|
||||
|
||||
func (h *Helper) Info(args ...interface{}) {
|
||||
if !h.Logger.Options().Level.Enabled(InfoLevel) {
|
||||
return
|
||||
}
|
||||
h.Logger.Fields(h.fields).Log(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func (h *Helper) Infof(template string, args ...interface{}) {
|
||||
if !h.Logger.Options().Level.Enabled(InfoLevel) {
|
||||
return
|
||||
}
|
||||
h.Logger.Fields(h.fields).Logf(InfoLevel, template, args...)
|
||||
}
|
||||
|
||||
func (h *Helper) Trace(args ...interface{}) {
|
||||
if !h.Logger.Options().Level.Enabled(TraceLevel) {
|
||||
return
|
||||
}
|
||||
h.Logger.Fields(h.fields).Log(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func (h *Helper) Tracef(template string, args ...interface{}) {
|
||||
if !h.Logger.Options().Level.Enabled(TraceLevel) {
|
||||
return
|
||||
}
|
||||
h.Logger.Fields(h.fields).Logf(TraceLevel, template, args...)
|
||||
}
|
||||
|
||||
func (h *Helper) Debug(args ...interface{}) {
|
||||
if !h.Logger.Options().Level.Enabled(DebugLevel) {
|
||||
return
|
||||
}
|
||||
h.Logger.Fields(h.fields).Log(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func (h *Helper) Debugf(template string, args ...interface{}) {
|
||||
if !h.Logger.Options().Level.Enabled(DebugLevel) {
|
||||
return
|
||||
}
|
||||
h.Logger.Fields(h.fields).Logf(DebugLevel, template, args...)
|
||||
}
|
||||
|
||||
func (h *Helper) Warn(args ...interface{}) {
|
||||
if !h.Logger.Options().Level.Enabled(WarnLevel) {
|
||||
return
|
||||
}
|
||||
h.Logger.Fields(h.fields).Log(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func (h *Helper) Warnf(template string, args ...interface{}) {
|
||||
if !h.Logger.Options().Level.Enabled(WarnLevel) {
|
||||
return
|
||||
}
|
||||
h.Logger.Fields(h.fields).Logf(WarnLevel, template, args...)
|
||||
}
|
||||
|
||||
func (h *Helper) Error(args ...interface{}) {
|
||||
if !h.Logger.Options().Level.Enabled(ErrorLevel) {
|
||||
return
|
||||
}
|
||||
h.Logger.Fields(h.fields).Log(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func (h *Helper) Errorf(template string, args ...interface{}) {
|
||||
if !h.Logger.Options().Level.Enabled(ErrorLevel) {
|
||||
return
|
||||
}
|
||||
h.Logger.Fields(h.fields).Logf(ErrorLevel, template, args...)
|
||||
}
|
||||
|
||||
func (h *Helper) Fatal(args ...interface{}) {
|
||||
if !h.Logger.Options().Level.Enabled(FatalLevel) {
|
||||
return
|
||||
}
|
||||
h.Logger.Fields(h.fields).Log(FatalLevel, args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (h *Helper) Fatalf(template string, args ...interface{}) {
|
||||
if !h.Logger.Options().Level.Enabled(FatalLevel) {
|
||||
return
|
||||
}
|
||||
h.Logger.Fields(h.fields).Logf(FatalLevel, template, args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func (h *Helper) WithError(err error) *Helper {
|
||||
fields := copyFields(h.fields)
|
||||
fields["error"] = err
|
||||
return &Helper{Logger: h.Logger, fields: fields}
|
||||
}
|
||||
|
||||
func (h *Helper) WithFields(fields map[string]interface{}) *Helper {
|
||||
nfields := copyFields(fields)
|
||||
for k, v := range h.fields {
|
||||
nfields[k] = v
|
||||
}
|
||||
return &Helper{Logger: h.Logger, fields: nfields}
|
||||
}
|
@@ -1,6 +1,9 @@
|
||||
package logger
|
||||
|
||||
import "fmt"
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Level int8
|
||||
|
||||
@@ -16,8 +19,6 @@ const (
|
||||
WarnLevel
|
||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||
ErrorLevel
|
||||
// PanicLevel level, logs the message and then panics.
|
||||
PanicLevel
|
||||
// FatalLevel level. Logs and then calls `logger.Exit(1)`. highest level of severity.
|
||||
FatalLevel
|
||||
)
|
||||
@@ -34,8 +35,6 @@ func (l Level) String() string {
|
||||
return "warn"
|
||||
case ErrorLevel:
|
||||
return "error"
|
||||
case PanicLevel:
|
||||
return "panic"
|
||||
case FatalLevel:
|
||||
return "fatal"
|
||||
}
|
||||
@@ -61,12 +60,10 @@ func GetLevel(levelStr string) (Level, error) {
|
||||
return WarnLevel, nil
|
||||
case ErrorLevel.String():
|
||||
return ErrorLevel, nil
|
||||
case PanicLevel.String():
|
||||
return PanicLevel, nil
|
||||
case FatalLevel.String():
|
||||
return FatalLevel, nil
|
||||
}
|
||||
return InfoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to NoLevel", levelStr)
|
||||
return InfoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to InfoLevel", levelStr)
|
||||
}
|
||||
|
||||
func Info(args ...interface{}) {
|
||||
@@ -111,8 +108,19 @@ func Errorf(template string, args ...interface{}) {
|
||||
|
||||
func Fatal(args ...interface{}) {
|
||||
DefaultLogger.Log(FatalLevel, args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func Fatalf(template string, args ...interface{}) {
|
||||
DefaultLogger.Logf(FatalLevel, template, args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Returns true if the given level is at or lower the current logger level
|
||||
func V(lvl Level, log Logger) bool {
|
||||
l := DefaultLogger
|
||||
if log != nil {
|
||||
l = log
|
||||
}
|
||||
return l.Options().Level <= lvl
|
||||
}
|
||||
|
@@ -3,7 +3,7 @@ package logger
|
||||
|
||||
var (
|
||||
// Default logger
|
||||
DefaultLogger Logger = NewLogger()
|
||||
DefaultLogger Logger = NewHelper(NewLogger())
|
||||
)
|
||||
|
||||
// Logger is a generic logging interface
|
||||
@@ -12,8 +12,6 @@ type Logger interface {
|
||||
Init(options ...Option) error
|
||||
// The Logger options
|
||||
Options() Options
|
||||
// Error set `error` field to be logged
|
||||
Error(err error) Logger
|
||||
// Fields set fields to always be logged
|
||||
Fields(fields map[string]interface{}) Logger
|
||||
// Log writes a log entry
|
||||
@@ -43,7 +41,3 @@ func Logf(level Level, format string, v ...interface{}) {
|
||||
func String() string {
|
||||
return DefaultLogger.String()
|
||||
}
|
||||
|
||||
func WithError(err error) Logger {
|
||||
return DefaultLogger.Error(err)
|
||||
}
|
||||
|
15
logger/logger_test.go
Normal file
15
logger/logger_test.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package logger
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestLogger(t *testing.T) {
|
||||
l := NewLogger(WithLevel(TraceLevel))
|
||||
h1 := NewHelper(l).WithFields(map[string]interface{}{"key1": "val1"})
|
||||
h1.Trace("trace_msg1")
|
||||
h1.Warn("warn_msg1")
|
||||
|
||||
h2 := NewHelper(l).WithFields(map[string]interface{}{"key2": "val2"})
|
||||
h2.Trace("trace_msg2")
|
||||
h2.Warn("warn_msg2")
|
||||
|
||||
}
|
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
cmucp "github.com/micro/go-micro/v2/client/mucp"
|
||||
rtr "github.com/micro/go-micro/v2/client/selector/router"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/network/resolver/dns"
|
||||
pbNet "github.com/micro/go-micro/v2/network/service/proto"
|
||||
"github.com/micro/go-micro/v2/proxy"
|
||||
@@ -223,7 +223,7 @@ func (n *network) acceptNetConn(l tunnel.Listener, recv chan *message) {
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
sleep := backoff.Do(i)
|
||||
log.Debugf("Network tunnel [%s] accept error: %v, backing off for %v", ControlChannel, err, sleep)
|
||||
logger.Debugf("Network tunnel [%s] accept error: %v, backing off for %v", ControlChannel, err, sleep)
|
||||
time.Sleep(sleep)
|
||||
i++
|
||||
continue
|
||||
@@ -232,7 +232,7 @@ func (n *network) acceptNetConn(l tunnel.Listener, recv chan *message) {
|
||||
select {
|
||||
case <-n.closed:
|
||||
if err := conn.Close(); err != nil {
|
||||
log.Debugf("Network tunnel [%s] failed to close connection: %v", NetworkChannel, err)
|
||||
logger.Debugf("Network tunnel [%s] failed to close connection: %v", NetworkChannel, err)
|
||||
}
|
||||
return
|
||||
default:
|
||||
@@ -250,7 +250,9 @@ func (n *network) acceptCtrlConn(l tunnel.Listener, recv chan *message) {
|
||||
conn, err := l.Accept()
|
||||
if err != nil {
|
||||
sleep := backoff.Do(i)
|
||||
log.Debugf("Network tunnel [%s] accept error: %v, backing off for %v", ControlChannel, err, sleep)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network tunnel [%s] accept error: %v, backing off for %v", ControlChannel, err, sleep)
|
||||
}
|
||||
time.Sleep(sleep)
|
||||
i++
|
||||
continue
|
||||
@@ -259,7 +261,9 @@ func (n *network) acceptCtrlConn(l tunnel.Listener, recv chan *message) {
|
||||
select {
|
||||
case <-n.closed:
|
||||
if err := conn.Close(); err != nil {
|
||||
log.Debugf("Network tunnel [%s] failed to close connection: %v", ControlChannel, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network tunnel [%s] failed to close connection: %v", ControlChannel, err)
|
||||
}
|
||||
}
|
||||
return
|
||||
default:
|
||||
@@ -355,7 +359,9 @@ func (n *network) advertise(advertChan <-chan *router.Advert) {
|
||||
for i := 0; i < max; i++ {
|
||||
if peer := n.node.GetPeerNode(peers[rnd.Intn(len(peers))].Id()); peer != nil {
|
||||
if err := n.sendTo("advert", ControlChannel, peer, msg); err != nil {
|
||||
log.Debugf("Network failed to advertise routes to %s: %v", peer.Id(), err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed to advertise routes to %s: %v", peer.Id(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -371,7 +377,9 @@ func (n *network) initNodes(startup bool) {
|
||||
// NOTE: this condition never fires
|
||||
// as resolveNodes() never returns error
|
||||
if err != nil && !startup {
|
||||
log.Debugf("Network failed to init nodes: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed to init nodes: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -390,8 +398,10 @@ func (n *network) initNodes(startup bool) {
|
||||
init = append(init, node)
|
||||
}
|
||||
|
||||
// initialize the tunnel
|
||||
log.Tracef("Network initialising nodes %+v\n", init)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
// initialize the tunnel
|
||||
logger.Tracef("Network initialising nodes %+v\n", init)
|
||||
}
|
||||
|
||||
n.tunnel.Init(
|
||||
tunnel.Nodes(nodes...),
|
||||
@@ -403,7 +413,9 @@ func (n *network) resolveNodes() ([]string, error) {
|
||||
// resolve the network address to network nodes
|
||||
records, err := n.options.Resolver.Resolve(n.options.Name)
|
||||
if err != nil {
|
||||
log.Debugf("Network failed to resolve nodes: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed to resolve nodes: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// sort by lowest priority
|
||||
@@ -444,7 +456,9 @@ func (n *network) resolveNodes() ([]string, error) {
|
||||
// resolve anything that looks like a host name
|
||||
records, err := dns.Resolve(node)
|
||||
if err != nil {
|
||||
log.Debugf("Failed to resolve %v %v", node, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Failed to resolve %v %v", node, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -464,7 +478,9 @@ func (n *network) handleNetConn(s tunnel.Session, msg chan *message) {
|
||||
for {
|
||||
m := new(transport.Message)
|
||||
if err := s.Recv(m); err != nil {
|
||||
log.Debugf("Network tunnel [%s] receive error: %v", NetworkChannel, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network tunnel [%s] receive error: %v", NetworkChannel, err)
|
||||
}
|
||||
switch err {
|
||||
case io.EOF, tunnel.ErrReadTimeout:
|
||||
s.Close()
|
||||
@@ -497,7 +513,9 @@ func (n *network) handleCtrlConn(s tunnel.Session, msg chan *message) {
|
||||
for {
|
||||
m := new(transport.Message)
|
||||
if err := s.Recv(m); err != nil {
|
||||
log.Debugf("Network tunnel [%s] receive error: %v", ControlChannel, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network tunnel [%s] receive error: %v", ControlChannel, err)
|
||||
}
|
||||
switch err {
|
||||
case io.EOF, tunnel.ErrReadTimeout:
|
||||
s.Close()
|
||||
@@ -575,12 +593,15 @@ func (n *network) getRouteMetric(router string, gateway string, link string) int
|
||||
return 2
|
||||
}
|
||||
|
||||
log.Tracef("Network looking up %s link to gateway: %s", link, gateway)
|
||||
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Network looking up %s link to gateway: %s", link, gateway)
|
||||
}
|
||||
// attempt to find link based on gateway address
|
||||
lnk, ok := n.peerLinks[gateway]
|
||||
if !ok {
|
||||
log.Debugf("Network failed to find a link to gateway: %s", gateway)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed to find a link to gateway: %s", gateway)
|
||||
}
|
||||
// no link found so infinite metric returned
|
||||
return math.MaxInt64
|
||||
}
|
||||
@@ -598,11 +619,15 @@ func (n *network) getRouteMetric(router string, gateway string, link string) int
|
||||
|
||||
// make sure length is non-zero
|
||||
if length == 0 {
|
||||
log.Debugf("Link length is 0 %v %v", link, lnk.Length())
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Link length is 0 %v %v", link, lnk.Length())
|
||||
}
|
||||
length = 10e9
|
||||
}
|
||||
|
||||
log.Tracef("Network calculated metric %v delay %v length %v distance %v", (delay*length*int64(hops))/10e6, delay, length, hops)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Network calculated metric %v delay %v length %v distance %v", (delay*length*int64(hops))/10e6, delay, length, hops)
|
||||
}
|
||||
|
||||
return (delay * length * int64(hops)) / 10e6
|
||||
}
|
||||
@@ -626,7 +651,9 @@ func (n *network) processCtrlChan(listener tunnel.Listener) {
|
||||
pbRtrAdvert := &pbRtr.Advert{}
|
||||
|
||||
if err := proto.Unmarshal(m.msg.Body, pbRtrAdvert); err != nil {
|
||||
log.Debugf("Network fail to unmarshal advert message: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network fail to unmarshal advert message: %v", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -634,14 +661,17 @@ func (n *network) processCtrlChan(listener tunnel.Listener) {
|
||||
if pbRtrAdvert.Id == n.options.Id {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("Network received advert message from: %s", pbRtrAdvert.Id)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network received advert message from: %s", pbRtrAdvert.Id)
|
||||
}
|
||||
|
||||
// loookup advertising node in our peer topology
|
||||
advertNode := n.node.GetPeerNode(pbRtrAdvert.Id)
|
||||
if advertNode == nil {
|
||||
// if we can't find the node in our topology (MaxDepth) we skipp prcessing adverts
|
||||
log.Debugf("Network skipping advert message from unknown peer: %s", pbRtrAdvert.Id)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network skipping advert message from unknown peer: %s", pbRtrAdvert.Id)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -658,7 +688,9 @@ func (n *network) processCtrlChan(listener tunnel.Listener) {
|
||||
// if the origin router is not the advertising node peer
|
||||
// we can't rule out potential routing loops so we bail here
|
||||
if peer := advertNode.GetPeerNode(event.Route.Router); peer == nil {
|
||||
log.Debugf("Network skipping advert message from peer: %s", pbRtrAdvert.Id)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network skipping advert message from peer: %s", pbRtrAdvert.Id)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
@@ -676,7 +708,9 @@ func (n *network) processCtrlChan(listener tunnel.Listener) {
|
||||
// calculate route metric and add to the advertised metric
|
||||
// we need to make sure we do not overflow math.MaxInt64
|
||||
metric := n.getRouteMetric(event.Route.Router, event.Route.Gateway, event.Route.Link)
|
||||
log.Tracef("Network metric for router %s and gateway %s: %v", event.Route.Router, event.Route.Gateway, metric)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Network metric for router %s and gateway %s: %v", event.Route.Router, event.Route.Gateway, metric)
|
||||
}
|
||||
|
||||
// check we don't overflow max int 64
|
||||
if d := route.Metric + metric; d <= 0 {
|
||||
@@ -698,7 +732,9 @@ func (n *network) processCtrlChan(listener tunnel.Listener) {
|
||||
|
||||
// if no events are eligible for processing continue
|
||||
if len(events) == 0 {
|
||||
log.Tracef("Network no events to be processed by router: %s", n.options.Id)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Network no events to be processed by router: %s", n.options.Id)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -711,9 +747,13 @@ func (n *network) processCtrlChan(listener tunnel.Listener) {
|
||||
Events: events,
|
||||
}
|
||||
|
||||
log.Tracef("Network router %s processing advert: %s", n.Id(), advert.Id)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Network router %s processing advert: %s", n.Id(), advert.Id)
|
||||
}
|
||||
if err := n.router.Process(advert); err != nil {
|
||||
log.Debugf("Network failed to process advert %s: %v", advert.Id, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed to process advert %s: %v", advert.Id, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-n.closed:
|
||||
@@ -743,7 +783,7 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
|
||||
pbNetConnect := &pbNet.Connect{}
|
||||
if err := proto.Unmarshal(m.msg.Body, pbNetConnect); err != nil {
|
||||
log.Debugf("Network tunnel [%s] connect unmarshal error: %v", NetworkChannel, err)
|
||||
logger.Debugf("Network tunnel [%s] connect unmarshal error: %v", NetworkChannel, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -752,7 +792,7 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("Network received connect message from: %s", pbNetConnect.Node.Id)
|
||||
logger.Debugf("Network received connect message from: %s", pbNetConnect.Node.Id)
|
||||
|
||||
peer := &node{
|
||||
id: pbNetConnect.Node.Id,
|
||||
@@ -768,15 +808,15 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
// TODO: should we do this only if we manage to add a peer
|
||||
// What should we do if the peer links failed to be updated?
|
||||
if err := n.updatePeerLinks(peer); err != nil {
|
||||
log.Debugf("Network failed updating peer links: %s", err)
|
||||
logger.Debugf("Network failed updating peer links: %s", err)
|
||||
}
|
||||
|
||||
// add peer to the list of node peers
|
||||
if err := n.AddPeer(peer); err == ErrPeerExists {
|
||||
log.Tracef("Network peer exists, refreshing: %s", peer.id)
|
||||
logger.Tracef("Network peer exists, refreshing: %s", peer.id)
|
||||
// update lastSeen time for the peer
|
||||
if err := n.RefreshPeer(peer.id, peer.link, now); err != nil {
|
||||
log.Debugf("Network failed refreshing peer %s: %v", peer.id, err)
|
||||
logger.Debugf("Network failed refreshing peer %s: %v", peer.id, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -796,14 +836,14 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
// get a list of the best routes for each service in our routing table
|
||||
routes, err := n.getProtoRoutes()
|
||||
if err != nil {
|
||||
log.Debugf("Network node %s failed listing routes: %v", n.id, err)
|
||||
logger.Debugf("Network node %s failed listing routes: %v", n.id, err)
|
||||
}
|
||||
// attached the routes to the message
|
||||
msg.Routes = routes
|
||||
|
||||
// send sync message to the newly connected peer
|
||||
if err := n.sendTo("sync", NetworkChannel, peer, msg); err != nil {
|
||||
log.Debugf("Network failed to send sync message: %v", err)
|
||||
logger.Debugf("Network failed to send sync message: %v", err)
|
||||
}
|
||||
}()
|
||||
case "peer":
|
||||
@@ -812,7 +852,7 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
pbNetPeer := &pbNet.Peer{}
|
||||
|
||||
if err := proto.Unmarshal(m.msg.Body, pbNetPeer); err != nil {
|
||||
log.Debugf("Network tunnel [%s] peer unmarshal error: %v", NetworkChannel, err)
|
||||
logger.Debugf("Network tunnel [%s] peer unmarshal error: %v", NetworkChannel, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -821,7 +861,7 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("Network received peer message from: %s %s", pbNetPeer.Node.Id, pbNetPeer.Node.Address)
|
||||
logger.Debugf("Network received peer message from: %s %s", pbNetPeer.Node.Id, pbNetPeer.Node.Address)
|
||||
|
||||
peer := &node{
|
||||
id: pbNetPeer.Node.Id,
|
||||
@@ -837,7 +877,7 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
// TODO: should we do this only if we manage to add a peer
|
||||
// What should we do if the peer links failed to be updated?
|
||||
if err := n.updatePeerLinks(peer); err != nil {
|
||||
log.Debugf("Network failed updating peer links: %s", err)
|
||||
logger.Debugf("Network failed updating peer links: %s", err)
|
||||
}
|
||||
|
||||
// if it's a new peer i.e. we do not have it in our graph, we request full sync
|
||||
@@ -853,29 +893,29 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
// get a list of the best routes for each service in our routing table
|
||||
routes, err := n.getProtoRoutes()
|
||||
if err != nil {
|
||||
log.Debugf("Network node %s failed listing routes: %v", n.id, err)
|
||||
logger.Debugf("Network node %s failed listing routes: %v", n.id, err)
|
||||
}
|
||||
// attached the routes to the message
|
||||
msg.Routes = routes
|
||||
|
||||
// send sync message to the newly connected peer
|
||||
if err := n.sendTo("sync", NetworkChannel, peer, msg); err != nil {
|
||||
log.Debugf("Network failed to send sync message: %v", err)
|
||||
logger.Debugf("Network failed to send sync message: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
continue
|
||||
// if we already have the peer in our graph, skip further steps
|
||||
} else if err != ErrPeerExists {
|
||||
log.Debugf("Network got error adding peer %v", err)
|
||||
logger.Debugf("Network got error adding peer %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Tracef("Network peer exists, refreshing: %s", pbNetPeer.Node.Id)
|
||||
logger.Tracef("Network peer exists, refreshing: %s", pbNetPeer.Node.Id)
|
||||
|
||||
// update lastSeen time for the peer
|
||||
if err := n.RefreshPeer(peer.id, peer.link, now); err != nil {
|
||||
log.Debugf("Network failed refreshing peer %s: %v", pbNetPeer.Node.Id, err)
|
||||
logger.Debugf("Network failed refreshing peer %s: %v", pbNetPeer.Node.Id, err)
|
||||
}
|
||||
|
||||
// NOTE: we don't unpack MaxDepth toplogy
|
||||
@@ -883,9 +923,9 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
// update the link
|
||||
peer.link = m.msg.Header["Micro-Link"]
|
||||
|
||||
log.Tracef("Network updating topology of node: %s", n.node.id)
|
||||
logger.Tracef("Network updating topology of node: %s", n.node.id)
|
||||
if err := n.node.UpdatePeer(peer); err != nil {
|
||||
log.Debugf("Network failed to update peers: %v", err)
|
||||
logger.Debugf("Network failed to update peers: %v", err)
|
||||
}
|
||||
|
||||
// tell the connect loop that we've been discovered
|
||||
@@ -901,7 +941,7 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
|
||||
pbNetSync := &pbNet.Sync{}
|
||||
if err := proto.Unmarshal(m.msg.Body, pbNetSync); err != nil {
|
||||
log.Debugf("Network tunnel [%s] sync unmarshal error: %v", NetworkChannel, err)
|
||||
logger.Debugf("Network tunnel [%s] sync unmarshal error: %v", NetworkChannel, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -910,7 +950,7 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("Network received sync message from: %s", pbNetSync.Peer.Node.Id)
|
||||
logger.Debugf("Network received sync message from: %s", pbNetSync.Peer.Node.Id)
|
||||
|
||||
peer := &node{
|
||||
id: pbNetSync.Peer.Node.Id,
|
||||
@@ -926,15 +966,21 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
// TODO: should we do this only if we manage to add a peer
|
||||
// What should we do if the peer links failed to be updated?
|
||||
if err := n.updatePeerLinks(peer); err != nil {
|
||||
log.Debugf("Network failed updating peer links: %s", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed updating peer links: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// add peer to the list of node peers
|
||||
if err := n.node.AddPeer(peer); err == ErrPeerExists {
|
||||
log.Tracef("Network peer exists, refreshing: %s", peer.id)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Network peer exists, refreshing: %s", peer.id)
|
||||
}
|
||||
// update lastSeen time for the existing node
|
||||
if err := n.RefreshPeer(peer.id, peer.link, now); err != nil {
|
||||
log.Debugf("Network failed refreshing peer %s: %v", peer.id, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed refreshing peer %s: %v", peer.id, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -947,7 +993,9 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
route := pbUtil.ProtoToRoute(pbRoute)
|
||||
// continue if we are the originator of the route
|
||||
if route.Router == n.router.Options().Id {
|
||||
log.Debugf("Network node %s skipping route addition: route already present", n.id)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network node %s skipping route addition: route already present", n.id)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -972,7 +1020,9 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
|
||||
routes, err := n.router.Table().Query(q...)
|
||||
if err != nil && err != router.ErrRouteNotFound {
|
||||
log.Debugf("Network node %s failed listing best routes for %s: %v", n.id, route.Service, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network node %s failed listing best routes for %s: %v", n.id, route.Service, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -980,7 +1030,9 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
// create the new route we have just received
|
||||
if len(routes) == 0 {
|
||||
if err := n.router.Table().Create(route); err != nil && err != router.ErrDuplicateRoute {
|
||||
log.Debugf("Network node %s failed to add route: %v", n.id, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network node %s failed to add route: %v", n.id, err)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -1006,14 +1058,18 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
|
||||
// add route to the routing table
|
||||
if err := n.router.Table().Create(route); err != nil && err != router.ErrDuplicateRoute {
|
||||
log.Debugf("Network node %s failed to add route: %v", n.id, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network node %s failed to add route: %v", n.id, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update your sync timestamp
|
||||
// NOTE: this might go away as we will be doing full table advert to random peer
|
||||
if err := n.RefreshSync(now); err != nil {
|
||||
log.Debugf("Network failed refreshing sync time: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed refreshing sync time: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
go func() {
|
||||
@@ -1022,13 +1078,17 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
|
||||
// advertise yourself to the new node
|
||||
if err := n.sendTo("peer", NetworkChannel, peer, msg); err != nil {
|
||||
log.Debugf("Network failed to advertise peers: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed to advertise peers: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
case "close":
|
||||
pbNetClose := &pbNet.Close{}
|
||||
if err := proto.Unmarshal(m.msg.Body, pbNetClose); err != nil {
|
||||
log.Debugf("Network tunnel [%s] close unmarshal error: %v", NetworkChannel, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network tunnel [%s] close unmarshal error: %v", NetworkChannel, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1037,7 +1097,9 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("Network received close message from: %s", pbNetClose.Node.Id)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network received close message from: %s", pbNetClose.Node.Id)
|
||||
}
|
||||
|
||||
peer := &node{
|
||||
id: pbNetClose.Node.Id,
|
||||
@@ -1045,11 +1107,15 @@ func (n *network) processNetChan(listener tunnel.Listener) {
|
||||
}
|
||||
|
||||
if err := n.DeletePeerNode(peer.id); err != nil {
|
||||
log.Debugf("Network failed to delete node %s routes: %v", peer.id, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed to delete node %s routes: %v", peer.id, err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := n.prunePeerRoutes(peer); err != nil {
|
||||
log.Debugf("Network failed pruning peer %s routes: %v", peer.id, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed pruning peer %s routes: %v", peer.id, err)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: we should maybe advertise this to the network so we converge faster on closed nodes
|
||||
@@ -1166,7 +1232,9 @@ func (n *network) manage() {
|
||||
// set the link via peer links
|
||||
l, ok := n.peerLinks[peer.address]
|
||||
if ok {
|
||||
log.Debugf("Network link not found for peer %s cannot announce", peer.id)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network link not found for peer %s cannot announce", peer.id)
|
||||
}
|
||||
continue
|
||||
}
|
||||
link = l.Id()
|
||||
@@ -1192,7 +1260,9 @@ func (n *network) manage() {
|
||||
for _, peer := range peers {
|
||||
// advertise yourself to the network
|
||||
if err := n.sendTo("peer", NetworkChannel, peer, msg); err != nil {
|
||||
log.Debugf("Network failed to advertise peer %s: %v", peer.id, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed to advertise peer %s: %v", peer.id, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1214,32 +1284,41 @@ func (n *network) manage() {
|
||||
|
||||
// unknown link and peer so lets do the connect flow
|
||||
if err := n.sendTo("connect", NetworkChannel, peer, msg); err != nil {
|
||||
log.Debugf("Network failed to connect %s: %v", peer.id, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed to connect %s: %v", peer.id, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
links[peer.link] = time.Now()
|
||||
}
|
||||
case <-prune.C:
|
||||
log.Debugf("Network node %s pruning stale peers", n.id)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network node %s pruning stale peers", n.id)
|
||||
}
|
||||
pruned := n.PruneStalePeers(PruneTime)
|
||||
|
||||
for id, peer := range pruned {
|
||||
log.Debugf("Network peer exceeded prune time: %s", id)
|
||||
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network peer exceeded prune time: %s", id)
|
||||
}
|
||||
n.Lock()
|
||||
delete(n.peerLinks, peer.address)
|
||||
n.Unlock()
|
||||
|
||||
if err := n.prunePeerRoutes(peer); err != nil {
|
||||
log.Debugf("Network failed pruning peer %s routes: %v", id, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed pruning peer %s routes: %v", id, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get a list of all routes
|
||||
routes, err := n.options.Router.Table().List()
|
||||
if err != nil {
|
||||
log.Debugf("Network failed listing routes when pruning peers: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed listing routes when pruning peers: %v", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1261,7 +1340,9 @@ func (n *network) manage() {
|
||||
}
|
||||
// otherwise delete all the routes originated by it
|
||||
if err := n.pruneRoutes(router.QueryRouter(route.Router)); err != nil {
|
||||
log.Debugf("Network failed deleting routes by %s: %v", route.Router, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed deleting routes by %s: %v", route.Router, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-netsync.C:
|
||||
@@ -1291,14 +1372,18 @@ func (n *network) manage() {
|
||||
// get a list of the best routes for each service in our routing table
|
||||
routes, err := n.getProtoRoutes()
|
||||
if err != nil {
|
||||
log.Debugf("Network node %s failed listing routes: %v", n.id, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network node %s failed listing routes: %v", n.id, err)
|
||||
}
|
||||
}
|
||||
// attached the routes to the message
|
||||
msg.Routes = routes
|
||||
|
||||
// send sync message to the newly connected peer
|
||||
if err := n.sendTo("sync", NetworkChannel, peer, msg); err != nil {
|
||||
log.Debugf("Network failed to send sync message: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed to send sync message: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
case <-resolve.C:
|
||||
@@ -1348,7 +1433,9 @@ func (n *network) sendConnect() {
|
||||
}
|
||||
|
||||
if err := n.sendMsg("connect", NetworkChannel, msg); err != nil {
|
||||
log.Debugf("Network failed to send connect message: %s", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed to send connect message: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1367,9 +1454,13 @@ func (n *network) sendTo(method, channel string, peer *node, msg proto.Message)
|
||||
if peerNode := n.GetPeerNode(peer.id); peerNode != nil {
|
||||
// update node status when error happens
|
||||
peerNode.status.err.Update(err)
|
||||
log.Debugf("Network increment peer %v error count to: %d", peerNode, peerNode, peerNode.status.Error().Count())
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network increment peer %v error count to: %d", peerNode, peerNode, peerNode.status.Error().Count())
|
||||
}
|
||||
if count := peerNode.status.Error().Count(); count == MaxPeerErrors {
|
||||
log.Debugf("Network peer %v error count exceeded %d. Prunning.", peerNode, MaxPeerErrors)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network peer %v error count exceeded %d. Prunning.", peerNode, MaxPeerErrors)
|
||||
}
|
||||
n.PrunePeer(peerNode.id)
|
||||
}
|
||||
}
|
||||
@@ -1383,8 +1474,9 @@ func (n *network) sendTo(method, channel string, peer *node, msg proto.Message)
|
||||
id = peer.link
|
||||
}
|
||||
|
||||
log.Debugf("Network sending %s message from: %s to %s", method, n.options.Id, id)
|
||||
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network sending %s message from: %s to %s", method, n.options.Id, id)
|
||||
}
|
||||
tmsg := &transport.Message{
|
||||
Header: map[string]string{
|
||||
"Micro-Method": method,
|
||||
@@ -1400,12 +1492,18 @@ func (n *network) sendTo(method, channel string, peer *node, msg proto.Message)
|
||||
if err := c.Send(tmsg); err != nil {
|
||||
// TODO: Lookup peer in our graph
|
||||
if peerNode := n.GetPeerNode(peer.id); peerNode != nil {
|
||||
log.Debugf("Network found peer %s: %v", peer.id, peerNode)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network found peer %s: %v", peer.id, peerNode)
|
||||
}
|
||||
// update node status when error happens
|
||||
peerNode.status.err.Update(err)
|
||||
log.Debugf("Network increment node peer %p %v count to: %d", peerNode, peerNode, peerNode.status.Error().Count())
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network increment node peer %p %v count to: %d", peerNode, peerNode, peerNode.status.Error().Count())
|
||||
}
|
||||
if count := peerNode.status.Error().Count(); count == MaxPeerErrors {
|
||||
log.Debugf("Network node peer %v count exceeded %d: %d", peerNode, MaxPeerErrors, peerNode.status.Error().Count())
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network node peer %v count exceeded %d: %d", peerNode, MaxPeerErrors, peerNode.status.Error().Count())
|
||||
}
|
||||
n.PrunePeer(peerNode.id)
|
||||
}
|
||||
}
|
||||
@@ -1431,7 +1529,9 @@ func (n *network) sendMsg(method, channel string, msg proto.Message) error {
|
||||
}
|
||||
n.RUnlock()
|
||||
|
||||
log.Debugf("Network sending %s message from: %s", method, n.options.Id)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network sending %s message from: %s", method, n.options.Id)
|
||||
}
|
||||
|
||||
return client.Send(&transport.Message{
|
||||
Header: map[string]string{
|
||||
@@ -1448,7 +1548,9 @@ func (n *network) updatePeerLinks(peer *node) error {
|
||||
|
||||
linkId := peer.link
|
||||
|
||||
log.Tracef("Network looking up link %s in the peer links", linkId)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Network looking up link %s in the peer links", linkId)
|
||||
}
|
||||
|
||||
// lookup the peer link
|
||||
var peerLink tunnel.Link
|
||||
@@ -1464,8 +1566,10 @@ func (n *network) updatePeerLinks(peer *node) error {
|
||||
return ErrPeerLinkNotFound
|
||||
}
|
||||
|
||||
// if the peerLink is found in the returned links update peerLinks
|
||||
log.Tracef("Network updating peer links for peer %s", peer.address)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
// if the peerLink is found in the returned links update peerLinks
|
||||
logger.Tracef("Network updating peer links for peer %s", peer.address)
|
||||
}
|
||||
|
||||
// lookup a link and update it if better link is available
|
||||
if link, ok := n.peerLinks[peer.address]; ok {
|
||||
@@ -1547,7 +1651,9 @@ func (n *network) connect() {
|
||||
// well functioning tunnel clients as "discovered" will be false until the
|
||||
// n.discovered channel is read at some point later on.
|
||||
if err := n.createClients(); err != nil {
|
||||
log.Debugf("Failed to recreate network/control clients: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Failed to recreate network/control clients: %v", err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -1756,7 +1862,9 @@ func (n *network) Close() error {
|
||||
}
|
||||
|
||||
if err := n.sendMsg("close", NetworkChannel, msg); err != nil {
|
||||
log.Debugf("Network failed to send close message: %s", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Network failed to send close message: %s", err)
|
||||
}
|
||||
}
|
||||
<-time.After(time.Millisecond * 100)
|
||||
}
|
||||
|
19
options.go
19
options.go
@@ -9,7 +9,9 @@ import (
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/client/selector"
|
||||
"github.com/micro/go-micro/v2/config"
|
||||
"github.com/micro/go-micro/v2/config/cmd"
|
||||
"github.com/micro/go-micro/v2/debug/profile"
|
||||
"github.com/micro/go-micro/v2/debug/trace"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
@@ -21,10 +23,12 @@ type Options struct {
|
||||
Auth auth.Auth
|
||||
Broker broker.Broker
|
||||
Cmd cmd.Cmd
|
||||
Config config.Config
|
||||
Client client.Client
|
||||
Server server.Server
|
||||
Registry registry.Registry
|
||||
Transport transport.Transport
|
||||
Profile profile.Profile
|
||||
|
||||
// Before and After funcs
|
||||
BeforeStart []func() error
|
||||
@@ -44,6 +48,7 @@ func newOptions(opts ...Option) Options {
|
||||
Auth: auth.DefaultAuth,
|
||||
Broker: broker.DefaultBroker,
|
||||
Cmd: cmd.DefaultCmd,
|
||||
Config: config.DefaultConfig,
|
||||
Client: client.DefaultClient,
|
||||
Server: server.DefaultServer,
|
||||
Registry: registry.DefaultRegistry,
|
||||
@@ -99,6 +104,13 @@ func HandleSignal(b bool) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// Profile to be used for debug profile
|
||||
func Profile(p profile.Profile) Option {
|
||||
return func(o *Options) {
|
||||
o.Profile = p
|
||||
}
|
||||
}
|
||||
|
||||
// Server to be used for service
|
||||
func Server(s server.Server) Option {
|
||||
return func(o *Options) {
|
||||
@@ -134,6 +146,13 @@ func Auth(a auth.Auth) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// Config sets the config for the service
|
||||
func Config(c config.Config) Option {
|
||||
return func(o *Options) {
|
||||
o.Config = c
|
||||
}
|
||||
}
|
||||
|
||||
// Selector sets the selector for the service client
|
||||
func Selector(s selector.Selector) Option {
|
||||
return func(o *Options) {
|
||||
|
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/micro/go-micro/v2/codec"
|
||||
"github.com/micro/go-micro/v2/codec/bytes"
|
||||
"github.com/micro/go-micro/v2/errors"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/metadata"
|
||||
"github.com/micro/go-micro/v2/proxy"
|
||||
"github.com/micro/go-micro/v2/router"
|
||||
@@ -163,7 +163,9 @@ func (p *Proxy) filterRoutes(ctx context.Context, routes []router.Route) []route
|
||||
filteredRoutes = append(filteredRoutes, route)
|
||||
}
|
||||
|
||||
log.Tracef("Proxy filtered routes %+v\n", filteredRoutes)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Proxy filtered routes %+v\n", filteredRoutes)
|
||||
}
|
||||
|
||||
return filteredRoutes
|
||||
}
|
||||
@@ -259,7 +261,9 @@ func (p *Proxy) manageRoutes(route router.Route, action string) error {
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
|
||||
log.Tracef("Proxy taking route action %v %+v\n", action, route)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Proxy taking route action %v %+v\n", action, route)
|
||||
}
|
||||
|
||||
switch action {
|
||||
case "create", "update":
|
||||
@@ -309,7 +313,9 @@ func (p *Proxy) ProcessMessage(ctx context.Context, msg server.Message) error {
|
||||
// TODO: check that we're not broadcast storming by sending to the same topic
|
||||
// that we're actually subscribed to
|
||||
|
||||
log.Tracef("Proxy received message for %s", msg.Topic())
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Proxy received message for %s", msg.Topic())
|
||||
}
|
||||
|
||||
var errors []string
|
||||
|
||||
@@ -350,7 +356,9 @@ func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server
|
||||
return errors.BadRequest("go.micro.proxy", "service name is blank")
|
||||
}
|
||||
|
||||
log.Tracef("Proxy received request for %s", service)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Proxy received request for %s", service)
|
||||
}
|
||||
|
||||
// are we network routing or local routing
|
||||
if len(p.Links) == 0 {
|
||||
@@ -410,7 +418,9 @@ func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server
|
||||
opts = append(opts, client.WithAddress(addresses...))
|
||||
}
|
||||
|
||||
log.Tracef("Proxy calling %+v\n", addresses)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Proxy calling %+v\n", addresses)
|
||||
}
|
||||
// serve the normal way
|
||||
return p.serveRequest(ctx, p.Client, service, endpoint, req, rsp, opts...)
|
||||
}
|
||||
@@ -433,7 +443,9 @@ func (p *Proxy) ServeRequest(ctx context.Context, req server.Request, rsp server
|
||||
continue
|
||||
}
|
||||
|
||||
log.Tracef("Proxy using route %+v\n", route)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Proxy using route %+v\n", route)
|
||||
}
|
||||
|
||||
// set the address to call
|
||||
addresses := toNodes([]router.Route{route})
|
||||
|
10
registry/cache/cache.go
vendored
10
registry/cache/cache.go
vendored
@@ -7,7 +7,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
)
|
||||
|
||||
@@ -339,7 +339,9 @@ func (c *cache) run() {
|
||||
c.setStatus(err)
|
||||
|
||||
if a > 3 {
|
||||
log.Info("rcache: ", err, " backing off ", d)
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Info("rcache: ", err, " backing off ", d)
|
||||
}
|
||||
a = 0
|
||||
}
|
||||
|
||||
@@ -362,7 +364,9 @@ func (c *cache) run() {
|
||||
c.setStatus(err)
|
||||
|
||||
if b > 3 {
|
||||
log.Info("rcache: ", err, " backing off ", d)
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Info("rcache: ", err, " backing off ", d)
|
||||
}
|
||||
b = 0
|
||||
}
|
||||
|
||||
|
@@ -15,7 +15,7 @@ import (
|
||||
|
||||
"github.com/coreos/etcd/clientv3"
|
||||
"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
hash "github.com/mitchellh/hashstructure"
|
||||
"go.uber.org/zap"
|
||||
@@ -191,13 +191,17 @@ func (e *etcdRegistry) registerNode(s *registry.Service, node *registry.Node, op
|
||||
|
||||
// renew the lease if it exists
|
||||
if leaseID > 0 {
|
||||
log.Tracef("Renewing existing lease for %s %d", s.Name, leaseID)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("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.Tracef("Lease not found for %s %d", s.Name, leaseID)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Lease not found for %s %d", s.Name, leaseID)
|
||||
}
|
||||
// lease not found do register
|
||||
leaseNotFound = true
|
||||
}
|
||||
@@ -216,7 +220,9 @@ func (e *etcdRegistry) registerNode(s *registry.Service, node *registry.Node, op
|
||||
|
||||
// the service is unchanged, skip registering
|
||||
if ok && v == h && !leaseNotFound {
|
||||
log.Tracef("Service %s node %s unchanged skipping registration", s.Name, node.Id)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Service %s node %s unchanged skipping registration", s.Name, node.Id)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -245,7 +251,9 @@ func (e *etcdRegistry) registerNode(s *registry.Service, node *registry.Node, op
|
||||
}
|
||||
}
|
||||
|
||||
log.Tracef("Registering %s id %s with lease %v and ttl %v", service.Name, node.Id, lgr, options.TTL)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("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))
|
||||
@@ -284,7 +292,9 @@ func (e *etcdRegistry) Deregister(s *registry.Service) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), e.options.Timeout)
|
||||
defer cancel()
|
||||
|
||||
log.Tracef("Deregistering %s id %s", s.Name, node.Id)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Deregistering %s id %s", s.Name, node.Id)
|
||||
}
|
||||
_, err := e.client.Delete(ctx, nodePath(s.Name, node.Id))
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/util/kubernetes/client"
|
||||
)
|
||||
@@ -132,7 +132,9 @@ func (k *k8sWatcher) buildPodResults(pod *client.Pod, cache *client.Pod) []*regi
|
||||
func (k *k8sWatcher) handleEvent(event client.Event) {
|
||||
var pod client.Pod
|
||||
if err := json.Unmarshal([]byte(event.Object), &pod); err != nil {
|
||||
log.Info("K8s Watcher: Couldnt unmarshal event object from pod")
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Info("K8s Watcher: Couldnt unmarshal event object from pod")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/mdns"
|
||||
)
|
||||
|
||||
@@ -148,7 +149,6 @@ func (m *mdnsRegistry) Register(service *Service, opts ...RegisterOption) error
|
||||
continue
|
||||
}
|
||||
|
||||
//
|
||||
host, pt, err := net.SplitHostPort(node.Address)
|
||||
if err != nil {
|
||||
gerr = err
|
||||
@@ -270,10 +270,22 @@ func (m *mdnsRegistry) GetService(service string) ([]*Service, error) {
|
||||
Endpoints: txt.Endpoints,
|
||||
}
|
||||
}
|
||||
|
||||
addr := ""
|
||||
// prefer ipv4 addrs
|
||||
if e.AddrV4 != nil {
|
||||
addr = e.AddrV4.String()
|
||||
// else use ipv6
|
||||
} else if e.AddrV6 != nil {
|
||||
addr = "[" + e.AddrV6.String() + "]"
|
||||
} else {
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Infof("[mdns]: invalid endpoint received: %v", e)
|
||||
}
|
||||
continue
|
||||
}
|
||||
s.Nodes = append(s.Nodes, &Node{
|
||||
Id: strings.TrimSuffix(e.Name, "."+p.Service+"."+p.Domain+"."),
|
||||
Address: fmt.Sprintf("%s:%d", e.AddrV4.String(), e.Port),
|
||||
Address: fmt.Sprintf("%s:%d", addr, e.Port),
|
||||
Metadata: txt.Metadata,
|
||||
})
|
||||
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
)
|
||||
|
||||
@@ -75,7 +75,9 @@ func (m *Registry) ttlPrune() {
|
||||
for version, record := range records {
|
||||
for id, n := range record.Nodes {
|
||||
if n.TTL != 0 && time.Since(n.LastSeen) > n.TTL {
|
||||
log.Debugf("Registry TTL expired for node %s of service %s", n.Id, name)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Registry TTL expired for node %s of service %s", n.Id, name)
|
||||
}
|
||||
delete(m.records[name][version].Nodes, id)
|
||||
}
|
||||
}
|
||||
@@ -158,7 +160,9 @@ func (m *Registry) Register(s *registry.Service, opts ...registry.RegisterOption
|
||||
|
||||
if _, ok := m.records[s.Name][s.Version]; !ok {
|
||||
m.records[s.Name][s.Version] = r
|
||||
log.Debugf("Registry added new service: %s, version: %s", s.Name, s.Version)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Registry added new service: %s, version: %s", s.Name, s.Version)
|
||||
}
|
||||
go m.sendEvent(®istry.Result{Action: "update", Service: s})
|
||||
return nil
|
||||
}
|
||||
@@ -184,14 +188,18 @@ func (m *Registry) Register(s *registry.Service, opts ...registry.RegisterOption
|
||||
}
|
||||
|
||||
if addedNodes {
|
||||
log.Debugf("Registry added new node to service: %s, version: %s", s.Name, s.Version)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("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.Debugf("Updated registration for service: %s, version: %s", s.Name, s.Version)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("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()
|
||||
}
|
||||
@@ -207,18 +215,24 @@ func (m *Registry) Deregister(s *registry.Service) error {
|
||||
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.Debugf("Registry removed node from service: %s, version: %s", s.Name, s.Version)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("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.Debugf("Registry removed service: %s, version: %s", s.Name, s.Version)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Registry removed service: %s, version: %s", s.Name, s.Version)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(m.records[s.Name]) == 0 {
|
||||
delete(m.records, s.Name)
|
||||
log.Debugf("Registry removed service: %s", s.Name)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Registry removed service: %s", s.Name)
|
||||
}
|
||||
}
|
||||
go m.sendEvent(®istry.Result{Action: "delete", Service: s})
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
)
|
||||
|
||||
@@ -308,11 +308,15 @@ func (m adverts) process(a *advert) error {
|
||||
// suppress/recover the event based on its penalty level
|
||||
switch {
|
||||
case a.penalty > AdvertSuppress && !a.isSuppressed:
|
||||
log.Debugf("Router suppressing advert %d %.2f for route %s %s", hash, a.penalty, service, address)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router suppressing advert %d %.2f for route %s %s", hash, a.penalty, service, address)
|
||||
}
|
||||
a.isSuppressed = true
|
||||
a.suppressTime = time.Now()
|
||||
case a.penalty < AdvertRecover && a.isSuppressed:
|
||||
log.Debugf("Router recovering advert %d %.2f for route %s %s", hash, a.penalty, service, address)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router recovering advert %d %.2f for route %s %s", hash, a.penalty, service, address)
|
||||
}
|
||||
a.isSuppressed = false
|
||||
}
|
||||
|
||||
@@ -357,14 +361,18 @@ func (r *router) advertiseEvents() error {
|
||||
// routing table watcher
|
||||
w, err = r.Watch()
|
||||
if err != nil {
|
||||
log.Errorf("Error creating watcher: %v", err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("Error creating watcher: %v", err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.watchTable(w); err != nil {
|
||||
log.Errorf("Error watching table: %v", err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("Error watching table: %v", err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
@@ -391,7 +399,9 @@ func (r *router) advertiseEvents() error {
|
||||
for key, advert := range adverts {
|
||||
// process the advert
|
||||
if err := adverts.process(advert); err != nil {
|
||||
log.Debugf("Router failed processing advert %d: %v", key, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router failed processing advert %d: %v", key, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// if suppressed go to the next advert
|
||||
@@ -416,7 +426,9 @@ func (r *router) advertiseEvents() error {
|
||||
|
||||
// advertise events to subscribers
|
||||
if len(events) > 0 {
|
||||
log.Debugf("Router publishing %d events", len(events))
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router publishing %d events", len(events))
|
||||
}
|
||||
go r.publishAdvert(RouteUpdate, events)
|
||||
}
|
||||
case e := <-r.eventChan:
|
||||
@@ -437,7 +449,9 @@ func (r *router) advertiseEvents() error {
|
||||
|
||||
now := time.Now()
|
||||
|
||||
log.Debugf("Router processing table event %s for service %s %s", e.Type, e.Route.Service, e.Route.Address)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router processing table event %s for service %s %s", e.Type, e.Route.Service, e.Route.Address)
|
||||
}
|
||||
|
||||
// check if we have already registered the route
|
||||
hash := e.Route.Hash()
|
||||
@@ -459,7 +473,9 @@ func (r *router) advertiseEvents() error {
|
||||
|
||||
// process the advert
|
||||
if err := adverts.process(a); err != nil {
|
||||
log.Debugf("Router error processing advert %d: %v", hash, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router error processing advert %d: %v", hash, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -467,7 +483,9 @@ func (r *router) advertiseEvents() error {
|
||||
a.lastSeen = now
|
||||
// increment the penalty
|
||||
a.penalty += Penalty
|
||||
log.Debugf("Router advert %d for route %s %s event penalty: %f", hash, a.event.Route.Service, a.event.Route.Address, a.penalty)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router advert %d for route %s %s event penalty: %f", hash, a.event.Route.Service, a.event.Route.Address, a.penalty)
|
||||
}
|
||||
case <-r.exit:
|
||||
if w != nil {
|
||||
w.Stop()
|
||||
@@ -542,14 +560,18 @@ func (r *router) Start() error {
|
||||
if w == nil {
|
||||
w, err = r.options.Registry.Watch()
|
||||
if err != nil {
|
||||
log.Errorf("failed creating registry watcher: %v", err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("failed creating registry watcher: %v", err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.watchRegistry(w); err != nil {
|
||||
log.Errorf("Error watching the registry: %v", err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("Error watching the registry: %v", err)
|
||||
}
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
@@ -606,7 +628,9 @@ func (r *router) Advertise() (<-chan *Advert, error) {
|
||||
return
|
||||
default:
|
||||
if err := r.advertiseEvents(); err != nil {
|
||||
log.Errorf("Error adveritising events: %v", err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("Error adveritising events: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -626,19 +650,25 @@ func (r *router) Process(a *Advert) error {
|
||||
return events[i].Timestamp.Before(events[j].Timestamp)
|
||||
})
|
||||
|
||||
log.Tracef("Router %s processing advert from: %s", r.options.Id, a.Id)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Router %s processing advert from: %s", r.options.Id, a.Id)
|
||||
}
|
||||
|
||||
for _, event := range events {
|
||||
// skip if the router is the origin of this route
|
||||
if event.Route.Router == r.options.Id {
|
||||
log.Tracef("Router skipping processing its own route: %s", r.options.Id)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Router skipping processing its own route: %s", r.options.Id)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// create a copy of the route
|
||||
route := event.Route
|
||||
action := event.Type
|
||||
|
||||
log.Tracef("Router %s applying %s from router %s for service %s %s", r.options.Id, action, route.Router, route.Service, route.Address)
|
||||
if logger.V(logger.TraceLevel, logger.DefaultLogger) {
|
||||
logger.Tracef("Router %s applying %s from router %s for service %s %s", r.options.Id, action, route.Router, route.Service, route.Address)
|
||||
}
|
||||
|
||||
if err := r.manageRoute(route, action.String()); err != nil {
|
||||
return fmt.Errorf("failed applying action %s to routing table: %s", action, err)
|
||||
@@ -661,7 +691,9 @@ func (r *router) flushRouteEvents(evType EventType) ([]*Event, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("Router advertising %d routes with strategy %s", len(routes), r.options.Advertise)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router advertising %d routes with strategy %s", len(routes), r.options.Advertise)
|
||||
}
|
||||
|
||||
// build a list of events to advertise
|
||||
events := make([]*Event, len(routes))
|
||||
|
@@ -6,7 +6,6 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry/memory"
|
||||
)
|
||||
|
||||
@@ -30,7 +29,7 @@ func TestRouterStartStop(t *testing.T) {
|
||||
if err := r.Stop(); err != nil {
|
||||
t.Errorf("failed to stop router: %v", err)
|
||||
}
|
||||
log.Debugf("TestRouterStartStop STOPPED")
|
||||
t.Logf("TestRouterStartStop STOPPED")
|
||||
}
|
||||
|
||||
func TestRouterAdvertise(t *testing.T) {
|
||||
@@ -50,7 +49,7 @@ func TestRouterAdvertise(t *testing.T) {
|
||||
|
||||
// receive announce event
|
||||
ann := <-ch
|
||||
log.Debugf("received announce advert: %v", ann)
|
||||
t.Logf("received announce advert: %v", ann)
|
||||
|
||||
// Generate random unique routes
|
||||
nrRoutes := 5
|
||||
@@ -82,9 +81,9 @@ func TestRouterAdvertise(t *testing.T) {
|
||||
wg.Done()
|
||||
defer close(createDone)
|
||||
for _, route := range routes {
|
||||
log.Debugf("Creating route %v", route)
|
||||
t.Logf("Creating route %v", route)
|
||||
if err := r.Table().Create(route); err != nil {
|
||||
log.Debugf("Failed to create route: %v", err)
|
||||
t.Logf("Failed to create route: %v", err)
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
@@ -106,7 +105,7 @@ func TestRouterAdvertise(t *testing.T) {
|
||||
t.Errorf("failed advertising events: %v", advertErr)
|
||||
default:
|
||||
// do nothing for now
|
||||
log.Debugf("Router advert received: %v", advert)
|
||||
t.Logf("Router advert received: %v", advert)
|
||||
adverts += len(advert.Events)
|
||||
}
|
||||
return
|
||||
|
@@ -6,7 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -68,7 +68,9 @@ func (t *table) Create(r Route) error {
|
||||
// add new route to the table for the route destination
|
||||
if _, ok := t.routes[service][sum]; !ok {
|
||||
t.routes[service][sum] = r
|
||||
log.Debugf("Router emitting %s for route: %s", Create, r.Address)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router emitting %s for route: %s", Create, r.Address)
|
||||
}
|
||||
go t.sendEvent(&Event{Type: Create, Timestamp: time.Now(), Route: r})
|
||||
return nil
|
||||
}
|
||||
@@ -93,7 +95,9 @@ func (t *table) Delete(r Route) error {
|
||||
}
|
||||
|
||||
delete(t.routes[service], sum)
|
||||
log.Debugf("Router emitting %s for route: %s", Delete, r.Address)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router emitting %s for route: %s", Delete, r.Address)
|
||||
}
|
||||
go t.sendEvent(&Event{Type: Delete, Timestamp: time.Now(), Route: r})
|
||||
|
||||
return nil
|
||||
@@ -114,7 +118,9 @@ func (t *table) Update(r Route) error {
|
||||
|
||||
if _, ok := t.routes[service][sum]; !ok {
|
||||
t.routes[service][sum] = r
|
||||
log.Debugf("Router emitting %s for route: %s", Update, r.Address)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router emitting %s for route: %s", Update, r.Address)
|
||||
}
|
||||
go t.sendEvent(&Event{Type: Update, Timestamp: time.Now(), Route: r})
|
||||
return nil
|
||||
}
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
type runtime struct {
|
||||
@@ -71,7 +71,9 @@ func (r *runtime) run(events <-chan Event) {
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Debugf("Runtime updating service %s", name)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime updating service %s", name)
|
||||
}
|
||||
|
||||
// this will cause a delete followed by created
|
||||
if err := r.Update(service.Service); err != nil {
|
||||
@@ -97,9 +99,13 @@ func (r *runtime) run(events <-chan Event) {
|
||||
}
|
||||
|
||||
// TODO: check service error
|
||||
log.Debugf("Runtime starting %s", service.Name)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime starting %s", service.Name)
|
||||
}
|
||||
if err := service.Start(); err != nil {
|
||||
log.Debugf("Runtime error starting %s: %v", service.Name, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime error starting %s: %v", service.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
r.RUnlock()
|
||||
@@ -108,12 +114,18 @@ func (r *runtime) run(events <-chan Event) {
|
||||
continue
|
||||
}
|
||||
// TODO: check service error
|
||||
log.Debugf("Runtime starting service %s", service.Name)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime starting service %s", service.Name)
|
||||
}
|
||||
if err := service.Start(); err != nil {
|
||||
log.Debugf("Runtime error starting service %s: %v", service.Name, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime error starting service %s: %v", service.Name, err)
|
||||
}
|
||||
}
|
||||
case event := <-events:
|
||||
log.Debugf("Runtime received notification event: %v", event)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime received notification event: %v", event)
|
||||
}
|
||||
// NOTE: we only handle Update events for now
|
||||
switch event.Type {
|
||||
case Update:
|
||||
@@ -122,11 +134,15 @@ func (r *runtime) run(events <-chan Event) {
|
||||
service, ok := r.services[event.Service]
|
||||
r.RUnlock()
|
||||
if !ok {
|
||||
log.Debugf("Runtime unknown service: %s", event.Service)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime unknown service: %s", event.Service)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if err := processEvent(event, service); err != nil {
|
||||
log.Debugf("Runtime error updating service %s: %v", event.Service, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime error updating service %s: %v", event.Service, err)
|
||||
}
|
||||
}
|
||||
continue
|
||||
}
|
||||
@@ -138,12 +154,16 @@ func (r *runtime) run(events <-chan Event) {
|
||||
// if blank service was received we update all services
|
||||
for _, service := range services {
|
||||
if err := processEvent(event, service); err != nil {
|
||||
log.Debugf("Runtime error updating service %s: %v", service.Name, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime error updating service %s: %v", service.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-r.closed:
|
||||
log.Debugf("Runtime stopped")
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime stopped")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -164,7 +184,8 @@ func (r *runtime) Create(s *Service, opts ...CreateOption) error {
|
||||
}
|
||||
|
||||
if len(options.Command) == 0 {
|
||||
options.Command = []string{"go", "run", "."}
|
||||
options.Command = []string{"go", "run"}
|
||||
options.Args = []string{"."}
|
||||
}
|
||||
|
||||
// create new service
|
||||
@@ -242,7 +263,9 @@ func (r *runtime) Delete(s *Service) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
log.Debugf("Runtime deleting service %s", s.Name)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime deleting service %s", s.Name)
|
||||
}
|
||||
if s, ok := r.services[s.Name]; ok {
|
||||
// check if running
|
||||
if s.Running() {
|
||||
@@ -295,7 +318,9 @@ func (r *runtime) Start() error {
|
||||
events, err = r.options.Scheduler.Notify()
|
||||
if err != nil {
|
||||
// TODO: should we bail here?
|
||||
log.Debugf("Runtime failed to start update notifier")
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime failed to start update notifier")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +349,9 @@ func (r *runtime) Stop() error {
|
||||
|
||||
// stop all the services
|
||||
for _, service := range r.services {
|
||||
log.Debugf("Runtime stopping %s", service.Name)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime stopping %s", service.Name)
|
||||
}
|
||||
service.Stop()
|
||||
}
|
||||
// stop the scheduler
|
||||
|
@@ -2,12 +2,10 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/runtime"
|
||||
"github.com/micro/go-micro/v2/util/kubernetes/client"
|
||||
)
|
||||
@@ -29,7 +27,7 @@ type kubernetes struct {
|
||||
|
||||
// getService queries kubernetes for micro service
|
||||
// NOTE: this function is not thread-safe
|
||||
func (k *kubernetes) getService(labels map[string]string) ([]*runtime.Service, error) {
|
||||
func (k *kubernetes) getService(labels map[string]string) ([]*service, error) {
|
||||
// get the service status
|
||||
serviceList := new(client.ServiceList)
|
||||
r := &client.Resource{
|
||||
@@ -48,14 +46,22 @@ func (k *kubernetes) getService(labels map[string]string) ([]*runtime.Service, e
|
||||
Kind: "deployment",
|
||||
Value: depList,
|
||||
}
|
||||
|
||||
// get the deployment from k8s
|
||||
if err := k.client.Get(d, labels); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// get the pods from k8s
|
||||
podList := new(client.PodList)
|
||||
p := &client.Resource{
|
||||
Kind: "pod",
|
||||
Value: podList,
|
||||
}
|
||||
if err := k.client.Get(p, labels); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// service map
|
||||
svcMap := make(map[string]*runtime.Service)
|
||||
svcMap := make(map[string]*service)
|
||||
|
||||
// collect info from kubernetes service
|
||||
for _, kservice := range serviceList.Items {
|
||||
@@ -65,15 +71,18 @@ func (k *kubernetes) getService(labels map[string]string) ([]*runtime.Service, e
|
||||
version := kservice.Metadata.Labels["version"]
|
||||
|
||||
// save as service
|
||||
svcMap[name+version] = &runtime.Service{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Metadata: make(map[string]string),
|
||||
svcMap[name+version] = &service{
|
||||
Service: &runtime.Service{
|
||||
Name: name,
|
||||
Version: version,
|
||||
Metadata: make(map[string]string),
|
||||
},
|
||||
kservice: &kservice,
|
||||
}
|
||||
|
||||
// copy annotations metadata into service metadata
|
||||
for k, v := range kservice.Metadata.Annotations {
|
||||
svcMap[name+version].Metadata[k] = v
|
||||
svcMap[name+version].Service.Metadata[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,9 +102,9 @@ func (k *kubernetes) getService(labels map[string]string) ([]*runtime.Service, e
|
||||
|
||||
// set the service name, version and source
|
||||
// based on existing annotations we stored
|
||||
svc.Name = kdep.Metadata.Annotations["name"]
|
||||
svc.Version = kdep.Metadata.Annotations["version"]
|
||||
svc.Source = kdep.Metadata.Annotations["source"]
|
||||
svc.Service.Name = kdep.Metadata.Annotations["name"]
|
||||
svc.Service.Version = kdep.Metadata.Annotations["version"]
|
||||
svc.Service.Source = kdep.Metadata.Annotations["source"]
|
||||
|
||||
// delete from metadata
|
||||
delete(kdep.Metadata.Annotations, "name")
|
||||
@@ -104,45 +113,37 @@ func (k *kubernetes) getService(labels map[string]string) ([]*runtime.Service, e
|
||||
|
||||
// copy all annotations metadata into service metadata
|
||||
for k, v := range kdep.Metadata.Annotations {
|
||||
svc.Metadata[k] = v
|
||||
svc.Service.Metadata[k] = v
|
||||
}
|
||||
|
||||
// parse out deployment status and inject into service metadata
|
||||
if len(kdep.Status.Conditions) > 0 {
|
||||
var status string
|
||||
switch kdep.Status.Conditions[0].Type {
|
||||
case "Available":
|
||||
status = "running"
|
||||
delete(svc.Metadata, "error")
|
||||
case "Progressing":
|
||||
status = "starting"
|
||||
delete(svc.Metadata, "error")
|
||||
// get the status from the pods
|
||||
var status string
|
||||
|
||||
for _, item := range podList.Items {
|
||||
switch item.Status.Phase {
|
||||
case "Failed":
|
||||
status = item.Status.Reason
|
||||
default:
|
||||
status = "error"
|
||||
svc.Metadata["error"] = kdep.Status.Conditions[0].Message
|
||||
status = item.Status.Phase
|
||||
}
|
||||
// pick the last known condition type and mark the service status with it
|
||||
log.Debugf("Runtime setting %s service deployment status: %v", name, status)
|
||||
svc.Metadata["status"] = status
|
||||
}
|
||||
|
||||
// parse out deployment build
|
||||
if build, ok := kdep.Spec.Template.Metadata.Annotations["build"]; ok {
|
||||
buildTime, err := time.Parse(time.RFC3339, build)
|
||||
if err != nil {
|
||||
log.Debugf("Runtime failed parsing build time for %s: %v", name, err)
|
||||
continue
|
||||
}
|
||||
svc.Metadata["build"] = fmt.Sprintf("%d", buildTime.Unix())
|
||||
continue
|
||||
// unknown status
|
||||
if len(status) == 0 {
|
||||
status = "n/a"
|
||||
}
|
||||
// if no build annotation is found, set it to current time
|
||||
svc.Metadata["build"] = fmt.Sprintf("%d", time.Now().Unix())
|
||||
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime setting %s service deployment status: %v", name, status)
|
||||
}
|
||||
svc.Service.Metadata["status"] = status
|
||||
// save deployment
|
||||
svc.kdeploy = &kdep
|
||||
}
|
||||
}
|
||||
|
||||
// collect all the services and return
|
||||
services := make([]*runtime.Service, 0, len(serviceList.Items))
|
||||
services := make([]*service, 0, len(serviceList.Items))
|
||||
|
||||
for _, service := range svcMap {
|
||||
services = append(services, service)
|
||||
@@ -163,7 +164,9 @@ func (k *kubernetes) run(events <-chan runtime.Event) {
|
||||
// - do we even need the ticker for k8s services?
|
||||
case event := <-events:
|
||||
// NOTE: we only handle Update events for now
|
||||
log.Debugf("Runtime received notification event: %v", event)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime received notification event: %v", event)
|
||||
}
|
||||
switch event.Type {
|
||||
case runtime.Update:
|
||||
// only process if there's an actual service
|
||||
@@ -195,7 +198,9 @@ func (k *kubernetes) run(events <-chan runtime.Event) {
|
||||
}, labels)
|
||||
|
||||
if err != nil {
|
||||
log.Debugf("Runtime update failed to get service %s: %v", event.Service, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime update failed to get service %s: %v", event.Service, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -222,16 +227,21 @@ func (k *kubernetes) run(events <-chan runtime.Event) {
|
||||
|
||||
// update the build time
|
||||
service.Spec.Template.Metadata.Annotations["build"] = event.Timestamp.Format(time.RFC3339)
|
||||
|
||||
log.Debugf("Runtime updating service: %s deployment: %s", event.Service, service.Metadata.Name)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime updating service: %s deployment: %s", event.Service, service.Metadata.Name)
|
||||
}
|
||||
if err := k.client.Update(deploymentResource(&service)); err != nil {
|
||||
log.Debugf("Runtime failed to update service %s: %v", event.Service, err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime failed to update service %s: %v", event.Service, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
case <-k.closed:
|
||||
log.Debugf("Runtime stopped")
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime stopped")
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -246,11 +256,6 @@ func (k *kubernetes) Init(opts ...runtime.Option) error {
|
||||
o(&k.options)
|
||||
}
|
||||
|
||||
// trim the source prefix if its a git url
|
||||
if strings.HasPrefix(k.options.Source, "github.com") {
|
||||
k.options.Source = strings.TrimPrefix(k.options.Source, "github.com/")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -266,14 +271,20 @@ func (k *kubernetes) Create(s *runtime.Service, opts ...runtime.CreateOption) er
|
||||
o(&options)
|
||||
}
|
||||
|
||||
// hackish
|
||||
// default type if it doesn't exist
|
||||
if len(options.Type) == 0 {
|
||||
options.Type = k.options.Type
|
||||
}
|
||||
|
||||
// determine the full source for this service
|
||||
options.Source = k.sourceForService(s.Name)
|
||||
// default the source if it doesn't exist
|
||||
if len(s.Source) == 0 {
|
||||
s.Source = k.options.Source
|
||||
}
|
||||
|
||||
// determine the image from the source and options
|
||||
options.Image = k.getImage(s, options)
|
||||
|
||||
// create new service
|
||||
service := newService(s, options)
|
||||
|
||||
// start the service
|
||||
@@ -308,7 +319,17 @@ func (k *kubernetes) Read(opts ...runtime.ReadOption) ([]*runtime.Service, error
|
||||
labels["micro"] = options.Type
|
||||
}
|
||||
|
||||
return k.getService(labels)
|
||||
srvs, err := k.getService(labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var services []*runtime.Service
|
||||
for _, service := range srvs {
|
||||
services = append(services, service.Service)
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
// List the managed services
|
||||
@@ -320,23 +341,68 @@ func (k *kubernetes) List() ([]*runtime.Service, error) {
|
||||
"micro": k.options.Type,
|
||||
}
|
||||
|
||||
log.Debugf("Runtime listing all micro services")
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime listing all micro services")
|
||||
}
|
||||
|
||||
return k.getService(labels)
|
||||
srvs, err := k.getService(labels)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var services []*runtime.Service
|
||||
for _, service := range srvs {
|
||||
services = append(services, service.Service)
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
|
||||
// Update the service in place
|
||||
func (k *kubernetes) Update(s *runtime.Service) error {
|
||||
// create new kubernetes micro service
|
||||
service := newService(s, runtime.CreateOptions{
|
||||
Type: k.options.Type,
|
||||
Source: k.sourceForService(s.Name),
|
||||
})
|
||||
// get the existing service
|
||||
// set the default labels
|
||||
labels := map[string]string{
|
||||
"micro": k.options.Type,
|
||||
}
|
||||
|
||||
// update build time annotation
|
||||
service.kdeploy.Spec.Template.Metadata.Annotations["build"] = time.Now().Format(time.RFC3339)
|
||||
if len(s.Name) > 0 {
|
||||
labels["name"] = client.Format(s.Name)
|
||||
}
|
||||
|
||||
return service.Update(k.client)
|
||||
if len(s.Version) > 0 {
|
||||
labels["version"] = s.Version
|
||||
}
|
||||
|
||||
// get the existing service
|
||||
services, err := k.getService(labels)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update the relevant services
|
||||
for _, service := range services {
|
||||
// nil check
|
||||
if service.kdeploy.Metadata == nil || service.kdeploy.Metadata.Annotations == nil {
|
||||
md := new(client.Metadata)
|
||||
md.Annotations = make(map[string]string)
|
||||
service.kdeploy.Metadata = md
|
||||
}
|
||||
|
||||
// update metadata
|
||||
for k, v := range s.Metadata {
|
||||
service.kdeploy.Metadata.Annotations[k] = v
|
||||
}
|
||||
// update build time annotation
|
||||
service.kdeploy.Spec.Template.Metadata.Annotations["build"] = time.Now().Format(time.RFC3339)
|
||||
|
||||
// update the service
|
||||
if err := service.Update(k.client); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete removes a service
|
||||
@@ -372,7 +438,9 @@ func (k *kubernetes) Start() error {
|
||||
events, err = k.options.Scheduler.Notify()
|
||||
if err != nil {
|
||||
// TODO: should we bail here?
|
||||
log.Debugf("Runtime failed to start update notifier")
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime failed to start update notifier")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -434,14 +502,15 @@ func NewRuntime(opts ...runtime.Option) runtime.Runtime {
|
||||
}
|
||||
}
|
||||
|
||||
// sourceForService determines the nested package name for github
|
||||
// e.g src: docker.pkg.github.com/micro/services an srv: users/api
|
||||
// would become docker.pkg.github.com/micro/services/users-api
|
||||
func (k *kubernetes) sourceForService(name string) string {
|
||||
if !strings.HasPrefix(k.options.Source, "docker.pkg.github.com") {
|
||||
return k.options.Source
|
||||
func (k *kubernetes) getImage(s *runtime.Service, options runtime.CreateOptions) string {
|
||||
// use the image when its specified
|
||||
if len(options.Image) > 0 {
|
||||
return options.Image
|
||||
}
|
||||
|
||||
formattedName := strings.ReplaceAll(name, "/", "-")
|
||||
return fmt.Sprintf("%v/%v", k.options.Source, formattedName)
|
||||
if len(k.options.Image) > 0 {
|
||||
return k.options.Image
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
@@ -3,9 +3,8 @@ package kubernetes
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/runtime"
|
||||
"github.com/micro/go-micro/v2/util/kubernetes/api"
|
||||
"github.com/micro/go-micro/v2/util/kubernetes/client"
|
||||
@@ -34,12 +33,20 @@ func newService(s *runtime.Service, c runtime.CreateOptions) *service {
|
||||
kservice := client.NewService(name, version, c.Type)
|
||||
kdeploy := client.NewDeployment(name, version, c.Type)
|
||||
|
||||
if len(c.Source) > 0 {
|
||||
for i := range kdeploy.Spec.Template.PodSpec.Containers {
|
||||
kdeploy.Spec.Template.PodSpec.Containers[i].Image = c.Source
|
||||
kdeploy.Spec.Template.PodSpec.Containers[i].Command = []string{}
|
||||
kdeploy.Spec.Template.PodSpec.Containers[i].Args = []string{name}
|
||||
}
|
||||
// ensure the metadata is set
|
||||
if kdeploy.Spec.Template.Metadata.Annotations == nil {
|
||||
kdeploy.Spec.Template.Metadata.Annotations = make(map[string]string)
|
||||
}
|
||||
|
||||
// create if non existent
|
||||
if s.Metadata == nil {
|
||||
s.Metadata = make(map[string]string)
|
||||
}
|
||||
|
||||
// add the service metadata to the k8s labels, do this first so we
|
||||
// don't override any labels used by the runtime, e.g. name
|
||||
for k, v := range s.Metadata {
|
||||
kdeploy.Metadata.Annotations[k] = v
|
||||
}
|
||||
|
||||
// attach our values to the deployment; name, version, source
|
||||
@@ -51,11 +58,14 @@ func newService(s *runtime.Service, c runtime.CreateOptions) *service {
|
||||
kdeploy.Metadata.Annotations["owner"] = "micro"
|
||||
kdeploy.Metadata.Annotations["group"] = "micro"
|
||||
|
||||
// set a build timestamp to the current time
|
||||
if kdeploy.Spec.Template.Metadata.Annotations == nil {
|
||||
kdeploy.Spec.Template.Metadata.Annotations = make(map[string]string)
|
||||
// update the deployment is a custom source is provided
|
||||
if len(c.Image) > 0 {
|
||||
for i := range kdeploy.Spec.Template.PodSpec.Containers {
|
||||
kdeploy.Spec.Template.PodSpec.Containers[i].Image = c.Image
|
||||
kdeploy.Spec.Template.PodSpec.Containers[i].Command = []string{}
|
||||
kdeploy.Spec.Template.PodSpec.Containers[i].Args = []string{}
|
||||
}
|
||||
}
|
||||
kdeploy.Spec.Template.Metadata.Annotations["build"] = time.Now().Format(time.RFC3339)
|
||||
|
||||
// define the environment values used by the container
|
||||
env := make([]client.EnvVar, 0, len(c.Env))
|
||||
@@ -69,11 +79,15 @@ func newService(s *runtime.Service, c runtime.CreateOptions) *service {
|
||||
kdeploy.Spec.Template.PodSpec.Containers[0].Env = append(kdeploy.Spec.Template.PodSpec.Containers[0].Env, env...)
|
||||
}
|
||||
|
||||
// specify the command to exec
|
||||
// set the command if specified
|
||||
if len(c.Command) > 0 {
|
||||
kdeploy.Spec.Template.PodSpec.Containers[0].Command = c.Command
|
||||
}
|
||||
|
||||
if len(c.Args) > 0 {
|
||||
kdeploy.Spec.Template.PodSpec.Containers[0].Args = c.Args
|
||||
}
|
||||
|
||||
return &service{
|
||||
Service: s,
|
||||
kservice: kservice,
|
||||
@@ -101,7 +115,9 @@ func serviceResource(s *client.Service) *client.Resource {
|
||||
func (s *service) Start(k client.Client) error {
|
||||
// create deployment first; if we fail, we dont create service
|
||||
if err := k.Create(deploymentResource(s.kdeploy)); err != nil {
|
||||
log.Debugf("Runtime failed to create deployment: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime failed to create deployment: %v", err)
|
||||
}
|
||||
s.Status("error", err)
|
||||
v := parseError(err)
|
||||
if v.Reason == "AlreadyExists" {
|
||||
@@ -111,7 +127,9 @@ func (s *service) Start(k client.Client) error {
|
||||
}
|
||||
// create service now that the deployment has been created
|
||||
if err := k.Create(serviceResource(s.kservice)); err != nil {
|
||||
log.Debugf("Runtime failed to create service: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime failed to create service: %v", err)
|
||||
}
|
||||
s.Status("error", err)
|
||||
v := parseError(err)
|
||||
if v.Reason == "AlreadyExists" {
|
||||
@@ -128,13 +146,17 @@ func (s *service) Start(k client.Client) error {
|
||||
func (s *service) Stop(k client.Client) error {
|
||||
// first attempt to delete service
|
||||
if err := k.Delete(serviceResource(s.kservice)); err != nil {
|
||||
log.Debugf("Runtime failed to delete service: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime failed to delete service: %v", err)
|
||||
}
|
||||
s.Status("error", err)
|
||||
return err
|
||||
}
|
||||
// delete deployment once the service has been deleted
|
||||
if err := k.Delete(deploymentResource(s.kdeploy)); err != nil {
|
||||
log.Debugf("Runtime failed to delete deployment: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime failed to delete deployment: %v", err)
|
||||
}
|
||||
s.Status("error", err)
|
||||
return err
|
||||
}
|
||||
@@ -146,12 +168,16 @@ func (s *service) Stop(k client.Client) error {
|
||||
|
||||
func (s *service) Update(k client.Client) error {
|
||||
if err := k.Update(deploymentResource(s.kdeploy)); err != nil {
|
||||
log.Debugf("Runtime failed to update deployment: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime failed to update deployment: %v", err)
|
||||
}
|
||||
s.Status("error", err)
|
||||
return err
|
||||
}
|
||||
if err := k.Update(serviceResource(s.kservice)); err != nil {
|
||||
log.Debugf("Runtime failed to update service: %v", err)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime failed to update service: %v", err)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
@@ -9,7 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/runtime/local/build"
|
||||
)
|
||||
|
||||
@@ -84,7 +84,7 @@ func NewBuilder(opts ...build.Option) build.Builder {
|
||||
endpoint := "unix:///var/run/docker.sock"
|
||||
client, err := docker.NewClient(endpoint)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
logger.Fatal(err)
|
||||
}
|
||||
return &Builder{
|
||||
Options: options,
|
||||
|
@@ -14,6 +14,8 @@ type Options struct {
|
||||
Type string
|
||||
// Source of the services repository
|
||||
Source string
|
||||
// Base image to use
|
||||
Image string
|
||||
}
|
||||
|
||||
// WithSource sets the base image / repository
|
||||
@@ -37,14 +39,23 @@ func WithType(t string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithImage sets the image to use
|
||||
func WithImage(t string) Option {
|
||||
return func(o *Options) {
|
||||
o.Image = t
|
||||
}
|
||||
}
|
||||
|
||||
type CreateOption func(o *CreateOptions)
|
||||
|
||||
type ReadOption func(o *ReadOptions)
|
||||
|
||||
// CreateOptions configure runtime services
|
||||
type CreateOptions struct {
|
||||
// command to execute including args
|
||||
// Command to execut
|
||||
Command []string
|
||||
// Args to pass into command
|
||||
Args []string
|
||||
// Environment to configure
|
||||
Env []string
|
||||
// Log output
|
||||
@@ -53,8 +64,8 @@ type CreateOptions struct {
|
||||
Type string
|
||||
// Retries before failing deploy
|
||||
Retries int
|
||||
// Source of the service
|
||||
Source string
|
||||
// Specify the image to use
|
||||
Image string
|
||||
}
|
||||
|
||||
// ReadOptions queries runtime services
|
||||
@@ -74,18 +85,26 @@ func CreateType(t string) CreateOption {
|
||||
}
|
||||
}
|
||||
|
||||
// CreateSource sets the source of service to create
|
||||
func CreateSource(t string) CreateOption {
|
||||
// CreateImage sets the image to use
|
||||
func CreateImage(img string) CreateOption {
|
||||
return func(o *CreateOptions) {
|
||||
o.Source = t
|
||||
o.Image = img
|
||||
}
|
||||
}
|
||||
|
||||
// WithCommand specifies the command to execute
|
||||
func WithCommand(args ...string) CreateOption {
|
||||
func WithCommand(cmd ...string) CreateOption {
|
||||
return func(o *CreateOptions) {
|
||||
// set command
|
||||
o.Command = args
|
||||
o.Command = cmd
|
||||
}
|
||||
}
|
||||
|
||||
// WithArgs specifies the command to execute
|
||||
func WithArgs(args ...string) CreateOption {
|
||||
return func(o *CreateOptions) {
|
||||
// set command
|
||||
o.Args = args
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,10 +3,11 @@ package runtime
|
||||
import (
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/runtime/local/build"
|
||||
"github.com/micro/go-micro/v2/runtime/local/process"
|
||||
proc "github.com/micro/go-micro/v2/runtime/local/process/os"
|
||||
@@ -41,11 +42,8 @@ func newService(s *Service, c CreateOptions) *service {
|
||||
var args []string
|
||||
|
||||
// set command
|
||||
exec = c.Command[0]
|
||||
// set args
|
||||
if len(c.Command) > 1 {
|
||||
args = c.Command[1:]
|
||||
}
|
||||
exec = strings.Join(c.Command, " ")
|
||||
args = c.Args
|
||||
|
||||
return &service{
|
||||
Service: s,
|
||||
@@ -111,7 +109,9 @@ func (s *service) Start() error {
|
||||
delete(s.Metadata, "error")
|
||||
|
||||
// TODO: pull source & build binary
|
||||
log.Debugf("Runtime service %s forking new process", s.Service.Name)
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime service %s forking new process", s.Service.Name)
|
||||
}
|
||||
p, err := s.Process.Fork(s.Exec)
|
||||
if err != nil {
|
||||
s.Metadata["status"] = "error"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: runtime/service/proto/runtime.proto
|
||||
// source: github.com/micro/go-micro/runtime/service/proto/runtime.proto
|
||||
|
||||
package go_micro_runtime
|
||||
|
||||
@@ -38,7 +38,7 @@ func (m *Service) Reset() { *m = Service{} }
|
||||
func (m *Service) String() string { return proto.CompactTextString(m) }
|
||||
func (*Service) ProtoMessage() {}
|
||||
func (*Service) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{0}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{0}
|
||||
}
|
||||
|
||||
func (m *Service) XXX_Unmarshal(b []byte) error {
|
||||
@@ -101,7 +101,7 @@ func (m *Event) Reset() { *m = Event{} }
|
||||
func (m *Event) String() string { return proto.CompactTextString(m) }
|
||||
func (*Event) ProtoMessage() {}
|
||||
func (*Event) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{1}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{1}
|
||||
}
|
||||
|
||||
func (m *Event) XXX_Unmarshal(b []byte) error {
|
||||
@@ -153,10 +153,16 @@ func (m *Event) GetVersion() string {
|
||||
type CreateOptions struct {
|
||||
// command to pass in
|
||||
Command []string `protobuf:"bytes,1,rep,name=command,proto3" json:"command,omitempty"`
|
||||
// args to pass into command
|
||||
Args []string `protobuf:"bytes,2,rep,name=args,proto3" json:"args,omitempty"`
|
||||
// environment to pass in
|
||||
Env []string `protobuf:"bytes,2,rep,name=env,proto3" json:"env,omitempty"`
|
||||
Env []string `protobuf:"bytes,3,rep,name=env,proto3" json:"env,omitempty"`
|
||||
// output to send to
|
||||
Output string `protobuf:"bytes,3,opt,name=output,proto3" json:"output,omitempty"`
|
||||
Output string `protobuf:"bytes,4,opt,name=output,proto3" json:"output,omitempty"`
|
||||
// create type of service
|
||||
Type string `protobuf:"bytes,5,opt,name=type,proto3" json:"type,omitempty"`
|
||||
// image to use
|
||||
Image string `protobuf:"bytes,6,opt,name=image,proto3" json:"image,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -166,7 +172,7 @@ func (m *CreateOptions) Reset() { *m = CreateOptions{} }
|
||||
func (m *CreateOptions) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateOptions) ProtoMessage() {}
|
||||
func (*CreateOptions) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{2}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{2}
|
||||
}
|
||||
|
||||
func (m *CreateOptions) XXX_Unmarshal(b []byte) error {
|
||||
@@ -194,6 +200,13 @@ func (m *CreateOptions) GetCommand() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *CreateOptions) GetArgs() []string {
|
||||
if m != nil {
|
||||
return m.Args
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *CreateOptions) GetEnv() []string {
|
||||
if m != nil {
|
||||
return m.Env
|
||||
@@ -208,6 +221,20 @@ func (m *CreateOptions) GetOutput() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *CreateOptions) GetType() string {
|
||||
if m != nil {
|
||||
return m.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *CreateOptions) GetImage() string {
|
||||
if m != nil {
|
||||
return m.Image
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type CreateRequest struct {
|
||||
Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
Options *CreateOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"`
|
||||
@@ -220,7 +247,7 @@ func (m *CreateRequest) Reset() { *m = CreateRequest{} }
|
||||
func (m *CreateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateRequest) ProtoMessage() {}
|
||||
func (*CreateRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{3}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{3}
|
||||
}
|
||||
|
||||
func (m *CreateRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -265,7 +292,7 @@ func (m *CreateResponse) Reset() { *m = CreateResponse{} }
|
||||
func (m *CreateResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*CreateResponse) ProtoMessage() {}
|
||||
func (*CreateResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{4}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{4}
|
||||
}
|
||||
|
||||
func (m *CreateResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -302,7 +329,7 @@ func (m *ReadOptions) Reset() { *m = ReadOptions{} }
|
||||
func (m *ReadOptions) String() string { return proto.CompactTextString(m) }
|
||||
func (*ReadOptions) ProtoMessage() {}
|
||||
func (*ReadOptions) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{5}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{5}
|
||||
}
|
||||
|
||||
func (m *ReadOptions) XXX_Unmarshal(b []byte) error {
|
||||
@@ -355,7 +382,7 @@ func (m *ReadRequest) Reset() { *m = ReadRequest{} }
|
||||
func (m *ReadRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ReadRequest) ProtoMessage() {}
|
||||
func (*ReadRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{6}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{6}
|
||||
}
|
||||
|
||||
func (m *ReadRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -394,7 +421,7 @@ func (m *ReadResponse) Reset() { *m = ReadResponse{} }
|
||||
func (m *ReadResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ReadResponse) ProtoMessage() {}
|
||||
func (*ReadResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{7}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{7}
|
||||
}
|
||||
|
||||
func (m *ReadResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -433,7 +460,7 @@ func (m *DeleteRequest) Reset() { *m = DeleteRequest{} }
|
||||
func (m *DeleteRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteRequest) ProtoMessage() {}
|
||||
func (*DeleteRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{8}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{8}
|
||||
}
|
||||
|
||||
func (m *DeleteRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -471,7 +498,7 @@ func (m *DeleteResponse) Reset() { *m = DeleteResponse{} }
|
||||
func (m *DeleteResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteResponse) ProtoMessage() {}
|
||||
func (*DeleteResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{9}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{9}
|
||||
}
|
||||
|
||||
func (m *DeleteResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -503,7 +530,7 @@ func (m *UpdateRequest) Reset() { *m = UpdateRequest{} }
|
||||
func (m *UpdateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateRequest) ProtoMessage() {}
|
||||
func (*UpdateRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{10}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{10}
|
||||
}
|
||||
|
||||
func (m *UpdateRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -541,7 +568,7 @@ func (m *UpdateResponse) Reset() { *m = UpdateResponse{} }
|
||||
func (m *UpdateResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateResponse) ProtoMessage() {}
|
||||
func (*UpdateResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{11}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{11}
|
||||
}
|
||||
|
||||
func (m *UpdateResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -572,7 +599,7 @@ func (m *ListRequest) Reset() { *m = ListRequest{} }
|
||||
func (m *ListRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListRequest) ProtoMessage() {}
|
||||
func (*ListRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{12}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{12}
|
||||
}
|
||||
|
||||
func (m *ListRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -604,7 +631,7 @@ func (m *ListResponse) Reset() { *m = ListResponse{} }
|
||||
func (m *ListResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListResponse) ProtoMessage() {}
|
||||
func (*ListResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{13}
|
||||
return fileDescriptor_976fccef828ab1f0, []int{13}
|
||||
}
|
||||
|
||||
func (m *ListResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -651,42 +678,45 @@ func init() {
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("runtime/service/proto/runtime.proto", fileDescriptor_2434d8152598889b)
|
||||
proto.RegisterFile("github.com/micro/go-micro/runtime/service/proto/runtime.proto", fileDescriptor_976fccef828ab1f0)
|
||||
}
|
||||
|
||||
var fileDescriptor_2434d8152598889b = []byte{
|
||||
// 521 bytes of a gzipped FileDescriptorProto
|
||||
var fileDescriptor_976fccef828ab1f0 = []byte{
|
||||
// 563 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0x4b, 0x6f, 0xd3, 0x40,
|
||||
0x10, 0xae, 0xeb, 0x34, 0x69, 0xc7, 0x18, 0x45, 0x2b, 0x84, 0x4c, 0xc5, 0x23, 0x32, 0x07, 0x7a,
|
||||
0x72, 0xa4, 0x54, 0x88, 0xd7, 0xb1, 0x09, 0x5c, 0x88, 0x90, 0x5c, 0xf5, 0x07, 0x2c, 0xc9, 0x08,
|
||||
0x59, 0xd4, 0xbb, 0xc6, 0xbb, 0xb6, 0x94, 0x13, 0x57, 0xfe, 0x1e, 0xff, 0x08, 0xed, 0x2b, 0xb6,
|
||||
0x53, 0x9b, 0x4b, 0x6e, 0x3b, 0xb3, 0x33, 0x9f, 0xbf, 0xc7, 0xca, 0xf0, 0xba, 0xac, 0x98, 0xcc,
|
||||
0x72, 0x9c, 0x0b, 0x2c, 0xeb, 0x6c, 0x83, 0xf3, 0xa2, 0xe4, 0x92, 0xcf, 0x6d, 0x37, 0xd1, 0x15,
|
||||
0x99, 0xfe, 0xe0, 0x49, 0x9e, 0x6d, 0x4a, 0x9e, 0xd8, 0x7e, 0xfc, 0xd7, 0x83, 0xc9, 0xad, 0xd9,
|
||||
0x20, 0x04, 0x46, 0x8c, 0xe6, 0x18, 0x79, 0x33, 0xef, 0xea, 0x22, 0xd5, 0x67, 0x12, 0xc1, 0xa4,
|
||||
0xc6, 0x52, 0x64, 0x9c, 0x45, 0xa7, 0xba, 0xed, 0x4a, 0xf2, 0x14, 0xc6, 0x82, 0x57, 0xe5, 0x06,
|
||||
0x23, 0x5f, 0x5f, 0xd8, 0x8a, 0xdc, 0xc0, 0x79, 0x8e, 0x92, 0x6e, 0xa9, 0xa4, 0xd1, 0x68, 0xe6,
|
||||
0x5f, 0x05, 0x8b, 0x37, 0xc9, 0xe1, 0x67, 0x13, 0xfb, 0xc9, 0x64, 0x6d, 0x27, 0x57, 0x4c, 0x96,
|
||||
0xbb, 0x74, 0xbf, 0x78, 0xf9, 0x09, 0xc2, 0xce, 0x15, 0x99, 0x82, 0xff, 0x13, 0x77, 0x96, 0x9a,
|
||||
0x3a, 0x92, 0x27, 0x70, 0x56, 0xd3, 0xfb, 0x0a, 0x2d, 0x2f, 0x53, 0x7c, 0x3c, 0x7d, 0xef, 0xc5,
|
||||
0x39, 0x9c, 0xad, 0x6a, 0x64, 0x52, 0x09, 0x92, 0xbb, 0x62, 0x2f, 0x48, 0x9d, 0xc9, 0x73, 0xb8,
|
||||
0x50, 0x0c, 0x84, 0xa4, 0x79, 0xa1, 0x57, 0xfd, 0xb4, 0x69, 0x28, 0xb9, 0xd6, 0x3f, 0xab, 0xca,
|
||||
0x95, 0x6d, 0x23, 0x46, 0x1d, 0x23, 0xe2, 0x5b, 0x08, 0x6f, 0x4a, 0xa4, 0x12, 0xbf, 0x15, 0x32,
|
||||
0xe3, 0x4c, 0xa8, 0xd1, 0x0d, 0xcf, 0x73, 0xca, 0xb6, 0x91, 0x37, 0xf3, 0xd5, 0xa8, 0x2d, 0x95,
|
||||
0x0a, 0x64, 0x75, 0x74, 0xaa, 0xbb, 0xea, 0xa8, 0x5c, 0xe4, 0x95, 0x2c, 0x2a, 0xe9, 0x5c, 0x34,
|
||||
0x55, 0xfc, 0xdb, 0x81, 0xa6, 0xf8, 0xab, 0x42, 0x21, 0xc9, 0x75, 0xc3, 0x4c, 0xc9, 0x09, 0x16,
|
||||
0xcf, 0x06, 0x5d, 0x6d, 0x48, 0x7f, 0x80, 0x09, 0x37, 0xa4, 0xb4, 0xd4, 0x60, 0xf1, 0xea, 0xe1,
|
||||
0x52, 0x87, 0x7b, 0xea, 0xe6, 0xe3, 0x29, 0x3c, 0x76, 0x04, 0x44, 0xc1, 0x99, 0xc0, 0xf8, 0x0e,
|
||||
0x82, 0x14, 0xe9, 0xb6, 0xa5, 0xb2, 0x4d, 0xa8, 0xdf, 0xaa, 0x83, 0x37, 0xe3, 0x02, 0xf1, 0x9b,
|
||||
0x40, 0xe2, 0xcf, 0x06, 0xd6, 0xe9, 0x7c, 0xd7, 0x50, 0x36, 0x3a, 0x5f, 0x3c, 0xa4, 0xdc, 0xa2,
|
||||
0xd1, 0x10, 0x5e, 0xc1, 0x23, 0x83, 0x63, 0xe8, 0x92, 0xb7, 0x70, 0x6e, 0x09, 0x09, 0x1d, 0xc3,
|
||||
0x7f, 0x1d, 0xdb, 0x8f, 0xc6, 0x4b, 0x08, 0x97, 0x78, 0x8f, 0xc7, 0x19, 0xaf, 0xdc, 0x73, 0x28,
|
||||
0xd6, 0xbd, 0x25, 0x84, 0x77, 0xc5, 0x96, 0x1e, 0x8f, 0xeb, 0x50, 0x2c, 0x6e, 0x08, 0xc1, 0xd7,
|
||||
0x4c, 0x48, 0x8b, 0xaa, 0x5c, 0x30, 0xe5, 0x51, 0x2e, 0x2c, 0xfe, 0xf8, 0x30, 0x49, 0xcd, 0x2d,
|
||||
0x59, 0xc3, 0xd8, 0xbc, 0x04, 0x32, 0xf8, 0x7a, 0xec, 0xd7, 0x2f, 0x67, 0xc3, 0x03, 0x96, 0xee,
|
||||
0x09, 0xf9, 0x02, 0x23, 0x95, 0x13, 0x19, 0xc8, 0xd5, 0x41, 0xbd, 0x1c, 0xba, 0xde, 0x03, 0xad,
|
||||
0x61, 0x6c, 0x3c, 0xee, 0xe3, 0xd5, 0xc9, 0xb0, 0x8f, 0xd7, 0x41, 0x3c, 0x1a, 0xce, 0x58, 0xdb,
|
||||
0x07, 0xd7, 0x89, 0xae, 0x0f, 0xee, 0x20, 0x15, 0x2d, 0x53, 0x05, 0xd1, 0x27, 0xb3, 0x95, 0x57,
|
||||
0x9f, 0xcc, 0x76, 0x7e, 0xf1, 0xc9, 0xf7, 0xb1, 0xfe, 0x75, 0x5f, 0xff, 0x0b, 0x00, 0x00, 0xff,
|
||||
0xff, 0x43, 0x9c, 0x97, 0x62, 0xe1, 0x05, 0x00, 0x00,
|
||||
0x10, 0xae, 0xe3, 0x3c, 0xda, 0x09, 0x41, 0xd1, 0xaa, 0x42, 0xa6, 0xe2, 0x11, 0xf9, 0x42, 0x2f,
|
||||
0x38, 0x52, 0x2a, 0xc4, 0x4b, 0x9c, 0x9a, 0xc0, 0x85, 0x08, 0xc9, 0xa8, 0x3f, 0x60, 0x9b, 0x8c,
|
||||
0x82, 0x45, 0xd7, 0x6b, 0xbc, 0xeb, 0x48, 0x39, 0x71, 0xe5, 0xca, 0x4f, 0xe3, 0x1f, 0xa1, 0x7d,
|
||||
0xd9, 0x4e, 0x6a, 0xf7, 0x92, 0xdb, 0xcc, 0xec, 0xec, 0xb7, 0xdf, 0xc3, 0x32, 0x7c, 0xda, 0x24,
|
||||
0xf2, 0x47, 0x71, 0x1b, 0xad, 0x38, 0x9b, 0xb2, 0x64, 0x95, 0xf3, 0xe9, 0x86, 0xbf, 0x36, 0x45,
|
||||
0x5e, 0xa4, 0x32, 0x61, 0x38, 0x15, 0x98, 0x6f, 0x93, 0x15, 0x4e, 0xb3, 0x9c, 0xcb, 0x72, 0x1a,
|
||||
0xe9, 0x8e, 0x8c, 0x37, 0x3c, 0xd2, 0xdb, 0x91, 0x9d, 0x87, 0xff, 0x3c, 0x18, 0x7c, 0x37, 0x37,
|
||||
0x08, 0x81, 0x6e, 0x4a, 0x19, 0x06, 0xde, 0xc4, 0xbb, 0x3c, 0x8b, 0x75, 0x4d, 0x02, 0x18, 0x6c,
|
||||
0x31, 0x17, 0x09, 0x4f, 0x83, 0x8e, 0x1e, 0xbb, 0x96, 0x3c, 0x81, 0xbe, 0xe0, 0x45, 0xbe, 0xc2,
|
||||
0xc0, 0xd7, 0x07, 0xb6, 0x23, 0xd7, 0x70, 0xca, 0x50, 0xd2, 0x35, 0x95, 0x34, 0xe8, 0x4e, 0xfc,
|
||||
0xcb, 0xe1, 0xec, 0x55, 0x74, 0xf8, 0x6c, 0x64, 0x9f, 0x8c, 0x96, 0x76, 0x73, 0x91, 0xca, 0x7c,
|
||||
0x17, 0x97, 0x17, 0x2f, 0x3e, 0xc2, 0x68, 0xef, 0x88, 0x8c, 0xc1, 0xff, 0x89, 0x3b, 0x4b, 0x4d,
|
||||
0x95, 0xe4, 0x1c, 0x7a, 0x5b, 0x7a, 0x57, 0xa0, 0xe5, 0x65, 0x9a, 0x0f, 0x9d, 0x77, 0x5e, 0xc8,
|
||||
0xa0, 0xb7, 0xd8, 0x62, 0x2a, 0x95, 0x20, 0xb9, 0xcb, 0x4a, 0x41, 0xaa, 0x26, 0xcf, 0xe0, 0x4c,
|
||||
0x31, 0x10, 0x92, 0xb2, 0x4c, 0x5f, 0xf5, 0xe3, 0x6a, 0xa0, 0xe4, 0x5a, 0xff, 0xac, 0x2a, 0xd7,
|
||||
0xd6, 0x8d, 0xe8, 0xee, 0x19, 0x11, 0xfe, 0xf5, 0x60, 0x74, 0x9d, 0x23, 0x95, 0xf8, 0x2d, 0x93,
|
||||
0x09, 0x4f, 0x85, 0xda, 0x5d, 0x71, 0xc6, 0x68, 0xba, 0x0e, 0xbc, 0x89, 0xaf, 0x76, 0x6d, 0xab,
|
||||
0x18, 0xd1, 0x7c, 0x23, 0x82, 0x8e, 0x1e, 0xeb, 0x5a, 0x49, 0xc3, 0x74, 0x1b, 0xf8, 0x7a, 0xa4,
|
||||
0x4a, 0x65, 0x2d, 0x2f, 0x64, 0x56, 0x48, 0xfb, 0x94, 0xed, 0x4a, 0x3d, 0xbd, 0x9a, 0x9e, 0x73,
|
||||
0xe8, 0x25, 0x8c, 0x6e, 0x30, 0xe8, 0x1b, 0x1b, 0x74, 0x13, 0xfe, 0x76, 0x94, 0x62, 0xfc, 0x55,
|
||||
0xa0, 0x90, 0xe4, 0xaa, 0x12, 0xa6, 0xdc, 0x18, 0xce, 0x9e, 0xb6, 0x86, 0x52, 0x69, 0x7e, 0x0f,
|
||||
0x03, 0x6e, 0x24, 0x69, 0xa7, 0x86, 0xb3, 0x97, 0xf7, 0x2f, 0xed, 0x29, 0x8f, 0xdd, 0x7e, 0x38,
|
||||
0x86, 0xc7, 0x8e, 0x80, 0xc8, 0x78, 0x2a, 0x30, 0xbc, 0x81, 0x61, 0x8c, 0x74, 0x5d, 0xf3, 0xa8,
|
||||
0x4e, 0xa8, 0xd9, 0xe9, 0x83, 0x4f, 0xce, 0xe9, 0xf7, 0x2b, 0xfd, 0xe1, 0x67, 0x03, 0xeb, 0x74,
|
||||
0xbe, 0xad, 0x28, 0x1b, 0x9d, 0xcf, 0xef, 0x53, 0xae, 0xd1, 0xa8, 0x08, 0x2f, 0xe0, 0x91, 0xc1,
|
||||
0x31, 0x74, 0xc9, 0x1b, 0x38, 0xb5, 0x84, 0x84, 0x0e, 0xf1, 0x41, 0xc7, 0xca, 0xd5, 0x70, 0x0e,
|
||||
0xa3, 0x39, 0xde, 0xe1, 0x71, 0xc6, 0x2b, 0xf7, 0x1c, 0x8a, 0x75, 0x6f, 0x0e, 0xa3, 0x9b, 0x6c,
|
||||
0x4d, 0x8f, 0xc7, 0x75, 0x28, 0x16, 0x77, 0x04, 0xc3, 0xaf, 0x89, 0x90, 0x16, 0x55, 0xb9, 0x60,
|
||||
0xda, 0xa3, 0x5c, 0x98, 0xfd, 0xf1, 0x61, 0x10, 0x9b, 0x53, 0xb2, 0x84, 0xbe, 0xf9, 0x12, 0x48,
|
||||
0xeb, 0xd7, 0x63, 0x5f, 0xbf, 0x98, 0xb4, 0x2f, 0x58, 0xba, 0x27, 0xe4, 0x0b, 0x74, 0x55, 0x4e,
|
||||
0xa4, 0x25, 0x57, 0x07, 0xf5, 0xa2, 0xed, 0xb8, 0x04, 0x5a, 0x42, 0xdf, 0x78, 0xdc, 0xc4, 0x6b,
|
||||
0x2f, 0xc3, 0x26, 0x5e, 0x07, 0xf1, 0x68, 0x38, 0x63, 0x6d, 0x13, 0xdc, 0x5e, 0x74, 0x4d, 0x70,
|
||||
0x07, 0xa9, 0x68, 0x99, 0x2a, 0x88, 0x26, 0x99, 0xb5, 0xbc, 0x9a, 0x64, 0xd6, 0xf3, 0x0b, 0x4f,
|
||||
0x6e, 0xfb, 0xfa, 0xcf, 0x7f, 0xf5, 0x3f, 0x00, 0x00, 0xff, 0xff, 0x14, 0xdd, 0xee, 0x9f, 0x3a,
|
||||
0x06, 0x00, 0x00,
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: runtime/service/proto/runtime.proto
|
||||
// source: github.com/micro/go-micro/runtime/service/proto/runtime.proto
|
||||
|
||||
package go_micro_runtime
|
||||
|
||||
|
@@ -31,10 +31,16 @@ message Event {
|
||||
message CreateOptions {
|
||||
// command to pass in
|
||||
repeated string command = 1;
|
||||
// args to pass into command
|
||||
repeated string args = 2;
|
||||
// environment to pass in
|
||||
repeated string env = 2;
|
||||
repeated string env = 3;
|
||||
// output to send to
|
||||
string output = 3;
|
||||
string output = 4;
|
||||
// create type of service
|
||||
string type = 5;
|
||||
// image to use
|
||||
string image = 6;
|
||||
}
|
||||
|
||||
message CreateRequest {
|
||||
|
@@ -50,7 +50,10 @@ func (s *svc) Create(svc *runtime.Service, opts ...runtime.CreateOption) error {
|
||||
},
|
||||
Options: &pb.CreateOptions{
|
||||
Command: options.Command,
|
||||
Args: options.Args,
|
||||
Env: options.Env,
|
||||
Type: options.Type,
|
||||
Image: options.Image,
|
||||
},
|
||||
}
|
||||
|
||||
|
@@ -17,7 +17,7 @@ import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/errors"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
meta "github.com/micro/go-micro/v2/metadata"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
@@ -279,6 +279,9 @@ func (g *grpcServer) handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
|
||||
// serve the actual request using the request router
|
||||
if err := r.ServeRequest(ctx, request, response); err != nil {
|
||||
if _, ok := status.FromError(err); ok {
|
||||
return err
|
||||
}
|
||||
return status.Errorf(codes.Internal, err.Error())
|
||||
}
|
||||
|
||||
@@ -358,8 +361,10 @@ func (g *grpcServer) processRequest(stream grpc.ServerStream, service *service,
|
||||
fn := func(ctx context.Context, req server.Request, rsp interface{}) (err error) {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("panic recovered: ", r)
|
||||
logger.Error(string(debug.Stack()))
|
||||
}
|
||||
err = errors.InternalServerError("go.micro.server", "panic recovered: %v", r)
|
||||
}
|
||||
}()
|
||||
@@ -377,7 +382,6 @@ func (g *grpcServer) processRequest(stream grpc.ServerStream, service *service,
|
||||
for i := len(g.opts.HdlrWrappers); i > 0; i-- {
|
||||
fn = g.opts.HdlrWrappers[i-1](fn)
|
||||
}
|
||||
|
||||
statusCode := codes.OK
|
||||
statusDesc := ""
|
||||
// execute the handler
|
||||
@@ -400,24 +404,19 @@ func (g *grpcServer) processRequest(stream grpc.ServerStream, service *service,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case *rpcError:
|
||||
// rpcError handling may be we have ability to attach it to details?
|
||||
statusCode = verr.code
|
||||
statusDesc = verr.desc
|
||||
errStatus = status.New(statusCode, statusDesc)
|
||||
default:
|
||||
// default case user pass own error type that not proto based
|
||||
statusCode = convertCode(verr)
|
||||
statusDesc = verr.Error()
|
||||
errStatus = status.New(statusCode, statusDesc)
|
||||
}
|
||||
|
||||
return errStatus.Err()
|
||||
}
|
||||
|
||||
if err := stream.SendMsg(replyv.Interface()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return status.New(statusCode, statusDesc).Err()
|
||||
}
|
||||
}
|
||||
@@ -457,8 +456,7 @@ func (g *grpcServer) processStream(stream grpc.ServerStream, service *service, m
|
||||
statusCode := codes.OK
|
||||
statusDesc := ""
|
||||
|
||||
appErr := fn(ctx, r, ss)
|
||||
if appErr != nil {
|
||||
if appErr := fn(ctx, r, ss); appErr != nil {
|
||||
var err error
|
||||
var errStatus *status.Status
|
||||
switch verr := appErr.(type) {
|
||||
@@ -478,11 +476,6 @@ func (g *grpcServer) processStream(stream grpc.ServerStream, service *service, m
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case *rpcError:
|
||||
// rpcError handling may be we have ability to attach it to details?
|
||||
statusCode = verr.code
|
||||
statusDesc = verr.desc
|
||||
errStatus = status.New(statusCode, statusDesc)
|
||||
default:
|
||||
// default case user pass own error type that not proto based
|
||||
statusCode = convertCode(verr)
|
||||
@@ -555,8 +548,8 @@ func (g *grpcServer) Subscribe(sb server.Subscriber) error {
|
||||
}
|
||||
|
||||
g.Lock()
|
||||
|
||||
if _, ok = g.subscribers[sub]; ok {
|
||||
g.Unlock()
|
||||
return fmt.Errorf("subscriber %v already exists", sub)
|
||||
}
|
||||
|
||||
@@ -658,7 +651,9 @@ func (g *grpcServer) Register() error {
|
||||
g.Unlock()
|
||||
|
||||
if !registered {
|
||||
log.Infof("Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Infof("Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
|
||||
}
|
||||
}
|
||||
|
||||
// create registry options
|
||||
@@ -693,7 +688,9 @@ func (g *grpcServer) Register() error {
|
||||
opts = append(opts, broker.DisableAutoAck())
|
||||
}
|
||||
|
||||
log.Infof("Subscribing to topic: %s", sb.Topic())
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Infof("Subscribing to topic: %s", sb.Topic())
|
||||
}
|
||||
sub, err := config.Broker.Subscribe(sb.Topic(), handler, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -745,7 +742,9 @@ func (g *grpcServer) Deregister() error {
|
||||
Nodes: []*registry.Node{node},
|
||||
}
|
||||
|
||||
log.Infof("Deregistering node: %s", node.Id)
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Infof("Deregistering node: %s", node.Id)
|
||||
}
|
||||
if err := config.Registry.Deregister(service); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -761,7 +760,9 @@ func (g *grpcServer) Deregister() error {
|
||||
|
||||
for sb, subs := range g.subscribers {
|
||||
for _, sub := range subs {
|
||||
log.Infof("Unsubscribing from topic: %s", sub.Topic())
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Infof("Unsubscribing from topic: %s", sub.Topic())
|
||||
}
|
||||
sub.Unsubscribe()
|
||||
}
|
||||
g.subscribers[sb] = nil
|
||||
@@ -807,7 +808,9 @@ func (g *grpcServer) Start() error {
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Server [grpc] Listening on %s", ts.Addr().String())
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Infof("Server [grpc] Listening on %s", ts.Addr().String())
|
||||
}
|
||||
g.Lock()
|
||||
g.opts.Address = ts.Addr().String()
|
||||
g.Unlock()
|
||||
@@ -819,18 +822,24 @@ func (g *grpcServer) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infof("Broker [%s] Connected to %s", config.Broker.String(), config.Broker.Address())
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Infof("Broker [%s] Connected to %s", config.Broker.String(), config.Broker.Address())
|
||||
}
|
||||
}
|
||||
|
||||
// announce self to the world
|
||||
if err := g.Register(); err != nil {
|
||||
log.Errorf("Server register error: ", err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("Server register error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
// micro: go ts.Accept(s.accept)
|
||||
go func() {
|
||||
if err := g.srv.Serve(ts); err != nil {
|
||||
log.Errorf("gRPC Server start error: ", err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("gRPC Server start error: ", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -852,7 +861,9 @@ func (g *grpcServer) Start() error {
|
||||
// register self on interval
|
||||
case <-t.C:
|
||||
if err := g.Register(); err != nil {
|
||||
log.Error("Server register error: ", err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("Server register error: ", err)
|
||||
}
|
||||
}
|
||||
// wait for exit
|
||||
case ch = <-g.exit:
|
||||
@@ -862,7 +873,9 @@ func (g *grpcServer) Start() error {
|
||||
|
||||
// deregister self
|
||||
if err := g.Deregister(); err != nil {
|
||||
log.Error("Server deregister error: ", err)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("Server deregister error: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
// wait for waitgroup
|
||||
@@ -887,7 +900,9 @@ func (g *grpcServer) Start() error {
|
||||
// close transport
|
||||
ch <- nil
|
||||
|
||||
log.Infof("Broker [%s] Disconnected from %s", config.Broker.String(), config.Broker.Address())
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Infof("Broker [%s] Disconnected from %s", config.Broker.String(), config.Broker.Address())
|
||||
}
|
||||
// disconnect broker
|
||||
config.Broker.Disconnect()
|
||||
}()
|
||||
|
@@ -1,12 +1,19 @@
|
||||
package grpc
|
||||
package grpc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/v2"
|
||||
bmemory "github.com/micro/go-micro/v2/broker/memory"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
gcli "github.com/micro/go-micro/v2/client/grpc"
|
||||
"github.com/micro/go-micro/v2/errors"
|
||||
"github.com/micro/go-micro/v2/registry/memory"
|
||||
rmemory "github.com/micro/go-micro/v2/registry/memory"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
gsrv "github.com/micro/go-micro/v2/server/grpc"
|
||||
tgrpc "github.com/micro/go-micro/v2/transport/grpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
@@ -14,7 +21,17 @@ import (
|
||||
)
|
||||
|
||||
// server is used to implement helloworld.GreeterServer.
|
||||
type testServer struct{}
|
||||
type testServer struct {
|
||||
msgCount int
|
||||
}
|
||||
|
||||
func (s *testServer) Handle(ctx context.Context, msg *pb.Request) error {
|
||||
s.msgCount++
|
||||
return nil
|
||||
}
|
||||
func (s *testServer) HandleError(ctx context.Context, msg *pb.Request) error {
|
||||
return fmt.Errorf("fake")
|
||||
}
|
||||
|
||||
// TestHello implements helloworld.GreeterServer
|
||||
func (s *testServer) Call(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
|
||||
@@ -26,14 +43,75 @@ func (s *testServer) Call(ctx context.Context, req *pb.Request, rsp *pb.Response
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestGRPCServer(t *testing.T) {
|
||||
r := memory.NewRegistry()
|
||||
s := NewServer(
|
||||
/*
|
||||
func BenchmarkServer(b *testing.B) {
|
||||
r := rmemory.NewRegistry()
|
||||
br := bmemory.NewBroker()
|
||||
tr := tgrpc.NewTransport()
|
||||
s := gsrv.NewServer(
|
||||
server.Broker(br),
|
||||
server.Name("foo"),
|
||||
server.Registry(r),
|
||||
server.Transport(tr),
|
||||
)
|
||||
c := gcli.NewClient(
|
||||
client.Registry(r),
|
||||
client.Broker(br),
|
||||
client.Transport(tr),
|
||||
)
|
||||
ctx := context.TODO()
|
||||
|
||||
pb.RegisterTestHandler(s, &testServer{})
|
||||
h := &testServer{}
|
||||
pb.RegisterTestHandler(s, h)
|
||||
if err := s.Start(); err != nil {
|
||||
b.Fatalf("failed to start: %v", err)
|
||||
}
|
||||
|
||||
// check registration
|
||||
services, err := r.GetService("foo")
|
||||
if err != nil || len(services) == 0 {
|
||||
b.Fatalf("failed to get service: %v # %d", err, len(services))
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := s.Stop(); err != nil {
|
||||
b.Fatalf("failed to stop: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Call()
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
func TestGRPCServer(t *testing.T) {
|
||||
r := rmemory.NewRegistry()
|
||||
b := bmemory.NewBroker()
|
||||
tr := tgrpc.NewTransport()
|
||||
s := gsrv.NewServer(
|
||||
server.Broker(b),
|
||||
server.Name("foo"),
|
||||
server.Registry(r),
|
||||
server.Transport(tr),
|
||||
)
|
||||
c := gcli.NewClient(
|
||||
client.Registry(r),
|
||||
client.Broker(b),
|
||||
client.Transport(tr),
|
||||
)
|
||||
ctx := context.TODO()
|
||||
|
||||
h := &testServer{}
|
||||
pb.RegisterTestHandler(s, h)
|
||||
|
||||
if err := micro.RegisterSubscriber("test_topic", s, h.Handle); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := micro.RegisterSubscriber("error_topic", s, h.HandleError); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := s.Start(); err != nil {
|
||||
t.Fatalf("failed to start: %v", err)
|
||||
@@ -51,6 +129,22 @@ func TestGRPCServer(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
pub := micro.NewEvent("test_topic", c)
|
||||
pubErr := micro.NewEvent("error_topic", c)
|
||||
cnt := 4
|
||||
for i := 0; i < cnt; i++ {
|
||||
if err = pub.Publish(ctx, &pb.Request{Name: fmt.Sprintf("msg %d", i)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if h.msgCount != cnt {
|
||||
t.Fatalf("pub/sub not work, or invalid message count %d", h.msgCount)
|
||||
}
|
||||
if err = pubErr.Publish(ctx, &pb.Request{}); err == nil {
|
||||
t.Fatal("this must return error, as we return error from handler")
|
||||
}
|
||||
|
||||
cc, err := grpc.Dial(s.Options().Address, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to dial server: %v", err)
|
||||
|
@@ -14,7 +14,7 @@ import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
)
|
||||
|
||||
@@ -86,7 +86,9 @@ func prepareEndpoint(method reflect.Method) *methodType {
|
||||
replyType = mtype.In(3)
|
||||
contextType = mtype.In(1)
|
||||
default:
|
||||
log.Error("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -94,7 +96,9 @@ func prepareEndpoint(method reflect.Method) *methodType {
|
||||
// check stream type
|
||||
streamType := reflect.TypeOf((*server.Stream)(nil)).Elem()
|
||||
if !argType.Implements(streamType) {
|
||||
log.Error(mname, "argument does not implement Streamer interface:", argType)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(mname, "argument does not implement Streamer interface:", argType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
@@ -102,30 +106,40 @@ func prepareEndpoint(method reflect.Method) *methodType {
|
||||
|
||||
// First arg need not be a pointer.
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
log.Error(mname, "argument type not exported:", argType)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(mname, "argument type not exported:", argType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if replyType.Kind() != reflect.Ptr {
|
||||
log.Error("method", mname, "reply type not a pointer:", replyType)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("method", mname, "reply type not a pointer:", replyType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reply type must be exported.
|
||||
if !isExportedOrBuiltinType(replyType) {
|
||||
log.Error("method", mname, "reply type not exported:", replyType)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("method", mname, "reply type not exported:", replyType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Endpoint() needs one out.
|
||||
if mtype.NumOut() != 1 {
|
||||
log.Error("method", mname, "has wrong number of outs:", mtype.NumOut())
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("method", mname, "has wrong number of outs:", mtype.NumOut())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// The return type of the method must be error.
|
||||
if returnType := mtype.Out(0); returnType != typeOfError {
|
||||
log.Error("method", mname, "returns", returnType.String(), "not error")
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("method", mname, "returns", returnType.String(), "not error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream}
|
||||
@@ -142,11 +156,13 @@ func (server *rServer) register(rcvr interface{}) error {
|
||||
s.rcvr = reflect.ValueOf(rcvr)
|
||||
sname := reflect.Indirect(s.rcvr).Type().Name()
|
||||
if sname == "" {
|
||||
log.Fatal("rpc: no service name for type", s.typ.String())
|
||||
logger.Fatal("rpc: no service name for type", s.typ.String())
|
||||
}
|
||||
if !isExported(sname) {
|
||||
s := "rpc Register: type " + sname + " is not exported"
|
||||
log.Error(s)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(s)
|
||||
}
|
||||
return errors.New(s)
|
||||
}
|
||||
if _, present := server.serviceMap[sname]; present {
|
||||
@@ -165,7 +181,9 @@ func (server *rServer) register(rcvr interface{}) error {
|
||||
|
||||
if len(s.method) == 0 {
|
||||
s := "rpc Register: type " + sname + " has no exported methods of suitable type"
|
||||
log.Error(s)
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(s)
|
||||
}
|
||||
return errors.New(s)
|
||||
}
|
||||
server.serviceMap[s.name] = s
|
||||
|
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/errors"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/metadata"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
@@ -171,13 +171,20 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("panic recovered: ", r)
|
||||
logger.Error(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
|
||||
@@ -246,18 +253,19 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
|
||||
if g.wg != nil {
|
||||
defer g.wg.Done()
|
||||
}
|
||||
results <- fn(ctx, &rpcMessage{
|
||||
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; err != nil {
|
||||
if rerr := <-results; rerr != nil {
|
||||
errors = append(errors, rerr.Error())
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
@@ -10,16 +9,6 @@ import (
|
||||
"google.golang.org/grpc/codes"
|
||||
)
|
||||
|
||||
// rpcError defines the status from an RPC.
|
||||
type rpcError struct {
|
||||
code codes.Code
|
||||
desc string
|
||||
}
|
||||
|
||||
func (e *rpcError) Error() string {
|
||||
return fmt.Sprintf("rpc error: code = %d desc = %s", e.code, e.desc)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
|
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
// event is a broker event we handle on the server transport
|
||||
type event struct {
|
||||
err error
|
||||
message *broker.Message
|
||||
}
|
||||
|
||||
@@ -19,6 +20,10 @@ func (e *event) Message() *broker.Message {
|
||||
return e.message
|
||||
}
|
||||
|
||||
func (e *event) Error() error {
|
||||
return e.err
|
||||
}
|
||||
|
||||
func (e *event) Topic() string {
|
||||
return e.message.Header["Micro-Topic"]
|
||||
}
|
||||
|
@@ -20,7 +20,6 @@ import (
|
||||
|
||||
"github.com/micro/go-micro/v2/codec"
|
||||
merrors "github.com/micro/go-micro/v2/errors"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -505,7 +504,6 @@ func (router *router) Subscribe(s Subscriber) error {
|
||||
}
|
||||
|
||||
func (router *router) ProcessMessage(ctx context.Context, msg Message) (err error) {
|
||||
|
||||
defer func() {
|
||||
// recover any panics
|
||||
if r := recover(); r != nil {
|
||||
@@ -516,16 +514,13 @@ func (router *router) ProcessMessage(ctx context.Context, msg Message) (err erro
|
||||
}()
|
||||
|
||||
router.su.RLock()
|
||||
|
||||
// get the subscribers by topic
|
||||
subs, ok := router.subscribers[msg.Topic()]
|
||||
if !ok {
|
||||
router.su.RUnlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// unlock since we only need to get the subs
|
||||
router.su.RUnlock()
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
var errResults []string
|
||||
|
||||
@@ -552,18 +547,6 @@ func (router *router) ProcessMessage(ctx context.Context, msg Message) (err erro
|
||||
req = req.Elem()
|
||||
}
|
||||
|
||||
if handler.reqType.Kind() == reflect.Ptr {
|
||||
req = reflect.New(handler.reqType.Elem())
|
||||
} else {
|
||||
req = reflect.New(handler.reqType)
|
||||
isVal = true
|
||||
}
|
||||
|
||||
// if its a value get the element
|
||||
if isVal {
|
||||
req = req.Elem()
|
||||
}
|
||||
|
||||
cc := msg.Codec()
|
||||
|
||||
// read the header. mostly a noop
|
||||
|
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/codec"
|
||||
raw "github.com/micro/go-micro/v2/codec/bytes"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/metadata"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/transport"
|
||||
@@ -158,8 +158,10 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
|
||||
// recover any panics
|
||||
if r := recover(); r != nil {
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
if logger.V(logger.ErrorLevel, log) {
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -377,8 +379,10 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
|
||||
// recover any panics for outbound process
|
||||
if r := recover(); r != nil {
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
if logger.V(logger.ErrorLevel, log) {
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -630,14 +634,17 @@ func (s *rpcServer) Register() error {
|
||||
// set what we're advertising
|
||||
s.opts.Advertise = addr
|
||||
|
||||
// subscribe to the topic with own name
|
||||
sub, err := s.opts.Broker.Subscribe(config.Name, s.HandleEvent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// router can exchange messages
|
||||
if s.opts.Router != nil {
|
||||
// subscribe to the topic with own name
|
||||
sub, err := s.opts.Broker.Subscribe(config.Name, s.HandleEvent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// save the subscriber
|
||||
s.subscriber = sub
|
||||
// save the subscriber
|
||||
s.subscriber = sub
|
||||
}
|
||||
|
||||
// subscribe for all of the subscribers
|
||||
for sb := range s.subscribers {
|
||||
@@ -654,11 +661,11 @@ func (s *rpcServer) Register() error {
|
||||
opts = append(opts, broker.DisableAutoAck())
|
||||
}
|
||||
|
||||
log.Infof("Subscribing to topic: %s", sub.Topic())
|
||||
sub, err := config.Broker.Subscribe(sb.Topic(), s.HandleEvent, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Infof("Subscribing to topic: %s", sub.Topic())
|
||||
|
||||
s.subscribers[sb] = []broker.Subscriber{sub}
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/v2/codec"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
)
|
||||
|
||||
@@ -139,6 +139,7 @@ var (
|
||||
|
||||
// NewServer creates a new server
|
||||
NewServer func(...Option) Server = newRpcServer
|
||||
log = logger.NewHelper(logger.DefaultLogger).WithFields(map[string]interface{}{"service": "server"})
|
||||
)
|
||||
|
||||
// DefaultOptions returns config options for the default service
|
||||
@@ -200,21 +201,26 @@ func Run() error {
|
||||
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT)
|
||||
log.Infof("Received signal %s", <-ch)
|
||||
|
||||
if logger.V(logger.InfoLevel, log) {
|
||||
log.Infof("Received signal %s", <-ch)
|
||||
}
|
||||
return Stop()
|
||||
}
|
||||
|
||||
// Start starts the default server
|
||||
func Start() error {
|
||||
config := DefaultServer.Options()
|
||||
log.Infof("Starting server %s id %s", config.Name, config.Id)
|
||||
if logger.V(logger.InfoLevel, log) {
|
||||
log.Infof("Starting server %s id %s", config.Name, config.Id)
|
||||
}
|
||||
return DefaultServer.Start()
|
||||
}
|
||||
|
||||
// Stop stops the default server
|
||||
func Stop() error {
|
||||
log.Infof("Stopping server")
|
||||
if logger.V(logger.InfoLevel, log) {
|
||||
log.Infof("Stopping server")
|
||||
}
|
||||
return DefaultServer.Stop()
|
||||
}
|
||||
|
||||
|
57
service.go
57
service.go
@@ -11,15 +11,14 @@ import (
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/config/cmd"
|
||||
"github.com/micro/go-micro/v2/debug/profile"
|
||||
"github.com/micro/go-micro/v2/debug/profile/http"
|
||||
"github.com/micro/go-micro/v2/debug/profile/pprof"
|
||||
"github.com/micro/go-micro/v2/debug/service/handler"
|
||||
"github.com/micro/go-micro/v2/debug/stats"
|
||||
"github.com/micro/go-micro/v2/debug/trace"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/plugin"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
"github.com/micro/go-micro/v2/store"
|
||||
"github.com/micro/go-micro/v2/util/config"
|
||||
"github.com/micro/go-micro/v2/util/wrapper"
|
||||
)
|
||||
|
||||
@@ -40,7 +39,7 @@ func newService(opts ...Option) Service {
|
||||
authFn := func() auth.Auth { return service.opts.Auth }
|
||||
|
||||
// wrap client to inject From-Service header on any calls
|
||||
options.Client = wrapper.FromService(serviceName, options.Client)
|
||||
options.Client = wrapper.FromService(serviceName, options.Client, authFn)
|
||||
options.Client = wrapper.TraceCall(serviceName, trace.DefaultTracer, options.Client)
|
||||
|
||||
// wrap the server to provide handler stats
|
||||
@@ -79,12 +78,12 @@ func (s *service) Init(opts ...Option) {
|
||||
// load the plugin
|
||||
c, err := plugin.Load(p)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
// initialise the plugin
|
||||
if err := plugin.Init(c); err != nil {
|
||||
log.Fatal(err)
|
||||
logger.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,9 +99,26 @@ func (s *service) Init(opts ...Option) {
|
||||
cmd.Registry(&s.opts.Registry),
|
||||
cmd.Transport(&s.opts.Transport),
|
||||
cmd.Client(&s.opts.Client),
|
||||
cmd.Config(&s.opts.Config),
|
||||
cmd.Server(&s.opts.Server),
|
||||
cmd.Profile(&s.opts.Profile),
|
||||
); err != nil {
|
||||
log.Fatal(err)
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
// If the store has no namespace set, fallback to the
|
||||
// services name
|
||||
if len(store.DefaultStore.Options().Namespace) == 0 {
|
||||
name := s.opts.Cmd.App().Name
|
||||
store.DefaultStore.Init(store.Namespace(name))
|
||||
}
|
||||
|
||||
// TODO: replace Cmd.Init with config.Load
|
||||
// Right now we're just going to load a token
|
||||
// May need to re-read value on change
|
||||
// TODO: should be scoped to micro/auth/token
|
||||
if tk, _ := config.Get("token"); len(tk) > 0 {
|
||||
s.opts.Auth.Init(auth.Token(tk))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -175,34 +191,21 @@ func (s *service) Run() error {
|
||||
)
|
||||
|
||||
// start the profiler
|
||||
// TODO: set as an option to the service, don't just use pprof
|
||||
if prof := os.Getenv("MICRO_DEBUG_PROFILE"); len(prof) > 0 {
|
||||
var profiler profile.Profile
|
||||
|
||||
if s.opts.Profile != nil {
|
||||
// to view mutex contention
|
||||
runtime.SetMutexProfileFraction(5)
|
||||
// to view blocking profile
|
||||
runtime.SetBlockProfileRate(1)
|
||||
|
||||
switch prof {
|
||||
case "http":
|
||||
profiler = http.NewProfile()
|
||||
default:
|
||||
service := s.opts.Server.Options().Name
|
||||
version := s.opts.Server.Options().Version
|
||||
id := s.opts.Server.Options().Id
|
||||
profiler = pprof.NewProfile(
|
||||
profile.Name(service + "." + version + "." + id),
|
||||
)
|
||||
}
|
||||
|
||||
if err := profiler.Start(); err != nil {
|
||||
if err := s.opts.Profile.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer profiler.Stop()
|
||||
defer s.opts.Profile.Stop()
|
||||
}
|
||||
|
||||
log.Infof("Starting [service] %s", s.Name())
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
logger.Infof("Starting [service] %s", s.Name())
|
||||
}
|
||||
|
||||
if err := s.Start(); err != nil {
|
||||
return err
|
||||
|
39
store/cache/cache.go
vendored
Normal file
39
store/cache/cache.go
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"github.com/micro/go-micro/v2/store"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Cache implements a cache in front of a micro Store
|
||||
type Cache struct {
|
||||
options store.Options
|
||||
store.Store
|
||||
|
||||
stores []store.Store
|
||||
}
|
||||
|
||||
// NewStore returns new cache
|
||||
func NewStore(opts ...store.Option) store.Store {
|
||||
s := &Cache{
|
||||
options: store.Options{},
|
||||
stores: []store.Store{},
|
||||
}
|
||||
for _, o := range opts {
|
||||
o(&s.options)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Init initialises a new cache
|
||||
func (c *Cache) Init(opts ...store.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&c.options)
|
||||
}
|
||||
for _, s := range c.stores {
|
||||
if err := s.Init(); err != nil {
|
||||
return errors.Wrapf(err, "Store %s failed to Init()", s.String())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
15
store/cache/cache_test.go
vendored
Normal file
15
store/cache/cache_test.go
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
package cache
|
||||
|
||||
// import "testing"
|
||||
|
||||
// func TestCache(t *testing.T) {
|
||||
// c := NewStore()
|
||||
// if err := c.Init(); err != nil {
|
||||
// //t.Fatal(err)
|
||||
// }
|
||||
// if results, err := c.Read("test"); err != nil {
|
||||
// //t.Fatal(err)
|
||||
// } else {
|
||||
// println(results)
|
||||
// }
|
||||
// }
|
@@ -19,6 +19,8 @@ import (
|
||||
|
||||
"github.com/micro/go-micro/v2/store"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/patrickmn/go-cache"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -35,6 +37,8 @@ type workersKV struct {
|
||||
namespace string
|
||||
// http client to use
|
||||
httpClient *http.Client
|
||||
// cache
|
||||
cache *cache.Cache
|
||||
}
|
||||
|
||||
// apiResponse is a cloudflare v4 api response
|
||||
@@ -43,12 +47,12 @@ type apiResponse struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Expiration string `json:"expiration"`
|
||||
Expiration int64 `json:"expiration"`
|
||||
Content string `json:"content"`
|
||||
Proxiable bool `json:"proxiable"`
|
||||
Proxied bool `json:"proxied"`
|
||||
TTL int `json:"ttl"`
|
||||
Priority int `json:"priority"`
|
||||
TTL int64 `json:"ttl"`
|
||||
Priority int64 `json:"priority"`
|
||||
Locked bool `json:"locked"`
|
||||
ZoneID string `json:"zone_id"`
|
||||
ZoneName string `json:"zone_name"`
|
||||
@@ -103,6 +107,14 @@ func (w *workersKV) Init(opts ...store.Option) error {
|
||||
if len(w.options.Namespace) > 0 {
|
||||
w.namespace = w.options.Namespace
|
||||
}
|
||||
ttl := w.options.Context.Value("STORE_CACHE_TTL")
|
||||
if ttl != nil {
|
||||
ttlduration, ok := ttl.(time.Duration)
|
||||
if !ok {
|
||||
log.Fatal("STORE_CACHE_TTL from context must be type int64")
|
||||
}
|
||||
w.cache = cache.New(ttlduration, 3*ttlduration)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -147,25 +159,13 @@ func (w *workersKV) list(prefix string) ([]string, error) {
|
||||
|
||||
// In the cloudflare workers KV implemention, List() doesn't guarantee
|
||||
// anything as the workers API is eventually consistent.
|
||||
func (w *workersKV) List() ([]*store.Record, error) {
|
||||
func (w *workersKV) List(opts ...store.ListOption) ([]string, error) {
|
||||
keys, err := w.list("")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var gerr error
|
||||
var records []*store.Record
|
||||
|
||||
for _, key := range keys {
|
||||
r, err := w.Read(key)
|
||||
if err != nil {
|
||||
gerr = err
|
||||
continue
|
||||
}
|
||||
records = append(records, r...)
|
||||
}
|
||||
|
||||
return records, gerr
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (w *workersKV) Read(key string, opts ...store.ReadOption) ([]*store.Record, error) {
|
||||
@@ -191,12 +191,25 @@ func (w *workersKV) Read(key string, opts ...store.ReadOption) ([]*store.Record,
|
||||
var records []*store.Record
|
||||
|
||||
for _, k := range keys {
|
||||
if w.cache != nil {
|
||||
if resp, hit := w.cache.Get(k); hit {
|
||||
if record, ok := resp.(*store.Record); ok {
|
||||
records = append(records, record)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path := fmt.Sprintf("accounts/%s/storage/kv/namespaces/%s/values/%s", w.account, w.namespace, url.PathEscape(k))
|
||||
response, headers, status, err := w.request(ctx, http.MethodGet, path, nil, make(http.Header))
|
||||
if err != nil {
|
||||
return records, err
|
||||
}
|
||||
if status < 200 || status >= 300 {
|
||||
if status == 404 {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
|
||||
return records, errors.New("Received unexpected Status " + strconv.Itoa(status) + string(response))
|
||||
}
|
||||
record := &store.Record{
|
||||
@@ -210,13 +223,20 @@ func (w *workersKV) Read(key string, opts ...store.ReadOption) ([]*store.Record,
|
||||
}
|
||||
record.Expiry = time.Until(time.Unix(expiryUnix, 0))
|
||||
}
|
||||
if w.cache != nil {
|
||||
w.cache.Set(record.Key, record, cache.DefaultExpiration)
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
|
||||
return records, nil
|
||||
}
|
||||
|
||||
func (w *workersKV) Write(r *store.Record) error {
|
||||
func (w *workersKV) Write(r *store.Record, opts ...store.WriteOption) error {
|
||||
// Set it in local cache, with the global TTL from options
|
||||
if w.cache != nil {
|
||||
w.cache.Set(r.Key, r, cache.DefaultExpiration)
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -250,7 +270,10 @@ func (w *workersKV) Write(r *store.Record) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *workersKV) Delete(key string) error {
|
||||
func (w *workersKV) Delete(key string, opts ...store.DeleteOption) error {
|
||||
if w.cache != nil {
|
||||
w.cache.Delete(key)
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||
defer cancel()
|
||||
|
||||
@@ -336,7 +359,11 @@ func (w *workersKV) String() string {
|
||||
return "cloudflare"
|
||||
}
|
||||
|
||||
// New returns a cloudflare Store implementation.
|
||||
func (w *workersKV) Options() store.Options {
|
||||
return w.options
|
||||
}
|
||||
|
||||
// NewStore returns a cloudflare Store implementation.
|
||||
// Account ID, Token and Namespace must either be passed as options or
|
||||
// environment variables. If set as env vars we expect the following;
|
||||
// CF_API_TOKEN to a cloudflare API token scoped to Workers KV.
|
||||
|
@@ -24,6 +24,7 @@ func TestCloudflare(t *testing.T) {
|
||||
Token(apiToken),
|
||||
Account(accountID),
|
||||
Namespace(kvID),
|
||||
CacheTTL(60000000000),
|
||||
)
|
||||
|
||||
records, err := wkv.List()
|
||||
|
@@ -2,6 +2,7 @@ package cloudflare
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/store"
|
||||
)
|
||||
@@ -51,3 +52,13 @@ func Namespace(ns string) store.Option {
|
||||
o.Namespace = ns
|
||||
}
|
||||
}
|
||||
|
||||
// CacheTTL sets the timeout in nanoseconds of the read/write cache
|
||||
func CacheTTL(ttl time.Duration) store.Option {
|
||||
return func(o *store.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, "STORE_CACHE_TTL", ttl)
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user