Compare commits

..

74 Commits

Author SHA1 Message Date
ab73127063 grpc client/server fixes (#1355)
* grpc client/server fixes

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-17 14:27:20 +03:00
Asim Aslam
03031a694d use pod phase/status (#1356) 2020-03-16 23:47:34 +00:00
li.peng
5712aafba9 fix: context cancel (#1350)
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-03-16 10:45:33 +00:00
ac333d9d47 client/grpc: unwrap error after call (#1352)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-16 13:33:38 +03:00
ben-toogood
247707f583 Return store.ErrNotFound if not found when calling over rpc (#1353)
Co-authored-by: Ben Toogood <ben@micro.mu>
2020-03-16 10:30:56 +00:00
ben-toogood
d91c14eb30 grpc client error fix (#1351)
Co-authored-by: Ben Toogood <ben@micro.mu>
2020-03-16 12:53:15 +03:00
Asim Aslam
ca8684a886 fix k8s issues (#1349) 2020-03-15 15:09:18 +00:00
Asim Aslam
0449138f61 fix panic (#1348) 2020-03-14 21:18:41 +00:00
609f4826b3 server: remove duplicate code (#1346)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-13 22:15:09 +00:00
60993e6275 config/source/service: base64 fix (#1345)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-13 21:44:55 +00:00
Asim Aslam
e803fb0855 Runtime hacks (#1344)
* Add Args/Image to runtime

* remove the hacks
2020-03-13 18:39:59 +00:00
3543b275e0 fix log level helper (#1342)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-13 17:36:42 +03:00
fbde872e7f Revert "server/grpc: fix ordering of register and check for registered (#1338)" (#1341)
This reverts commit 62a644ddd8.
2020-03-13 09:30:44 +00:00
Asim Aslam
078dd4eb9b fix etcd (#1340)
* fix etcd

* update go mod
2020-03-13 08:55:23 +00:00
62a644ddd8 server/grpc: fix ordering of register and check for registered (#1338)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-12 22:04:11 +00:00
Asim Aslam
d8cfa7a295 add config to cmd (#1337)
* add config to cmd

* fix build
2020-03-12 18:47:40 +00:00
ben-toogood
47f1203e97 Add Config to service options (#1336)
Co-authored-by: Ben Toogood <ben@micro.mu>
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-03-12 18:13:03 +00:00
Jake Sanders
1b4e881d74 Rewrite the store interface (#1335)
* WIP store rewrite

* Fix memory store tests

* Store hard expiry times rather than duration!

* Clarify memory test

* Add limit to store interface

* Implement suffix option

* Don't return nils from noop store

* Fix syncmap

* Start fixing store service

* wip service and cache

* Use _ for special characters in cockroachdb namespace

* Improve cockroach namespace comment

* Use service name as default store namespace

* Fixes

* Implement Store Scope

* Start fixing etcd

* implement read and write with expiry and prefix

* Fix etcd tests

* Fix cockroach store

* Fix cloudflare interface

* Fix certmagic / cloudflare store

* comment lint

* cache isn't implemented yet

* Only prepare DB staements once

Co-authored-by: Ben Toogood <ben@micro.mu>
Co-authored-by: ben-toogood <bentoogood@gmail.com>
2020-03-12 13:41:30 +00:00
ben-toogood
20ce61da5a Oauth google fixes (#1330)
* Fix Auth Headers

* Tweak Oauth to work for Google

Co-authored-by: Ben Toogood <ben@micro.mu>
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-03-12 13:11:35 +00:00
chengguoqiang
eef4825be4 Update etcd.go (#1334)
add leaseId to the trace log
2020-03-12 10:09:38 +00:00
Asim Aslam
be9c6141f5 delete options (#1333) 2020-03-12 09:05:09 +00:00
Asim Aslam
1ca4619506 return store.ErrNotFound (#1332) 2020-03-11 23:09:42 +00:00
Asim Aslam
f55493993c set namespace rather than key (#1331) 2020-03-11 22:31:24 +00:00
7b385bf163 minimize allocations in logger and tunnel code (#1323)
* logs alloc

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* fix allocs

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* fix allocs

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* tunnel allocs

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* try to fix tunnel

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* cache cipher for send

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* more logger

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* more logger

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* more logger

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* more logger

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* more logger

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* more logger

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* more logger

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-11 17:55:39 +00:00
Jake Sanders
4125ae8d53 Add secrets interface to config/secrets (#1325)
* Interface for secrets

* Add secretbox secrets implementation

* Start working on box

* typo

* Add asymmetric encryption implementation

* go mod tidy

* Fix review comments

Co-authored-by: Asim Aslam <asim@aslam.me>
2020-03-10 22:52:06 +00:00
ben-toogood
48b2a5c37c Fix Auth Headers (#1324)
Co-authored-by: Ben Toogood <ben@micro.mu>
2020-03-10 16:47:01 +00:00
Asim Aslam
ed83c27f0e add websocket streaming to api rpc handler (#1326) 2020-03-10 15:21:43 +00:00
241614ff68 add helper function to determine logger level (#1321)
* add helper function to determine logger level

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-09 23:43:05 +03:00
mlboy
1a4f608ed1 add: auth add generate options Expiry for set token expires (#1319)
Co-authored-by: mlboy <ml3@meitu.com>
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-03-09 17:16:31 +00:00
43b0dbb123 tunnel: reduce allocation and improve performance (#1320)
* tunnel: reduce allocation and improve performance

BenchmarkSha256Old-16 100000 156748 ns/op 11835 B/op 168 allocs/op
BenchmarkSha256Old-16 100000 156229 ns/op 11819 B/op 168 allocs/op

BenchmarkSha256New-16 100000 154751 ns/op 11107 B/op 161 allocs/op
BenchmarkSha256New-16 100000 154263 ns/op 11110 B/op 161 allocs/op

simple change lowers allocations and brings performance

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* fix

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* tunnel: reuse buf in Decrypt

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* fix unneeded conversations

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* base32 string is smaller than hex string

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-09 17:10:08 +00:00
ben-toogood
b344171c80 URL Encode Provider.Endpoint() (#1317)
Co-authored-by: Ben Toogood <ben@micro.mu>
2020-03-09 10:21:49 +00:00
ben-toogood
e3ce45495a os.Exit on log.Fatal (#1316)
* os.Exit on log.Fatal

* Fix TestOptions

Co-authored-by: Ben Toogood <ben@micro.mu>
2020-03-09 09:23:42 +00:00
f01664a551 Merge pull request #1313 from micro/upstream
fix ipv6 address usage in mdns registry and util/addr
2020-03-07 23:50:03 +03:00
8ecbdc1cd6 registry/mdns: add logging for invalid endpoint
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-07 23:19:48 +03:00
55c19afb0b registry/mdns: fix ipv6 addr in mdns registry
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-07 23:17:00 +03:00
077063c212 util/addr: check ip addrs before return
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-07 23:13:56 +03:00
ben-toogood
9a7a65f05e Auth Provider (#1309)
* auth provider mock interface

* Auth Provider Options

* Implement API Server Auth Package

* Add weh utils

* Add Login URL

* Auth Provider Options

* Add auth provider scope and setting token in cookie

* Remove auth_login_url flag

Co-authored-by: Asim Aslam <asim@aslam.me>
Co-authored-by: Ben Toogood <ben@micro.mu>
2020-03-07 11:06:57 +00:00
8ee5607254 [WIP]: broker ErrorHandler option (#1296)
* broker ErrorHandler option

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* rewrite Event interface, add error

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* implement new interface

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* change ErrorHandler func to broker.Handler

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* fix

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-06 21:25:16 +00:00
11be2c68b9 util/stream: fix imports (#1310)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-06 21:17:57 +00:00
a864f812f1 web: fix ipv6 address issue (#1308)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-06 18:44:56 +03:00
Asim Aslam
ae60bea8d8 add stream fix (#1305) 2020-03-06 14:40:47 +00:00
Jake Sanders
a851b9db7a Comment typo in gRPC subscriber (#1304) 2020-03-05 14:55:46 +00:00
d807dac2a7 server/grpc: avoid panic in case of nil Header (#1303)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-05 17:45:31 +03:00
ce2ba71002 server: subscribe to topic with own name if router not nil (#1295)
* server: subscribe to topic with own name if router not nil

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-05 10:29:50 +03:00
Asim Aslam
67c26c71b6 add jitter (#1298) 2020-03-04 15:37:17 +00:00
ben-toogood
9386f36a13 Exit on log.Fatal (#1297) 2020-03-04 13:46:01 +00:00
ben-toogood
6d803d9e45 Implement api/server/cors (#1294) 2020-03-04 11:40:53 +00:00
ben-toogood
6a9001bdb1 Set auth account in context (#1293) 2020-03-04 09:54:52 +00:00
Jake Sanders
3f0c28a815 Expiration is actually a unix timestamp (#1290)
* Expiration is actually a unix timestamp

* int -> int64
2020-03-03 18:15:50 +00:00
Asim Aslam
49ffc60afb Use Foo.Call on /foo (#1286)
Co-authored-by: Jake Sanders <i@am.so-aweso.me>
2020-03-03 16:47:15 +00:00
Jake Sanders
beb5e80e87 Fix nil pointer dereference (#1289) 2020-03-03 13:54:56 +00:00
Jake Sanders
eebd69c995 Change from renekroon/ttlcache to patrickmn/go-cache (#1288) 2020-03-03 13:35:49 +00:00
Jake Sanders
bc71989e2c int64 -> time.Duration (#1287) 2020-03-03 13:15:26 +00:00
89ba602e17 logger fixes and improvements (#1285)
* fix helper fields
* add metadata output for default logger

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-03 11:07:37 +03:00
Jake Sanders
f6102bde70 Add a cache to workers KV storage implementation (#1284)
* cloudflare-cache

* go mod tidy
2020-03-02 18:14:25 +00:00
Pieter Voorwinden
7cad77bfc0 Initialize header to prevent assignment to entry in nil map error (#1282)
Co-authored-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-02 19:17:26 +03:00
ben-toogood
1f2e067f71 k8s runtime - get status from pods (#1283) 2020-03-02 15:49:10 +00:00
b555269b1b copy fields in helper (#1281)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-03-02 14:18:36 +00:00
ben-toogood
9200c70202 Replace validation error with regex for cockroach namespace (#1270)
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-03-01 22:09:06 +00:00
Sumanth Chinthagunta
d8377e09c9 feat(dockerfile): adding dumb-init to base image (#1278) 2020-02-29 21:55:15 +00:00
0754229878 broker/memory: add codec support (#1276)
allow easy testing of other services with memory broker
and also allows to more deeply simulate real brokers

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-29 23:00:29 +03:00
6b8930a960 add new helper method to logger (#1273)
Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-29 00:39:41 +00:00
d0a978bd50 redesign logger (#1272)
* redesign logger

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-29 03:31:59 +03:00
ben-toogood
afe6861e2f Update the k8s deployment to use metadata labels & custom source (#1271) 2020-02-28 15:07:55 +00:00
ben-toogood
962567ef42 Implement config singleton (#1268)
* Implement config singleton

* Pass token in grpc request headers

* Refactor BearerScheme

* Fix typo
2020-02-28 12:58:27 +00:00
Asim Aslam
e21ed3a183 gen account on base32 decode failure (#1269) 2020-02-27 16:11:05 +00:00
64a5ce9607 various fixes (#1267)
* logger: remove Panic log level

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* server/grpc: add missing Unlock in Subscribe error

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* server: minor code change

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* server/grpc: extend test suite with pub/sub testing

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* server/grpc: fix invalid check and allow subscriber error to be returned

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* server/grpc: add pubsub tests

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>

* client/grpc: check for nil req/rsp

Signed-off-by: Vasiliy Tolstov <v.tolstov@unistack.org>
2020-02-26 18:34:40 +00:00
Asim Aslam
d651b16acd generate pseudo accounts (#1264)
* generate pseudo accounts

* when you think you're being clever

* return garbage pseudo account when no token
2020-02-26 13:42:32 +00:00
Eric
1034837f69 Adjusting the BeforeStart () position (#1263)
Co-authored-by: Asim Aslam <asim@aslam.me>
2020-02-26 11:44:10 +03:00
Lars Lehtonen
80f2bfd5d0 config: remove unused sep variable (#1262) 2020-02-26 08:25:33 +00:00
Asim Aslam
6aaaf54275 add MICRO_AUTH_TOKEN, parse token in wrapper, preload config and othe… (#1261)
* add MICRO_AUTH_TOKEN, parse token in wrapper, preload config and other things

* fix wrapper panic
2020-02-25 22:15:44 +00:00
Di Wu
603d37b135 Set option and cli args to the service profile (#1259) 2020-02-25 16:42:42 +00:00
Eric
53c3bff819 add Panic & Panicf to logger (#1258)
* add Panic & Panicf to logger
2020-02-25 17:44:29 +03:00
ben-toogood
dcf859098b Fix k8s commands for github (#1257) 2020-02-25 11:39:03 +00:00
140 changed files with 5404 additions and 1714 deletions

View File

@@ -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 /

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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
View 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
}

View File

@@ -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

View File

@@ -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()

View File

@@ -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
View 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
View 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")
}

View File

@@ -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)
}
}()

View File

@@ -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

View File

@@ -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
}

View File

@@ -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"
}

View File

@@ -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

View File

@@ -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
}

View 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 ""
}

View 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
View 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
View 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
}

View File

@@ -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,
}

View File

@@ -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 {

View File

@@ -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 {}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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)
}

View File

@@ -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())
}

View File

@@ -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
}

View File

@@ -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)
}
}

View File

@@ -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) {

View File

@@ -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

View File

@@ -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() {

View File

@@ -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()))

View File

@@ -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"
}

View File

@@ -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
View 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
}

View 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)
}
}

View 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
}

View 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
View 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)
}
}

View File

@@ -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)
}
}

View File

@@ -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,
}

View File

@@ -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)
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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),

View File

@@ -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

View File

@@ -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
}

View File

@@ -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
View File

@@ -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
View File

@@ -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=

View File

@@ -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
View 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}
}

View File

@@ -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
}

View File

@@ -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
View 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")
}

View File

@@ -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)
}

View File

@@ -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) {

View File

@@ -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})

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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,
})

View File

@@ -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(&registry.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(&registry.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(&registry.Result{Action: "delete", Service: s})
}

View File

@@ -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))

View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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 ""
}

View File

@@ -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
}

View File

@@ -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,

View File

@@ -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
}
}

View File

@@ -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"

View File

@@ -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,
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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,
},
}

View File

@@ -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()
}()

View File

@@ -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)

View File

@@ -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

View File

@@ -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())
}
}

View File

@@ -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 {

View File

@@ -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"]
}

View File

@@ -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

View File

@@ -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}
}

View File

@@ -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()
}

View File

@@ -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
View 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
View 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)
// }
// }

View File

@@ -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.

View File

@@ -24,6 +24,7 @@ func TestCloudflare(t *testing.T) {
Token(apiToken),
Account(accountID),
Namespace(kvID),
CacheTTL(60000000000),
)
records, err := wkv.List()

View File

@@ -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