Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
afe6861e2f | ||
|
962567ef42 | ||
|
e21ed3a183 | ||
64a5ce9607 | |||
|
d651b16acd | ||
|
1034837f69 | ||
|
80f2bfd5d0 | ||
|
6aaaf54275 | ||
|
603d37b135 | ||
|
53c3bff819 | ||
|
dcf859098b | ||
b4a743898e | |||
|
f1e7ea3020 | ||
|
5e8d5834eb | ||
|
ffdf986aac | ||
|
56f8115ea8 | ||
5b0175c2e5 | |||
|
01d88601c0 | ||
|
d467236f8f | ||
24d574ae71 | |||
cf0b39eaac | |||
1f767ba18c | |||
|
915c424213 | ||
117f56ebf7 | |||
|
ceed8942fc | ||
d1e25e7ead | |||
|
7e24c0c1cf | ||
|
ca251ba111 | ||
|
116855572b | ||
|
ee977acfef | ||
|
3fa7c26946 | ||
|
88457b812e | ||
|
78df154a4d | ||
|
c7eed618c2 | ||
|
36bcd3bd82 | ||
|
f4118dc357 | ||
58598d0fe0 | |||
6248f05f74 | |||
|
aa9a0a8d23 | ||
|
1e40c86dfe | ||
|
9696efde02 | ||
|
b3fc8be24e | ||
|
fc5339a368 | ||
|
964b7dee3f | ||
|
158949d0d0 | ||
|
eed8a0bf50 | ||
|
c691d116ab | ||
|
cbe8b7dd09 | ||
|
203486fd31 | ||
|
d9b3b17582 | ||
|
e080ecb43a |
19
.github/workflows/docker.yml
vendored
Normal file
19
.github/workflows/docker.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
name: Check out repository
|
||||
- uses: elgohr/Publish-Docker-Github-Action@2.12
|
||||
name: Build and Push Docker Image
|
||||
with:
|
||||
name: micro/go-micro
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
28
.github/workflows/pr.yml
vendored
Normal file
28
.github/workflows/pr.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: PR Sanity Check
|
||||
on: pull_request
|
||||
|
||||
jobs:
|
||||
|
||||
prtest:
|
||||
name: PR sanity check
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.13
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.13
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
|
||||
- name: Run tests
|
||||
id: tests
|
||||
env:
|
||||
IN_TRAVIS_CI: yes
|
||||
run: go test -v ./...
|
51
.github/workflows/tests.yml
vendored
Normal file
51
.github/workflows/tests.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
name: Run tests
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
|
||||
test:
|
||||
name: Test repo
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.13
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.13
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
go get -v -t -d ./...
|
||||
|
||||
- name: Run tests
|
||||
id: tests
|
||||
env:
|
||||
IN_TRAVIS_CI: yes
|
||||
run: go test -v ./...
|
||||
|
||||
- name: Notify of test failure
|
||||
if: failure()
|
||||
uses: rtCamp/action-slack-notify@v2.0.0
|
||||
env:
|
||||
SLACK_CHANNEL: build
|
||||
SLACK_COLOR: '#BF280A'
|
||||
SLACK_ICON: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png
|
||||
SLACK_TITLE: Tests Failed
|
||||
SLACK_USERNAME: GitHub Actions
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
|
||||
- name: Notify of test success
|
||||
if: success()
|
||||
uses: rtCamp/action-slack-notify@v2.0.0
|
||||
env:
|
||||
SLACK_CHANNEL: build
|
||||
SLACK_COLOR: '#1FAD2B'
|
||||
SLACK_ICON: https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png
|
||||
SLACK_TITLE: Tests Passed
|
||||
SLACK_USERNAME: GitHub Actions
|
||||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
|
17
.travis.yml
17
.travis.yml
@@ -1,17 +0,0 @@
|
||||
language: go
|
||||
go:
|
||||
- 1.13.x
|
||||
env:
|
||||
- GO111MODULE=on IN_TRAVIS_CI=yes
|
||||
before_script:
|
||||
- go install github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||
script:
|
||||
# - golangci-lint run || true
|
||||
# - go test -v -race ./... || true
|
||||
- go test -v ./...
|
||||
notifications:
|
||||
slack:
|
||||
secure: aEvhLbhujaGaKSrOokiG3//PaVHTIrc3fBpoRbCRqfZpyq6WREoapJJhF+tIpWWOwaC9GmChbD6aHo/jMUgwKXVyPSaNjiEL87YzUUpL8B2zslNp1rgfTg/LrzthOx3Q1TYwpaAl3to0fuHUVFX4yMeC2vuThq7WSXgMMxFCtbc=
|
||||
cache:
|
||||
directories:
|
||||
- $GOPATH/pkg/mod
|
@@ -1,4 +1,4 @@
|
||||
# Go Micro [](https://opensource.org/licenses/Apache-2.0) [](https://godoc.org/github.com/micro/go-micro) [](https://travis-ci.org/micro/go-micro) [](https://goreportcard.com/report/github.com/micro/go-micro)
|
||||
# Go Micro [](https://opensource.org/licenses/Apache-2.0) [](https://pkg.go.dev/github.com/micro/go-micro?tab=doc) [](https://travis-ci.org/micro/go-micro) [](https://goreportcard.com/report/github.com/micro/go-micro)
|
||||
|
||||
Go Micro is a framework for microservice development.
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Go Micro [](https://opensource.org/licenses/Apache-2.0) [](https://godoc.org/github.com/micro/go-micro) [](https://travis-ci.org/micro/go-micro) [](https://goreportcard.com/report/github.com/micro/go-micro)
|
||||
# Go Micro [](https://opensource.org/licenses/Apache-2.0) [](https://pkg.go.dev/github.com/micro/go-micro?tab=doc) [](https://travis-ci.org/micro/go-micro) [](https://goreportcard.com/report/github.com/micro/go-micro)
|
||||
|
||||
Go Micro是基于Golang的微服务开发框架。
|
||||
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/bwmarrin/discordgo"
|
||||
"github.com/micro/go-micro/v2/agent/input"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
type discordConn struct {
|
||||
@@ -74,7 +74,7 @@ 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.Log("[bot][loop][send]", err)
|
||||
log.Error("[bot][loop][send]", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/forestgiant/sliceutil"
|
||||
"github.com/micro/go-micro/v2/agent/input"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
tgbotapi "gopkg.in/telegram-bot-api.v4"
|
||||
)
|
||||
|
||||
@@ -104,7 +104,7 @@ 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.Log("[telegram][Send] error:", err)
|
||||
log.Error("[telegram][Send] error:", err)
|
||||
msgConfig.Text = "This bot couldn't send the response (Internal error)"
|
||||
tc.input.api.Send(msgConfig)
|
||||
}
|
||||
|
@@ -8,12 +8,13 @@ import (
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/micro/go-micro/v2/api/handler"
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -26,6 +27,7 @@ const (
|
||||
)
|
||||
|
||||
type brokerHandler struct {
|
||||
once atomic.Value
|
||||
opts handler.Options
|
||||
u websocket.Upgrader
|
||||
}
|
||||
@@ -42,7 +44,6 @@ type conn struct {
|
||||
}
|
||||
|
||||
var (
|
||||
once sync.Once
|
||||
contentType = "text/plain"
|
||||
)
|
||||
|
||||
@@ -135,7 +136,7 @@ func (c *conn) writeLoop() {
|
||||
}()
|
||||
|
||||
if err != nil {
|
||||
log.Log(err.Error())
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -155,10 +156,15 @@ func (b *brokerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
br := b.opts.Service.Client().Options().Broker
|
||||
|
||||
// Setup the broker
|
||||
once.Do(func() {
|
||||
br.Init()
|
||||
br.Connect()
|
||||
})
|
||||
if !b.once.Load().(bool) {
|
||||
if err := br.Init(); err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
}
|
||||
if err := br.Connect(); err != nil {
|
||||
http.Error(w, err.Error(), 500)
|
||||
}
|
||||
b.once.Store(true)
|
||||
}
|
||||
|
||||
// Parse
|
||||
r.ParseForm()
|
||||
@@ -208,7 +214,7 @@ func (b *brokerHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
ws, err := b.u.Upgrade(w, r, nil)
|
||||
if err != nil {
|
||||
log.Log(err.Error())
|
||||
log.Error(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
@@ -235,7 +241,7 @@ func (b *brokerHandler) String() string {
|
||||
}
|
||||
|
||||
func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
return &brokerHandler{
|
||||
h := &brokerHandler{
|
||||
u: websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
@@ -245,6 +251,8 @@ func NewHandler(opts ...handler.Option) handler.Handler {
|
||||
},
|
||||
opts: handler.NewOptions(opts...),
|
||||
}
|
||||
h.once.Store(true)
|
||||
return h
|
||||
}
|
||||
|
||||
func WithCors(cors map[string]bool, opts ...handler.Option) handler.Handler {
|
||||
|
@@ -2,6 +2,7 @@
|
||||
package acme
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"net"
|
||||
)
|
||||
@@ -14,7 +15,10 @@ var (
|
||||
|
||||
// Provider is a ACME provider interface
|
||||
type Provider interface {
|
||||
NewListener(...string) (net.Listener, error)
|
||||
// Listen returns a new listener
|
||||
Listen(...string) (net.Listener, error)
|
||||
// TLSConfig returns a tls config
|
||||
TLSConfig(...string) (*tls.Config, error)
|
||||
}
|
||||
|
||||
// The Let's Encrypt ACME endpoints
|
||||
|
@@ -3,7 +3,10 @@
|
||||
package autocert
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/micro/go-micro/v2/api/server/acme"
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
@@ -12,12 +15,30 @@ import (
|
||||
// autoCertACME is the ACME provider from golang.org/x/crypto/acme/autocert
|
||||
type autocertProvider struct{}
|
||||
|
||||
// NewListener implements acme.Provider
|
||||
func (a *autocertProvider) NewListener(ACMEHosts ...string) (net.Listener, error) {
|
||||
return autocert.NewListener(ACMEHosts...), nil
|
||||
// Listen implements acme.Provider
|
||||
func (a *autocertProvider) Listen(hosts ...string) (net.Listener, error) {
|
||||
return autocert.NewListener(hosts...), nil
|
||||
}
|
||||
|
||||
// TLSConfig returns a new tls config
|
||||
func (a *autocertProvider) TLSConfig(hosts ...string) (*tls.Config, error) {
|
||||
// create a new manager
|
||||
m := &autocert.Manager{
|
||||
Prompt: autocert.AcceptTOS,
|
||||
}
|
||||
if len(hosts) > 0 {
|
||||
m.HostPolicy = autocert.HostWhitelist(hosts...)
|
||||
}
|
||||
dir := cacheDir()
|
||||
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||
log.Printf("warning: autocert not using a cache: %v", err)
|
||||
} else {
|
||||
m.Cache = autocert.DirCache(dir)
|
||||
}
|
||||
return m.TLSConfig(), nil
|
||||
}
|
||||
|
||||
// New returns an autocert acme.Provider
|
||||
func New() acme.Provider {
|
||||
func NewProvider() acme.Provider {
|
||||
return &autocertProvider{}
|
||||
}
|
||||
|
@@ -5,9 +5,9 @@ import (
|
||||
)
|
||||
|
||||
func TestAutocert(t *testing.T) {
|
||||
l := New()
|
||||
l := NewProvider()
|
||||
if _, ok := l.(*autocertProvider); !ok {
|
||||
t.Error("New() didn't return an autocertProvider")
|
||||
t.Error("NewProvider() didn't return an autocertProvider")
|
||||
}
|
||||
// TODO: Travis CI doesn't let us bind :443
|
||||
// if _, err := l.NewListener(); err != nil {
|
||||
|
37
api/server/acme/autocert/cache.go
Normal file
37
api/server/acme/autocert/cache.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package autocert
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func homeDir() string {
|
||||
if runtime.GOOS == "windows" {
|
||||
return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
|
||||
}
|
||||
if h := os.Getenv("HOME"); h != "" {
|
||||
return h
|
||||
}
|
||||
return "/"
|
||||
}
|
||||
|
||||
func cacheDir() string {
|
||||
const base = "golang-autocert"
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
return filepath.Join(homeDir(), "Library", "Caches", base)
|
||||
case "windows":
|
||||
for _, ev := range []string{"APPDATA", "CSIDL_APPDATA", "TEMP", "TMP"} {
|
||||
if v := os.Getenv(ev); v != "" {
|
||||
return filepath.Join(v, base)
|
||||
}
|
||||
}
|
||||
// Worst case:
|
||||
return filepath.Join(homeDir(), base)
|
||||
}
|
||||
if xdg := os.Getenv("XDG_CACHE_HOME"); xdg != "" {
|
||||
return filepath.Join(xdg, base)
|
||||
}
|
||||
return filepath.Join(homeDir(), ".cache", base)
|
||||
}
|
@@ -2,6 +2,7 @@
|
||||
package certmagic
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
@@ -16,7 +17,8 @@ type certmagicProvider struct {
|
||||
opts acme.Options
|
||||
}
|
||||
|
||||
func (c *certmagicProvider) NewListener(ACMEHosts ...string) (net.Listener, error) {
|
||||
// TODO: set self-contained options
|
||||
func (c *certmagicProvider) setup() {
|
||||
certmagic.Default.CA = c.opts.CA
|
||||
if c.opts.ChallengeProvider != nil {
|
||||
// Enabling DNS Challenge disables the other challenges
|
||||
@@ -34,12 +36,20 @@ func (c *certmagicProvider) NewListener(ACMEHosts ...string) (net.Listener, erro
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
randomDuration := (7 * 24 * time.Hour) + (time.Duration(rand.Intn(504)) * time.Hour)
|
||||
certmagic.Default.RenewDurationBefore = randomDuration
|
||||
}
|
||||
|
||||
return certmagic.Listen(ACMEHosts)
|
||||
func (c *certmagicProvider) Listen(hosts ...string) (net.Listener, error) {
|
||||
c.setup()
|
||||
return certmagic.Listen(hosts)
|
||||
}
|
||||
|
||||
func (c *certmagicProvider) TLSConfig(hosts ...string) (*tls.Config, error) {
|
||||
c.setup()
|
||||
return certmagic.TLS(hosts)
|
||||
}
|
||||
|
||||
// New returns a certmagic provider
|
||||
func New(options ...acme.Option) acme.Provider {
|
||||
func NewProvider(options ...acme.Option) acme.Provider {
|
||||
opts := acme.DefaultOptions()
|
||||
|
||||
for _, o := range options {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package certmagic
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"reflect"
|
||||
@@ -19,8 +20,11 @@ func TestCertMagic(t *testing.T) {
|
||||
if len(os.Getenv("IN_TRAVIS_CI")) != 0 {
|
||||
t.Skip("Travis doesn't let us bind :443")
|
||||
}
|
||||
l, err := New().NewListener()
|
||||
l, err := NewProvider().Listen()
|
||||
if err != nil {
|
||||
if _, ok := err.(*net.OpError); ok {
|
||||
t.Skip("Run under non privileged user")
|
||||
}
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
l.Close()
|
||||
@@ -36,10 +40,10 @@ func TestCertMagic(t *testing.T) {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
l, err = New(acme.AcceptToS(true),
|
||||
l, err = NewProvider(acme.AcceptToS(true),
|
||||
acme.CA(acme.LetsEncryptStagingCA),
|
||||
acme.ChallengeProvider(p),
|
||||
).NewListener()
|
||||
).Listen()
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
@@ -180,7 +184,7 @@ func TestStorageImplementation(t *testing.T) {
|
||||
|
||||
// New interface doesn't return an error, so call it in case any log.Fatal
|
||||
// happens
|
||||
New(acme.Cache(s))
|
||||
NewProvider(acme.Cache(s))
|
||||
}
|
||||
|
||||
// Full test with a real zone, with against LE staging
|
||||
@@ -207,7 +211,7 @@ func TestE2e(t *testing.T) {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
||||
testProvider := New(
|
||||
testProvider := NewProvider(
|
||||
acme.AcceptToS(true),
|
||||
acme.Cache(testStorage),
|
||||
acme.CA(acme.LetsEncryptStagingCA),
|
||||
@@ -215,7 +219,7 @@ func TestE2e(t *testing.T) {
|
||||
acme.OnDemand(false),
|
||||
)
|
||||
|
||||
listener, err := testProvider.NewListener("*.micro.mu", "micro.mu")
|
||||
listener, err := testProvider.Listen("*.micro.mu", "micro.mu")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ import (
|
||||
|
||||
"github.com/gorilla/handlers"
|
||||
"github.com/micro/go-micro/v2/api/server"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
type httpServer struct {
|
||||
@@ -54,7 +54,7 @@ func (s *httpServer) Start() error {
|
||||
|
||||
if s.opts.EnableACME && s.opts.ACMEProvider != nil {
|
||||
// should we check the address to make sure its using :443?
|
||||
l, err = s.opts.ACMEProvider.NewListener(s.opts.ACMEHosts...)
|
||||
l, err = s.opts.ACMEProvider.Listen(s.opts.ACMEHosts...)
|
||||
} else if s.opts.EnableTLS && s.opts.TLSConfig != nil {
|
||||
l, err = tls.Listen("tcp", s.address, s.opts.TLSConfig)
|
||||
} else {
|
||||
@@ -65,7 +65,7 @@ func (s *httpServer) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Logf("HTTP API Listening on %s", l.Addr().String())
|
||||
log.Infof("HTTP API Listening on %s", l.Addr().String())
|
||||
|
||||
s.mtx.Lock()
|
||||
s.address = l.Addr().String()
|
||||
|
17
auth/auth.go
17
auth/auth.go
@@ -7,8 +7,6 @@ import (
|
||||
|
||||
// Auth providers authentication and authorization
|
||||
type Auth interface {
|
||||
// String to identify the package
|
||||
String() string
|
||||
// Init the auth package
|
||||
Init(opts ...Option) error
|
||||
// Options returns the options set
|
||||
@@ -17,8 +15,10 @@ 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
|
||||
}
|
||||
|
||||
// Resource is an entity such as a user or
|
||||
@@ -31,16 +31,19 @@ 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 string `json: "id"`
|
||||
Id string `json:"id"`
|
||||
// Token used to authenticate
|
||||
Token string `json: "token"`
|
||||
Token string `json:"token"`
|
||||
// Time of Account creation
|
||||
Created time.Time `json:"created"`
|
||||
// Time of Account expiry
|
||||
|
123
auth/default.go
123
auth/default.go
@@ -1,39 +1,122 @@
|
||||
package auth
|
||||
|
||||
var (
|
||||
DefaultAuth Auth = new(noop)
|
||||
import (
|
||||
"encoding/base32"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type noop struct {
|
||||
options Options
|
||||
var (
|
||||
DefaultAuth = NewAuth()
|
||||
)
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
// String name of implementation
|
||||
func (a *noop) String() string {
|
||||
return "noop"
|
||||
// NewAuth returns a new default registry which is memory
|
||||
func NewAuth(opts ...Option) Auth {
|
||||
var options Options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return &memory{
|
||||
accounts: make(map[string]*Account),
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
// Init the svc
|
||||
func (a *noop) Init(...Option) error {
|
||||
// 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 (n *memory) Init(opts ...Option) error {
|
||||
for _, o := range opts {
|
||||
o(&n.opts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Options set in init
|
||||
func (a *noop) Options() Options {
|
||||
return a.options
|
||||
func (n *memory) Options() Options {
|
||||
return n.opts
|
||||
}
|
||||
|
||||
// Generate a new auth Account
|
||||
func (a *noop) Generate(id string, ops ...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
|
||||
}
|
||||
|
||||
// Revoke an authorization Account
|
||||
func (a *noop) Revoke(token string) error {
|
||||
func (n *memory) Revoke(token string) error {
|
||||
n.Lock()
|
||||
delete(n.accounts, token)
|
||||
n.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate a account token
|
||||
func (a *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 (n *memory) String() string {
|
||||
return "memory"
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
@@ -8,14 +9,19 @@ import (
|
||||
"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
|
||||
ErrMissingToken = errors.New("A valid JWT is required")
|
||||
)
|
||||
|
||||
// NewAuth returns a new instance of the Auth service
|
||||
func NewAuth(opts ...auth.Option) auth.Auth {
|
||||
@@ -56,7 +62,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
|
||||
}
|
||||
@@ -64,7 +76,7 @@ func (s *svc) Generate(id string, ops ...auth.GenerateOption) (*auth.Account, er
|
||||
options := auth.NewGenerateOptions(ops...)
|
||||
account := jwt.NewWithClaims(jwt.SigningMethodRS256, AuthClaims{
|
||||
id, options.Roles, options.Metadata, jwt.StandardClaims{
|
||||
Subject: "TODO",
|
||||
Subject: id,
|
||||
ExpiresAt: time.Now().Add(time.Hour * 24).Unix(),
|
||||
},
|
||||
})
|
||||
@@ -87,10 +99,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
|
||||
@@ -100,7 +122,10 @@ func (s *svc) Validate(token string) (*auth.Account, error) {
|
||||
return nil, ErrInvalidToken
|
||||
}
|
||||
|
||||
claims := res.Claims.(*AuthClaims)
|
||||
claims, ok := res.Claims.(*AuthClaims)
|
||||
if !ok {
|
||||
return nil, ErrInvalidToken
|
||||
}
|
||||
|
||||
return &auth.Account{
|
||||
Id: claims.Id,
|
||||
|
@@ -1,41 +1,51 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
b64 "encoding/base64"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
type GenerateOptions struct {
|
||||
// Metadata associated with the account
|
||||
Metadata map[string]string
|
||||
Roles []*Role
|
||||
// Roles/scopes associated with the account
|
||||
Roles []*Role
|
||||
}
|
||||
|
||||
type GenerateOption func(o *GenerateOptions)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: auth/service/proto/auth.proto
|
||||
// source: micro/go-micro/auth/service/proto/auth.proto
|
||||
|
||||
package go_micro_auth
|
||||
|
||||
@@ -36,7 +36,7 @@ func (m *Account) Reset() { *m = Account{} }
|
||||
func (m *Account) String() string { return proto.CompactTextString(m) }
|
||||
func (*Account) ProtoMessage() {}
|
||||
func (*Account) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{0}
|
||||
return fileDescriptor_de609d4872dacc78, []int{0}
|
||||
}
|
||||
|
||||
func (m *Account) XXX_Unmarshal(b []byte) error {
|
||||
@@ -111,7 +111,7 @@ func (m *Role) Reset() { *m = Role{} }
|
||||
func (m *Role) String() string { return proto.CompactTextString(m) }
|
||||
func (*Role) ProtoMessage() {}
|
||||
func (*Role) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{1}
|
||||
return fileDescriptor_de609d4872dacc78, []int{1}
|
||||
}
|
||||
|
||||
func (m *Role) XXX_Unmarshal(b []byte) error {
|
||||
@@ -158,7 +158,7 @@ func (m *Resource) Reset() { *m = Resource{} }
|
||||
func (m *Resource) String() string { return proto.CompactTextString(m) }
|
||||
func (*Resource) ProtoMessage() {}
|
||||
func (*Resource) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{2}
|
||||
return fileDescriptor_de609d4872dacc78, []int{2}
|
||||
}
|
||||
|
||||
func (m *Resource) XXX_Unmarshal(b []byte) error {
|
||||
@@ -204,7 +204,7 @@ func (m *GenerateRequest) Reset() { *m = GenerateRequest{} }
|
||||
func (m *GenerateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*GenerateRequest) ProtoMessage() {}
|
||||
func (*GenerateRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{3}
|
||||
return fileDescriptor_de609d4872dacc78, []int{3}
|
||||
}
|
||||
|
||||
func (m *GenerateRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -243,7 +243,7 @@ func (m *GenerateResponse) Reset() { *m = GenerateResponse{} }
|
||||
func (m *GenerateResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*GenerateResponse) ProtoMessage() {}
|
||||
func (*GenerateResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{4}
|
||||
return fileDescriptor_de609d4872dacc78, []int{4}
|
||||
}
|
||||
|
||||
func (m *GenerateResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -271,78 +271,78 @@ func (m *GenerateResponse) GetAccount() *Account {
|
||||
return nil
|
||||
}
|
||||
|
||||
type ValidateRequest struct {
|
||||
type VerifyRequest struct {
|
||||
Token string `protobuf:"bytes,1,opt,name=token,proto3" json:"token,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ValidateRequest) Reset() { *m = ValidateRequest{} }
|
||||
func (m *ValidateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ValidateRequest) ProtoMessage() {}
|
||||
func (*ValidateRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{5}
|
||||
func (m *VerifyRequest) Reset() { *m = VerifyRequest{} }
|
||||
func (m *VerifyRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*VerifyRequest) ProtoMessage() {}
|
||||
func (*VerifyRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_de609d4872dacc78, []int{5}
|
||||
}
|
||||
|
||||
func (m *ValidateRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ValidateRequest.Unmarshal(m, b)
|
||||
func (m *VerifyRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_VerifyRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ValidateRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ValidateRequest.Marshal(b, m, deterministic)
|
||||
func (m *VerifyRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_VerifyRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ValidateRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ValidateRequest.Merge(m, src)
|
||||
func (m *VerifyRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_VerifyRequest.Merge(m, src)
|
||||
}
|
||||
func (m *ValidateRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_ValidateRequest.Size(m)
|
||||
func (m *VerifyRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_VerifyRequest.Size(m)
|
||||
}
|
||||
func (m *ValidateRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ValidateRequest.DiscardUnknown(m)
|
||||
func (m *VerifyRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_VerifyRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ValidateRequest proto.InternalMessageInfo
|
||||
var xxx_messageInfo_VerifyRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *ValidateRequest) GetToken() string {
|
||||
func (m *VerifyRequest) GetToken() string {
|
||||
if m != nil {
|
||||
return m.Token
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type ValidateResponse struct {
|
||||
type VerifyResponse struct {
|
||||
Account *Account `protobuf:"bytes,1,opt,name=account,proto3" json:"account,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ValidateResponse) Reset() { *m = ValidateResponse{} }
|
||||
func (m *ValidateResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ValidateResponse) ProtoMessage() {}
|
||||
func (*ValidateResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{6}
|
||||
func (m *VerifyResponse) Reset() { *m = VerifyResponse{} }
|
||||
func (m *VerifyResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*VerifyResponse) ProtoMessage() {}
|
||||
func (*VerifyResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_de609d4872dacc78, []int{6}
|
||||
}
|
||||
|
||||
func (m *ValidateResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ValidateResponse.Unmarshal(m, b)
|
||||
func (m *VerifyResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_VerifyResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ValidateResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ValidateResponse.Marshal(b, m, deterministic)
|
||||
func (m *VerifyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_VerifyResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ValidateResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ValidateResponse.Merge(m, src)
|
||||
func (m *VerifyResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_VerifyResponse.Merge(m, src)
|
||||
}
|
||||
func (m *ValidateResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_ValidateResponse.Size(m)
|
||||
func (m *VerifyResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_VerifyResponse.Size(m)
|
||||
}
|
||||
func (m *ValidateResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ValidateResponse.DiscardUnknown(m)
|
||||
func (m *VerifyResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_VerifyResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ValidateResponse proto.InternalMessageInfo
|
||||
var xxx_messageInfo_VerifyResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *ValidateResponse) GetAccount() *Account {
|
||||
func (m *VerifyResponse) GetAccount() *Account {
|
||||
if m != nil {
|
||||
return m.Account
|
||||
}
|
||||
@@ -360,7 +360,7 @@ func (m *RevokeRequest) Reset() { *m = RevokeRequest{} }
|
||||
func (m *RevokeRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*RevokeRequest) ProtoMessage() {}
|
||||
func (*RevokeRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{7}
|
||||
return fileDescriptor_de609d4872dacc78, []int{7}
|
||||
}
|
||||
|
||||
func (m *RevokeRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -398,7 +398,7 @@ func (m *RevokeResponse) Reset() { *m = RevokeResponse{} }
|
||||
func (m *RevokeResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*RevokeResponse) ProtoMessage() {}
|
||||
func (*RevokeResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_21300bfacc51fc2a, []int{8}
|
||||
return fileDescriptor_de609d4872dacc78, []int{8}
|
||||
}
|
||||
|
||||
func (m *RevokeResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -426,41 +426,43 @@ func init() {
|
||||
proto.RegisterType((*Resource)(nil), "go.micro.auth.Resource")
|
||||
proto.RegisterType((*GenerateRequest)(nil), "go.micro.auth.GenerateRequest")
|
||||
proto.RegisterType((*GenerateResponse)(nil), "go.micro.auth.GenerateResponse")
|
||||
proto.RegisterType((*ValidateRequest)(nil), "go.micro.auth.ValidateRequest")
|
||||
proto.RegisterType((*ValidateResponse)(nil), "go.micro.auth.ValidateResponse")
|
||||
proto.RegisterType((*VerifyRequest)(nil), "go.micro.auth.VerifyRequest")
|
||||
proto.RegisterType((*VerifyResponse)(nil), "go.micro.auth.VerifyResponse")
|
||||
proto.RegisterType((*RevokeRequest)(nil), "go.micro.auth.RevokeRequest")
|
||||
proto.RegisterType((*RevokeResponse)(nil), "go.micro.auth.RevokeResponse")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("auth/service/proto/auth.proto", fileDescriptor_21300bfacc51fc2a) }
|
||||
|
||||
var fileDescriptor_21300bfacc51fc2a = []byte{
|
||||
// 429 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0x4d, 0x6f, 0xd3, 0x40,
|
||||
0x10, 0xad, 0x3f, 0xe2, 0x98, 0x89, 0xd2, 0x46, 0x03, 0x2a, 0x56, 0x44, 0x21, 0xb2, 0x40, 0x84,
|
||||
0x8b, 0x83, 0xdc, 0x0b, 0x82, 0x0b, 0x15, 0xa0, 0x9e, 0x2a, 0xa4, 0x3d, 0x70, 0x5f, 0xec, 0x11,
|
||||
0xb5, 0xe2, 0x78, 0xcd, 0x7a, 0x1d, 0xe1, 0xdf, 0xc0, 0x6f, 0xe5, 0x3f, 0x20, 0xaf, 0xbd, 0x69,
|
||||
0xea, 0xb4, 0xaa, 0xd4, 0xdb, 0x7c, 0xbc, 0x79, 0xf3, 0xde, 0x68, 0x17, 0xce, 0x78, 0xad, 0xae,
|
||||
0x57, 0x15, 0xc9, 0x6d, 0x96, 0xd0, 0xaa, 0x94, 0x42, 0x89, 0x55, 0x5b, 0x8a, 0x74, 0x88, 0xd3,
|
||||
0x5f, 0x22, 0xda, 0x64, 0x89, 0x14, 0x51, 0x5b, 0x0c, 0xff, 0xda, 0x30, 0xbe, 0x48, 0x12, 0x51,
|
||||
0x17, 0x0a, 0x8f, 0xc1, 0xce, 0xd2, 0xc0, 0x5a, 0x58, 0xcb, 0x27, 0xcc, 0xce, 0x52, 0x7c, 0x06,
|
||||
0x23, 0x25, 0xd6, 0x54, 0x04, 0xb6, 0x2e, 0x75, 0x09, 0x06, 0x30, 0x4e, 0x24, 0x71, 0x45, 0x69,
|
||||
0xe0, 0x2c, 0xac, 0xa5, 0xc3, 0x4c, 0x8a, 0xa7, 0xe0, 0xd1, 0x9f, 0x32, 0x93, 0x4d, 0xe0, 0xea,
|
||||
0x46, 0x9f, 0xe1, 0x3b, 0x18, 0x49, 0x91, 0x53, 0x15, 0x8c, 0x16, 0xce, 0x72, 0x12, 0x3f, 0x8d,
|
||||
0x6e, 0x49, 0x88, 0x98, 0xc8, 0x89, 0x75, 0x08, 0xfc, 0x0c, 0xfe, 0x86, 0x14, 0x4f, 0xb9, 0xe2,
|
||||
0x81, 0xa7, 0xd1, 0xaf, 0x07, 0xe8, 0x5e, 0x6c, 0x74, 0xd5, 0xc3, 0xbe, 0x15, 0x4a, 0x36, 0x6c,
|
||||
0x37, 0x35, 0xff, 0x04, 0xd3, 0x5b, 0x2d, 0x9c, 0x81, 0xb3, 0xa6, 0xa6, 0xb7, 0xd5, 0x86, 0xad,
|
||||
0xaf, 0x2d, 0xcf, 0x6b, 0x32, 0xbe, 0x74, 0xf2, 0xd1, 0xfe, 0x60, 0x85, 0xdf, 0xc1, 0x6d, 0xd5,
|
||||
0x20, 0x82, 0x5b, 0xf0, 0x0d, 0xf5, 0x43, 0x3a, 0xc6, 0x73, 0xf0, 0x25, 0x55, 0xa2, 0x96, 0x49,
|
||||
0x37, 0x38, 0x89, 0x9f, 0x0f, 0x8d, 0xf4, 0x6d, 0xb6, 0x03, 0x86, 0x31, 0xf8, 0xa6, 0x7a, 0x27,
|
||||
0x29, 0x82, 0xab, 0x9a, 0xd2, 0x28, 0xd1, 0x71, 0xf8, 0x05, 0x4e, 0x2e, 0xa9, 0x20, 0xc9, 0x15,
|
||||
0x31, 0xfa, 0x5d, 0x53, 0xa5, 0xf0, 0x3d, 0x8c, 0x79, 0xe7, 0x5b, 0x4f, 0x4f, 0xe2, 0xd3, 0xbb,
|
||||
0xaf, 0xc2, 0x0c, 0x2c, 0xfc, 0x0a, 0xb3, 0x1b, 0x92, 0xaa, 0x14, 0x45, 0x45, 0x8f, 0x60, 0x79,
|
||||
0x0b, 0x27, 0x3f, 0x78, 0x9e, 0xa5, 0x7b, 0x52, 0x76, 0x8f, 0xc2, 0xda, 0x7b, 0x14, 0xed, 0xba,
|
||||
0x1b, 0xe0, 0xa3, 0xd7, 0xbd, 0x81, 0x29, 0xa3, 0xad, 0x58, 0x3f, 0xb0, 0x6c, 0x06, 0xc7, 0x06,
|
||||
0xd6, 0xad, 0x8a, 0xff, 0x59, 0xe0, 0x5e, 0xd4, 0xea, 0x1a, 0xaf, 0xc0, 0x37, 0xb6, 0xf1, 0xe5,
|
||||
0x60, 0xdd, 0xe0, 0xa8, 0xf3, 0x57, 0xf7, 0xf6, 0x3b, 0xd6, 0xf0, 0xa8, 0xa5, 0x33, 0xb6, 0x0e,
|
||||
0xe8, 0x06, 0x87, 0x39, 0xa0, 0x1b, 0xde, 0x23, 0x3c, 0xc2, 0x4b, 0xf0, 0x3a, 0xe1, 0xf8, 0xe2,
|
||||
0xe0, 0xe9, 0xec, 0xd9, 0x9e, 0x9f, 0xdd, 0xd3, 0x35, 0x44, 0x3f, 0x3d, 0xfd, 0x97, 0xcf, 0xff,
|
||||
0x07, 0x00, 0x00, 0xff, 0xff, 0x79, 0x35, 0xb2, 0x7e, 0xec, 0x03, 0x00, 0x00,
|
||||
func init() {
|
||||
proto.RegisterFile("micro/go-micro/auth/service/proto/auth.proto", fileDescriptor_de609d4872dacc78)
|
||||
}
|
||||
|
||||
var fileDescriptor_de609d4872dacc78 = []byte{
|
||||
// 432 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x53, 0x4b, 0x6f, 0xd3, 0x40,
|
||||
0x10, 0xae, 0x1d, 0xe7, 0xc1, 0x44, 0x09, 0xd1, 0x80, 0x8a, 0x15, 0xf1, 0x88, 0x56, 0x20, 0x05,
|
||||
0x09, 0x1c, 0xe4, 0x5e, 0x10, 0x5c, 0x28, 0x0f, 0xf5, 0x54, 0x21, 0xed, 0x81, 0xfb, 0xe2, 0x0c,
|
||||
0xad, 0x95, 0xc4, 0x6b, 0xd6, 0xeb, 0x08, 0xff, 0x06, 0x7e, 0x28, 0x7f, 0x03, 0x79, 0xd7, 0x1b,
|
||||
0x6a, 0xb7, 0xe5, 0x00, 0xb7, 0x79, 0x7c, 0xf3, 0xcd, 0xf7, 0x8d, 0x76, 0xe1, 0xc5, 0x2e, 0x4d,
|
||||
0x94, 0x5c, 0x5d, 0xc8, 0x97, 0x36, 0x10, 0xa5, 0xbe, 0x5c, 0x15, 0xa4, 0xf6, 0x69, 0x42, 0xab,
|
||||
0x5c, 0x49, 0x6d, 0x4b, 0x91, 0x09, 0x71, 0x72, 0x21, 0x23, 0x83, 0x8b, 0xea, 0x22, 0xfb, 0xe9,
|
||||
0xc3, 0xf0, 0x34, 0x49, 0x64, 0x99, 0x69, 0x9c, 0x82, 0x9f, 0xae, 0x43, 0x6f, 0xe1, 0x2d, 0xef,
|
||||
0x70, 0x3f, 0x5d, 0xe3, 0x7d, 0xe8, 0x6b, 0xb9, 0xa1, 0x2c, 0xf4, 0x4d, 0xc9, 0x26, 0x18, 0xc2,
|
||||
0x30, 0x51, 0x24, 0x34, 0xad, 0xc3, 0xde, 0xc2, 0x5b, 0xf6, 0xb8, 0x4b, 0xf1, 0x18, 0x06, 0xf4,
|
||||
0x23, 0x4f, 0x55, 0x15, 0x06, 0xa6, 0xd1, 0x64, 0xf8, 0x1c, 0xfa, 0x4a, 0x6e, 0xa9, 0x08, 0xfb,
|
||||
0x8b, 0xde, 0x72, 0x1c, 0xdf, 0x8b, 0x5a, 0x12, 0x22, 0x2e, 0xb7, 0xc4, 0x2d, 0x02, 0xdf, 0xc1,
|
||||
0x68, 0x47, 0x5a, 0xac, 0x85, 0x16, 0xe1, 0xc0, 0xa0, 0x9f, 0x76, 0xd0, 0x8d, 0xd8, 0xe8, 0xbc,
|
||||
0x81, 0x7d, 0xca, 0xb4, 0xaa, 0xf8, 0x61, 0x6a, 0xfe, 0x16, 0x26, 0xad, 0x16, 0xce, 0xa0, 0xb7,
|
||||
0xa1, 0xaa, 0xb1, 0x55, 0x87, 0xb5, 0xaf, 0xbd, 0xd8, 0x96, 0xe4, 0x7c, 0x99, 0xe4, 0x8d, 0xff,
|
||||
0xda, 0x63, 0x9f, 0x21, 0xa8, 0xd5, 0x20, 0x42, 0x90, 0x89, 0x1d, 0x35, 0x43, 0x26, 0xc6, 0x13,
|
||||
0x18, 0x29, 0x2a, 0x64, 0xa9, 0x12, 0x3b, 0x38, 0x8e, 0x1f, 0x74, 0x8d, 0x34, 0x6d, 0x7e, 0x00,
|
||||
0xb2, 0x18, 0x46, 0xae, 0x7a, 0x23, 0x29, 0x42, 0xa0, 0xab, 0xdc, 0x29, 0x31, 0x31, 0xfb, 0x00,
|
||||
0x77, 0xcf, 0x28, 0x23, 0x25, 0x34, 0x71, 0xfa, 0x5e, 0x52, 0xa1, 0xf1, 0x15, 0x0c, 0x85, 0xf5,
|
||||
0x6d, 0xa6, 0xc7, 0xf1, 0xf1, 0xcd, 0x57, 0xe1, 0x0e, 0xc6, 0x3e, 0xc2, 0xec, 0x0f, 0x49, 0x91,
|
||||
0xcb, 0xac, 0xa0, 0x7f, 0x60, 0x79, 0x06, 0x93, 0x2f, 0xa4, 0xd2, 0x6f, 0x95, 0x13, 0x72, 0x78,
|
||||
0x12, 0xde, 0x95, 0x27, 0xc1, 0xde, 0xc3, 0xd4, 0xc1, 0xfe, 0x67, 0x15, 0xa7, 0xbd, 0xdc, 0xd0,
|
||||
0xdf, 0x57, 0xcd, 0x60, 0xea, 0x60, 0x76, 0x55, 0xfc, 0xcb, 0x83, 0xe0, 0xb4, 0xd4, 0x97, 0x78,
|
||||
0x0e, 0x23, 0x67, 0x19, 0x1f, 0x77, 0xd6, 0x75, 0x0e, 0x3a, 0x7f, 0x72, 0x6b, 0xdf, 0xb2, 0xb2,
|
||||
0x23, 0x3c, 0x83, 0x81, 0x35, 0x85, 0x0f, 0x3b, 0xe0, 0xd6, 0x49, 0xe6, 0x8f, 0x6e, 0xe9, 0x5e,
|
||||
0x25, 0xb2, 0x92, 0xaf, 0x11, 0xb5, 0x0c, 0x5f, 0x23, 0x6a, 0xfb, 0x64, 0x47, 0x5f, 0x07, 0xe6,
|
||||
0x07, 0x9f, 0xfc, 0x0e, 0x00, 0x00, 0xff, 0xff, 0xf0, 0x34, 0xce, 0x17, 0xf1, 0x03, 0x00, 0x00,
|
||||
}
|
||||
|
@@ -1,16 +1,16 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: auth/service/proto/auth.proto
|
||||
// source: micro/go-micro/auth/service/proto/auth.proto
|
||||
|
||||
package go_micro_auth
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
math "math"
|
||||
|
||||
context "context"
|
||||
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
math "math"
|
||||
)
|
||||
|
||||
import (
|
||||
context "context"
|
||||
client "github.com/micro/go-micro/v2/client"
|
||||
server "github.com/micro/go-micro/v2/server"
|
||||
)
|
||||
@@ -35,7 +35,7 @@ var _ server.Option
|
||||
|
||||
type AuthService interface {
|
||||
Generate(ctx context.Context, in *GenerateRequest, opts ...client.CallOption) (*GenerateResponse, error)
|
||||
Validate(ctx context.Context, in *ValidateRequest, opts ...client.CallOption) (*ValidateResponse, error)
|
||||
Verify(ctx context.Context, in *VerifyRequest, opts ...client.CallOption) (*VerifyResponse, error)
|
||||
Revoke(ctx context.Context, in *RevokeRequest, opts ...client.CallOption) (*RevokeResponse, error)
|
||||
}
|
||||
|
||||
@@ -45,12 +45,6 @@ type authService struct {
|
||||
}
|
||||
|
||||
func NewAuthService(name string, c client.Client) AuthService {
|
||||
if c == nil {
|
||||
c = client.NewClient()
|
||||
}
|
||||
if len(name) == 0 {
|
||||
name = "go.micro.auth"
|
||||
}
|
||||
return &authService{
|
||||
c: c,
|
||||
name: name,
|
||||
@@ -67,9 +61,9 @@ func (c *authService) Generate(ctx context.Context, in *GenerateRequest, opts ..
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *authService) Validate(ctx context.Context, in *ValidateRequest, opts ...client.CallOption) (*ValidateResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Auth.Validate", in)
|
||||
out := new(ValidateResponse)
|
||||
func (c *authService) Verify(ctx context.Context, in *VerifyRequest, opts ...client.CallOption) (*VerifyResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Auth.Verify", in)
|
||||
out := new(VerifyResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -91,14 +85,14 @@ func (c *authService) Revoke(ctx context.Context, in *RevokeRequest, opts ...cli
|
||||
|
||||
type AuthHandler interface {
|
||||
Generate(context.Context, *GenerateRequest, *GenerateResponse) error
|
||||
Validate(context.Context, *ValidateRequest, *ValidateResponse) error
|
||||
Verify(context.Context, *VerifyRequest, *VerifyResponse) error
|
||||
Revoke(context.Context, *RevokeRequest, *RevokeResponse) error
|
||||
}
|
||||
|
||||
func RegisterAuthHandler(s server.Server, hdlr AuthHandler, opts ...server.HandlerOption) error {
|
||||
type auth interface {
|
||||
Generate(ctx context.Context, in *GenerateRequest, out *GenerateResponse) error
|
||||
Validate(ctx context.Context, in *ValidateRequest, out *ValidateResponse) error
|
||||
Verify(ctx context.Context, in *VerifyRequest, out *VerifyResponse) error
|
||||
Revoke(ctx context.Context, in *RevokeRequest, out *RevokeResponse) error
|
||||
}
|
||||
type Auth struct {
|
||||
@@ -116,8 +110,8 @@ func (h *authHandler) Generate(ctx context.Context, in *GenerateRequest, out *Ge
|
||||
return h.AuthHandler.Generate(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *authHandler) Validate(ctx context.Context, in *ValidateRequest, out *ValidateResponse) error {
|
||||
return h.AuthHandler.Validate(ctx, in, out)
|
||||
func (h *authHandler) Verify(ctx context.Context, in *VerifyRequest, out *VerifyResponse) error {
|
||||
return h.AuthHandler.Verify(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *authHandler) Revoke(ctx context.Context, in *RevokeRequest, out *RevokeResponse) error {
|
||||
|
@@ -4,47 +4,47 @@ package go.micro.auth;
|
||||
|
||||
service Auth {
|
||||
rpc Generate(GenerateRequest) returns (GenerateResponse) {};
|
||||
rpc Validate(ValidateRequest) returns (ValidateResponse) {};
|
||||
rpc Verify(VerifyRequest) returns (VerifyResponse) {};
|
||||
rpc Revoke(RevokeRequest) returns (RevokeResponse) {};
|
||||
}
|
||||
|
||||
message Account{
|
||||
string id = 1;
|
||||
string token = 2;
|
||||
int64 created = 3;
|
||||
int64 expiry = 4;
|
||||
repeated Role roles = 5;
|
||||
string id = 1;
|
||||
string token = 2;
|
||||
int64 created = 3;
|
||||
int64 expiry = 4;
|
||||
repeated Role roles = 5;
|
||||
map<string, string> metadata = 6;
|
||||
}
|
||||
|
||||
message Role {
|
||||
string name = 1;
|
||||
Resource resource = 2;
|
||||
string name = 1;
|
||||
Resource resource = 2;
|
||||
}
|
||||
|
||||
message Resource{
|
||||
string name = 1;
|
||||
string type = 2;
|
||||
string name = 1;
|
||||
string type = 2;
|
||||
}
|
||||
|
||||
message GenerateRequest {
|
||||
Account account = 1;
|
||||
Account account = 1;
|
||||
}
|
||||
|
||||
message GenerateResponse {
|
||||
Account account = 1;
|
||||
Account account = 1;
|
||||
}
|
||||
|
||||
message ValidateRequest {
|
||||
string token = 1;
|
||||
message VerifyRequest {
|
||||
string token = 1;
|
||||
}
|
||||
|
||||
message ValidateResponse {
|
||||
Account account = 1;
|
||||
message VerifyResponse {
|
||||
Account account = 1;
|
||||
}
|
||||
|
||||
message RevokeRequest {
|
||||
string token = 1;
|
||||
string token = 1;
|
||||
}
|
||||
|
||||
message RevokeResponse {}
|
||||
|
@@ -72,9 +72,9 @@ func (s *svc) Revoke(token string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate an account token
|
||||
func (s *svc) Validate(token string) (*auth.Account, error) {
|
||||
resp, err := s.auth.Validate(context.Background(), &pb.ValidateRequest{Token: token})
|
||||
// Verify an account token
|
||||
func (s *svc) Verify(token string) (*auth.Account, error) {
|
||||
resp, err := s.auth.Verify(context.Background(), &pb.VerifyRequest{Token: token})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
130
auth/store/store.go
Normal file
130
auth/store/store.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"time"
|
||||
|
||||
"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 {
|
||||
var options auth.Options
|
||||
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
return &Auth{
|
||||
store: store.DefaultStore,
|
||||
opts: options,
|
||||
}
|
||||
}
|
||||
|
||||
// Init the auth package
|
||||
func (a *Auth) Init(opts ...auth.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&a.opts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Options returns the options set
|
||||
func (a *Auth) Options() auth.Options {
|
||||
return a.opts
|
||||
}
|
||||
|
||||
// Generate a new auth Account
|
||||
func (a *Auth) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) {
|
||||
// generate the token
|
||||
token, err := uuid.NewUUID()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// parse the options
|
||||
options := auth.NewGenerateOptions(opts...)
|
||||
|
||||
// construct the account
|
||||
sa := auth.Account{
|
||||
Id: id,
|
||||
Token: token.String(),
|
||||
Created: time.Now(),
|
||||
Metadata: options.Metadata,
|
||||
Roles: options.Roles,
|
||||
}
|
||||
|
||||
// encode the data to bytes
|
||||
// TODO: replace with json
|
||||
buf := &bytes.Buffer{}
|
||||
e := gob.NewEncoder(buf)
|
||||
if err := e.Encode(sa); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// write to the store
|
||||
err = a.store.Write(&store.Record{
|
||||
Key: token.String(),
|
||||
Value: buf.Bytes(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// return the result
|
||||
return &sa, nil
|
||||
}
|
||||
|
||||
// Revoke an authorization Account
|
||||
func (a *Auth) Revoke(token string) error {
|
||||
records, err := a.store.Read(token, store.ReadSuffix())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(records) == 0 {
|
||||
return errors.BadRequest("go.micro.auth", "token not found")
|
||||
}
|
||||
|
||||
for _, r := range records {
|
||||
if err := a.store.Delete(r.Key); err != nil {
|
||||
return errors.InternalServerError("go.micro.auth", "error deleting from store")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return nil, errors.Unauthorized("go.micro.auth", "invalid token")
|
||||
} else if err != nil {
|
||||
return nil, errors.InternalServerError("go.micro.auth", "error reading store")
|
||||
}
|
||||
|
||||
// decode the result
|
||||
// TODO: replace with json
|
||||
b := bytes.NewBuffer(records[0].Value)
|
||||
decoder := gob.NewDecoder(b)
|
||||
var sa auth.Account
|
||||
err = decoder.Decode(&sa)
|
||||
|
||||
// return the result
|
||||
return &sa, err
|
||||
}
|
||||
|
||||
// String returns the implementation
|
||||
func (a *Auth) String() string {
|
||||
return "store"
|
||||
}
|
@@ -11,9 +11,9 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/codec/json"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/util/addr"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
"github.com/nats-io/nats-server/v2/server"
|
||||
nats "github.com/nats-io/nats.go"
|
||||
)
|
||||
@@ -167,7 +167,7 @@ func (n *natsBroker) serve(exit chan bool) error {
|
||||
for _, node := range service.Nodes {
|
||||
u, err := url.Parse("nats://" + node.Address)
|
||||
if err != nil {
|
||||
log.Log(err)
|
||||
log.Info(err)
|
||||
continue
|
||||
}
|
||||
// append to the cluster routes
|
||||
@@ -242,7 +242,7 @@ func (n *natsBroker) serve(exit chan bool) error {
|
||||
select {
|
||||
case err := <-n.closeCh:
|
||||
if err != nil {
|
||||
log.Log(err)
|
||||
log.Info(err)
|
||||
}
|
||||
case <-exit:
|
||||
// deregister on exit
|
||||
|
@@ -6,16 +6,6 @@ import (
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
)
|
||||
|
||||
// setSubscribeOption returns a function to setup a context with given value
|
||||
func setSubscribeOption(k, v interface{}) broker.SubscribeOption {
|
||||
return func(o *broker.SubscribeOptions) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// setBrokerOption returns a function to setup a context with given value
|
||||
func setBrokerOption(k, v interface{}) broker.Option {
|
||||
return func(o *broker.Options) {
|
||||
@@ -25,13 +15,3 @@ func setBrokerOption(k, v interface{}) broker.Option {
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
|
||||
// setPublishOption returns a function to setup a context with given value
|
||||
func setPublishOption(k, v interface{}) broker.PublishOption {
|
||||
return func(o *broker.PublishOptions) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
|
@@ -13,9 +13,9 @@ 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/registry"
|
||||
"github.com/micro/go-micro/v2/util/addr"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
"github.com/nats-io/nats-server/v2/server"
|
||||
nats "github.com/nats-io/nats.go"
|
||||
)
|
||||
@@ -164,7 +164,7 @@ func (n *natsBroker) serve(exit chan bool) error {
|
||||
for _, node := range service.Nodes {
|
||||
u, err := url.Parse("nats://" + node.Address)
|
||||
if err != nil {
|
||||
log.Log(err)
|
||||
log.Error(err)
|
||||
continue
|
||||
}
|
||||
// append to the cluster routes
|
||||
|
@@ -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"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
type serviceBroker struct {
|
||||
|
@@ -3,7 +3,7 @@ package service
|
||||
import (
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
pb "github.com/micro/go-micro/v2/broker/service/proto"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
type serviceSub struct {
|
||||
|
@@ -155,7 +155,7 @@ func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error {
|
||||
m = new(codec.Message)
|
||||
}
|
||||
if m.Header == nil {
|
||||
m.Header = make(map[string]string)
|
||||
m.Header = make(map[string]string, len(md))
|
||||
}
|
||||
for k, v := range md {
|
||||
m.Header[k] = strings.Join(v, ",")
|
||||
|
@@ -5,8 +5,10 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
@@ -16,6 +18,7 @@ import (
|
||||
"github.com/micro/go-micro/v2/errors"
|
||||
"github.com/micro/go-micro/v2/metadata"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/util/config"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
@@ -23,10 +26,14 @@ import (
|
||||
gmetadata "google.golang.org/grpc/metadata"
|
||||
)
|
||||
|
||||
var (
|
||||
BearerScheme = "Bearer "
|
||||
)
|
||||
|
||||
type grpcClient struct {
|
||||
once sync.Once
|
||||
opts client.Options
|
||||
pool *pool
|
||||
once atomic.Value
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -36,14 +43,36 @@ func init() {
|
||||
}
|
||||
|
||||
// secure returns the dial option for whether its a secure or insecure connection
|
||||
func (g *grpcClient) secure() grpc.DialOption {
|
||||
func (g *grpcClient) secure(addr string) grpc.DialOption {
|
||||
// first we check if theres'a tls config
|
||||
if g.opts.Context != nil {
|
||||
if v := g.opts.Context.Value(tlsAuth{}); v != nil {
|
||||
tls := v.(*tls.Config)
|
||||
creds := credentials.NewTLS(tls)
|
||||
// return tls config if it exists
|
||||
return grpc.WithTransportCredentials(creds)
|
||||
}
|
||||
}
|
||||
|
||||
// default config
|
||||
tlsConfig := &tls.Config{}
|
||||
defaultCreds := grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))
|
||||
|
||||
// check if the address is prepended with https
|
||||
if strings.HasPrefix(addr, "https://") {
|
||||
return defaultCreds
|
||||
}
|
||||
|
||||
// if no port is specified or port is 443 default to tls
|
||||
_, port, err := net.SplitHostPort(addr)
|
||||
// assuming with no port its going to be secured
|
||||
if port == "443" {
|
||||
return defaultCreds
|
||||
} else if err != nil && strings.Contains(err.Error(), "missing port in address") {
|
||||
return defaultCreds
|
||||
}
|
||||
|
||||
// other fallback to insecure
|
||||
return grpc.WithInsecure()
|
||||
}
|
||||
|
||||
@@ -52,6 +81,10 @@ func (g *grpcClient) next(request client.Request, opts client.CallOptions) (sele
|
||||
|
||||
// get proxy
|
||||
if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 {
|
||||
// default name
|
||||
if prx == "service" {
|
||||
prx = "go.micro.proxy"
|
||||
}
|
||||
service = prx
|
||||
}
|
||||
|
||||
@@ -82,19 +115,28 @@ func (g *grpcClient) next(request client.Request, opts client.CallOptions) (sele
|
||||
}
|
||||
|
||||
func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error {
|
||||
var header map[string]string
|
||||
|
||||
address := node.Address
|
||||
|
||||
header := make(map[string]string)
|
||||
header = make(map[string]string)
|
||||
if md, ok := metadata.FromContext(ctx); ok {
|
||||
header = make(map[string]string, len(md))
|
||||
for k, v := range md {
|
||||
header[k] = v
|
||||
}
|
||||
} else {
|
||||
header = make(map[string]string)
|
||||
}
|
||||
|
||||
// set timeout in nanoseconds
|
||||
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"] = BearerScheme + token
|
||||
}
|
||||
|
||||
md := gmetadata.New(header)
|
||||
ctx = gmetadata.NewOutgoingContext(ctx, md)
|
||||
@@ -112,7 +154,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
|
||||
grpcDialOptions := []grpc.DialOption{
|
||||
grpc.WithDefaultCallOptions(grpc.ForceCodec(cf)),
|
||||
grpc.WithTimeout(opts.DialTimeout),
|
||||
g.secure(),
|
||||
g.secure(address),
|
||||
grpc.WithDefaultCallOptions(
|
||||
grpc.MaxCallRecvMsgSize(maxRecvMsgSize),
|
||||
grpc.MaxCallSendMsgSize(maxSendMsgSize),
|
||||
@@ -154,13 +196,17 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
|
||||
}
|
||||
|
||||
func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client.Request, opts client.CallOptions) (client.Stream, error) {
|
||||
var header map[string]string
|
||||
|
||||
address := node.Address
|
||||
|
||||
header := make(map[string]string)
|
||||
if md, ok := metadata.FromContext(ctx); ok {
|
||||
header = make(map[string]string, len(md))
|
||||
for k, v := range md {
|
||||
header[k] = v
|
||||
}
|
||||
} else {
|
||||
header = make(map[string]string)
|
||||
}
|
||||
|
||||
// set timeout in nanoseconds
|
||||
@@ -189,7 +235,8 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
|
||||
|
||||
grpcDialOptions := []grpc.DialOption{
|
||||
grpc.WithDefaultCallOptions(grpc.ForceCodec(wc)),
|
||||
g.secure(),
|
||||
grpc.WithTimeout(opts.DialTimeout),
|
||||
g.secure(address),
|
||||
}
|
||||
|
||||
if opts := g.getGrpcDialOptions(); opts != nil {
|
||||
@@ -217,6 +264,12 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
|
||||
|
||||
st, err := cc.NewStream(newCtx, desc, methodToGRPC(req.Service(), req.Endpoint()), grpcCallOptions...)
|
||||
if err != nil {
|
||||
// we need to cleanup as we dialled and created a context
|
||||
// cancel the context
|
||||
cancel()
|
||||
// close the connection
|
||||
cc.Close()
|
||||
// now return the error
|
||||
return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err))
|
||||
}
|
||||
|
||||
@@ -339,6 +392,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 {
|
||||
@@ -559,17 +617,15 @@ func (g *grpcClient) Publish(ctx context.Context, p client.Message, opts ...clie
|
||||
body = b
|
||||
}
|
||||
|
||||
g.once.Do(func() {
|
||||
g.opts.Broker.Connect()
|
||||
})
|
||||
if !g.once.Load().(bool) {
|
||||
if err = g.opts.Broker.Connect(); err != nil {
|
||||
return errors.InternalServerError("go.micro.client", err.Error())
|
||||
}
|
||||
g.once.Store(true)
|
||||
}
|
||||
|
||||
topic := p.Topic()
|
||||
|
||||
// get proxy topic
|
||||
if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 {
|
||||
options.Exchange = prx
|
||||
}
|
||||
|
||||
// get the exchange
|
||||
if len(options.Exchange) > 0 {
|
||||
topic = options.Exchange
|
||||
@@ -635,9 +691,9 @@ func newClient(opts ...client.Option) client.Client {
|
||||
}
|
||||
|
||||
rc := &grpcClient{
|
||||
once: sync.Once{},
|
||||
opts: options,
|
||||
}
|
||||
rc.once.Store(false)
|
||||
|
||||
rc.pool = newPool(options.PoolSize, options.PoolTTL, rc.poolMaxIdle(), rc.poolMaxStreams())
|
||||
|
||||
|
@@ -27,7 +27,7 @@ func (r *response) Header() map[string]string {
|
||||
if err != nil {
|
||||
return map[string]string{}
|
||||
}
|
||||
hdr := make(map[string]string)
|
||||
hdr := make(map[string]string, len(md))
|
||||
for k, v := range md {
|
||||
hdr[k] = strings.Join(v, ",")
|
||||
}
|
||||
|
@@ -291,6 +291,12 @@ func WithDialTimeout(d time.Duration) CallOption {
|
||||
}
|
||||
}
|
||||
|
||||
func WithMessageContentType(ct string) MessageOption {
|
||||
return func(o *MessageOptions) {
|
||||
o.ContentType = ct
|
||||
}
|
||||
}
|
||||
|
||||
// Request Options
|
||||
|
||||
func WithContentType(ct string) RequestOption {
|
||||
|
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
@@ -22,7 +21,7 @@ import (
|
||||
)
|
||||
|
||||
type rpcClient struct {
|
||||
once sync.Once
|
||||
once atomic.Value
|
||||
opts Options
|
||||
pool pool.Pool
|
||||
seq uint64
|
||||
@@ -38,11 +37,11 @@ func newRpcClient(opt ...Option) Client {
|
||||
)
|
||||
|
||||
rc := &rpcClient{
|
||||
once: sync.Once{},
|
||||
opts: opts,
|
||||
pool: p,
|
||||
seq: 0,
|
||||
}
|
||||
rc.once.Store(false)
|
||||
|
||||
c := Client(rc)
|
||||
|
||||
@@ -342,6 +341,10 @@ func (r *rpcClient) next(request Request, opts CallOptions) (selector.Next, erro
|
||||
|
||||
// get proxy
|
||||
if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 {
|
||||
// default name
|
||||
if prx == "service" {
|
||||
prx = "go.micro.proxy"
|
||||
}
|
||||
service = prx
|
||||
}
|
||||
|
||||
@@ -606,11 +609,6 @@ func (r *rpcClient) Publish(ctx context.Context, msg Message, opts ...PublishOpt
|
||||
// set the topic
|
||||
topic := msg.Topic()
|
||||
|
||||
// get proxy
|
||||
if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 {
|
||||
options.Exchange = prx
|
||||
}
|
||||
|
||||
// get the exchange
|
||||
if len(options.Exchange) > 0 {
|
||||
topic = options.Exchange
|
||||
@@ -646,9 +644,12 @@ func (r *rpcClient) Publish(ctx context.Context, msg Message, opts ...PublishOpt
|
||||
body = b.Bytes()
|
||||
}
|
||||
|
||||
r.once.Do(func() {
|
||||
r.opts.Broker.Connect()
|
||||
})
|
||||
if !r.once.Load().(bool) {
|
||||
if err = r.opts.Broker.Connect(); err != nil {
|
||||
return errors.InternalServerError("go.micro.client", err.Error())
|
||||
}
|
||||
r.once.Store(true)
|
||||
}
|
||||
|
||||
return r.opts.Broker.Publish(topic, &broker.Message{
|
||||
Header: md,
|
||||
|
@@ -2,6 +2,7 @@
|
||||
package codec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
@@ -12,6 +13,10 @@ const (
|
||||
Event
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidMessage = errors.New("invalid message")
|
||||
)
|
||||
|
||||
type MessageType int
|
||||
|
||||
// Takes in a connection/buffer and returns a new Codec
|
||||
|
@@ -25,13 +25,17 @@ func (c *Codec) ReadBody(b interface{}) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return proto.Unmarshal(buf, b.(proto.Message))
|
||||
m, ok := b.(proto.Message)
|
||||
if !ok {
|
||||
return codec.ErrInvalidMessage
|
||||
}
|
||||
return proto.Unmarshal(buf, m)
|
||||
}
|
||||
|
||||
func (c *Codec) Write(m *codec.Message, b interface{}) error {
|
||||
p, ok := b.(proto.Message)
|
||||
if !ok {
|
||||
return nil
|
||||
return codec.ErrInvalidMessage
|
||||
}
|
||||
buf, err := proto.Marshal(p)
|
||||
if err != nil {
|
||||
|
@@ -56,8 +56,12 @@ func (c *protoCodec) Write(m *codec.Message, b interface{}) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Of course this is a protobuf! Trust me or detonate the program.
|
||||
data, err = proto.Marshal(b.(proto.Message))
|
||||
// dont trust or incoming message
|
||||
m, ok := b.(proto.Message)
|
||||
if !ok {
|
||||
return codec.ErrInvalidMessage
|
||||
}
|
||||
data, err = proto.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -100,7 +104,11 @@ func (c *protoCodec) Write(m *codec.Message, b interface{}) error {
|
||||
}
|
||||
}
|
||||
case codec.Event:
|
||||
data, err := proto.Marshal(b.(proto.Message))
|
||||
m, ok := b.(proto.Message)
|
||||
if !ok {
|
||||
return codec.ErrInvalidMessage
|
||||
}
|
||||
data, err := proto.Marshal(m)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@@ -11,13 +11,16 @@ 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/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/registry"
|
||||
"github.com/micro/go-micro/v2/runtime"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
"github.com/micro/go-micro/v2/store"
|
||||
"github.com/micro/go-micro/v2/transport"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
|
||||
// clients
|
||||
cgrpc "github.com/micro/go-micro/v2/client/grpc"
|
||||
@@ -25,6 +28,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"
|
||||
|
||||
@@ -65,6 +69,7 @@ import (
|
||||
// auth
|
||||
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"
|
||||
)
|
||||
|
||||
type Cmd interface {
|
||||
@@ -244,6 +249,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"},
|
||||
@@ -257,7 +267,7 @@ var (
|
||||
&cli.StringSliceFlag{
|
||||
Name: "auth_exclude",
|
||||
EnvVars: []string{"MICRO_AUTH_EXCLUDE"},
|
||||
Usage: "Comma-separated list of endpoints excluded from authentication",
|
||||
Usage: "Comma-separated list of endpoints excluded from authentication, e.g. Users.ListUsers",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -314,8 +324,14 @@ var (
|
||||
|
||||
DefaultAuths = map[string]func(...auth.Option) auth.Auth{
|
||||
"service": sAuth.NewAuth,
|
||||
"store": storeAuth.NewAuth,
|
||||
"jwt": jwtAuth.NewAuth,
|
||||
}
|
||||
|
||||
DefaultProfiles = map[string]func(...profile.Option) profile.Profile{
|
||||
"http": http.NewProfile,
|
||||
"pprof": pprof.NewProfile,
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -334,6 +350,7 @@ func newCmd(opts ...Option) Cmd {
|
||||
Runtime: &runtime.DefaultRuntime,
|
||||
Store: &store.DefaultStore,
|
||||
Tracer: &trace.DefaultTracer,
|
||||
Profile: &profile.DefaultProfile,
|
||||
|
||||
Brokers: DefaultBrokers,
|
||||
Clients: DefaultClients,
|
||||
@@ -345,6 +362,7 @@ func newCmd(opts ...Option) Cmd {
|
||||
Stores: DefaultStores,
|
||||
Tracers: DefaultTracers,
|
||||
Auths: DefaultAuths,
|
||||
Profiles: DefaultProfiles,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
@@ -428,6 +446,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
|
||||
@@ -583,6 +611,10 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
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")))
|
||||
}
|
||||
@@ -592,7 +624,7 @@ 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 len(authOpts) > 0 {
|
||||
|
@@ -7,6 +7,7 @@ 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/debug/profile"
|
||||
"github.com/micro/go-micro/v2/debug/trace"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/runtime"
|
||||
@@ -32,6 +33,7 @@ type Options struct {
|
||||
Store *store.Store
|
||||
Tracer *trace.Tracer
|
||||
Auth *auth.Auth
|
||||
Profile *profile.Profile
|
||||
|
||||
Brokers map[string]func(...broker.Option) broker.Broker
|
||||
Clients map[string]func(...client.Option) client.Client
|
||||
@@ -43,6 +45,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
|
||||
@@ -118,6 +121,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) {
|
||||
|
@@ -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()))
|
||||
|
@@ -6,7 +6,7 @@ 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"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
|
123
debug/log/os.go
123
debug/log/os.go
@@ -1,13 +1,7 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/v2/util/ring"
|
||||
@@ -25,106 +19,10 @@ type osLog struct {
|
||||
|
||||
type osStream struct {
|
||||
stream chan Record
|
||||
stop chan bool
|
||||
}
|
||||
|
||||
// watch io stream
|
||||
func (o *osLog) run() {
|
||||
// save outputs
|
||||
stdout := *os.Stdout
|
||||
stderr := *os.Stderr
|
||||
|
||||
// new os pipe
|
||||
r, w := io.Pipe()
|
||||
|
||||
// create new iopipes
|
||||
r1, w1, _ := os.Pipe()
|
||||
r2, w2, _ := os.Pipe()
|
||||
|
||||
// create tea readers
|
||||
tee1 := io.TeeReader(r1, &stdout)
|
||||
tee2 := io.TeeReader(r2, &stderr)
|
||||
|
||||
// start copying
|
||||
go io.Copy(w, tee1)
|
||||
go io.Copy(w, tee2)
|
||||
|
||||
// set default go log output
|
||||
//log.SetOutput(w2)
|
||||
|
||||
// replace os stdout and os stderr
|
||||
*os.Stdout = *w1
|
||||
*os.Stderr = *w2
|
||||
|
||||
// this should short circuit everything
|
||||
defer func() {
|
||||
// reset stdout and stderr
|
||||
*os.Stdout = stdout
|
||||
*os.Stderr = stderr
|
||||
//log.SetOutput(stderr)
|
||||
|
||||
// close all the outputs
|
||||
r.Close()
|
||||
r1.Close()
|
||||
r2.Close()
|
||||
w.Close()
|
||||
w1.Close()
|
||||
w2.Close()
|
||||
}()
|
||||
|
||||
// read from standard error
|
||||
scanner := bufio.NewReader(r)
|
||||
|
||||
for {
|
||||
// read the line
|
||||
line, err := scanner.ReadString('\n')
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// check if the line exists
|
||||
if len(line) == 0 {
|
||||
continue
|
||||
}
|
||||
// parse the record
|
||||
var r Record
|
||||
if line[0] == '{' {
|
||||
json.Unmarshal([]byte(line), &r)
|
||||
} else {
|
||||
r = Record{
|
||||
Timestamp: time.Now(),
|
||||
Message: strings.TrimSuffix(line, "\n"),
|
||||
Metadata: make(map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
o.Lock()
|
||||
|
||||
// write to the buffer
|
||||
o.buffer.Put(r)
|
||||
|
||||
// check subs and send to stream
|
||||
for id, sub := range o.subs {
|
||||
// send to stream
|
||||
select {
|
||||
case <-sub.stop:
|
||||
delete(o.subs, id)
|
||||
case sub.stream <- r:
|
||||
// send to stream
|
||||
default:
|
||||
// do not block
|
||||
}
|
||||
}
|
||||
|
||||
o.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
// Read reads log entries from the logger
|
||||
func (o *osLog) Read(...ReadOption) ([]Record, error) {
|
||||
o.once.Do(func() {
|
||||
go o.run()
|
||||
})
|
||||
|
||||
var records []Record
|
||||
|
||||
// read the last 100 records
|
||||
@@ -137,29 +35,18 @@ func (o *osLog) Read(...ReadOption) ([]Record, error) {
|
||||
|
||||
// Write writes records to log
|
||||
func (o *osLog) Write(r Record) error {
|
||||
o.once.Do(func() {
|
||||
go o.run()
|
||||
})
|
||||
|
||||
// generate output
|
||||
out := o.format(r) + "\n"
|
||||
_, err := os.Stderr.Write([]byte(out))
|
||||
return err
|
||||
o.buffer.Put(r)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stream log records
|
||||
func (o *osLog) Stream() (Stream, error) {
|
||||
o.once.Do(func() {
|
||||
go o.run()
|
||||
})
|
||||
|
||||
o.Lock()
|
||||
defer o.Unlock()
|
||||
|
||||
// create stream
|
||||
st := &osStream{
|
||||
stream: make(chan Record, 128),
|
||||
stop: make(chan bool),
|
||||
}
|
||||
|
||||
// save stream
|
||||
@@ -173,12 +60,6 @@ func (o *osStream) Chan() <-chan Record {
|
||||
}
|
||||
|
||||
func (o *osStream) Stop() error {
|
||||
select {
|
||||
case <-o.stop:
|
||||
return nil
|
||||
default:
|
||||
close(o.stop)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@@ -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
|
||||
|
10
go.mod
10
go.mod
@@ -37,12 +37,12 @@ require (
|
||||
github.com/leodido/go-urn v1.2.0 // indirect
|
||||
github.com/lib/pq v1.3.0
|
||||
github.com/lucas-clemente/quic-go v0.14.1
|
||||
github.com/mholt/certmagic v0.9.1
|
||||
github.com/micro/cli/v2 v2.1.2-0.20200203150404-894195727d9c
|
||||
github.com/mholt/certmagic v0.9.3
|
||||
github.com/micro/cli/v2 v2.1.2
|
||||
github.com/micro/mdns v0.3.0
|
||||
github.com/miekg/dns v1.1.27
|
||||
github.com/mitchellh/hashstructure v1.0.0
|
||||
github.com/nats-io/nats-server/v2 v2.1.2
|
||||
github.com/nats-io/nats-server/v2 v2.1.4
|
||||
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
|
||||
@@ -54,8 +54,8 @@ require (
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
|
||||
go.etcd.io/bbolt v1.3.3 // indirect
|
||||
go.uber.org/zap v1.13.0
|
||||
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0
|
||||
golang.org/x/sys v0.0.0-20191110163157-d32e6e3b99c4 // indirect
|
||||
google.golang.org/grpc v1.26.0
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||
|
21
go.sum
21
go.sum
@@ -280,10 +280,11 @@ github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzp
|
||||
github.com/mattn/go-tty v0.0.0-20180219170247-931426f7535a/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/mholt/certmagic v0.9.1 h1:wPzyouOyE+30NIQETJuhTB5ZQWz+0Hy038vaR5WWQDE=
|
||||
github.com/mholt/certmagic v0.9.1/go.mod h1:nu8jbsbtwK4205EDH/ZUMTKsfYpJA1Q7MKXHfgTihNw=
|
||||
github.com/micro/cli/v2 v2.1.2-0.20200203150404-894195727d9c h1:oohy8v2QQeXfDe9/BaM0b+5wETzoMiemOs3fhPhnFTg=
|
||||
github.com/micro/cli/v2 v2.1.2-0.20200203150404-894195727d9c/go.mod h1:EguNh6DAoWKm9nmk+k/Rg0H3lQnDxqzu5x5srOtGtYg=
|
||||
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=
|
||||
@@ -309,8 +310,8 @@ github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04/go.mod h1:5sN+Lt1CaY
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/jwt v0.3.2 h1:+RB5hMpXUUA2dfxuhBTEkMOrYmM+gKIZYS1KjSostMI=
|
||||
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
|
||||
github.com/nats-io/nats-server/v2 v2.1.2 h1:i2Ly0B+1+rzNZHHWtD4ZwKi+OU5l+uQo1iDHZ2PmiIc=
|
||||
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
|
||||
github.com/nats-io/nats-server/v2 v2.1.4 h1:BILRnsJ2Yb/fefiFbBWADpViGF69uh4sxe8poVDQ06g=
|
||||
github.com/nats-io/nats-server/v2 v2.1.4/go.mod h1:Jw1Z28soD/QasIA2uWjXyM9El1jly3YwyFOuR8tH1rg=
|
||||
github.com/nats-io/nats.go v1.9.1 h1:ik3HbLhZ0YABLto7iX80pZLPw/6dx3T+++MZJwLnMrQ=
|
||||
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
@@ -457,8 +458,8 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20190829043050-9756ffdc2472/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190927123631-a832865fa7ad/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg=
|
||||
golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d h1:1ZiEyfaQIg3Qh0EoqpwAakHVhecoE5wlSg5GjnafJGw=
|
||||
golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
@@ -502,8 +503,8 @@ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0 h1:MsuvTghUPjX762sGLnGsxC3HM0B5r83wEtYcYR8/vRs=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
|
133
logger/default.go
Normal file
133
logger/default.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
dlog "github.com/micro/go-micro/v2/debug/log"
|
||||
)
|
||||
|
||||
type defaultLogger struct {
|
||||
sync.RWMutex
|
||||
opts Options
|
||||
err error
|
||||
}
|
||||
|
||||
// Init(opts...) should only overwrite provided options
|
||||
func (l *defaultLogger) Init(opts ...Option) error {
|
||||
for _, o := range opts {
|
||||
o(&l.opts)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *defaultLogger) String() string {
|
||||
return "default"
|
||||
}
|
||||
|
||||
func (l *defaultLogger) Fields(fields map[string]interface{}) Logger {
|
||||
l.Lock()
|
||||
l.opts.Fields = copyFields(fields)
|
||||
l.Unlock()
|
||||
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 {
|
||||
dst[k] = v
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func (l *defaultLogger) Log(level Level, v ...interface{}) {
|
||||
// TODO decide does we need to write message if log level not used?
|
||||
if !l.opts.Level.Enabled(level) {
|
||||
return
|
||||
}
|
||||
|
||||
l.RLock()
|
||||
fields := copyFields(l.opts.Fields)
|
||||
if l.err != nil {
|
||||
fields["error"] = l.err.Error()
|
||||
}
|
||||
l.RUnlock()
|
||||
|
||||
fields["level"] = level.String()
|
||||
|
||||
rec := dlog.Record{
|
||||
Timestamp: time.Now(),
|
||||
Message: fmt.Sprint(v...),
|
||||
Metadata: make(map[string]string, len(fields)),
|
||||
}
|
||||
for k, v := range fields {
|
||||
rec.Metadata[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
dlog.DefaultLog.Write(rec)
|
||||
|
||||
t := rec.Timestamp.Format("2006-01-02 15:04:05")
|
||||
fmt.Printf("%s %v\n", t, rec.Message)
|
||||
}
|
||||
|
||||
func (l *defaultLogger) Logf(level Level, format string, v ...interface{}) {
|
||||
// TODO decide does we need to write message if log level not used?
|
||||
if level < l.opts.Level {
|
||||
return
|
||||
}
|
||||
|
||||
l.RLock()
|
||||
fields := copyFields(l.opts.Fields)
|
||||
if l.err != nil {
|
||||
fields["error"] = l.err.Error()
|
||||
}
|
||||
l.RUnlock()
|
||||
|
||||
fields["level"] = level.String()
|
||||
|
||||
rec := dlog.Record{
|
||||
Timestamp: time.Now(),
|
||||
Message: fmt.Sprintf(format, v...),
|
||||
Metadata: make(map[string]string, len(fields)),
|
||||
}
|
||||
for k, v := range fields {
|
||||
rec.Metadata[k] = fmt.Sprintf("%v", v)
|
||||
}
|
||||
|
||||
dlog.DefaultLog.Write(rec)
|
||||
|
||||
t := rec.Timestamp.Format("2006-01-02 15:04:05")
|
||||
fmt.Printf("%s %v\n", t, rec.Message)
|
||||
}
|
||||
|
||||
func (n *defaultLogger) Options() Options {
|
||||
return n.opts
|
||||
}
|
||||
|
||||
// NewLogger builds a new logger based on options
|
||||
func NewLogger(opts ...Option) Logger {
|
||||
// Default options
|
||||
options := Options{
|
||||
Level: InfoLevel,
|
||||
Fields: make(map[string]interface{}),
|
||||
Out: os.Stderr,
|
||||
Context: context.Background(),
|
||||
}
|
||||
|
||||
l := &defaultLogger{opts: options}
|
||||
if err := l.Init(opts...); err != nil {
|
||||
l.Log(FatalLevel, err)
|
||||
}
|
||||
|
||||
return l
|
||||
}
|
@@ -1,43 +0,0 @@
|
||||
package logger
|
||||
|
||||
type FieldType uint8
|
||||
|
||||
type Encode func(*Field) string
|
||||
|
||||
type Field struct {
|
||||
Key string
|
||||
Type FieldType
|
||||
Value interface{}
|
||||
Encode Encode
|
||||
}
|
||||
|
||||
func (f *Field) GetValue() interface{} {
|
||||
if f.Encode != nil {
|
||||
return f.Encode(f)
|
||||
}
|
||||
|
||||
return f.Value
|
||||
}
|
||||
|
||||
// preset common types for choosing encoder faster
|
||||
const (
|
||||
UnknownType FieldType = iota
|
||||
BoolType
|
||||
DurationType
|
||||
Float64Type
|
||||
Float32Type
|
||||
Int64Type
|
||||
Int32Type
|
||||
Int16Type
|
||||
Int8Type
|
||||
Uint64Type
|
||||
Uint32Type
|
||||
Uint16Type
|
||||
Uint8Type
|
||||
StringType
|
||||
TimeType
|
||||
)
|
||||
|
||||
func Bool(key string, val bool) Field {
|
||||
return Field{Key: key, Type: BoolType, Value: val}
|
||||
}
|
103
logger/level.go
103
logger/level.go
@@ -1,13 +1,112 @@
|
||||
package logger
|
||||
|
||||
import "fmt"
|
||||
|
||||
type Level int8
|
||||
|
||||
const (
|
||||
TraceLevel Level = iota - 1
|
||||
// TraceLevel level. Designates finer-grained informational events than the Debug.
|
||||
TraceLevel Level = iota - 2
|
||||
// DebugLevel level. Usually only enabled when debugging. Very verbose logging.
|
||||
DebugLevel
|
||||
// InfoLevel is the default logging priority.
|
||||
// General operational entries about what's going on inside the application.
|
||||
InfoLevel
|
||||
// WarnLevel level. Non-critical entries that deserve eyes.
|
||||
WarnLevel
|
||||
// ErrorLevel level. Logs. Used for errors that should definitely be noted.
|
||||
ErrorLevel
|
||||
PanicLevel
|
||||
// FatalLevel level. Logs and then calls `logger.Exit(1)`. highest level of severity.
|
||||
FatalLevel
|
||||
)
|
||||
|
||||
func (l Level) String() string {
|
||||
switch l {
|
||||
case TraceLevel:
|
||||
return "trace"
|
||||
case DebugLevel:
|
||||
return "debug"
|
||||
case InfoLevel:
|
||||
return "info"
|
||||
case WarnLevel:
|
||||
return "warn"
|
||||
case ErrorLevel:
|
||||
return "error"
|
||||
case FatalLevel:
|
||||
return "fatal"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// Enabled returns true if the given level is at or above this level.
|
||||
func (l Level) Enabled(lvl Level) bool {
|
||||
return lvl >= l
|
||||
}
|
||||
|
||||
// GetLevel converts a level string into a logger Level value.
|
||||
// returns an error if the input string does not match known values.
|
||||
func GetLevel(levelStr string) (Level, error) {
|
||||
switch levelStr {
|
||||
case TraceLevel.String():
|
||||
return TraceLevel, nil
|
||||
case DebugLevel.String():
|
||||
return DebugLevel, nil
|
||||
case InfoLevel.String():
|
||||
return InfoLevel, nil
|
||||
case WarnLevel.String():
|
||||
return WarnLevel, nil
|
||||
case ErrorLevel.String():
|
||||
return ErrorLevel, nil
|
||||
case FatalLevel.String():
|
||||
return FatalLevel, nil
|
||||
}
|
||||
return InfoLevel, fmt.Errorf("Unknown Level String: '%s', defaulting to InfoLevel", levelStr)
|
||||
}
|
||||
|
||||
func Info(args ...interface{}) {
|
||||
DefaultLogger.Log(InfoLevel, args...)
|
||||
}
|
||||
|
||||
func Infof(template string, args ...interface{}) {
|
||||
DefaultLogger.Logf(InfoLevel, template, args...)
|
||||
}
|
||||
|
||||
func Trace(args ...interface{}) {
|
||||
DefaultLogger.Log(TraceLevel, args...)
|
||||
}
|
||||
|
||||
func Tracef(template string, args ...interface{}) {
|
||||
DefaultLogger.Logf(TraceLevel, template, args...)
|
||||
}
|
||||
|
||||
func Debug(args ...interface{}) {
|
||||
DefaultLogger.Log(DebugLevel, args...)
|
||||
}
|
||||
|
||||
func Debugf(template string, args ...interface{}) {
|
||||
DefaultLogger.Logf(DebugLevel, template, args...)
|
||||
}
|
||||
|
||||
func Warn(args ...interface{}) {
|
||||
DefaultLogger.Log(WarnLevel, args...)
|
||||
}
|
||||
|
||||
func Warnf(template string, args ...interface{}) {
|
||||
DefaultLogger.Logf(WarnLevel, template, args...)
|
||||
}
|
||||
|
||||
func Error(args ...interface{}) {
|
||||
DefaultLogger.Log(ErrorLevel, args...)
|
||||
}
|
||||
|
||||
func Errorf(template string, args ...interface{}) {
|
||||
DefaultLogger.Logf(ErrorLevel, template, args...)
|
||||
}
|
||||
|
||||
func Fatal(args ...interface{}) {
|
||||
DefaultLogger.Log(FatalLevel, args...)
|
||||
}
|
||||
|
||||
func Fatalf(template string, args ...interface{}) {
|
||||
DefaultLogger.Logf(FatalLevel, template, args...)
|
||||
}
|
||||
|
@@ -1,49 +1,49 @@
|
||||
// Package log provides a log interface
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
var (
|
||||
// Default logger
|
||||
DefaultLogger Logger = NewLogger()
|
||||
)
|
||||
|
||||
// Logger is a generic logging interface
|
||||
type Logger interface {
|
||||
// Init initialises options
|
||||
Init(options ...Option) error
|
||||
// Level returns the logging level
|
||||
Level() Level
|
||||
// Log inserts a log entry. Arguments may be handled in the manner
|
||||
// of fmt.Print, but the underlying logger may also decide to handle
|
||||
// them differently.
|
||||
Log(level Level, v ...interface{})
|
||||
// Logf insets a log entry. Arguments are handled in the manner of
|
||||
// fmt.Printf.
|
||||
Logf(level Level, format string, v ...interface{})
|
||||
// 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 ...Field) Logger
|
||||
// SetLevel updates the logging level.
|
||||
SetLevel(Level)
|
||||
Fields(fields map[string]interface{}) Logger
|
||||
// Log writes a log entry
|
||||
Log(level Level, v ...interface{})
|
||||
// Logf writes a formatted log entry
|
||||
Logf(level Level, format string, v ...interface{})
|
||||
// String returns the name of logger
|
||||
String() string
|
||||
}
|
||||
|
||||
var (
|
||||
mtx sync.Mutex
|
||||
loggerMap = map[string]Logger{}
|
||||
)
|
||||
|
||||
func Register(logger Logger) {
|
||||
mtx.Lock()
|
||||
defer mtx.Unlock()
|
||||
|
||||
loggerMap[logger.String()] = logger
|
||||
func Init(opts ...Option) error {
|
||||
return DefaultLogger.Init(opts...)
|
||||
}
|
||||
|
||||
func GetLogger(name string) (Logger, error) {
|
||||
l := loggerMap[name]
|
||||
if l == nil {
|
||||
return nil, fmt.Errorf("no such name logger found %s", name)
|
||||
}
|
||||
|
||||
return l, nil
|
||||
func Fields(fields map[string]interface{}) Logger {
|
||||
return DefaultLogger.Fields(fields)
|
||||
}
|
||||
|
||||
func Log(level Level, v ...interface{}) {
|
||||
DefaultLogger.Log(level, v...)
|
||||
}
|
||||
|
||||
func Logf(level Level, format string, v ...interface{}) {
|
||||
DefaultLogger.Logf(level, format, v...)
|
||||
}
|
||||
|
||||
func String() string {
|
||||
return DefaultLogger.String()
|
||||
}
|
||||
|
||||
func WithError(err error) Logger {
|
||||
return DefaultLogger.Error(err)
|
||||
}
|
||||
|
@@ -2,20 +2,48 @@ package logger
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Option for load profiles maybe
|
||||
// eg. yml
|
||||
// micro:
|
||||
// logger:
|
||||
// name:
|
||||
// dialect: zap/default/logrus
|
||||
// zap:
|
||||
// xxx:
|
||||
// logrus:
|
||||
// xxx:
|
||||
type Option func(*Options)
|
||||
|
||||
type Options struct {
|
||||
// The logging level the logger should log at. default is `InfoLevel`
|
||||
Level Level
|
||||
// fields to always be logged
|
||||
Fields map[string]interface{}
|
||||
// It's common to set this to a file, or leave it default which is `os.Stderr`
|
||||
Out io.Writer
|
||||
// Alternative options
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
// WithFields set default fields for the logger
|
||||
func WithFields(fields map[string]interface{}) Option {
|
||||
return func(args *Options) {
|
||||
args.Fields = fields
|
||||
}
|
||||
}
|
||||
|
||||
// WithLevel set default level for the logger
|
||||
func WithLevel(level Level) Option {
|
||||
return func(args *Options) {
|
||||
args.Level = level
|
||||
}
|
||||
}
|
||||
|
||||
// WithOutput set default output writer for the logger
|
||||
func WithOutput(out io.Writer) Option {
|
||||
return func(args *Options) {
|
||||
args.Out = out
|
||||
}
|
||||
}
|
||||
|
||||
func SetOption(k, v interface{}) Option {
|
||||
return func(o *Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,16 @@ func Copy(md Metadata) Metadata {
|
||||
return cmd
|
||||
}
|
||||
|
||||
// Set add key with val to metadata
|
||||
func Set(ctx context.Context, k, v string) context.Context {
|
||||
md, ok := FromContext(ctx)
|
||||
if !ok {
|
||||
md = make(Metadata)
|
||||
}
|
||||
md[k] = v
|
||||
return context.WithValue(ctx, metaKey{}, md)
|
||||
}
|
||||
|
||||
// Get returns a single value from metadata in the context
|
||||
func Get(ctx context.Context, key string) (string, bool) {
|
||||
md, ok := FromContext(ctx)
|
||||
@@ -48,7 +58,7 @@ func FromContext(ctx context.Context) (Metadata, bool) {
|
||||
}
|
||||
|
||||
// capitalise all values
|
||||
newMD := make(map[string]string)
|
||||
newMD := make(map[string]string, len(md))
|
||||
for k, v := range md {
|
||||
newMD[strings.Title(k)] = v
|
||||
}
|
||||
|
@@ -6,6 +6,18 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMetadataSet(t *testing.T) {
|
||||
ctx := Set(context.TODO(), "Key", "val")
|
||||
|
||||
val, ok := Get(ctx, "Key")
|
||||
if !ok {
|
||||
t.Fatal("key Key not found")
|
||||
}
|
||||
if val != "val" {
|
||||
t.Errorf("key Key with value val != %v", val)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetadataCopy(t *testing.T) {
|
||||
md := Metadata{
|
||||
"Foo": "bar",
|
||||
|
@@ -15,6 +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/network/resolver/dns"
|
||||
pbNet "github.com/micro/go-micro/v2/network/service/proto"
|
||||
"github.com/micro/go-micro/v2/proxy"
|
||||
@@ -27,7 +28,6 @@ import (
|
||||
bun "github.com/micro/go-micro/v2/tunnel/broker"
|
||||
tun "github.com/micro/go-micro/v2/tunnel/transport"
|
||||
"github.com/micro/go-micro/v2/util/backoff"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
pbUtil "github.com/micro/go-micro/v2/util/proto"
|
||||
)
|
||||
|
||||
|
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/client/selector"
|
||||
"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"
|
||||
@@ -25,6 +26,7 @@ type Options struct {
|
||||
Server server.Server
|
||||
Registry registry.Registry
|
||||
Transport transport.Transport
|
||||
Profile profile.Profile
|
||||
|
||||
// Before and After funcs
|
||||
BeforeStart []func() error
|
||||
@@ -99,6 +101,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) {
|
||||
|
@@ -15,11 +15,11 @@ 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/metadata"
|
||||
"github.com/micro/go-micro/v2/proxy"
|
||||
"github.com/micro/go-micro/v2/router"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
// Proxy will transparently proxy requests to an endpoint.
|
||||
@@ -203,22 +203,33 @@ func (p *Proxy) cacheRoutes(service string) ([]router.Route, error) {
|
||||
// lookup the routes in the router
|
||||
results, err := p.Router.Lookup(router.QueryService(service))
|
||||
if err != nil {
|
||||
// assumption that we're ok with stale routes
|
||||
|
||||
// otherwise return the error
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// update the proxy cache
|
||||
p.Lock()
|
||||
|
||||
// delete the existing reference to the service
|
||||
delete(p.Routes, service)
|
||||
|
||||
for _, route := range results {
|
||||
// create if does not exist
|
||||
if _, ok := p.Routes[service]; !ok {
|
||||
p.Routes[service] = make(map[uint64]router.Route)
|
||||
}
|
||||
// cache the route based on its unique hash
|
||||
p.Routes[service][route.Hash()] = route
|
||||
}
|
||||
|
||||
// make a copy of the service routes
|
||||
routes := p.Routes[service]
|
||||
|
||||
p.Unlock()
|
||||
|
||||
// return routes to the caller
|
||||
return toSlice(routes), nil
|
||||
}
|
||||
|
||||
|
6
registry/cache/cache.go
vendored
6
registry/cache/cache.go
vendored
@@ -7,8 +7,8 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
log "github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
// Cache is the registry cache interface
|
||||
@@ -339,7 +339,7 @@ func (c *cache) run() {
|
||||
c.setStatus(err)
|
||||
|
||||
if a > 3 {
|
||||
log.Log("rcache: ", err, " backing off ", d)
|
||||
log.Info("rcache: ", err, " backing off ", d)
|
||||
a = 0
|
||||
}
|
||||
|
||||
@@ -362,7 +362,7 @@ func (c *cache) run() {
|
||||
c.setStatus(err)
|
||||
|
||||
if b > 3 {
|
||||
log.Log("rcache: ", err, " backing off ", d)
|
||||
log.Info("rcache: ", err, " backing off ", d)
|
||||
b = 0
|
||||
}
|
||||
|
||||
|
@@ -15,8 +15,8 @@ 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/registry"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
hash "github.com/mitchellh/hashstructure"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@@ -48,6 +48,9 @@ func (ew *etcdWatcher) Next() (*registry.Result, error) {
|
||||
if wresp.Err() != nil {
|
||||
return nil, wresp.Err()
|
||||
}
|
||||
if wresp.Canceled {
|
||||
return nil, errors.New("could not get next")
|
||||
}
|
||||
for _, ev := range wresp.Events {
|
||||
service := decode(ev.Kv.Value)
|
||||
var action string
|
||||
|
@@ -6,9 +6,9 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/util/kubernetes/client"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
type k8sWatcher struct {
|
||||
@@ -132,7 +132,7 @@ 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.Log("K8s Watcher: Couldnt unmarshal event object from pod")
|
||||
log.Info("K8s Watcher: Couldnt unmarshal event object from pod")
|
||||
return
|
||||
}
|
||||
|
||||
|
@@ -7,8 +7,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@@ -7,12 +7,12 @@ import (
|
||||
)
|
||||
|
||||
func serviceToRecord(s *registry.Service, ttl time.Duration) *record {
|
||||
metadata := make(map[string]string)
|
||||
metadata := make(map[string]string, len(s.Metadata))
|
||||
for k, v := range s.Metadata {
|
||||
metadata[k] = v
|
||||
}
|
||||
|
||||
nodes := make(map[string]*node)
|
||||
nodes := make(map[string]*node, len(s.Nodes))
|
||||
for _, n := range s.Nodes {
|
||||
nodes[n.Id] = &node{
|
||||
Node: n,
|
||||
@@ -36,7 +36,7 @@ func serviceToRecord(s *registry.Service, ttl time.Duration) *record {
|
||||
}
|
||||
|
||||
func recordToService(r *record) *registry.Service {
|
||||
metadata := make(map[string]string)
|
||||
metadata := make(map[string]string, len(r.Metadata))
|
||||
for k, v := range r.Metadata {
|
||||
metadata[k] = v
|
||||
}
|
||||
@@ -52,7 +52,7 @@ func recordToService(r *record) *registry.Service {
|
||||
*response = *e.Response
|
||||
}
|
||||
|
||||
metadata := make(map[string]string)
|
||||
metadata := make(map[string]string, len(e.Metadata))
|
||||
for k, v := range e.Metadata {
|
||||
metadata[k] = v
|
||||
}
|
||||
@@ -68,7 +68,7 @@ func recordToService(r *record) *registry.Service {
|
||||
nodes := make([]*registry.Node, len(r.Nodes))
|
||||
i := 0
|
||||
for _, n := range r.Nodes {
|
||||
metadata := make(map[string]string)
|
||||
metadata := make(map[string]string, len(n.Metadata))
|
||||
for k, v := range n.Metadata {
|
||||
metadata[k] = v
|
||||
}
|
||||
|
@@ -10,8 +10,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -357,20 +357,22 @@ func (r *router) advertiseEvents() error {
|
||||
// routing table watcher
|
||||
w, err = r.Watch()
|
||||
if err != nil {
|
||||
log.Logf("Error creating watcher: %v", err)
|
||||
log.Errorf("Error creating watcher: %v", err)
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.watchTable(w); err != nil {
|
||||
log.Logf("Error watching table: %v", err)
|
||||
log.Errorf("Error watching table: %v", err)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
// reset
|
||||
w.Stop()
|
||||
w = nil
|
||||
if w != nil {
|
||||
// reset
|
||||
w.Stop()
|
||||
w = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -467,7 +469,9 @@ func (r *router) advertiseEvents() error {
|
||||
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)
|
||||
case <-r.exit:
|
||||
w.Stop()
|
||||
if w != nil {
|
||||
w.Stop()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -538,14 +542,14 @@ func (r *router) Start() error {
|
||||
if w == nil {
|
||||
w, err = r.options.Registry.Watch()
|
||||
if err != nil {
|
||||
log.Logf("failed creating registry watcher: %v", err)
|
||||
log.Errorf("failed creating registry watcher: %v", err)
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if err := r.watchRegistry(w); err != nil {
|
||||
log.Logf("Error watching the registry: %v", err)
|
||||
log.Errorf("Error watching the registry: %v", err)
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
|
||||
@@ -602,7 +606,7 @@ func (r *router) Advertise() (<-chan *Advert, error) {
|
||||
return
|
||||
default:
|
||||
if err := r.advertiseEvents(); err != nil {
|
||||
log.Logf("Error adveritising events: %v", err)
|
||||
log.Errorf("Error adveritising events: %v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -700,16 +704,15 @@ func (r *router) Stop() error {
|
||||
// extract the events
|
||||
r.drain()
|
||||
|
||||
r.sub.Lock()
|
||||
// close advert subscribers
|
||||
for id, sub := range r.subscribers {
|
||||
// close the channel
|
||||
close(sub)
|
||||
|
||||
// delete the subscriber
|
||||
r.sub.Lock()
|
||||
delete(r.subscribers, id)
|
||||
r.sub.Unlock()
|
||||
}
|
||||
r.sub.Unlock()
|
||||
}
|
||||
|
||||
// remove event chan
|
||||
|
@@ -6,8 +6,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry/memory"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
func routerTestSetup() Router {
|
||||
|
@@ -6,7 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@@ -5,7 +5,7 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
type runtime struct {
|
||||
|
@@ -7,9 +7,9 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/runtime"
|
||||
"github.com/micro/go-micro/v2/util/kubernetes/client"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
// action to take on runtime service
|
||||
@@ -270,9 +270,9 @@ func (k *kubernetes) Create(s *runtime.Service, opts ...runtime.CreateOption) er
|
||||
if len(options.Type) == 0 {
|
||||
options.Type = k.options.Type
|
||||
}
|
||||
if len(k.options.Source) > 0 {
|
||||
s.Source = k.options.Source
|
||||
}
|
||||
|
||||
// determine the full source for this service
|
||||
options.Source = k.sourceForService(s.Name)
|
||||
|
||||
service := newService(s, options)
|
||||
|
||||
@@ -329,7 +329,8 @@ func (k *kubernetes) List() ([]*runtime.Service, error) {
|
||||
func (k *kubernetes) Update(s *runtime.Service) error {
|
||||
// create new kubernetes micro service
|
||||
service := newService(s, runtime.CreateOptions{
|
||||
Type: k.options.Type,
|
||||
Type: k.options.Type,
|
||||
Source: k.sourceForService(s.Name),
|
||||
})
|
||||
|
||||
// update build time annotation
|
||||
@@ -432,3 +433,15 @@ func NewRuntime(opts ...runtime.Option) runtime.Runtime {
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
formattedName := strings.ReplaceAll(name, "/", "-")
|
||||
return fmt.Sprintf("%v/%v", k.options.Source, formattedName)
|
||||
}
|
||||
|
@@ -3,12 +3,11 @@ package kubernetes
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
log "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"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
@@ -34,12 +33,15 @@ 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(s.Source) > 0 {
|
||||
for i := range kdeploy.Spec.Template.PodSpec.Containers {
|
||||
kdeploy.Spec.Template.PodSpec.Containers[i].Image = s.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)
|
||||
}
|
||||
|
||||
// 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 +53,16 @@ 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.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}
|
||||
}
|
||||
|
||||
kdeploy.Metadata.Annotations["source"] = c.Source
|
||||
}
|
||||
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))
|
||||
@@ -70,7 +77,7 @@ func newService(s *runtime.Service, c runtime.CreateOptions) *service {
|
||||
}
|
||||
|
||||
// specify the command to exec
|
||||
if len(c.Command) > 0 {
|
||||
if strings.HasPrefix(c.Source, "github.com") && len(c.Command) > 0 {
|
||||
kdeploy.Spec.Template.PodSpec.Containers[0].Command = c.Command
|
||||
}
|
||||
|
||||
|
@@ -9,8 +9,8 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/runtime/local/build"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
type Builder struct {
|
||||
|
@@ -53,6 +53,8 @@ type CreateOptions struct {
|
||||
Type string
|
||||
// Retries before failing deploy
|
||||
Retries int
|
||||
// Source of the service
|
||||
Source string
|
||||
}
|
||||
|
||||
// ReadOptions queries runtime services
|
||||
@@ -72,6 +74,13 @@ func CreateType(t string) CreateOption {
|
||||
}
|
||||
}
|
||||
|
||||
// CreateSource sets the source of service to create
|
||||
func CreateSource(t string) CreateOption {
|
||||
return func(o *CreateOptions) {
|
||||
o.Source = t
|
||||
}
|
||||
}
|
||||
|
||||
// WithCommand specifies the command to execute
|
||||
func WithCommand(args ...string) CreateOption {
|
||||
return func(o *CreateOptions) {
|
||||
|
@@ -6,10 +6,10 @@ import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
log "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"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
type service struct {
|
||||
|
@@ -35,6 +35,11 @@ func (s *svc) Create(svc *runtime.Service, opts ...runtime.CreateOption) error {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
// set the default source from MICRO_RUNTIME_SOURCE
|
||||
if len(svc.Source) == 0 {
|
||||
svc.Source = s.options.Source
|
||||
}
|
||||
|
||||
// runtime service create request
|
||||
req := &pb.CreateRequest{
|
||||
Service: &pb.Service{
|
||||
|
@@ -2,7 +2,6 @@ package grpc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
b "bytes"
|
||||
@@ -11,8 +10,6 @@ import (
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/micro/go-micro/v2/codec"
|
||||
"github.com/micro/go-micro/v2/codec/bytes"
|
||||
"github.com/micro/go-micro/v2/codec/jsonrpc"
|
||||
"github.com/micro/go-micro/v2/codec/protorpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/encoding"
|
||||
"google.golang.org/grpc/metadata"
|
||||
@@ -36,14 +33,6 @@ var (
|
||||
"application/grpc+proto": protoCodec{},
|
||||
"application/grpc+bytes": bytesCodec{},
|
||||
}
|
||||
|
||||
defaultRPCCodecs = map[string]codec.NewCodec{
|
||||
"application/json": jsonrpc.NewCodec,
|
||||
"application/json-rpc": jsonrpc.NewCodec,
|
||||
"application/protobuf": protorpc.NewCodec,
|
||||
"application/proto-rpc": protorpc.NewCodec,
|
||||
"application/octet-stream": protorpc.NewCodec,
|
||||
}
|
||||
)
|
||||
|
||||
func (w wrapCodec) String() string {
|
||||
@@ -71,11 +60,19 @@ func (w wrapCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
}
|
||||
|
||||
func (protoCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
return proto.Marshal(v.(proto.Message))
|
||||
m, ok := v.(proto.Message)
|
||||
if !ok {
|
||||
return nil, codec.ErrInvalidMessage
|
||||
}
|
||||
return proto.Marshal(m)
|
||||
}
|
||||
|
||||
func (protoCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
return proto.Unmarshal(data, v.(proto.Message))
|
||||
m, ok := v.(proto.Message)
|
||||
if !ok {
|
||||
return codec.ErrInvalidMessage
|
||||
}
|
||||
return proto.Unmarshal(data, m)
|
||||
}
|
||||
|
||||
func (protoCodec) Name() string {
|
||||
@@ -85,7 +82,6 @@ func (protoCodec) Name() string {
|
||||
func (jsonCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
if pb, ok := v.(proto.Message); ok {
|
||||
s, err := jsonpbMarshaler.MarshalToString(pb)
|
||||
|
||||
return []byte(s), err
|
||||
}
|
||||
|
||||
@@ -109,7 +105,7 @@ func (jsonCodec) Name() string {
|
||||
func (bytesCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
b, ok := v.(*[]byte)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("failed to marshal: %v is not type of *[]byte", v)
|
||||
return nil, codec.ErrInvalidMessage
|
||||
}
|
||||
return *b, nil
|
||||
}
|
||||
@@ -117,7 +113,7 @@ func (bytesCodec) Marshal(v interface{}) ([]byte, error) {
|
||||
func (bytesCodec) Unmarshal(data []byte, v interface{}) error {
|
||||
b, ok := v.(*[]byte)
|
||||
if !ok {
|
||||
return fmt.Errorf("failed to unmarshal: %v is not type of *[]byte", v)
|
||||
return codec.ErrInvalidMessage
|
||||
}
|
||||
*b = data
|
||||
return nil
|
||||
@@ -144,7 +140,7 @@ func (g *grpcCodec) ReadHeader(m *codec.Message, mt codec.MessageType) error {
|
||||
m = new(codec.Message)
|
||||
}
|
||||
if m.Header == nil {
|
||||
m.Header = make(map[string]string)
|
||||
m.Header = make(map[string]string, len(md))
|
||||
}
|
||||
for k, v := range md {
|
||||
m.Header[k] = strings.Join(v, ",")
|
||||
|
16
server/grpc/context.go
Normal file
16
server/grpc/context.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
)
|
||||
|
||||
func setServerOption(k, v interface{}) server.Option {
|
||||
return func(o *server.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, k, v)
|
||||
}
|
||||
}
|
@@ -16,15 +16,15 @@ import (
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/codec"
|
||||
"github.com/micro/go-micro/v2/errors"
|
||||
log "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"
|
||||
"github.com/micro/go-micro/v2/util/addr"
|
||||
mgrpc "github.com/micro/go-micro/v2/util/grpc"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
mnet "github.com/micro/go-micro/v2/util/net"
|
||||
"golang.org/x/net/netutil"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
@@ -143,9 +143,8 @@ func (g *grpcServer) getMaxMsgSize() int {
|
||||
|
||||
func (g *grpcServer) getCredentials() credentials.TransportCredentials {
|
||||
if g.opts.Context != nil {
|
||||
if v := g.opts.Context.Value(tlsAuth{}); v != nil {
|
||||
tls := v.(*tls.Config)
|
||||
return credentials.NewTLS(tls)
|
||||
if v, ok := g.opts.Context.Value(tlsAuth{}).(*tls.Config); ok && v != nil {
|
||||
return credentials.NewTLS(v)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -156,21 +155,26 @@ func (g *grpcServer) getGrpcOptions() []grpc.ServerOption {
|
||||
return nil
|
||||
}
|
||||
|
||||
v := g.opts.Context.Value(grpcOptions{})
|
||||
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
opts, ok := v.([]grpc.ServerOption)
|
||||
|
||||
if !ok {
|
||||
opts, ok := g.opts.Context.Value(grpcOptions{}).([]grpc.ServerOption)
|
||||
if !ok || opts == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
func (g *grpcServer) getListener() net.Listener {
|
||||
if g.opts.Context == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if l, ok := g.opts.Context.Value(netListener{}).(net.Listener); ok && l != nil {
|
||||
return l
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcServer) handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
if g.wg != nil {
|
||||
g.wg.Add(1)
|
||||
@@ -354,8 +358,8 @@ 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.Log("panic recovered: ", r)
|
||||
log.Logf(string(debug.Stack()))
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
err = errors.InternalServerError("go.micro.server", "panic recovered: %v", r)
|
||||
}
|
||||
}()
|
||||
@@ -494,8 +498,8 @@ func (g *grpcServer) processStream(stream grpc.ServerStream, service *service, m
|
||||
func (g *grpcServer) newGRPCCodec(contentType string) (encoding.Codec, error) {
|
||||
codecs := make(map[string]encoding.Codec)
|
||||
if g.opts.Context != nil {
|
||||
if v := g.opts.Context.Value(codecsKey{}); v != nil {
|
||||
codecs = v.(map[string]encoding.Codec)
|
||||
if v, ok := g.opts.Context.Value(codecsKey{}).(map[string]encoding.Codec); ok && v != nil {
|
||||
codecs = v
|
||||
}
|
||||
}
|
||||
if c, ok := codecs[contentType]; ok {
|
||||
@@ -507,16 +511,6 @@ func (g *grpcServer) newGRPCCodec(contentType string) (encoding.Codec, error) {
|
||||
return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType)
|
||||
}
|
||||
|
||||
func (g *grpcServer) newCodec(contentType string) (codec.NewCodec, error) {
|
||||
if cf, ok := g.opts.Codecs[contentType]; ok {
|
||||
return cf, nil
|
||||
}
|
||||
if cf, ok := defaultRPCCodecs[contentType]; ok {
|
||||
return cf, nil
|
||||
}
|
||||
return nil, fmt.Errorf("Unsupported Content-Type: %s", contentType)
|
||||
}
|
||||
|
||||
func (g *grpcServer) Options() server.Options {
|
||||
g.RLock()
|
||||
opts := g.opts
|
||||
@@ -561,11 +555,11 @@ func (g *grpcServer) Subscribe(sb server.Subscriber) error {
|
||||
}
|
||||
|
||||
g.Lock()
|
||||
|
||||
_, ok = g.subscribers[sub]
|
||||
if ok {
|
||||
if _, ok = g.subscribers[sub]; ok {
|
||||
g.Unlock()
|
||||
return fmt.Errorf("subscriber %v already exists", sub)
|
||||
}
|
||||
|
||||
g.subscribers[sub] = nil
|
||||
g.Unlock()
|
||||
return nil
|
||||
@@ -664,7 +658,7 @@ func (g *grpcServer) Register() error {
|
||||
g.Unlock()
|
||||
|
||||
if !registered {
|
||||
log.Logf("Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
|
||||
log.Infof("Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
|
||||
}
|
||||
|
||||
// create registry options
|
||||
@@ -699,7 +693,7 @@ func (g *grpcServer) Register() error {
|
||||
opts = append(opts, broker.DisableAutoAck())
|
||||
}
|
||||
|
||||
log.Logf("Subscribing to topic: %s", sb.Topic())
|
||||
log.Infof("Subscribing to topic: %s", sb.Topic())
|
||||
sub, err := config.Broker.Subscribe(sb.Topic(), handler, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -751,7 +745,7 @@ func (g *grpcServer) Deregister() error {
|
||||
Nodes: []*registry.Node{node},
|
||||
}
|
||||
|
||||
log.Logf("Deregistering node: %s", node.Id)
|
||||
log.Infof("Deregistering node: %s", node.Id)
|
||||
if err := config.Registry.Deregister(service); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -767,7 +761,7 @@ func (g *grpcServer) Deregister() error {
|
||||
|
||||
for sb, subs := range g.subscribers {
|
||||
for _, sub := range subs {
|
||||
log.Logf("Unsubscribing from topic: %s", sub.Topic())
|
||||
log.Infof("Unsubscribing from topic: %s", sub.Topic())
|
||||
sub.Unsubscribe()
|
||||
}
|
||||
g.subscribers[sb] = nil
|
||||
@@ -788,12 +782,32 @@ func (g *grpcServer) Start() error {
|
||||
config := g.Options()
|
||||
|
||||
// micro: config.Transport.Listen(config.Address)
|
||||
ts, err := net.Listen("tcp", config.Address)
|
||||
if err != nil {
|
||||
return err
|
||||
var ts net.Listener
|
||||
|
||||
if l := g.getListener(); l != nil {
|
||||
ts = l
|
||||
} else {
|
||||
var err error
|
||||
|
||||
// check the tls config for secure connect
|
||||
if tc := config.TLSConfig; tc != nil {
|
||||
ts, err = tls.Listen("tcp", config.Address, tc)
|
||||
// otherwise just plain tcp listener
|
||||
} else {
|
||||
ts, err = net.Listen("tcp", config.Address)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
log.Logf("Server [grpc] Listening on %s", ts.Addr().String())
|
||||
if g.opts.Context != nil {
|
||||
if c, ok := g.opts.Context.Value(maxConnKey{}).(int); ok && c > 0 {
|
||||
ts = netutil.LimitListener(ts, c)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Server [grpc] Listening on %s", ts.Addr().String())
|
||||
g.Lock()
|
||||
g.opts.Address = ts.Addr().String()
|
||||
g.Unlock()
|
||||
@@ -805,18 +819,18 @@ func (g *grpcServer) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Logf("Broker [%s] Connected to %s", config.Broker.String(), config.Broker.Address())
|
||||
log.Infof("Broker [%s] Connected to %s", config.Broker.String(), config.Broker.Address())
|
||||
}
|
||||
|
||||
// announce self to the world
|
||||
if err := g.Register(); err != nil {
|
||||
log.Log("Server register error: ", err)
|
||||
log.Errorf("Server register error: ", err)
|
||||
}
|
||||
|
||||
// micro: go ts.Accept(s.accept)
|
||||
go func() {
|
||||
if err := g.srv.Serve(ts); err != nil {
|
||||
log.Log("gRPC Server start error: ", err)
|
||||
log.Errorf("gRPC Server start error: ", err)
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -838,7 +852,7 @@ func (g *grpcServer) Start() error {
|
||||
// register self on interval
|
||||
case <-t.C:
|
||||
if err := g.Register(); err != nil {
|
||||
log.Log("Server register error: ", err)
|
||||
log.Error("Server register error: ", err)
|
||||
}
|
||||
// wait for exit
|
||||
case ch = <-g.exit:
|
||||
@@ -848,7 +862,7 @@ func (g *grpcServer) Start() error {
|
||||
|
||||
// deregister self
|
||||
if err := g.Deregister(); err != nil {
|
||||
log.Log("Server deregister error: ", err)
|
||||
log.Error("Server deregister error: ", err)
|
||||
}
|
||||
|
||||
// wait for waitgroup
|
||||
@@ -873,7 +887,7 @@ func (g *grpcServer) Start() error {
|
||||
// close transport
|
||||
ch <- nil
|
||||
|
||||
log.Logf("Broker [%s] Disconnected from %s", config.Broker.String(), config.Broker.Address())
|
||||
log.Infof("Broker [%s] Disconnected from %s", config.Broker.String(), config.Broker.Address())
|
||||
// disconnect broker
|
||||
config.Broker.Disconnect()
|
||||
}()
|
||||
|
@@ -1,12 +1,19 @@
|
||||
package grpc
|
||||
package grpc_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/v2"
|
||||
bmemory "github.com/micro/go-micro/v2/broker/memory"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
gcli "github.com/micro/go-micro/v2/client/grpc"
|
||||
"github.com/micro/go-micro/v2/errors"
|
||||
"github.com/micro/go-micro/v2/registry/memory"
|
||||
rmemory "github.com/micro/go-micro/v2/registry/memory"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
gsrv "github.com/micro/go-micro/v2/server/grpc"
|
||||
tgrpc "github.com/micro/go-micro/v2/transport/grpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/status"
|
||||
|
||||
@@ -14,7 +21,17 @@ import (
|
||||
)
|
||||
|
||||
// server is used to implement helloworld.GreeterServer.
|
||||
type testServer struct{}
|
||||
type testServer struct {
|
||||
msgCount int
|
||||
}
|
||||
|
||||
func (s *testServer) Handle(ctx context.Context, msg *pb.Request) error {
|
||||
s.msgCount++
|
||||
return nil
|
||||
}
|
||||
func (s *testServer) HandleError(ctx context.Context, msg *pb.Request) error {
|
||||
return fmt.Errorf("fake")
|
||||
}
|
||||
|
||||
// TestHello implements helloworld.GreeterServer
|
||||
func (s *testServer) Call(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
|
||||
@@ -26,14 +43,75 @@ func (s *testServer) Call(ctx context.Context, req *pb.Request, rsp *pb.Response
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestGRPCServer(t *testing.T) {
|
||||
r := memory.NewRegistry()
|
||||
s := NewServer(
|
||||
/*
|
||||
func BenchmarkServer(b *testing.B) {
|
||||
r := rmemory.NewRegistry()
|
||||
br := bmemory.NewBroker()
|
||||
tr := tgrpc.NewTransport()
|
||||
s := gsrv.NewServer(
|
||||
server.Broker(br),
|
||||
server.Name("foo"),
|
||||
server.Registry(r),
|
||||
server.Transport(tr),
|
||||
)
|
||||
c := gcli.NewClient(
|
||||
client.Registry(r),
|
||||
client.Broker(br),
|
||||
client.Transport(tr),
|
||||
)
|
||||
ctx := context.TODO()
|
||||
|
||||
pb.RegisterTestHandler(s, &testServer{})
|
||||
h := &testServer{}
|
||||
pb.RegisterTestHandler(s, h)
|
||||
if err := s.Start(); err != nil {
|
||||
b.Fatalf("failed to start: %v", err)
|
||||
}
|
||||
|
||||
// check registration
|
||||
services, err := r.GetService("foo")
|
||||
if err != nil || len(services) == 0 {
|
||||
b.Fatalf("failed to get service: %v # %d", err, len(services))
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := s.Stop(); err != nil {
|
||||
b.Fatalf("failed to stop: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
c.Call()
|
||||
}
|
||||
|
||||
}
|
||||
*/
|
||||
func TestGRPCServer(t *testing.T) {
|
||||
r := rmemory.NewRegistry()
|
||||
b := bmemory.NewBroker()
|
||||
tr := tgrpc.NewTransport()
|
||||
s := gsrv.NewServer(
|
||||
server.Broker(b),
|
||||
server.Name("foo"),
|
||||
server.Registry(r),
|
||||
server.Transport(tr),
|
||||
)
|
||||
c := gcli.NewClient(
|
||||
client.Registry(r),
|
||||
client.Broker(b),
|
||||
client.Transport(tr),
|
||||
)
|
||||
ctx := context.TODO()
|
||||
|
||||
h := &testServer{}
|
||||
pb.RegisterTestHandler(s, h)
|
||||
|
||||
if err := micro.RegisterSubscriber("test_topic", s, h.Handle); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := micro.RegisterSubscriber("error_topic", s, h.HandleError); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := s.Start(); err != nil {
|
||||
t.Fatalf("failed to start: %v", err)
|
||||
@@ -51,6 +129,22 @@ func TestGRPCServer(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
pub := micro.NewEvent("test_topic", c)
|
||||
pubErr := micro.NewEvent("error_topic", c)
|
||||
cnt := 4
|
||||
for i := 0; i < cnt; i++ {
|
||||
if err = pub.Publish(ctx, &pb.Request{Name: fmt.Sprintf("msg %d", i)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
if h.msgCount != cnt {
|
||||
t.Fatalf("pub/sub not work, or invalid message count %d", h.msgCount)
|
||||
}
|
||||
if err = pubErr.Publish(ctx, &pb.Request{}); err == nil {
|
||||
t.Fatal("this must return error, as we return error from handler")
|
||||
}
|
||||
|
||||
cc, err := grpc.Dial(s.Options().Address, grpc.WithInsecure())
|
||||
if err != nil {
|
||||
t.Fatalf("failed to dial server: %v", err)
|
||||
|
@@ -3,6 +3,7 @@ package grpc
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"net"
|
||||
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/codec"
|
||||
@@ -14,9 +15,11 @@ import (
|
||||
)
|
||||
|
||||
type codecsKey struct{}
|
||||
type tlsAuth struct{}
|
||||
type maxMsgSizeKey struct{}
|
||||
type grpcOptions struct{}
|
||||
type netListener struct{}
|
||||
type maxMsgSizeKey struct{}
|
||||
type maxConnKey struct{}
|
||||
type tlsAuth struct{}
|
||||
|
||||
// gRPC Codec to be used to encode/decode requests for a given content type
|
||||
func Codec(contentType string, c encoding.Codec) server.Option {
|
||||
@@ -25,8 +28,8 @@ func Codec(contentType string, c encoding.Codec) server.Option {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
if v := o.Context.Value(codecsKey{}); v != nil {
|
||||
codecs = v.(map[string]encoding.Codec)
|
||||
if v, ok := o.Context.Value(codecsKey{}).(map[string]encoding.Codec); ok && v != nil {
|
||||
codecs = v
|
||||
}
|
||||
codecs[contentType] = c
|
||||
o.Context = context.WithValue(o.Context, codecsKey{}, codecs)
|
||||
@@ -35,22 +38,22 @@ func Codec(contentType string, c encoding.Codec) server.Option {
|
||||
|
||||
// AuthTLS should be used to setup a secure authentication using TLS
|
||||
func AuthTLS(t *tls.Config) server.Option {
|
||||
return func(o *server.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, tlsAuth{}, t)
|
||||
}
|
||||
return setServerOption(tlsAuth{}, t)
|
||||
}
|
||||
|
||||
// MaxConn specifies maximum number of max simultaneous connections to server
|
||||
func MaxConn(n int) server.Option {
|
||||
return setServerOption(maxConnKey{}, n)
|
||||
}
|
||||
|
||||
// Listener specifies the net.Listener to use instead of the default
|
||||
func Listener(l net.Listener) server.Option {
|
||||
return setServerOption(netListener{}, l)
|
||||
}
|
||||
|
||||
// Options to be used to configure gRPC options
|
||||
func Options(opts ...grpc.ServerOption) server.Option {
|
||||
return func(o *server.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, grpcOptions{}, opts)
|
||||
}
|
||||
return setServerOption(grpcOptions{}, opts)
|
||||
}
|
||||
|
||||
//
|
||||
@@ -58,51 +61,25 @@ func Options(opts ...grpc.ServerOption) server.Option {
|
||||
// send. Default maximum message size is 4 MB.
|
||||
//
|
||||
func MaxMsgSize(s int) server.Option {
|
||||
return func(o *server.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
o.Context = context.WithValue(o.Context, maxMsgSizeKey{}, s)
|
||||
}
|
||||
return setServerOption(maxMsgSizeKey{}, s)
|
||||
}
|
||||
|
||||
func newOptions(opt ...server.Option) server.Options {
|
||||
opts := server.Options{
|
||||
Codecs: make(map[string]codec.NewCodec),
|
||||
Metadata: map[string]string{},
|
||||
Codecs: make(map[string]codec.NewCodec),
|
||||
Metadata: map[string]string{},
|
||||
Broker: broker.DefaultBroker,
|
||||
Registry: registry.DefaultRegistry,
|
||||
Transport: transport.DefaultTransport,
|
||||
Address: server.DefaultAddress,
|
||||
Name: server.DefaultName,
|
||||
Id: server.DefaultId,
|
||||
Version: server.DefaultVersion,
|
||||
}
|
||||
|
||||
for _, o := range opt {
|
||||
o(&opts)
|
||||
}
|
||||
|
||||
if opts.Broker == nil {
|
||||
opts.Broker = broker.DefaultBroker
|
||||
}
|
||||
|
||||
if opts.Registry == nil {
|
||||
opts.Registry = registry.DefaultRegistry
|
||||
}
|
||||
|
||||
if opts.Transport == nil {
|
||||
opts.Transport = transport.DefaultTransport
|
||||
}
|
||||
|
||||
if len(opts.Address) == 0 {
|
||||
opts.Address = server.DefaultAddress
|
||||
}
|
||||
|
||||
if len(opts.Name) == 0 {
|
||||
opts.Name = server.DefaultName
|
||||
}
|
||||
|
||||
if len(opts.Id) == 0 {
|
||||
opts.Id = server.DefaultId
|
||||
}
|
||||
|
||||
if len(opts.Version) == 0 {
|
||||
opts.Version = server.DefaultVersion
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
@@ -14,8 +14,8 @@ import (
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -86,7 +86,7 @@ func prepareEndpoint(method reflect.Method) *methodType {
|
||||
replyType = mtype.In(3)
|
||||
contextType = mtype.In(1)
|
||||
default:
|
||||
log.Log("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
|
||||
log.Error("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ func prepareEndpoint(method reflect.Method) *methodType {
|
||||
// check stream type
|
||||
streamType := reflect.TypeOf((*server.Stream)(nil)).Elem()
|
||||
if !argType.Implements(streamType) {
|
||||
log.Log(mname, "argument does not implement Streamer interface:", argType)
|
||||
log.Error(mname, "argument does not implement Streamer interface:", argType)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
@@ -102,30 +102,30 @@ func prepareEndpoint(method reflect.Method) *methodType {
|
||||
|
||||
// First arg need not be a pointer.
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
log.Log(mname, "argument type not exported:", argType)
|
||||
log.Error(mname, "argument type not exported:", argType)
|
||||
return nil
|
||||
}
|
||||
|
||||
if replyType.Kind() != reflect.Ptr {
|
||||
log.Log("method", mname, "reply type not a pointer:", replyType)
|
||||
log.Error("method", mname, "reply type not a pointer:", replyType)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reply type must be exported.
|
||||
if !isExportedOrBuiltinType(replyType) {
|
||||
log.Log("method", mname, "reply type not exported:", replyType)
|
||||
log.Error("method", mname, "reply type not exported:", replyType)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Endpoint() needs one out.
|
||||
if mtype.NumOut() != 1 {
|
||||
log.Log("method", mname, "has wrong number of outs:", mtype.NumOut())
|
||||
log.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.Log("method", mname, "returns", returnType.String(), "not error")
|
||||
log.Error("method", mname, "returns", returnType.String(), "not error")
|
||||
return nil
|
||||
}
|
||||
return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream}
|
||||
@@ -146,7 +146,7 @@ func (server *rServer) register(rcvr interface{}) error {
|
||||
}
|
||||
if !isExported(sname) {
|
||||
s := "rpc Register: type " + sname + " is not exported"
|
||||
log.Log(s)
|
||||
log.Error(s)
|
||||
return errors.New(s)
|
||||
}
|
||||
if _, present := server.serviceMap[sname]; present {
|
||||
@@ -165,7 +165,7 @@ 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.Log(s)
|
||||
log.Error(s)
|
||||
return errors.New(s)
|
||||
}
|
||||
server.serviceMap[s.name] = s
|
||||
|
@@ -9,10 +9,10 @@ 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/metadata"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -171,8 +171,8 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Log("panic recovered: ", r)
|
||||
log.Logf(string(debug.Stack()))
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
err = errors.InternalServerError("go.micro.server", "panic recovered: %v", r)
|
||||
}
|
||||
}()
|
||||
@@ -188,7 +188,7 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
|
||||
return err
|
||||
}
|
||||
|
||||
hdr := make(map[string]string)
|
||||
hdr := make(map[string]string, len(msg.Header))
|
||||
for k, v := range msg.Header {
|
||||
hdr[k] = v
|
||||
}
|
||||
@@ -246,18 +246,19 @@ func (g *grpcServer) createSubHandler(sb *subscriber, opts server.Options) broke
|
||||
if g.wg != nil {
|
||||
defer g.wg.Done()
|
||||
}
|
||||
results <- fn(ctx, &rpcMessage{
|
||||
err := fn(ctx, &rpcMessage{
|
||||
topic: sb.topic,
|
||||
contentType: ct,
|
||||
payload: req.Interface(),
|
||||
header: msg.Header,
|
||||
body: msg.Body,
|
||||
})
|
||||
results <- err
|
||||
}()
|
||||
}
|
||||
var errors []string
|
||||
for i := 0; i < len(sb.handlers); i++ {
|
||||
if rerr := <-results; err != nil {
|
||||
if rerr := <-results; rerr != nil {
|
||||
errors = append(errors, rerr.Error())
|
||||
}
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -39,6 +40,9 @@ type Options struct {
|
||||
// The router for requests
|
||||
Router Router
|
||||
|
||||
// TLSConfig specifies tls.Config for secure serving
|
||||
TLSConfig *tls.Config
|
||||
|
||||
// Other options for implementations of the interface
|
||||
// can be stored in a context
|
||||
Context context.Context
|
||||
@@ -205,6 +209,26 @@ func RegisterInterval(t time.Duration) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// TLSConfig specifies a *tls.Config
|
||||
func TLSConfig(t *tls.Config) Option {
|
||||
return func(o *Options) {
|
||||
// set the internal tls
|
||||
o.TLSConfig = t
|
||||
|
||||
// set the default transport if one is not
|
||||
// already set. Required for Init call below.
|
||||
if o.Transport == nil {
|
||||
o.Transport = transport.DefaultTransport
|
||||
}
|
||||
|
||||
// set the transport tls
|
||||
o.Transport.Init(
|
||||
transport.Secure(true),
|
||||
transport.TLSConfig(t),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// WithRouter sets the request router
|
||||
func WithRouter(r Router) Option {
|
||||
return func(o *Options) {
|
||||
|
@@ -20,7 +20,7 @@ import (
|
||||
|
||||
"github.com/micro/go-micro/v2/codec"
|
||||
merrors "github.com/micro/go-micro/v2/errors"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -141,7 +141,7 @@ func prepareMethod(method reflect.Method) *methodType {
|
||||
replyType = mtype.In(3)
|
||||
contextType = mtype.In(1)
|
||||
default:
|
||||
log.Log("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
|
||||
log.Error("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ func prepareMethod(method reflect.Method) *methodType {
|
||||
// check stream type
|
||||
streamType := reflect.TypeOf((*Stream)(nil)).Elem()
|
||||
if !argType.Implements(streamType) {
|
||||
log.Log(mname, "argument does not implement Stream interface:", argType)
|
||||
log.Error(mname, "argument does not implement Stream interface:", argType)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
@@ -157,30 +157,30 @@ func prepareMethod(method reflect.Method) *methodType {
|
||||
|
||||
// First arg need not be a pointer.
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
log.Log(mname, "argument type not exported:", argType)
|
||||
log.Error(mname, "argument type not exported:", argType)
|
||||
return nil
|
||||
}
|
||||
|
||||
if replyType.Kind() != reflect.Ptr {
|
||||
log.Log("method", mname, "reply type not a pointer:", replyType)
|
||||
log.Error("method", mname, "reply type not a pointer:", replyType)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reply type must be exported.
|
||||
if !isExportedOrBuiltinType(replyType) {
|
||||
log.Log("method", mname, "reply type not exported:", replyType)
|
||||
log.Error("method", mname, "reply type not exported:", replyType)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Method needs one out.
|
||||
if mtype.NumOut() != 1 {
|
||||
log.Log("method", mname, "has wrong number of outs:", mtype.NumOut())
|
||||
log.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.Log("method", mname, "returns", returnType.String(), "not error")
|
||||
log.Error("method", mname, "returns", returnType.String(), "not error")
|
||||
return nil
|
||||
}
|
||||
return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream}
|
||||
@@ -505,27 +505,23 @@ 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 {
|
||||
log.Log("panic recovered: ", r)
|
||||
log.Log(string(debug.Stack()))
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
err = merrors.InternalServerError("go.micro.server", "panic recovered: %v", r)
|
||||
}
|
||||
}()
|
||||
|
||||
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
|
||||
|
||||
|
@@ -15,11 +15,11 @@ 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/metadata"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/transport"
|
||||
"github.com/micro/go-micro/v2/util/addr"
|
||||
log "github.com/micro/go-micro/v2/util/log"
|
||||
mnet "github.com/micro/go-micro/v2/util/net"
|
||||
"github.com/micro/go-micro/v2/util/socket"
|
||||
)
|
||||
@@ -85,7 +85,7 @@ func (s *rpcServer) HandleEvent(e broker.Event) error {
|
||||
}
|
||||
|
||||
// copy headers
|
||||
hdr := make(map[string]string)
|
||||
hdr := make(map[string]string, len(msg.Header))
|
||||
for k, v := range msg.Header {
|
||||
hdr[k] = v
|
||||
}
|
||||
@@ -158,8 +158,8 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
|
||||
// recover any panics
|
||||
if r := recover(); r != nil {
|
||||
log.Log("panic recovered: ", r)
|
||||
log.Log(string(debug.Stack()))
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -262,7 +262,7 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
ct := msg.Header["Content-Type"]
|
||||
|
||||
// copy the message headers
|
||||
hdr := make(map[string]string)
|
||||
hdr := make(map[string]string, len(msg.Header))
|
||||
for k, v := range msg.Header {
|
||||
hdr[k] = v
|
||||
}
|
||||
@@ -377,8 +377,8 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
|
||||
// recover any panics for outbound process
|
||||
if r := recover(); r != nil {
|
||||
log.Log("panic recovered: ", r)
|
||||
log.Log(string(debug.Stack()))
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -409,8 +409,8 @@ func (s *rpcServer) ServeConn(sock transport.Socket) {
|
||||
|
||||
// recover any panics for call handler
|
||||
if r := recover(); r != nil {
|
||||
log.Log("panic recovered: ", r)
|
||||
log.Log(string(debug.Stack()))
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
}
|
||||
}()
|
||||
|
||||
@@ -608,7 +608,7 @@ func (s *rpcServer) Register() error {
|
||||
s.RUnlock()
|
||||
|
||||
if !registered {
|
||||
log.Logf("Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
|
||||
log.Infof("Registry [%s] Registering node: %s", config.Registry.String(), node.Id)
|
||||
}
|
||||
|
||||
// create registry options
|
||||
@@ -654,7 +654,7 @@ func (s *rpcServer) Register() error {
|
||||
opts = append(opts, broker.DisableAutoAck())
|
||||
}
|
||||
|
||||
log.Logf("Subscribing to topic: %s", sub.Topic())
|
||||
log.Infof("Subscribing to topic: %s", sub.Topic())
|
||||
sub, err := config.Broker.Subscribe(sb.Topic(), s.HandleEvent, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -712,7 +712,7 @@ func (s *rpcServer) Deregister() error {
|
||||
Nodes: []*registry.Node{node},
|
||||
}
|
||||
|
||||
log.Logf("Registry [%s] Deregistering node: %s", config.Registry.String(), node.Id)
|
||||
log.Infof("Registry [%s] Deregistering node: %s", config.Registry.String(), node.Id)
|
||||
if err := config.Registry.Deregister(service); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -734,7 +734,7 @@ func (s *rpcServer) Deregister() error {
|
||||
|
||||
for sb, subs := range s.subscribers {
|
||||
for _, sub := range subs {
|
||||
log.Logf("Unsubscribing %s from topic: %s", node.Id, sub.Topic())
|
||||
log.Infof("Unsubscribing %s from topic: %s", node.Id, sub.Topic())
|
||||
sub.Unsubscribe()
|
||||
}
|
||||
s.subscribers[sb] = nil
|
||||
@@ -760,7 +760,7 @@ func (s *rpcServer) Start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Logf("Transport [%s] Listening on %s", config.Transport.String(), ts.Addr())
|
||||
log.Infof("Transport [%s] Listening on %s", config.Transport.String(), ts.Addr())
|
||||
|
||||
// swap address
|
||||
s.Lock()
|
||||
@@ -775,15 +775,15 @@ func (s *rpcServer) Start() error {
|
||||
|
||||
bname := config.Broker.String()
|
||||
|
||||
log.Logf("Broker [%s] Connected to %s", bname, config.Broker.Address())
|
||||
log.Infof("Broker [%s] Connected to %s", bname, config.Broker.Address())
|
||||
|
||||
// use RegisterCheck func before register
|
||||
if err = s.opts.RegisterCheck(s.opts.Context); err != nil {
|
||||
log.Logf("Server %s-%s register check error: %s", config.Name, config.Id, err)
|
||||
log.Errorf("Server %s-%s register check error: %s", config.Name, config.Id, err)
|
||||
} else {
|
||||
// announce self to the world
|
||||
if err = s.Register(); err != nil {
|
||||
log.Logf("Server %s-%s register error: %s", config.Name, config.Id, err)
|
||||
log.Errorf("Server %s-%s register error: %s", config.Name, config.Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -804,7 +804,7 @@ func (s *rpcServer) Start() error {
|
||||
// check the error and backoff
|
||||
default:
|
||||
if err != nil {
|
||||
log.Logf("Accept error: %v", err)
|
||||
log.Errorf("Accept error: %v", err)
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
@@ -837,17 +837,17 @@ func (s *rpcServer) Start() error {
|
||||
s.RUnlock()
|
||||
rerr := s.opts.RegisterCheck(s.opts.Context)
|
||||
if rerr != nil && registered {
|
||||
log.Logf("Server %s-%s register check error: %s, deregister it", config.Name, config.Id, err)
|
||||
log.Errorf("Server %s-%s register check error: %s, deregister it", config.Name, config.Id, err)
|
||||
// deregister self in case of error
|
||||
if err := s.Deregister(); err != nil {
|
||||
log.Logf("Server %s-%s deregister error: %s", config.Name, config.Id, err)
|
||||
log.Errorf("Server %s-%s deregister error: %s", config.Name, config.Id, err)
|
||||
}
|
||||
} else if rerr != nil && !registered {
|
||||
log.Logf("Server %s-%s register check error: %s", config.Name, config.Id, err)
|
||||
log.Errorf("Server %s-%s register check error: %s", config.Name, config.Id, err)
|
||||
continue
|
||||
}
|
||||
if err := s.Register(); err != nil {
|
||||
log.Logf("Server %s-%s register error: %s", config.Name, config.Id, err)
|
||||
log.Errorf("Server %s-%s register error: %s", config.Name, config.Id, err)
|
||||
}
|
||||
// wait for exit
|
||||
case ch = <-s.exit:
|
||||
@@ -863,7 +863,7 @@ func (s *rpcServer) Start() error {
|
||||
if registered {
|
||||
// deregister self
|
||||
if err := s.Deregister(); err != nil {
|
||||
log.Logf("Server %s-%s deregister error: %s", config.Name, config.Id, err)
|
||||
log.Errorf("Server %s-%s deregister error: %s", config.Name, config.Id, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -879,7 +879,7 @@ func (s *rpcServer) Start() error {
|
||||
// close transport listener
|
||||
ch <- ts.Close()
|
||||
|
||||
log.Logf("Broker [%s] Disconnected from %s", bname, config.Broker.Address())
|
||||
log.Infof("Broker [%s] Disconnected from %s", bname, config.Broker.Address())
|
||||
// disconnect the broker
|
||||
config.Broker.Disconnect()
|
||||
|
||||
|
@@ -10,8 +10,8 @@ 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/registry"
|
||||
log "github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
// Server is a simple micro server abstraction
|
||||
@@ -200,7 +200,7 @@ func Run() error {
|
||||
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT)
|
||||
log.Logf("Received signal %s", <-ch)
|
||||
log.Infof("Received signal %s", <-ch)
|
||||
|
||||
return Stop()
|
||||
}
|
||||
@@ -208,13 +208,13 @@ func Run() error {
|
||||
// Start starts the default server
|
||||
func Start() error {
|
||||
config := DefaultServer.Options()
|
||||
log.Logf("Starting server %s id %s", config.Name, config.Id)
|
||||
log.Infof("Starting server %s id %s", config.Name, config.Id)
|
||||
return DefaultServer.Start()
|
||||
}
|
||||
|
||||
// Stop stops the default server
|
||||
func Stop() error {
|
||||
log.Logf("Stopping server")
|
||||
log.Infof("Stopping server")
|
||||
return DefaultServer.Stop()
|
||||
}
|
||||
|
||||
|
40
service.go
40
service.go
@@ -11,15 +11,13 @@ 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/plugin"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
"github.com/micro/go-micro/v2/util/config"
|
||||
"github.com/micro/go-micro/v2/util/wrapper"
|
||||
)
|
||||
|
||||
@@ -40,7 +38,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
|
||||
@@ -101,9 +99,18 @@ func (s *service) Init(opts ...Option) {
|
||||
cmd.Transport(&s.opts.Transport),
|
||||
cmd.Client(&s.opts.Client),
|
||||
cmd.Server(&s.opts.Server),
|
||||
cmd.Profile(&s.opts.Profile),
|
||||
); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// 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 +182,19 @@ 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.Logf("Starting [service] %s", s.Name())
|
||||
log.Infof("Starting [service] %s", s.Name())
|
||||
|
||||
if err := s.Start(); err != nil {
|
||||
return err
|
||||
|
@@ -7,10 +7,8 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/debug/log/noop"
|
||||
proto "github.com/micro/go-micro/v2/debug/service/proto"
|
||||
"github.com/micro/go-micro/v2/registry/memory"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
"github.com/micro/go-micro/v2/util/test"
|
||||
)
|
||||
|
||||
@@ -24,9 +22,6 @@ func testShutdown(wg *sync.WaitGroup, cancel func()) {
|
||||
}
|
||||
|
||||
func testService(ctx context.Context, wg *sync.WaitGroup, name string) Service {
|
||||
// set no op logger
|
||||
log.SetLogger(noop.NewLog())
|
||||
|
||||
// add self
|
||||
wg.Add(1)
|
||||
|
||||
|
@@ -10,8 +10,8 @@ import (
|
||||
"unicode"
|
||||
|
||||
"github.com/lib/pq"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/store"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
|
@@ -5,10 +5,10 @@ import (
|
||||
"math"
|
||||
"time"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/sync/leader/etcd"
|
||||
"github.com/micro/go-micro/v2/sync/task"
|
||||
"github.com/micro/go-micro/v2/sync/task/local"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
type syncCron struct {
|
||||
@@ -35,7 +35,7 @@ func (c *syncCron) Schedule(s task.Schedule, t task.Command) error {
|
||||
// leader election
|
||||
e, err := c.opts.Leader.Elect(id)
|
||||
if err != nil {
|
||||
log.Logf("[cron] leader election error: %v", err)
|
||||
log.Errorf("[cron] leader election error: %v", err)
|
||||
time.Sleep(backoff(i))
|
||||
i++
|
||||
continue
|
||||
@@ -55,9 +55,9 @@ func (c *syncCron) Schedule(s task.Schedule, t task.Command) error {
|
||||
break Tick
|
||||
}
|
||||
|
||||
log.Logf("[cron] executing command %s", t.Name)
|
||||
log.Infof("[cron] executing command %s", t.Name)
|
||||
if err := c.opts.Task.Run(t); err != nil {
|
||||
log.Logf("[cron] error executing command %s: %v", t.Name, err)
|
||||
log.Errorf("[cron] error executing command %s: %v", t.Name, err)
|
||||
}
|
||||
// leader revoked
|
||||
case <-r:
|
||||
|
@@ -4,9 +4,9 @@ import (
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/micro/go-micro/v2/errors"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/transport"
|
||||
pb "github.com/micro/go-micro/v2/transport/grpc/proto"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
"google.golang.org/grpc/peer"
|
||||
)
|
||||
|
||||
@@ -30,7 +30,7 @@ func (m *microTransport) Stream(ts pb.Transport_StreamServer) (err error) {
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
log.Log(r, string(debug.Stack()))
|
||||
log.Error(r, string(debug.Stack()))
|
||||
sock.Close()
|
||||
err = errors.InternalServerError("go.micro.transport", "panic recovered: %v", r)
|
||||
}
|
||||
|
@@ -156,7 +156,7 @@ func (h *httpTransportClient) Recv(m *Message) error {
|
||||
m.Body = b
|
||||
|
||||
if m.Header == nil {
|
||||
m.Header = make(map[string]string)
|
||||
m.Header = make(map[string]string, len(rsp.Header))
|
||||
}
|
||||
|
||||
for k, v := range rsp.Header {
|
||||
@@ -193,10 +193,6 @@ func (h *httpTransportSocket) Recv(m *Message) error {
|
||||
return errors.New("message passed in is nil")
|
||||
}
|
||||
|
||||
if m.Header == nil {
|
||||
m.Header = make(map[string]string)
|
||||
}
|
||||
|
||||
// process http 1
|
||||
if h.r.ProtoMajor == 1 {
|
||||
// set timeout if its greater than 0
|
||||
@@ -228,6 +224,10 @@ func (h *httpTransportSocket) Recv(m *Message) error {
|
||||
r.Body.Close()
|
||||
m.Body = b
|
||||
|
||||
if m.Header == nil {
|
||||
m.Header = make(map[string]string, len(r.Header))
|
||||
}
|
||||
|
||||
// set headers
|
||||
for k, v := range r.Header {
|
||||
if len(v) > 0 {
|
||||
|
@@ -5,7 +5,16 @@ import (
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"io"
|
||||
|
||||
"github.com/oxtoacart/bpool"
|
||||
)
|
||||
|
||||
var (
|
||||
// the local buffer pool
|
||||
// gcmStandardNonceSize from crypto/cipher/gcm.go is 12 bytes
|
||||
// 100 - is max size of pool
|
||||
noncePool = bpool.NewBytePool(100, 12)
|
||||
hashPool = bpool.NewBytePool(1024*32, 32)
|
||||
)
|
||||
|
||||
// hash hahes the data into 32 bytes key and returns it
|
||||
@@ -13,7 +22,10 @@ import (
|
||||
func hash(key string) []byte {
|
||||
hasher := sha256.New()
|
||||
hasher.Write([]byte(key))
|
||||
return hasher.Sum(nil)
|
||||
out := hashPool.Get()
|
||||
defer hashPool.Put(out[:0])
|
||||
out = hasher.Sum(out[:0])
|
||||
return out
|
||||
}
|
||||
|
||||
// Encrypt encrypts data and returns the encrypted data
|
||||
@@ -32,12 +44,13 @@ func Encrypt(data []byte, key string) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// create a new byte array the size of the nonce
|
||||
// get new byte array the size of the nonce from pool
|
||||
// NOTE: we might use smaller nonce size in the future
|
||||
nonce := make([]byte, gcm.NonceSize())
|
||||
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
||||
nonce := noncePool.Get()
|
||||
if _, err = rand.Read(nonce); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer noncePool.Put(nonce)
|
||||
|
||||
// NOTE: we prepend the nonce to the payload
|
||||
// we need to do this as we need the same nonce
|
||||
|
@@ -8,8 +8,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/transport"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -131,6 +131,7 @@ func (t *tun) newSession(channel, sessionId string) (*session, bool) {
|
||||
recv: make(chan *message, 128),
|
||||
send: t.send,
|
||||
errChan: make(chan error, 1),
|
||||
key: t.token + channel + sessionId,
|
||||
}
|
||||
|
||||
// save session
|
||||
@@ -949,7 +950,7 @@ func (t *tun) connect() error {
|
||||
|
||||
// still connected but the tunnel died
|
||||
if err != nil && t.connected {
|
||||
log.Logf("Tunnel listener died: %v", err)
|
||||
log.Errorf("Tunnel listener died: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
|
@@ -8,8 +8,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/transport"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
type link struct {
|
||||
@@ -107,32 +107,6 @@ func newLink(s transport.Socket) *link {
|
||||
return l
|
||||
}
|
||||
|
||||
func (l *link) connect(addr string) error {
|
||||
c, err := l.transport.Dial(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.Lock()
|
||||
l.Socket = c
|
||||
l.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *link) accept(sock transport.Socket) error {
|
||||
l.Lock()
|
||||
l.Socket = sock
|
||||
l.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *link) setLoopback(v bool) {
|
||||
l.Lock()
|
||||
l.loopback = v
|
||||
l.Unlock()
|
||||
}
|
||||
|
||||
// setRate sets the bits per second rate as a float64
|
||||
func (l *link) setRate(bits int64, delta time.Duration) {
|
||||
// rate of send in bits per nanosecond
|
||||
|
@@ -4,7 +4,7 @@ import (
|
||||
"io"
|
||||
"sync"
|
||||
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
type tunListener struct {
|
||||
@@ -77,6 +77,8 @@ func (t *tunListener) process() {
|
||||
|
||||
// create a new session session
|
||||
sess = &session{
|
||||
// the session key
|
||||
key: t.token + m.channel + sessionId,
|
||||
// the id of the remote side
|
||||
tunnel: m.tunnel,
|
||||
// the channel
|
||||
|
@@ -5,8 +5,8 @@ import (
|
||||
"io"
|
||||
"time"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/transport"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
// session is our pseudo session for transport.Socket
|
||||
@@ -47,6 +47,8 @@ type session struct {
|
||||
link string
|
||||
// the error response
|
||||
errChan chan error
|
||||
// key for session encryption
|
||||
key string
|
||||
}
|
||||
|
||||
// message is sent over the send channel
|
||||
@@ -326,22 +328,22 @@ func (s *session) Announce() error {
|
||||
// Send is used to send a message
|
||||
func (s *session) Send(m *transport.Message) error {
|
||||
// encrypt the transport message payload
|
||||
body, err := Encrypt(m.Body, s.token+s.channel+s.session)
|
||||
body, err := Encrypt(m.Body, s.key)
|
||||
if err != nil {
|
||||
log.Debugf("failed to encrypt message body: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// make copy
|
||||
// make copy, without rehash and realloc
|
||||
data := &transport.Message{
|
||||
Header: make(map[string]string),
|
||||
Header: make(map[string]string, len(m.Header)),
|
||||
Body: body,
|
||||
}
|
||||
|
||||
// encrypt all the headers
|
||||
for k, v := range m.Header {
|
||||
// encrypt the transport message payload
|
||||
val, err := Encrypt([]byte(v), s.token+s.channel+s.session)
|
||||
val, err := Encrypt([]byte(v), s.key)
|
||||
if err != nil {
|
||||
log.Debugf("failed to encrypt message header %s: %v", k, err)
|
||||
return err
|
||||
@@ -387,14 +389,14 @@ func (s *session) Recv(m *transport.Message) error {
|
||||
default:
|
||||
}
|
||||
|
||||
//log.Tracef("Received %+v from recv backlog", msg)
|
||||
log.Tracef("Received %+v from recv backlog", msg)
|
||||
|
||||
key := s.token + s.channel + msg.session
|
||||
// decrypt the received payload using the token
|
||||
// we have to used msg.session because multicast has a shared
|
||||
// session id of "multicast" in this session struct on
|
||||
// the listener side
|
||||
body, err := Decrypt(msg.data.Body, s.token+s.channel+msg.session)
|
||||
body, err := Decrypt(msg.data.Body, key)
|
||||
if err != nil {
|
||||
log.Debugf("failed to decrypt message body: %v", err)
|
||||
return err
|
||||
@@ -410,7 +412,7 @@ func (s *session) Recv(m *transport.Message) error {
|
||||
return err
|
||||
}
|
||||
// encrypt the transport message payload
|
||||
val, err := Decrypt([]byte(h), s.token+s.channel+msg.session)
|
||||
val, err := Decrypt([]byte(h), key)
|
||||
if err != nil {
|
||||
log.Debugf("failed to decrypt message header %s: %v", k, err)
|
||||
return err
|
||||
|
90
util/config/config.go
Normal file
90
util/config/config.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
conf "github.com/micro/go-micro/v2/config"
|
||||
"github.com/micro/go-micro/v2/config/source/file"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
// FileName for global micro config
|
||||
const FileName = ".micro"
|
||||
|
||||
// config is a singleton which is required to ensure
|
||||
// each function call doesn't load the .micro file
|
||||
// from disk
|
||||
var config = newConfig()
|
||||
|
||||
// Get a value from the .micro file
|
||||
func Get(key string) (string, error) {
|
||||
tk := config.Get(key).String("")
|
||||
return strings.TrimSpace(tk), nil
|
||||
}
|
||||
|
||||
// Set a value in the .micro file
|
||||
func Set(key, value string) error {
|
||||
// get the filepath
|
||||
fp, err := filePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the value
|
||||
config.Set(value, key)
|
||||
|
||||
// write to the file
|
||||
return ioutil.WriteFile(fp, config.Bytes(), 0644)
|
||||
}
|
||||
|
||||
func filePath() (string, error) {
|
||||
usr, err := user.Current()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(usr.HomeDir, FileName), nil
|
||||
}
|
||||
|
||||
// newConfig returns a loaded config
|
||||
func newConfig() conf.Config {
|
||||
// get the filepath
|
||||
fp, err := filePath()
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return conf.DefaultConfig
|
||||
}
|
||||
|
||||
// write the file if it does not exist
|
||||
if _, err := os.Stat(fp); os.IsNotExist(err) {
|
||||
ioutil.WriteFile(fp, []byte{}, 0644)
|
||||
} else if err != nil {
|
||||
log.Error(err)
|
||||
return conf.DefaultConfig
|
||||
}
|
||||
|
||||
// create a new config
|
||||
c, err := conf.NewConfig(
|
||||
conf.WithSource(
|
||||
file.NewSource(
|
||||
file.WithPath(fp),
|
||||
),
|
||||
),
|
||||
)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return conf.DefaultConfig
|
||||
}
|
||||
|
||||
// load the config
|
||||
if err := c.Load(); err != nil {
|
||||
log.Error(err)
|
||||
return conf.DefaultConfig
|
||||
}
|
||||
|
||||
// return the conf
|
||||
return c
|
||||
}
|
@@ -12,8 +12,8 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/util/kubernetes/api"
|
||||
"github.com/micro/go-micro/v2/util/log"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@@ -91,6 +91,8 @@ func CertsFromPEM(pemCerts []byte) ([]*x509.Certificate, error) {
|
||||
func Format(v string) string {
|
||||
// to lower case
|
||||
v = strings.ToLower(v)
|
||||
// / to dashes
|
||||
v = strings.ReplaceAll(v, "/", "-")
|
||||
// dots to dashes
|
||||
v = strings.ReplaceAll(v, ".", "-")
|
||||
// limit to 253 chars
|
||||
|
@@ -1,5 +1,7 @@
|
||||
# Log
|
||||
|
||||
DEPRECATED: use github.com/micro/go-micro/v2/logger interface
|
||||
|
||||
This is the global logger for all micro based libraries.
|
||||
|
||||
## Set Logger
|
||||
|
@@ -1,13 +1,14 @@
|
||||
// Package log is a global internal logger
|
||||
// DEPRECATED: this is frozen package, use github.com/micro/go-micro/v2/logger
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/debug/log"
|
||||
dlog "github.com/micro/go-micro/v2/debug/log"
|
||||
nlog "github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
// level is a log level
|
||||
@@ -22,9 +23,13 @@ const (
|
||||
LevelTrace
|
||||
)
|
||||
|
||||
type elog struct {
|
||||
dlog dlog.Log
|
||||
}
|
||||
|
||||
var (
|
||||
// the local logger
|
||||
logger log.Log = log.DefaultLog
|
||||
logger dlog.Log = &elog{}
|
||||
|
||||
// default log level is info
|
||||
level = LevelInfo
|
||||
@@ -33,6 +38,24 @@ var (
|
||||
prefix string
|
||||
)
|
||||
|
||||
func levelToLevel(l Level) nlog.Level {
|
||||
switch l {
|
||||
case LevelTrace:
|
||||
return nlog.TraceLevel
|
||||
case LevelDebug:
|
||||
return nlog.DebugLevel
|
||||
case LevelWarn:
|
||||
return nlog.WarnLevel
|
||||
case LevelInfo:
|
||||
return nlog.InfoLevel
|
||||
case LevelError:
|
||||
return nlog.ErrorLevel
|
||||
case LevelFatal:
|
||||
return nlog.FatalLevel
|
||||
}
|
||||
return nlog.InfoLevel
|
||||
}
|
||||
|
||||
func init() {
|
||||
switch os.Getenv("MICRO_LOG_LEVEL") {
|
||||
case "trace":
|
||||
@@ -69,18 +92,24 @@ func (l Level) String() string {
|
||||
}
|
||||
}
|
||||
|
||||
func (el *elog) Read(opt ...dlog.ReadOption) ([]dlog.Record, error) {
|
||||
return el.dlog.Read(opt...)
|
||||
}
|
||||
|
||||
func (el *elog) Write(r dlog.Record) error {
|
||||
return el.dlog.Write(r)
|
||||
}
|
||||
|
||||
func (el *elog) Stream() (dlog.Stream, error) {
|
||||
return el.dlog.Stream()
|
||||
}
|
||||
|
||||
// Log makes use of github.com/micro/debug/log
|
||||
func Log(v ...interface{}) {
|
||||
if len(prefix) > 0 {
|
||||
v = append([]interface{}{prefix, " "}, v...)
|
||||
}
|
||||
logger.Write(log.Record{
|
||||
Timestamp: time.Now(),
|
||||
Message: fmt.Sprint(v...),
|
||||
Metadata: map[string]string{
|
||||
"level": level.String(),
|
||||
},
|
||||
})
|
||||
nlog.DefaultLogger.Log(levelToLevel(level), v)
|
||||
}
|
||||
|
||||
// Logf makes use of github.com/micro/debug/log
|
||||
@@ -88,13 +117,7 @@ func Logf(format string, v ...interface{}) {
|
||||
if len(prefix) > 0 {
|
||||
format = prefix + " " + format
|
||||
}
|
||||
logger.Write(log.Record{
|
||||
Timestamp: time.Now(),
|
||||
Message: fmt.Sprintf(format, v...),
|
||||
Metadata: map[string]string{
|
||||
"level": level.String(),
|
||||
},
|
||||
})
|
||||
nlog.DefaultLogger.Log(levelToLevel(level), format, v)
|
||||
}
|
||||
|
||||
// WithLevel logs with the level specified
|
||||
@@ -166,22 +189,20 @@ func Errorf(format string, v ...interface{}) {
|
||||
// Fatal logs with Log and then exits with os.Exit(1)
|
||||
func Fatal(v ...interface{}) {
|
||||
WithLevel(LevelFatal, v...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Fatalf logs with Logf and then exits with os.Exit(1)
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
WithLevelf(LevelFatal, format, v...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// SetLogger sets the local logger
|
||||
func SetLogger(l log.Log) {
|
||||
func SetLogger(l dlog.Log) {
|
||||
logger = l
|
||||
}
|
||||
|
||||
// GetLogger returns the local logger
|
||||
func GetLogger() log.Log {
|
||||
func GetLogger() dlog.Log {
|
||||
return logger
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,10 @@ import (
|
||||
|
||||
type clientWrapper struct {
|
||||
client.Client
|
||||
|
||||
// Auth interface
|
||||
auth func() auth.Auth
|
||||
// headers to inject
|
||||
headers metadata.Metadata
|
||||
}
|
||||
|
||||
@@ -27,7 +31,7 @@ type traceWrapper struct {
|
||||
|
||||
var (
|
||||
HeaderPrefix = "Micro-"
|
||||
BearerSchema = "Bearer "
|
||||
BearerScheme = "Bearer "
|
||||
)
|
||||
|
||||
func (c *clientWrapper) setHeaders(ctx context.Context) context.Context {
|
||||
@@ -35,6 +39,15 @@ func (c *clientWrapper) setHeaders(ctx context.Context) context.Context {
|
||||
mda, _ := metadata.FromContext(ctx)
|
||||
md := metadata.Copy(mda)
|
||||
|
||||
// get auth token
|
||||
if a := c.auth(); a != nil {
|
||||
tk := a.Options().Token
|
||||
// if the token if exists and auth header isn't set then set it
|
||||
if len(tk) > 0 && len(md["Authorization"]) == 0 {
|
||||
md["Authorization"] = BearerScheme + tk
|
||||
}
|
||||
}
|
||||
|
||||
// set headers
|
||||
for k, v := range c.headers {
|
||||
if _, ok := md[k]; !ok {
|
||||
@@ -75,10 +88,11 @@ func (c *traceWrapper) Call(ctx context.Context, req client.Request, rsp interfa
|
||||
return err
|
||||
}
|
||||
|
||||
// FromService wraps a client to inject From-Service header into metadata
|
||||
func FromService(name string, c client.Client) client.Client {
|
||||
// FromService wraps a client to inject service and auth metadata
|
||||
func FromService(name string, c client.Client, fn func() auth.Auth) client.Client {
|
||||
return &clientWrapper{
|
||||
c,
|
||||
fn,
|
||||
metadata.Metadata{
|
||||
HeaderPrefix + "From-Service": name,
|
||||
},
|
||||
@@ -145,18 +159,14 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper {
|
||||
// get the auth.Auth interface
|
||||
a := fn()
|
||||
|
||||
// Extract endpoint and remove service name prefix
|
||||
// (e.g. Platform.ListServices => ListServices)
|
||||
var endpoint string
|
||||
if ec := strings.Split(req.Endpoint(), "."); len(ec) == 2 {
|
||||
endpoint = ec[1]
|
||||
// Check for debug endpoints which should be excluded from auth
|
||||
if strings.HasPrefix(req.Endpoint(), "Debug.") {
|
||||
return h(ctx, req, rsp)
|
||||
}
|
||||
|
||||
// Check for endpoints excluded from auth. If the endpoint
|
||||
// matches, execute the handler and return
|
||||
excludes := append(a.Options().Excludes, "Stats", "Trace")
|
||||
for _, e := range excludes {
|
||||
if e == endpoint {
|
||||
// Exclude any user excluded endpoints
|
||||
for _, e := range a.Options().Exclude {
|
||||
if e == req.Endpoint() {
|
||||
return h(ctx, req, rsp)
|
||||
}
|
||||
}
|
||||
@@ -166,15 +176,15 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper {
|
||||
var token string
|
||||
if header, ok := metadata.Get(ctx, "Authorization"); ok {
|
||||
// Ensure the correct scheme is being used
|
||||
if !strings.HasPrefix(header, BearerSchema) {
|
||||
if !strings.HasPrefix(header, BearerScheme) {
|
||||
return errors.Unauthorized("go.micro.auth", "invalid authorization header. expected Bearer schema")
|
||||
}
|
||||
|
||||
token = header[len(BearerSchema):]
|
||||
token = header[len(BearerScheme):]
|
||||
}
|
||||
|
||||
// Validate the token
|
||||
if _, err := a.Validate(token); err != nil {
|
||||
// Verify the token
|
||||
if _, err := a.Verify(token); err != nil {
|
||||
return errors.Unauthorized("go.micro.auth", err.Error())
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user