Compare commits
176 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
0327f30e3c | ||
|
0ce132eb8f | ||
|
00b76e0a64 | ||
|
aec27be9b4 | ||
|
86dfcb819b | ||
|
d613804b0a | ||
92e9d05432 | |||
|
8dfd93e915 | ||
|
e5136332e3 | ||
|
f10fd4b479 | ||
|
74368026a5 | ||
|
fde1aa9d6a | ||
|
f45cdba9ba | ||
|
b270860b79 | ||
|
e7ba930236 | ||
|
aa679f7a73 | ||
|
7b379bf1f1 | ||
|
e4e56b0f3f | ||
|
219d29f664 | ||
|
8fb138af06 | ||
|
a39e6515da | ||
|
2c7fd286de | ||
|
8aa2712b4d | ||
|
b5c2121cef | ||
|
ca9b877646 | ||
|
ff49b4fc71 | ||
|
222431b57a | ||
|
ddb51529a7 | ||
|
7c048f331a | ||
|
8475183bbb | ||
|
10f35db3ed | ||
|
b68af8ab63 | ||
|
266602a3d6 | ||
|
15d5142d9b | ||
|
0d88650511 | ||
|
8660370dc9 | ||
|
73339dde85 | ||
|
3f354f3c30 | ||
|
c08eb5f892 | ||
|
27e41c4ad5 | ||
|
1da8a640da | ||
|
e7ad031eb8 | ||
|
192f548c83 | ||
|
d85b4197b4 | ||
|
bb5f2e5525 | ||
|
f00b696282 | ||
|
e2d662608c | ||
|
9e9773c9c7 | ||
|
2f8e2487f7 | ||
|
d6c1fbf841 | ||
|
c3b404bab0 | ||
|
cd283654eb | ||
|
5712cc9c62 | ||
|
be5a10a4d4 | ||
|
b53a2c67f1 | ||
|
cc79692d68 | ||
|
796a598b37 | ||
|
73b4423682 | ||
|
198e942889 | ||
|
95703e4565 | ||
|
2729569f66 | ||
|
67146ecdc2 | ||
|
bd049a51e6 | ||
|
ffd89599a0 | ||
|
496293afa1 | ||
|
7d7f4046e8 | ||
|
c800070477 | ||
|
877fe5fb0a | ||
|
dad011cab4 | ||
|
f939200b34 | ||
|
9c072a372c | ||
|
fbb91c6cb7 | ||
|
b2cf501952 | ||
|
1fce0f02b6 | ||
|
12061bd006 | ||
|
856c73b341 | ||
|
4de19805ba | ||
|
c09b871a6b | ||
|
e876cb917d | ||
|
8f5ef012ff | ||
|
287992cef3 | ||
|
344ce061ce | ||
|
5d14970a55 | ||
|
0615fe825f | ||
|
6a661fd08c | ||
|
f6d9416a9e | ||
|
a29676b86a | ||
|
dc10f88c12 | ||
|
e61edf6280 | ||
|
3410a0949b | ||
|
9216a47724 | ||
|
cf37d64819 | ||
|
f0c0f3d4c4 | ||
|
c4e3f8c336 | ||
|
8875719619 | ||
|
c19b349e96 | ||
|
14155c7e02 | ||
|
3d36398818 | ||
|
56a7897c91 | ||
|
5efb386224 | ||
|
4d2de923cd | ||
|
f64b1468a5 | ||
|
56f281002b | ||
|
0d7250352f | ||
|
ef43f01da4 | ||
|
c9e5ae6a2b | ||
|
8a802d8f7a | ||
|
331ab3715c | ||
|
6b451a2197 | ||
|
b4c0224746 | ||
|
500d793fc4 | ||
|
16af265e8b | ||
|
b222cf8e13 | ||
|
f549e20fa2 | ||
|
83e9c1fad2 | ||
|
c220686c29 | ||
|
1b18730d54 | ||
|
5764519f5b | ||
|
957001f8ad | ||
|
0955671e45 | ||
|
57b060bac5 | ||
|
3136e1409e | ||
|
ca791d7e8d | ||
|
05858b746c | ||
|
09d1450d7d | ||
|
1ca1fd411a | ||
|
a2d4d62f1c | ||
|
8ab20f501c | ||
|
366fb228e5 | ||
|
bba8c254d7 | ||
|
ebd53794af | ||
|
2299244332 | ||
|
cf61d98635 | ||
|
15d1967aaf | ||
|
410fec8ee4 | ||
|
c831b6c03a | ||
|
290595f88e | ||
|
ba64518ebd | ||
|
b14d63b4a1 | ||
|
af2db0a0d9 | ||
|
fb255a7e5a | ||
|
47c1cb433e | ||
|
3fac7d79ab | ||
|
25c937fd0e | ||
|
e5c1fbc591 | ||
|
d781c9ae2d | ||
|
54951740bf | ||
|
0fb4734e67 | ||
|
346e034d0a | ||
|
116cc1e9ee | ||
|
762a5bc9e8 | ||
|
d39b723511 | ||
|
5494e935f4 | ||
|
e0863bb7eb | ||
|
89f86167ad | ||
|
dfec1ad6b1 | ||
|
66d3e4a595 | ||
|
19a03babc4 | ||
|
ee24b4f083 | ||
|
937ecc8d2f | ||
|
6078adb8bc | ||
|
39f18b0b70 | ||
|
efb64b7dbb | ||
|
f892b41299 | ||
|
1eb63635b5 | ||
|
688228377b | ||
|
506006f0fa | ||
|
22de001a80 | ||
|
d90cc8bf2f | ||
|
5a8f19589b | ||
|
d61df6363b | ||
|
f062013a7b | ||
|
fea93a5b7a | ||
|
30dc29e17f | ||
|
5387f73b5d | ||
90dd1f63c8 |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,3 +1,3 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: asim
|
||||
github: micro
|
||||
|
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
10
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
## Pull Request template
|
||||
Please, go through these steps before clicking submit on this PR.
|
||||
|
||||
1. Make sure this PR targets the `develop` branch. We follow the git-flow branching model.
|
||||
2. Give a descriptive title to your PR.
|
||||
3. Provide a description of your changes.
|
||||
4. Make sure you have some relevant tests.
|
||||
5. Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes (if applicable).
|
||||
|
||||
**PLEASE REMOVE THIS TEMPLATE BEFORE SUBMITTING**
|
34
.github/workflows/micro-examples.yml
vendored
Normal file
34
.github/workflows/micro-examples.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Build all github.com/micro/examples
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'release-**'
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
name: Build repos
|
||||
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 this code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: 'go-micro'
|
||||
|
||||
- name: Check out code examples
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: 'micro/examples'
|
||||
path: 'examples'
|
||||
|
||||
- name: Build all
|
||||
run: $GITHUB_WORKSPACE/go-micro/.github/workflows/scripts/build-all-examples.sh $GITHUB_SHA
|
||||
working-directory: examples
|
||||
|
34
.github/workflows/micro-main.yml
vendored
Normal file
34
.github/workflows/micro-main.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
name: Build and test micro
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'release-**'
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
name: Build and test micro
|
||||
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 this code
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
path: 'go-micro'
|
||||
|
||||
- name: Check out micro
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: 'micro/micro'
|
||||
path: 'micro'
|
||||
|
||||
- name: Build all
|
||||
run: $GITHUB_WORKSPACE/go-micro/.github/workflows/scripts/build-micro.sh $GITHUB_SHA
|
||||
working-directory: micro
|
||||
|
41
.github/workflows/scripts/build-all-examples.sh
vendored
Executable file
41
.github/workflows/scripts/build-all-examples.sh
vendored
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
# set -x
|
||||
|
||||
function build_binary {
|
||||
echo building $1
|
||||
pushd $1
|
||||
go build -o _main
|
||||
local ret=$?
|
||||
if [ $ret -gt 0 ]; then
|
||||
failed=1
|
||||
failed_arr+=($1)
|
||||
fi
|
||||
popd
|
||||
}
|
||||
|
||||
function is_main {
|
||||
grep "package main" -l -dskip $1/*.go > /dev/null 2>&1
|
||||
}
|
||||
|
||||
|
||||
function check_dir {
|
||||
is_main $1
|
||||
local ret=$?
|
||||
if [ $ret == 0 ]; then
|
||||
build_binary $1 $2
|
||||
fi
|
||||
for filename in $1/*; do
|
||||
if [ -d $filename ]; then
|
||||
check_dir $filename $2
|
||||
fi
|
||||
done
|
||||
}
|
||||
failed_arr=()
|
||||
failed=0
|
||||
go mod edit -replace github.com/micro/go-micro/v2=github.com/micro/go-micro/v2@$1
|
||||
check_dir . $1
|
||||
if [ $failed -gt 0 ]; then
|
||||
echo Some builds failed
|
||||
printf '%s\n' "${failed_arr[@]}"
|
||||
fi
|
||||
exit $failed
|
14
.github/workflows/scripts/build-micro.sh
vendored
Executable file
14
.github/workflows/scripts/build-micro.sh
vendored
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
# set -x
|
||||
|
||||
failed=0
|
||||
go mod edit -replace github.com/micro/go-micro/v2=github.com/micro/go-micro/v2@$1
|
||||
# basic test, build the binary
|
||||
go build
|
||||
failed=$?
|
||||
if [ $failed -gt 0 ]; then
|
||||
exit $failed
|
||||
fi
|
||||
# unit tests
|
||||
IN_TRAVIS_CI=yes go test -v ./...
|
||||
# TODO integration tests
|
40
README.md
40
README.md
@@ -1,23 +1,27 @@
|
||||
# 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 [](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 distributed systems development.
|
||||
|
||||
## Overview
|
||||
|
||||
Go Micro provides the core requirements for distributed systems development including RPC and Event driven communication.
|
||||
The **micro** philosophy is sane defaults with a pluggable architecture. We provide defaults to get you started quickly
|
||||
The **Micro** philosophy is sane defaults with a pluggable architecture. We provide defaults to get you started quickly
|
||||
but everything can be easily swapped out.
|
||||
|
||||
<img src="https://micro.mu/docs/images/go-micro.svg" />
|
||||
|
||||
Plugins are available at [github.com/micro/go-plugins](https://github.com/micro/go-plugins).
|
||||
|
||||
Follow us on [Twitter](https://twitter.com/microhq) or join the [Community](https://micro.mu/slack).
|
||||
|
||||
## Features
|
||||
|
||||
Go Micro abstracts away the details of distributed systems. Here are the main features.
|
||||
|
||||
- **Authentication** - Auth is built in as a first class citizen. Authentication and authorization enable secure
|
||||
zero trust networking by providing every service an identity and certificates. This additionally includes rule
|
||||
based access control.
|
||||
|
||||
- **Dynamic Config** - Load and hot reload dynamic config from anywhere. The config interface provides a way to load application
|
||||
level config from any source such as env vars, file, etcd. You can merge the sources and even define fallbacks.
|
||||
|
||||
- **Data Storage** - A simple data store interface to read, write and delete records. It includes support for memory, file and
|
||||
CockroachDB by default. State and persistence becomes a core requirement beyond prototyping and Micro looks to build that into the framework.
|
||||
|
||||
- **Service Discovery** - Automatic service registration and name resolution. Service discovery is at the core of micro service
|
||||
development. When service A needs to speak to service B it needs the location of that service. The default discovery mechanism is
|
||||
multicast DNS (mdns), a zeroconf system.
|
||||
@@ -30,13 +34,14 @@ across the services and retry a different node if there's a problem.
|
||||
to seamlessly encode and decode Go types for you. Any variety of messages could be encoded and sent from different clients. The client
|
||||
and server handle this by default. This includes protobuf and json by default.
|
||||
|
||||
- **Request/Response** - RPC based request/response with support for bidirectional streaming. We provide an abstraction for synchronous
|
||||
communication. A request made to a service will be automatically resolved, load balanced, dialled and streamed. The default
|
||||
transport is [gRPC](https://grpc.io/).
|
||||
- **gRPC Transport** - gRPC based request/response with support for bidirectional streaming. We provide an abstraction for synchronous communication. A request made to a service will be automatically resolved, load balanced, dialled and streamed.
|
||||
|
||||
- **Async Messaging** - PubSub is built in as a first class citizen for asynchronous communication and event driven architectures.
|
||||
Event notifications are a core pattern in micro service development. The default messaging system is a HTTP event message broker.
|
||||
|
||||
- **Synchronization** - Distributed systems are often built in an eventually consistent manner. Support for distributed locking and
|
||||
leadership are built in as a Sync interface. When using an eventually consistent database or scheduling use the Sync interface.
|
||||
|
||||
- **Pluggable Interfaces** - Go Micro makes use of Go interfaces for each distributed system abstraction. Because of this these interfaces
|
||||
are pluggable and allows Go Micro to be runtime agnostic. You can plugin any underlying technology. Find plugins in
|
||||
[github.com/micro/go-plugins](https://github.com/micro/go-plugins).
|
||||
@@ -47,9 +52,20 @@ To make use of Go Micro
|
||||
|
||||
```golang
|
||||
import "github.com/micro/go-micro/v2"
|
||||
|
||||
// create a new service
|
||||
service := micro.NewService(
|
||||
micro.Name("helloworld"),
|
||||
)
|
||||
|
||||
// initialise flags
|
||||
service.Init()
|
||||
|
||||
// start the service
|
||||
service.Run()
|
||||
```
|
||||
|
||||
See the [docs](https://micro.mu/docs/framework.html) for detailed information on the architecture, installation and use of go-micro.
|
||||
See the [docs](https://dev.m3o.com) for detailed information on the architecture, installation and use of go-micro.
|
||||
|
||||
## License
|
||||
|
||||
|
@@ -1,36 +0,0 @@
|
||||
# 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的微服务开发框架。
|
||||
|
||||
## 概览
|
||||
|
||||
Go Micro提供分布式系统开发的核心库,包含RPC与事件驱动的通信机制。
|
||||
|
||||
**micro**的设计哲学是可插拔的架构理念,她提供可快速构建系统的组件,并且可以根据自身的需求剥离默认实现并自行定制。
|
||||
|
||||
<img src="https://micro.mu/docs/images/go-micro.svg" />
|
||||
|
||||
所有插件可在仓库[github.com/micro/go-plugins](https://github.com/micro/go-plugins)中找到。
|
||||
|
||||
可以订阅我们的[Twitter](https://twitter.com/microhq)或者加入[Slack](http://slack.micro.mu/)论坛。
|
||||
|
||||
## 特性
|
||||
|
||||
Go Micro把分布式系统的各种细节抽象出来。下面是它的主要特性。
|
||||
|
||||
- **服务发现(Service Discovery)** - 自动服务注册与名称解析。服务发现是微服务开发中的核心。当服务A要与服务B协作时,它得知道B在哪里。默认的服务发现系统是Consul,而multicast DNS (mdns,组播)机制作为本地解决方案,或者零依赖的P2P网络中的SWIM协议(gossip)。
|
||||
|
||||
- **负载均衡(Load Balancing)** - 在服务发现之上构建了负载均衡机制。当我们得到一个服务的任意多个的实例节点时,我们要一个机制去决定要路由到哪一个节点。我们使用随机处理过的哈希负载均衡机制来保证对服务请求颁发的均匀分布,并且在发生问题时进行重试。
|
||||
|
||||
- **消息编码(Message Encoding)** - 支持基于内容类型(content-type)动态编码消息。客户端和服务端会一起使用content-type的格式来对Go进行无缝编/解码。各种各样的消息被编码会发送到不同的客户端,客户端服服务端默认会处理这些消息。content-type默认包含proto-rpc和json-rpc。
|
||||
|
||||
- **Request/Response** - RPC通信基于支持双向流的请求/响应方式,我们提供有抽象的同步通信机制。请求发送到服务时,会自动解析、负载均衡、拨号、转成字节流。默认的传输协议是http/1.1,而tls下使用http2协议。
|
||||
|
||||
- **异步消息(Async Messaging)** - 发布订阅(PubSub)头等功能内置在异步通信与事件驱动架构中。事件通知在微服务开发中处于核心位置。默认的消息传送使用点到点http/1.1,激活tls时则使用http2。
|
||||
|
||||
- **可插拔接口(Pluggable Interfaces)** - Go Micro为每个分布式系统抽象出接口。因此,Go Micro的接口都是可插拔的,允许其在运行时不可知的情况下仍可支持。所以只要实现接口,可以在内部使用任何的技术。更多插件请参考:[github.com/micro/go-plugins](https://github.com/micro/go-plugins)。
|
||||
|
||||
## 快速上手
|
||||
|
||||
更多关于架构、安装的资料可以查看[文档](https://micro.mu/docs/cn/)。
|
||||
|
@@ -397,13 +397,29 @@ func requestPayload(r *http.Request) ([]byte, error) {
|
||||
return out, nil
|
||||
}
|
||||
}
|
||||
var jsonbody map[string]interface{}
|
||||
if json.Valid(bodybuf) {
|
||||
if err = json.Unmarshal(bodybuf, &jsonbody); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
dstmap := make(map[string]interface{})
|
||||
ps := strings.Split(bodydst, ".")
|
||||
if len(ps) == 1 {
|
||||
dstmap[ps[0]] = bodybuf
|
||||
if jsonbody != nil {
|
||||
dstmap[ps[0]] = jsonbody
|
||||
} else {
|
||||
// old unexpected behaviour
|
||||
dstmap[ps[0]] = bodybuf
|
||||
}
|
||||
} else {
|
||||
em := make(map[string]interface{})
|
||||
em[ps[len(ps)-1]] = bodybuf
|
||||
if jsonbody != nil {
|
||||
em[ps[len(ps)-1]] = jsonbody
|
||||
} else {
|
||||
// old unexpected behaviour
|
||||
em[ps[len(ps)-1]] = bodybuf
|
||||
}
|
||||
for i := len(ps) - 2; i > 0; i-- {
|
||||
nm := make(map[string]interface{})
|
||||
nm[ps[i]] = em
|
||||
|
@@ -185,7 +185,11 @@ func writeLoop(rw io.ReadWriter, stream client.Stream) {
|
||||
if err != nil {
|
||||
if wserr, ok := err.(wsutil.ClosedError); ok {
|
||||
switch wserr.Code {
|
||||
case ws.StatusGoingAway:
|
||||
// this happens when user leave the page
|
||||
return
|
||||
case ws.StatusNormalClosure, ws.StatusNoStatusRcvd:
|
||||
// this happens when user close ws connection, or we don't get any status
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@@ -2,8 +2,6 @@ package resolver
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
)
|
||||
|
||||
// NewOptions returns new initialised options
|
||||
@@ -14,7 +12,7 @@ func NewOptions(opts ...Option) Options {
|
||||
}
|
||||
|
||||
if options.Namespace == nil {
|
||||
options.Namespace = StaticNamespace(auth.DefaultNamespace)
|
||||
options.Namespace = StaticNamespace("go.micro")
|
||||
}
|
||||
|
||||
return options
|
||||
|
@@ -3,7 +3,6 @@ package vpath
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -28,8 +27,6 @@ func (r *Resolver) Resolve(req *http.Request) (*resolver.Endpoint, error) {
|
||||
return nil, errors.New("unknown name")
|
||||
}
|
||||
|
||||
fmt.Println(req.URL.Path)
|
||||
|
||||
parts := strings.Split(req.URL.Path[1:], "/")
|
||||
if len(parts) == 1 {
|
||||
return &resolver.Endpoint{
|
||||
|
@@ -188,7 +188,7 @@ func (r *registryRouter) store(services []*registry.Service) {
|
||||
for _, p := range ep.Endpoint.Path {
|
||||
var pcreok bool
|
||||
|
||||
if p[0] == '^' && p[len(p)-1] != '$' {
|
||||
if p[0] == '^' && p[len(p)-1] == '$' {
|
||||
pcrereg, err := regexp.CompilePOSIX(p)
|
||||
if err == nil {
|
||||
cep.pcreregs = append(cep.pcreregs, pcrereg)
|
||||
|
34
api/router/registry/registry_test.go
Normal file
34
api/router/registry/registry_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package registry
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestStoreRegex(t *testing.T) {
|
||||
router := newRouter()
|
||||
router.store([]*registry.Service{
|
||||
{
|
||||
Name: "Foobar",
|
||||
Version: "latest",
|
||||
Endpoints: []*registry.Endpoint{
|
||||
{
|
||||
Name: "foo",
|
||||
Metadata: map[string]string{
|
||||
"endpoint": "FooEndpoint",
|
||||
"description": "Some description",
|
||||
"method": "POST",
|
||||
"path": "^/foo/$",
|
||||
"handler": "rpc",
|
||||
},
|
||||
},
|
||||
},
|
||||
Metadata: map[string]string{},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
assert.Len(t, router.ceps["Foobar.foo"].pcreregs, 1)
|
||||
}
|
@@ -1,4 +1,4 @@
|
||||
// Package certmagic is the ACME provider from github.com/mholt/certmagic
|
||||
// Package certmagic is the ACME provider from github.com/caddyserver/certmagic
|
||||
package certmagic
|
||||
|
||||
import (
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/mholt/certmagic"
|
||||
"github.com/caddyserver/certmagic"
|
||||
"github.com/micro/go-micro/v2/api/server/acme"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
@@ -18,10 +18,10 @@ type certmagicProvider struct {
|
||||
|
||||
// TODO: set self-contained options
|
||||
func (c *certmagicProvider) setup() {
|
||||
certmagic.Default.CA = c.opts.CA
|
||||
certmagic.DefaultACME.CA = c.opts.CA
|
||||
if c.opts.ChallengeProvider != nil {
|
||||
// Enabling DNS Challenge disables the other challenges
|
||||
certmagic.Default.DNSProvider = c.opts.ChallengeProvider
|
||||
certmagic.DefaultACME.DNSProvider = c.opts.ChallengeProvider
|
||||
}
|
||||
if c.opts.OnDemand {
|
||||
certmagic.Default.OnDemand = new(certmagic.OnDemandConfig)
|
||||
@@ -32,9 +32,10 @@ func (c *certmagicProvider) setup() {
|
||||
}
|
||||
// If multiple instances of the provider are running, inject some
|
||||
// randomness so they don't collide
|
||||
// RenewalWindowRatio [0.33 - 0.50)
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
randomDuration := (7 * 24 * time.Hour) + (time.Duration(rand.Intn(504)) * time.Hour)
|
||||
certmagic.Default.RenewDurationBefore = randomDuration
|
||||
randomRatio := float64(rand.Intn(17)+33) * 0.01
|
||||
certmagic.Default.RenewalWindowRatio = randomRatio
|
||||
}
|
||||
|
||||
func (c *certmagicProvider) Listen(hosts ...string) (net.Listener, error) {
|
||||
|
@@ -9,7 +9,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/mholt/certmagic"
|
||||
"github.com/caddyserver/certmagic"
|
||||
"github.com/micro/go-micro/v2/store"
|
||||
"github.com/micro/go-micro/v2/sync"
|
||||
)
|
||||
|
103
auth/auth.go
103
auth/auth.go
@@ -7,20 +7,23 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// BearerScheme used for Authorization header
|
||||
BearerScheme = "Bearer "
|
||||
// ScopePublic is the scope applied to a rule to allow access to the public
|
||||
ScopePublic = ""
|
||||
// ScopeAccount is the scope applied to a rule to limit to users with any valid account
|
||||
ScopeAccount = "*"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNotFound is returned when a resouce cannot be found
|
||||
ErrNotFound = errors.New("not found")
|
||||
// ErrEncodingToken is returned when the service encounters an error during encoding
|
||||
ErrEncodingToken = errors.New("error encoding the token")
|
||||
// ErrInvalidToken is returned when the token provided is not valid
|
||||
// ErrInvalidToken is when the token provided is not valid
|
||||
ErrInvalidToken = errors.New("invalid token provided")
|
||||
// ErrInvalidRole is returned when the role provided was invalid
|
||||
ErrInvalidRole = errors.New("invalid role")
|
||||
// ErrForbidden is returned when a user does not have the necessary roles to access a resource
|
||||
// ErrForbidden is when a user does not have the necessary scope to access a resource
|
||||
ErrForbidden = errors.New("resource forbidden")
|
||||
)
|
||||
|
||||
// Auth providers authentication and authorization
|
||||
// Auth provides authentication and authorization
|
||||
type Auth interface {
|
||||
// Init the auth
|
||||
Init(opts ...Option)
|
||||
@@ -28,46 +31,34 @@ type Auth interface {
|
||||
Options() Options
|
||||
// Generate a new account
|
||||
Generate(id string, opts ...GenerateOption) (*Account, error)
|
||||
// Grant access to a resource
|
||||
Grant(role string, res *Resource) error
|
||||
// Revoke access to a resource
|
||||
Revoke(role string, res *Resource) error
|
||||
// Verify an account has access to a resource
|
||||
Verify(acc *Account, res *Resource) error
|
||||
// Verify an account has access to a resource using the rules
|
||||
Verify(acc *Account, res *Resource, opts ...VerifyOption) error
|
||||
// Inspect a token
|
||||
Inspect(token string) (*Account, error)
|
||||
// Token generated using refresh token
|
||||
// Token generated using refresh token or credentials
|
||||
Token(opts ...TokenOption) (*Token, error)
|
||||
// Grant access to a resource
|
||||
Grant(rule *Rule) error
|
||||
// Revoke access to a resource
|
||||
Revoke(rule *Rule) error
|
||||
// Rules returns all the rules used to verify requests
|
||||
Rules(...RulesOption) ([]*Rule, error)
|
||||
// String returns the name of the implementation
|
||||
String() string
|
||||
}
|
||||
|
||||
// Resource is an entity such as a user or
|
||||
type Resource struct {
|
||||
// Name of the resource
|
||||
Name string `json:"name"`
|
||||
// Type of resource, e.g.
|
||||
Type string `json:"type"`
|
||||
// Endpoint resource e.g NotesService.Create
|
||||
Endpoint string `json:"endpoint"`
|
||||
// Namespace the resource belongs to
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
// Account provided by an auth provider
|
||||
type Account struct {
|
||||
// ID of the account e.g. email
|
||||
ID string `json:"id"`
|
||||
// Type of the account, e.g. service
|
||||
Type string `json:"type"`
|
||||
// Provider who issued the account
|
||||
Provider string `json:"provider"`
|
||||
// Roles associated with the Account
|
||||
Roles []string `json:"roles"`
|
||||
// Issuer of the account
|
||||
Issuer string `json:"issuer"`
|
||||
// Any other associated metadata
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
// Namespace the account belongs to
|
||||
Namespace string `json:"namespace"`
|
||||
// Scopes the account has access to
|
||||
Scopes []string `json:"scopes"`
|
||||
// Secret for the account, e.g. the password
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
@@ -84,15 +75,47 @@ type Token struct {
|
||||
Expiry time.Time `json:"expiry"`
|
||||
}
|
||||
|
||||
// Expired returns a boolean indicating if the token needs to be refreshed
|
||||
func (t *Token) Expired() bool {
|
||||
return t.Expiry.Unix() < time.Now().Unix()
|
||||
}
|
||||
|
||||
// Resource is an entity such as a user or
|
||||
type Resource struct {
|
||||
// Name of the resource, e.g. go.micro.service.notes
|
||||
Name string `json:"name"`
|
||||
// Type of resource, e.g. service
|
||||
Type string `json:"type"`
|
||||
// Endpoint resource e.g NotesService.Create
|
||||
Endpoint string `json:"endpoint"`
|
||||
}
|
||||
|
||||
// Access defines the type of access a rule grants
|
||||
type Access int
|
||||
|
||||
const (
|
||||
// DefaultNamespace used for auth
|
||||
DefaultNamespace = "go.micro"
|
||||
// TokenCookieName is the name of the cookie which stores the auth token
|
||||
TokenCookieName = "micro-token"
|
||||
// BearerScheme used for Authorization header
|
||||
BearerScheme = "Bearer "
|
||||
// AccessGranted to a resource
|
||||
AccessGranted Access = iota
|
||||
// AccessDenied to a resource
|
||||
AccessDenied
|
||||
)
|
||||
|
||||
// Rule is used to verify access to a resource
|
||||
type Rule struct {
|
||||
// ID of the rule, e.g. "public"
|
||||
ID string
|
||||
// Scope the rule requires, a blank scope indicates open to the public and * indicates the rule
|
||||
// applies to any valid account
|
||||
Scope string
|
||||
// Resource the rule applies to
|
||||
Resource *Resource
|
||||
// Access determines if the rule grants or denies access to the resource
|
||||
Access Access
|
||||
// Priority the rule should take when verifying a request, the higher the value the sooner the
|
||||
// rule will be applied
|
||||
Priority int32
|
||||
}
|
||||
|
||||
type accountKey struct{}
|
||||
|
||||
// AccountFromContext gets the account from the context, which
|
||||
|
@@ -49,35 +49,37 @@ func (n *noop) Generate(id string, opts ...GenerateOption) (*Account, error) {
|
||||
options := NewGenerateOptions(opts...)
|
||||
|
||||
return &Account{
|
||||
ID: id,
|
||||
Roles: options.Roles,
|
||||
Secret: options.Secret,
|
||||
Metadata: options.Metadata,
|
||||
Namespace: DefaultNamespace,
|
||||
ID: id,
|
||||
Secret: options.Secret,
|
||||
Metadata: options.Metadata,
|
||||
Scopes: options.Scopes,
|
||||
Issuer: n.Options().Namespace,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Grant access to a resource
|
||||
func (n *noop) Grant(role string, res *Resource) error {
|
||||
func (n *noop) Grant(rule *Rule) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Revoke access to a resource
|
||||
func (n *noop) Revoke(role string, res *Resource) error {
|
||||
func (n *noop) Revoke(rule *Rule) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rules used to verify requests
|
||||
func (n *noop) Rules(opts ...RulesOption) ([]*Rule, error) {
|
||||
return []*Rule{}, nil
|
||||
}
|
||||
|
||||
// Verify an account has access to a resource
|
||||
func (n *noop) Verify(acc *Account, res *Resource) error {
|
||||
func (n *noop) Verify(acc *Account, res *Resource, opts ...VerifyOption) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Inspect a token
|
||||
func (n *noop) Inspect(token string) (*Account, error) {
|
||||
return &Account{
|
||||
ID: uuid.New().String(),
|
||||
Namespace: DefaultNamespace,
|
||||
}, nil
|
||||
return &Account{ID: uuid.New().String(), Issuer: n.Options().Namespace}, nil
|
||||
}
|
||||
|
||||
// Token generation using an account id and secret
|
||||
|
115
auth/jwt/jwt.go
115
auth/jwt/jwt.go
@@ -2,8 +2,10 @@ package jwt
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
"github.com/micro/go-micro/v2/auth/rules"
|
||||
"github.com/micro/go-micro/v2/auth/token"
|
||||
jwtToken "github.com/micro/go-micro/v2/auth/token/jwt"
|
||||
)
|
||||
@@ -15,15 +17,10 @@ func NewAuth(opts ...auth.Option) auth.Auth {
|
||||
return j
|
||||
}
|
||||
|
||||
type rule struct {
|
||||
role string
|
||||
resource *auth.Resource
|
||||
}
|
||||
|
||||
type jwt struct {
|
||||
options auth.Options
|
||||
jwt token.Provider
|
||||
rules []*rule
|
||||
rules []*auth.Rule
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
@@ -40,10 +37,6 @@ func (j *jwt) Init(opts ...auth.Option) {
|
||||
o(&j.options)
|
||||
}
|
||||
|
||||
if len(j.options.Namespace) == 0 {
|
||||
j.options.Namespace = auth.DefaultNamespace
|
||||
}
|
||||
|
||||
j.jwt = jwtToken.NewTokenProvider(
|
||||
token.WithPrivateKey(j.options.PrivateKey),
|
||||
token.WithPublicKey(j.options.PublicKey),
|
||||
@@ -59,12 +52,11 @@ func (j *jwt) Options() auth.Options {
|
||||
func (j *jwt) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) {
|
||||
options := auth.NewGenerateOptions(opts...)
|
||||
account := &auth.Account{
|
||||
ID: id,
|
||||
Type: options.Type,
|
||||
Roles: options.Roles,
|
||||
Provider: options.Provider,
|
||||
Metadata: options.Metadata,
|
||||
Namespace: options.Namespace,
|
||||
ID: id,
|
||||
Type: options.Type,
|
||||
Scopes: options.Scopes,
|
||||
Metadata: options.Metadata,
|
||||
Issuer: j.Options().Namespace,
|
||||
}
|
||||
|
||||
// generate a JWT secret which can be provided to the Token() method
|
||||
@@ -79,84 +71,44 @@ func (j *jwt) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, e
|
||||
return account, nil
|
||||
}
|
||||
|
||||
func (j *jwt) Grant(role string, res *auth.Resource) error {
|
||||
func (j *jwt) Grant(rule *auth.Rule) error {
|
||||
j.Lock()
|
||||
defer j.Unlock()
|
||||
j.rules = append(j.rules, &rule{role, res})
|
||||
j.rules = append(j.rules, rule)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *jwt) Revoke(role string, res *auth.Resource) error {
|
||||
func (j *jwt) Revoke(rule *auth.Rule) error {
|
||||
j.Lock()
|
||||
defer j.Unlock()
|
||||
|
||||
rules := make([]*rule, 0, len(j.rules))
|
||||
|
||||
var ruleFound bool
|
||||
for _, r := range rules {
|
||||
if r.role == role && r.resource == res {
|
||||
ruleFound = true
|
||||
} else {
|
||||
rules := []*auth.Rule{}
|
||||
for _, r := range j.rules {
|
||||
if r.ID != rule.ID {
|
||||
rules = append(rules, r)
|
||||
}
|
||||
}
|
||||
|
||||
if !ruleFound {
|
||||
return auth.ErrNotFound
|
||||
}
|
||||
|
||||
j.rules = rules
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *jwt) Verify(acc *auth.Account, res *auth.Resource) error {
|
||||
func (j *jwt) Verify(acc *auth.Account, res *auth.Resource, opts ...auth.VerifyOption) error {
|
||||
j.Lock()
|
||||
if len(res.Namespace) == 0 {
|
||||
res.Namespace = j.options.Namespace
|
||||
}
|
||||
rules := j.rules
|
||||
j.Unlock()
|
||||
defer j.Unlock()
|
||||
|
||||
for _, rule := range rules {
|
||||
// validate the rule applies to the requested resource
|
||||
if rule.resource.Namespace != "*" && rule.resource.Namespace != res.Namespace {
|
||||
continue
|
||||
}
|
||||
if rule.resource.Type != "*" && rule.resource.Type != res.Type {
|
||||
continue
|
||||
}
|
||||
if rule.resource.Name != "*" && rule.resource.Name != res.Name {
|
||||
continue
|
||||
}
|
||||
if rule.resource.Endpoint != "*" && rule.resource.Endpoint != res.Endpoint {
|
||||
continue
|
||||
}
|
||||
|
||||
// a blank role indicates anyone can access the resource, even without an account
|
||||
if rule.role == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// all furter checks require an account
|
||||
if acc == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// this rule allows any account access, allow the request
|
||||
if rule.role == "*" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if the account has the necessary role, allow the request
|
||||
for _, r := range acc.Roles {
|
||||
if r == rule.role {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
var options auth.VerifyOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
// no rules matched, forbid the request
|
||||
return auth.ErrForbidden
|
||||
return rules.Verify(j.rules, acc, res)
|
||||
}
|
||||
|
||||
func (j *jwt) Rules(opts ...auth.RulesOption) ([]*auth.Rule, error) {
|
||||
j.Lock()
|
||||
defer j.Unlock()
|
||||
return j.rules, nil
|
||||
}
|
||||
|
||||
func (j *jwt) Inspect(token string) (*auth.Account, error) {
|
||||
@@ -176,15 +128,20 @@ func (j *jwt) Token(opts ...auth.TokenOption) (*auth.Token, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tok, err := j.jwt.Generate(account, token.WithExpiry(options.Expiry))
|
||||
access, err := j.jwt.Generate(account, token.WithExpiry(options.Expiry))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
refresh, err := j.jwt.Generate(account, token.WithExpiry(options.Expiry+time.Hour))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &auth.Token{
|
||||
Created: tok.Created,
|
||||
Expiry: tok.Expiry,
|
||||
AccessToken: tok.Token,
|
||||
RefreshToken: tok.Token,
|
||||
Created: access.Created,
|
||||
Expiry: access.Expiry,
|
||||
AccessToken: access.Token,
|
||||
RefreshToken: refresh.Token,
|
||||
}, nil
|
||||
}
|
||||
|
@@ -1,9 +1,11 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth/provider"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/store"
|
||||
)
|
||||
|
||||
@@ -12,9 +14,8 @@ func NewOptions(opts ...Option) Options {
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
if len(options.Namespace) == 0 {
|
||||
options.Namespace = DefaultNamespace
|
||||
if options.Client == nil {
|
||||
options.Client = client.DefaultClient
|
||||
}
|
||||
|
||||
return options
|
||||
@@ -39,10 +40,21 @@ type Options struct {
|
||||
LoginURL string
|
||||
// Store to back auth
|
||||
Store store.Store
|
||||
// Client to use for RPC
|
||||
Client client.Client
|
||||
// Addrs sets the addresses of auth
|
||||
Addrs []string
|
||||
}
|
||||
|
||||
type Option func(o *Options)
|
||||
|
||||
// Addrs is the auth addresses to use
|
||||
func Addrs(addrs ...string) Option {
|
||||
return func(o *Options) {
|
||||
o.Addrs = addrs
|
||||
}
|
||||
}
|
||||
|
||||
// Namespace the service belongs to
|
||||
func Namespace(n string) Option {
|
||||
return func(o *Options) {
|
||||
@@ -100,13 +112,18 @@ func LoginURL(url string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithClient sets the client to use when making requests
|
||||
func WithClient(c client.Client) Option {
|
||||
return func(o *Options) {
|
||||
o.Client = c
|
||||
}
|
||||
}
|
||||
|
||||
type GenerateOptions struct {
|
||||
// Metadata associated with the account
|
||||
Metadata map[string]string
|
||||
// Roles/scopes associated with the account
|
||||
Roles []string
|
||||
// Namespace the account belongs too
|
||||
Namespace string
|
||||
// Scopes the account has access too
|
||||
Scopes []string
|
||||
// Provider of the account, e.g. oauth
|
||||
Provider string
|
||||
// Type of the account, e.g. user
|
||||
@@ -138,20 +155,6 @@ func WithMetadata(md map[string]string) GenerateOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithRoles for the generated account
|
||||
func WithRoles(rs ...string) GenerateOption {
|
||||
return func(o *GenerateOptions) {
|
||||
o.Roles = rs
|
||||
}
|
||||
}
|
||||
|
||||
// WithNamespace for the generated account
|
||||
func WithNamespace(n string) GenerateOption {
|
||||
return func(o *GenerateOptions) {
|
||||
o.Namespace = n
|
||||
}
|
||||
}
|
||||
|
||||
// WithProvider for the generated account
|
||||
func WithProvider(p string) GenerateOption {
|
||||
return func(o *GenerateOptions) {
|
||||
@@ -159,6 +162,13 @@ func WithProvider(p string) GenerateOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithScopes for the generated account
|
||||
func WithScopes(s ...string) GenerateOption {
|
||||
return func(o *GenerateOptions) {
|
||||
o.Scopes = s
|
||||
}
|
||||
}
|
||||
|
||||
// NewGenerateOptions from a slice of options
|
||||
func NewGenerateOptions(opts ...GenerateOption) GenerateOptions {
|
||||
var options GenerateOptions
|
||||
@@ -215,3 +225,27 @@ func NewTokenOptions(opts ...TokenOption) TokenOptions {
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
type VerifyOptions struct {
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
type VerifyOption func(o *VerifyOptions)
|
||||
|
||||
func VerifyContext(ctx context.Context) VerifyOption {
|
||||
return func(o *VerifyOptions) {
|
||||
o.Context = ctx
|
||||
}
|
||||
}
|
||||
|
||||
type RulesOptions struct {
|
||||
Context context.Context
|
||||
}
|
||||
|
||||
type RulesOption func(o *RulesOptions)
|
||||
|
||||
func RulesContext(ctx context.Context) RulesOption {
|
||||
return func(o *RulesOptions) {
|
||||
o.Context = ctx
|
||||
}
|
||||
}
|
||||
|
93
auth/rules/rules.go
Normal file
93
auth/rules/rules.go
Normal file
@@ -0,0 +1,93 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
)
|
||||
|
||||
// Verify an account has access to a resource using the rules provided. If the account does not have
|
||||
// access an error will be returned. If there are no rules provided which match the resource, an error
|
||||
// will be returned
|
||||
func Verify(rules []*auth.Rule, acc *auth.Account, res *auth.Resource) error {
|
||||
// the rule is only to be applied if the type matches the resource or is catch-all (*)
|
||||
validTypes := []string{"*", res.Type}
|
||||
|
||||
// the rule is only to be applied if the name matches the resource or is catch-all (*)
|
||||
validNames := []string{"*", res.Name}
|
||||
|
||||
// rules can have wildcard excludes on endpoints since this can also be a path for web services,
|
||||
// e.g. /foo/* would include /foo/bar. We also want to check for wildcards and the exact endpoint
|
||||
validEndpoints := []string{"*", res.Endpoint}
|
||||
if comps := strings.Split(res.Endpoint, "/"); len(comps) > 1 {
|
||||
for i := 1; i < len(comps)+1; i++ {
|
||||
wildcard := fmt.Sprintf("%v/*", strings.Join(comps[0:i], "/"))
|
||||
validEndpoints = append(validEndpoints, wildcard)
|
||||
}
|
||||
}
|
||||
|
||||
// filter the rules to the ones which match the criteria above
|
||||
filteredRules := make([]*auth.Rule, 0)
|
||||
for _, rule := range rules {
|
||||
if !include(validTypes, rule.Resource.Type) {
|
||||
continue
|
||||
}
|
||||
if !include(validNames, rule.Resource.Name) {
|
||||
continue
|
||||
}
|
||||
if !include(validEndpoints, rule.Resource.Endpoint) {
|
||||
continue
|
||||
}
|
||||
filteredRules = append(filteredRules, rule)
|
||||
}
|
||||
|
||||
// sort the filtered rules by priority, highest to lowest
|
||||
sort.SliceStable(filteredRules, func(i, j int) bool {
|
||||
return filteredRules[i].Priority > filteredRules[j].Priority
|
||||
})
|
||||
|
||||
// loop through the rules and check for a rule which applies to this account
|
||||
for _, rule := range filteredRules {
|
||||
// a blank scope indicates the rule applies to everyone, even nil accounts
|
||||
if rule.Scope == auth.ScopePublic && rule.Access == auth.AccessDenied {
|
||||
return auth.ErrForbidden
|
||||
} else if rule.Scope == auth.ScopePublic && rule.Access == auth.AccessGranted {
|
||||
return nil
|
||||
}
|
||||
|
||||
// all further checks require an account
|
||||
if acc == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// this rule applies to any account
|
||||
if rule.Scope == auth.ScopeAccount && rule.Access == auth.AccessDenied {
|
||||
return auth.ErrForbidden
|
||||
} else if rule.Scope == auth.ScopeAccount && rule.Access == auth.AccessGranted {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if the account has the necessary scope
|
||||
if include(acc.Scopes, rule.Scope) && rule.Access == auth.AccessDenied {
|
||||
return auth.ErrForbidden
|
||||
} else if include(acc.Scopes, rule.Scope) && rule.Access == auth.AccessGranted {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// if no rules matched then return forbidden
|
||||
return auth.ErrForbidden
|
||||
}
|
||||
|
||||
// include is a helper function which checks to see if the slice contains the value. includes is
|
||||
// not case sensitive.
|
||||
func include(slice []string, val string) bool {
|
||||
for _, s := range slice {
|
||||
if strings.ToLower(s) == strings.ToLower(val) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
290
auth/rules/rules_test.go
Normal file
290
auth/rules/rules_test.go
Normal file
@@ -0,0 +1,290 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
)
|
||||
|
||||
func TestVerify(t *testing.T) {
|
||||
srvResource := &auth.Resource{
|
||||
Type: "service",
|
||||
Name: "go.micro.service.foo",
|
||||
Endpoint: "Foo.Bar",
|
||||
}
|
||||
|
||||
webResource := &auth.Resource{
|
||||
Type: "service",
|
||||
Name: "go.micro.web.foo",
|
||||
Endpoint: "/foo/bar",
|
||||
}
|
||||
|
||||
catchallResource := &auth.Resource{
|
||||
Type: "*",
|
||||
Name: "*",
|
||||
Endpoint: "*",
|
||||
}
|
||||
|
||||
tt := []struct {
|
||||
Name string
|
||||
Rules []*auth.Rule
|
||||
Account *auth.Account
|
||||
Resource *auth.Resource
|
||||
Error error
|
||||
}{
|
||||
{
|
||||
Name: "NoRules",
|
||||
Rules: []*auth.Rule{},
|
||||
Account: nil,
|
||||
Resource: srvResource,
|
||||
Error: auth.ErrForbidden,
|
||||
},
|
||||
{
|
||||
Name: "CatchallPublicAccount",
|
||||
Account: &auth.Account{},
|
||||
Resource: srvResource,
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "",
|
||||
Resource: catchallResource,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "CatchallPublicNoAccount",
|
||||
Resource: srvResource,
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "",
|
||||
Resource: catchallResource,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "CatchallPrivateAccount",
|
||||
Account: &auth.Account{},
|
||||
Resource: srvResource,
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: catchallResource,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "CatchallPrivateNoAccount",
|
||||
Resource: srvResource,
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: catchallResource,
|
||||
},
|
||||
},
|
||||
Error: auth.ErrForbidden,
|
||||
},
|
||||
{
|
||||
Name: "CatchallServiceRuleMatch",
|
||||
Resource: srvResource,
|
||||
Account: &auth.Account{},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: &auth.Resource{
|
||||
Type: srvResource.Type,
|
||||
Name: srvResource.Name,
|
||||
Endpoint: "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "CatchallServiceRuleNoMatch",
|
||||
Resource: srvResource,
|
||||
Account: &auth.Account{},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: &auth.Resource{
|
||||
Type: srvResource.Type,
|
||||
Name: "wrongname",
|
||||
Endpoint: "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Error: auth.ErrForbidden,
|
||||
},
|
||||
{
|
||||
Name: "ExactRuleValidScope",
|
||||
Resource: srvResource,
|
||||
Account: &auth.Account{
|
||||
Scopes: []string{"neededscope"},
|
||||
},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "neededscope",
|
||||
Resource: srvResource,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ExactRuleInvalidScope",
|
||||
Resource: srvResource,
|
||||
Account: &auth.Account{
|
||||
Scopes: []string{"neededscope"},
|
||||
},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "invalidscope",
|
||||
Resource: srvResource,
|
||||
},
|
||||
},
|
||||
Error: auth.ErrForbidden,
|
||||
},
|
||||
{
|
||||
Name: "CatchallDenyWithAccount",
|
||||
Resource: srvResource,
|
||||
Account: &auth.Account{},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: catchallResource,
|
||||
Access: auth.AccessDenied,
|
||||
},
|
||||
},
|
||||
Error: auth.ErrForbidden,
|
||||
},
|
||||
{
|
||||
Name: "CatchallDenyWithNoAccount",
|
||||
Resource: srvResource,
|
||||
Account: &auth.Account{},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: catchallResource,
|
||||
Access: auth.AccessDenied,
|
||||
},
|
||||
},
|
||||
Error: auth.ErrForbidden,
|
||||
},
|
||||
{
|
||||
Name: "RulePriorityGrantFirst",
|
||||
Resource: srvResource,
|
||||
Account: &auth.Account{},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: catchallResource,
|
||||
Access: auth.AccessGranted,
|
||||
Priority: 1,
|
||||
},
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: catchallResource,
|
||||
Access: auth.AccessDenied,
|
||||
Priority: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "RulePriorityDenyFirst",
|
||||
Resource: srvResource,
|
||||
Account: &auth.Account{},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: catchallResource,
|
||||
Access: auth.AccessGranted,
|
||||
Priority: 0,
|
||||
},
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: catchallResource,
|
||||
Access: auth.AccessDenied,
|
||||
Priority: 1,
|
||||
},
|
||||
},
|
||||
Error: auth.ErrForbidden,
|
||||
},
|
||||
{
|
||||
Name: "WebExactEndpointValid",
|
||||
Resource: webResource,
|
||||
Account: &auth.Account{},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: webResource,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "WebExactEndpointInalid",
|
||||
Resource: webResource,
|
||||
Account: &auth.Account{},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: &auth.Resource{
|
||||
Type: webResource.Type,
|
||||
Name: webResource.Name,
|
||||
Endpoint: "invalidendpoint",
|
||||
},
|
||||
},
|
||||
},
|
||||
Error: auth.ErrForbidden,
|
||||
},
|
||||
{
|
||||
Name: "WebWildcardEndpoint",
|
||||
Resource: webResource,
|
||||
Account: &auth.Account{},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: &auth.Resource{
|
||||
Type: webResource.Type,
|
||||
Name: webResource.Name,
|
||||
Endpoint: "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "WebWildcardPathEndpointValid",
|
||||
Resource: webResource,
|
||||
Account: &auth.Account{},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: &auth.Resource{
|
||||
Type: webResource.Type,
|
||||
Name: webResource.Name,
|
||||
Endpoint: "/foo/*",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "WebWildcardPathEndpointInvalid",
|
||||
Resource: webResource,
|
||||
Account: &auth.Account{},
|
||||
Rules: []*auth.Rule{
|
||||
&auth.Rule{
|
||||
Scope: "*",
|
||||
Resource: &auth.Resource{
|
||||
Type: webResource.Type,
|
||||
Name: webResource.Name,
|
||||
Endpoint: "/bar/*",
|
||||
},
|
||||
},
|
||||
},
|
||||
Error: auth.ErrForbidden,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
if err := Verify(tc.Rules, tc.Account, tc.Resource); err != tc.Error {
|
||||
t.Errorf("Expected %v but got %v", tc.Error, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@@ -188,10 +188,9 @@ func (m *Token) GetExpiry() int64 {
|
||||
type Account struct {
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Roles []string `protobuf:"bytes,3,rep,name=roles,proto3" json:"roles,omitempty"`
|
||||
Metadata map[string]string `protobuf:"bytes,4,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Namespace string `protobuf:"bytes,5,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
||||
Provider string `protobuf:"bytes,6,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
Scopes []string `protobuf:"bytes,5,rep,name=scopes,proto3" json:"scopes,omitempty"`
|
||||
Issuer string `protobuf:"bytes,6,opt,name=issuer,proto3" json:"issuer,omitempty"`
|
||||
Secret string `protobuf:"bytes,7,opt,name=secret,proto3" json:"secret,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
@@ -237,13 +236,6 @@ func (m *Account) GetType() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Account) GetRoles() []string {
|
||||
if m != nil {
|
||||
return m.Roles
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Account) GetMetadata() map[string]string {
|
||||
if m != nil {
|
||||
return m.Metadata
|
||||
@@ -251,16 +243,16 @@ func (m *Account) GetMetadata() map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Account) GetNamespace() string {
|
||||
func (m *Account) GetScopes() []string {
|
||||
if m != nil {
|
||||
return m.Namespace
|
||||
return m.Scopes
|
||||
}
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Account) GetProvider() string {
|
||||
func (m *Account) GetIssuer() string {
|
||||
if m != nil {
|
||||
return m.Provider
|
||||
return m.Issuer
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -276,7 +268,6 @@ type Resource struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Endpoint string `protobuf:"bytes,3,opt,name=endpoint,proto3" json:"endpoint,omitempty"`
|
||||
Namespace string `protobuf:"bytes,4,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
@@ -328,18 +319,10 @@ func (m *Resource) GetEndpoint() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Resource) GetNamespace() string {
|
||||
if m != nil {
|
||||
return m.Namespace
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type GenerateRequest struct {
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Roles []string `protobuf:"bytes,2,rep,name=roles,proto3" json:"roles,omitempty"`
|
||||
Metadata map[string]string `protobuf:"bytes,3,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
Namespace string `protobuf:"bytes,4,opt,name=namespace,proto3" json:"namespace,omitempty"`
|
||||
Scopes []string `protobuf:"bytes,4,rep,name=scopes,proto3" json:"scopes,omitempty"`
|
||||
Secret string `protobuf:"bytes,5,opt,name=secret,proto3" json:"secret,omitempty"`
|
||||
Type string `protobuf:"bytes,6,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Provider string `protobuf:"bytes,7,opt,name=provider,proto3" json:"provider,omitempty"`
|
||||
@@ -380,13 +363,6 @@ func (m *GenerateRequest) GetId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *GenerateRequest) GetRoles() []string {
|
||||
if m != nil {
|
||||
return m.Roles
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *GenerateRequest) GetMetadata() map[string]string {
|
||||
if m != nil {
|
||||
return m.Metadata
|
||||
@@ -394,11 +370,11 @@ func (m *GenerateRequest) GetMetadata() map[string]string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *GenerateRequest) GetNamespace() string {
|
||||
func (m *GenerateRequest) GetScopes() []string {
|
||||
if m != nil {
|
||||
return m.Namespace
|
||||
return m.Scopes
|
||||
}
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *GenerateRequest) GetSecret() string {
|
||||
@@ -462,7 +438,7 @@ func (m *GenerateResponse) GetAccount() *Account {
|
||||
}
|
||||
|
||||
type GrantRequest struct {
|
||||
Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
|
||||
Scope string `protobuf:"bytes,1,opt,name=scope,proto3" json:"scope,omitempty"`
|
||||
Resource *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
@@ -494,9 +470,9 @@ func (m *GrantRequest) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_GrantRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *GrantRequest) GetRole() string {
|
||||
func (m *GrantRequest) GetScope() string {
|
||||
if m != nil {
|
||||
return m.Role
|
||||
return m.Scope
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -540,7 +516,7 @@ func (m *GrantResponse) XXX_DiscardUnknown() {
|
||||
var xxx_messageInfo_GrantResponse proto.InternalMessageInfo
|
||||
|
||||
type RevokeRequest struct {
|
||||
Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
|
||||
Scope string `protobuf:"bytes,1,opt,name=scope,proto3" json:"scope,omitempty"`
|
||||
Resource *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
@@ -572,9 +548,9 @@ func (m *RevokeRequest) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_RevokeRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *RevokeRequest) GetRole() string {
|
||||
func (m *RevokeRequest) GetScope() string {
|
||||
if m != nil {
|
||||
return m.Role
|
||||
return m.Scope
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -799,7 +775,7 @@ func (m *TokenResponse) GetToken() *Token {
|
||||
|
||||
type Rule struct {
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Role string `protobuf:"bytes,2,opt,name=role,proto3" json:"role,omitempty"`
|
||||
Scope string `protobuf:"bytes,2,opt,name=scope,proto3" json:"scope,omitempty"`
|
||||
Resource *Resource `protobuf:"bytes,3,opt,name=resource,proto3" json:"resource,omitempty"`
|
||||
Access Access `protobuf:"varint,4,opt,name=access,proto3,enum=go.micro.auth.Access" json:"access,omitempty"`
|
||||
Priority int32 `protobuf:"varint,5,opt,name=priority,proto3" json:"priority,omitempty"`
|
||||
@@ -840,9 +816,9 @@ func (m *Rule) GetId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Rule) GetRole() string {
|
||||
func (m *Rule) GetScope() string {
|
||||
if m != nil {
|
||||
return m.Role
|
||||
return m.Scope
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@@ -869,13 +845,10 @@ func (m *Rule) GetPriority() int32 {
|
||||
}
|
||||
|
||||
type CreateRequest struct {
|
||||
Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
|
||||
Resource *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"`
|
||||
Access Access `protobuf:"varint,3,opt,name=access,proto3,enum=go.micro.auth.Access" json:"access,omitempty"`
|
||||
Priority int32 `protobuf:"varint,4,opt,name=priority,proto3" json:"priority,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Rule *Rule `protobuf:"bytes,1,opt,name=rule,proto3" json:"rule,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CreateRequest) Reset() { *m = CreateRequest{} }
|
||||
@@ -903,34 +876,13 @@ func (m *CreateRequest) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_CreateRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *CreateRequest) GetRole() string {
|
||||
func (m *CreateRequest) GetRule() *Rule {
|
||||
if m != nil {
|
||||
return m.Role
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *CreateRequest) GetResource() *Resource {
|
||||
if m != nil {
|
||||
return m.Resource
|
||||
return m.Rule
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *CreateRequest) GetAccess() Access {
|
||||
if m != nil {
|
||||
return m.Access
|
||||
}
|
||||
return Access_UNKNOWN
|
||||
}
|
||||
|
||||
func (m *CreateRequest) GetPriority() int32 {
|
||||
if m != nil {
|
||||
return m.Priority
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type CreateResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
@@ -963,13 +915,10 @@ func (m *CreateResponse) XXX_DiscardUnknown() {
|
||||
var xxx_messageInfo_CreateResponse proto.InternalMessageInfo
|
||||
|
||||
type DeleteRequest struct {
|
||||
Role string `protobuf:"bytes,1,opt,name=role,proto3" json:"role,omitempty"`
|
||||
Resource *Resource `protobuf:"bytes,2,opt,name=resource,proto3" json:"resource,omitempty"`
|
||||
Access Access `protobuf:"varint,3,opt,name=access,proto3,enum=go.micro.auth.Access" json:"access,omitempty"`
|
||||
Priority int32 `protobuf:"varint,4,opt,name=priority,proto3" json:"priority,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *DeleteRequest) Reset() { *m = DeleteRequest{} }
|
||||
@@ -997,34 +946,13 @@ func (m *DeleteRequest) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_DeleteRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *DeleteRequest) GetRole() string {
|
||||
func (m *DeleteRequest) GetId() string {
|
||||
if m != nil {
|
||||
return m.Role
|
||||
return m.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *DeleteRequest) GetResource() *Resource {
|
||||
if m != nil {
|
||||
return m.Resource
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *DeleteRequest) GetAccess() Access {
|
||||
if m != nil {
|
||||
return m.Access
|
||||
}
|
||||
return Access_UNKNOWN
|
||||
}
|
||||
|
||||
func (m *DeleteRequest) GetPriority() int32 {
|
||||
if m != nil {
|
||||
return m.Priority
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type DeleteResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
@@ -1157,64 +1085,62 @@ func init() {
|
||||
func init() { proto.RegisterFile("auth/service/proto/auth.proto", fileDescriptor_21300bfacc51fc2a) }
|
||||
|
||||
var fileDescriptor_21300bfacc51fc2a = []byte{
|
||||
// 900 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x56, 0xdd, 0x8e, 0xdb, 0x44,
|
||||
0x14, 0x5e, 0xff, 0xc4, 0xc9, 0x9e, 0xfc, 0x6c, 0x34, 0xdd, 0x16, 0x2b, 0xed, 0x96, 0xad, 0x8b,
|
||||
0xd0, 0x52, 0x41, 0x16, 0xa5, 0x37, 0x40, 0x6f, 0x58, 0x35, 0x51, 0x68, 0xa1, 0x41, 0x58, 0x45,
|
||||
0xe5, 0x06, 0x55, 0xc6, 0x39, 0xb0, 0xd6, 0x66, 0x6d, 0x33, 0x33, 0x5e, 0x91, 0x1b, 0x24, 0xde,
|
||||
0x81, 0x37, 0x80, 0x2b, 0x9e, 0x89, 0x7b, 0x5e, 0x03, 0xcd, 0x9f, 0x37, 0x76, 0x9c, 0xaa, 0x40,
|
||||
0x2f, 0xb8, 0x9b, 0x33, 0xe7, 0xf8, 0xcc, 0xf7, 0x7d, 0xe7, 0xcc, 0xf1, 0xc0, 0x51, 0x54, 0xf0,
|
||||
0xf3, 0x53, 0x86, 0xf4, 0x2a, 0x89, 0xf1, 0x34, 0xa7, 0x19, 0xcf, 0x4e, 0xc5, 0xd6, 0x58, 0x2e,
|
||||
0x49, 0xff, 0x87, 0x6c, 0x7c, 0x99, 0xc4, 0x34, 0x1b, 0x8b, 0xcd, 0xe0, 0x26, 0xdc, 0xf8, 0x22,
|
||||
0x61, 0xfc, 0x2c, 0x8e, 0xb3, 0x22, 0xe5, 0x2c, 0xc4, 0x1f, 0x0b, 0x64, 0x3c, 0x78, 0x0a, 0x87,
|
||||
0xd5, 0x6d, 0x96, 0x67, 0x29, 0x43, 0x32, 0x81, 0x4e, 0xa4, 0xf7, 0x7c, 0xeb, 0xd8, 0x39, 0xe9,
|
||||
0x4e, 0x6e, 0x8d, 0x2b, 0x09, 0xc7, 0xfa, 0x93, 0xb0, 0x8c, 0x0b, 0x7e, 0xb1, 0xa0, 0xf5, 0x3c,
|
||||
0xbb, 0xc0, 0x94, 0xdc, 0x83, 0x5e, 0x14, 0xc7, 0xc8, 0xd8, 0x4b, 0x2e, 0x6c, 0xdf, 0x3a, 0xb6,
|
||||
0x4e, 0xf6, 0xc3, 0xae, 0xda, 0x53, 0x21, 0xf7, 0xa1, 0x4f, 0xf1, 0x7b, 0x8a, 0xec, 0x5c, 0xc7,
|
||||
0xd8, 0x32, 0xa6, 0xa7, 0x37, 0x55, 0x90, 0x0f, 0xed, 0x98, 0x62, 0xc4, 0x71, 0xe9, 0x3b, 0xc7,
|
||||
0xd6, 0x89, 0x13, 0x1a, 0x93, 0xdc, 0x02, 0x0f, 0x7f, 0xca, 0x13, 0xba, 0xf6, 0x5d, 0xe9, 0xd0,
|
||||
0x56, 0xf0, 0xab, 0x0d, 0x6d, 0x8d, 0x8c, 0x0c, 0xc0, 0x4e, 0x96, 0xfa, 0x6c, 0x3b, 0x59, 0x12,
|
||||
0x02, 0x2e, 0x5f, 0xe7, 0xa8, 0x4f, 0x92, 0x6b, 0x72, 0x08, 0x2d, 0x9a, 0xad, 0x90, 0xf9, 0xce,
|
||||
0xb1, 0x73, 0xb2, 0x1f, 0x2a, 0x83, 0x7c, 0x0a, 0x9d, 0x4b, 0xe4, 0xd1, 0x32, 0xe2, 0x91, 0xef,
|
||||
0x4a, 0xf6, 0xef, 0x34, 0xb3, 0x1f, 0x3f, 0xd3, 0x61, 0xb3, 0x94, 0xd3, 0x75, 0x58, 0x7e, 0x45,
|
||||
0xee, 0xc0, 0x7e, 0x1a, 0x5d, 0x22, 0xcb, 0xa3, 0x18, 0xfd, 0x96, 0x3c, 0xf0, 0x7a, 0x83, 0x8c,
|
||||
0xa0, 0x93, 0xd3, 0xec, 0x2a, 0x59, 0x22, 0xf5, 0x3d, 0xe9, 0x2c, 0x6d, 0xc1, 0x8c, 0x61, 0x4c,
|
||||
0x91, 0xfb, 0x6d, 0xe9, 0xd1, 0xd6, 0xe8, 0x11, 0xf4, 0x2b, 0x87, 0x91, 0x21, 0x38, 0x17, 0xb8,
|
||||
0xd6, 0xfc, 0xc4, 0x52, 0x90, 0xb9, 0x8a, 0x56, 0x85, 0x61, 0xa8, 0x8c, 0x4f, 0xec, 0x8f, 0xac,
|
||||
0x60, 0x05, 0x9d, 0x10, 0x59, 0x56, 0xd0, 0x18, 0x85, 0x0c, 0x02, 0x89, 0xfe, 0x50, 0xae, 0x1b,
|
||||
0xa5, 0x19, 0x41, 0x07, 0xd3, 0x65, 0x9e, 0x25, 0x29, 0x97, 0xea, 0xef, 0x87, 0xa5, 0x5d, 0xa5,
|
||||
0xe7, 0xd6, 0xe8, 0x05, 0xbf, 0xdb, 0x70, 0x30, 0xc7, 0x14, 0x69, 0xc4, 0x51, 0x37, 0xda, 0x56,
|
||||
0x31, 0x4a, 0xe1, 0xed, 0x4d, 0xe1, 0x3f, 0xdb, 0x10, 0xde, 0x91, 0xc2, 0xbf, 0x5f, 0x13, 0xbe,
|
||||
0x96, 0xf7, 0xf5, 0x0a, 0x50, 0x47, 0xb8, 0x21, 0x72, 0x6b, 0x53, 0xe4, 0x52, 0x07, 0xaf, 0xaa,
|
||||
0x43, 0x59, 0xac, 0x76, 0xb5, 0x58, 0xff, 0xad, 0x28, 0x53, 0x18, 0x5e, 0xb3, 0xd1, 0xf7, 0xee,
|
||||
0x43, 0x68, 0xeb, 0xfb, 0x24, 0x73, 0xec, 0xbe, 0x76, 0x26, 0x2c, 0x78, 0x01, 0xbd, 0x39, 0x8d,
|
||||
0x52, 0x6e, 0x84, 0x26, 0xe0, 0x0a, 0x2d, 0x4d, 0x79, 0xc5, 0x9a, 0x3c, 0x84, 0x0e, 0xd5, 0xe5,
|
||||
0x97, 0x30, 0xba, 0x93, 0xb7, 0x6a, 0x69, 0x4d, 0x77, 0x84, 0x65, 0x60, 0x70, 0x00, 0x7d, 0x9d,
|
||||
0x58, 0x61, 0x0b, 0xbe, 0x81, 0x7e, 0x88, 0x57, 0xd9, 0x05, 0xbe, 0xf1, 0xa3, 0x86, 0x30, 0x30,
|
||||
0x99, 0xf5, 0x59, 0xef, 0xc2, 0xe0, 0x49, 0xca, 0x72, 0x8c, 0x4b, 0x5e, 0x87, 0xd0, 0xda, 0x1c,
|
||||
0x26, 0xca, 0x08, 0x1e, 0xc3, 0x41, 0x19, 0xf7, 0xaf, 0x25, 0xfc, 0x19, 0x7a, 0x72, 0xde, 0xec,
|
||||
0xea, 0xd5, 0xeb, 0x6e, 0xb1, 0x2b, 0xdd, 0xb2, 0x35, 0xc3, 0x9c, 0x86, 0x19, 0x76, 0x0f, 0x7a,
|
||||
0xd2, 0xf9, 0xb2, 0x32, 0xaf, 0xba, 0x72, 0x6f, 0xa6, 0x86, 0xd6, 0x23, 0xe8, 0xeb, 0xf3, 0x35,
|
||||
0x85, 0x07, 0x9b, 0x5c, 0xbb, 0x93, 0xc3, 0x1a, 0x01, 0x15, 0xac, 0x15, 0xf8, 0xc3, 0x02, 0x37,
|
||||
0x2c, 0x56, 0xd8, 0x34, 0xee, 0x64, 0x75, 0xec, 0x1d, 0xd5, 0x71, 0x5e, 0xb3, 0x3a, 0xe4, 0x03,
|
||||
0xf0, 0xd4, 0xe4, 0x96, 0xd8, 0x07, 0x93, 0x9b, 0xdb, 0x7a, 0x22, 0x63, 0xa1, 0x0e, 0x52, 0xf7,
|
||||
0x25, 0xc9, 0x68, 0xc2, 0xd7, 0xf2, 0x76, 0xb5, 0xc2, 0xd2, 0x0e, 0x7e, 0xb3, 0xa0, 0xff, 0x58,
|
||||
0x8e, 0xf0, 0x37, 0xdd, 0x43, 0x1b, 0x28, 0x9d, 0x7f, 0x8a, 0xd2, 0xad, 0xa1, 0x1c, 0xc2, 0xc0,
|
||||
0x80, 0xd4, 0xed, 0x28, 0x70, 0x4f, 0x71, 0x85, 0xff, 0x7b, 0xdc, 0x06, 0xa4, 0xc6, 0xdd, 0x87,
|
||||
0xae, 0xf8, 0xbd, 0x9b, 0xbf, 0xfd, 0xc7, 0xd0, 0x53, 0xa6, 0xee, 0xb3, 0xf7, 0xa0, 0x45, 0x0b,
|
||||
0x31, 0x84, 0xd5, 0x2f, 0xfe, 0x46, 0x1d, 0x6d, 0xb1, 0xc2, 0x50, 0x45, 0x3c, 0x18, 0x83, 0xa7,
|
||||
0x90, 0x90, 0x2e, 0xb4, 0xbf, 0x5e, 0x7c, 0xbe, 0xf8, 0xf2, 0xc5, 0x62, 0xb8, 0x27, 0x8c, 0x79,
|
||||
0x78, 0xb6, 0x78, 0x3e, 0x9b, 0x0e, 0x2d, 0x02, 0xe0, 0x4d, 0x67, 0x8b, 0x27, 0xb3, 0xe9, 0xd0,
|
||||
0x9e, 0xfc, 0x65, 0x81, 0x7b, 0x56, 0xf0, 0x73, 0xf2, 0x0c, 0x3a, 0x66, 0xca, 0x91, 0xbb, 0xaf,
|
||||
0x1e, 0xe6, 0xa3, 0xb7, 0x77, 0xfa, 0x35, 0x9f, 0x3d, 0xf2, 0x14, 0xda, 0xfa, 0xc2, 0x93, 0xa3,
|
||||
0x5a, 0x74, 0x75, 0x60, 0x8c, 0xee, 0xee, 0x72, 0x97, 0xb9, 0xa6, 0xe6, 0xbd, 0x72, 0xbb, 0xf1,
|
||||
0x82, 0xe9, 0x3c, 0x77, 0x9a, 0x9d, 0x26, 0xcb, 0xe4, 0x5b, 0xe8, 0x98, 0xe7, 0x13, 0xf9, 0x0a,
|
||||
0x5c, 0x21, 0x30, 0x09, 0x6a, 0xdf, 0x34, 0x3c, 0xbd, 0x46, 0xf7, 0x5f, 0x19, 0x53, 0xa6, 0xff,
|
||||
0xd3, 0x82, 0x96, 0x28, 0x04, 0x23, 0x73, 0xf0, 0x54, 0x5b, 0x92, 0x3a, 0xa4, 0xca, 0x95, 0x1a,
|
||||
0x1d, 0xed, 0xf0, 0x96, 0xbc, 0xe7, 0xe0, 0xa9, 0x3e, 0xd9, 0x4a, 0x54, 0xe9, 0xf1, 0xad, 0x44,
|
||||
0xb5, 0xe6, 0xda, 0x23, 0x67, 0x9a, 0xee, 0xa8, 0x81, 0x8a, 0x49, 0x72, 0xbb, 0xd1, 0x67, 0x52,
|
||||
0x7c, 0xe7, 0xc9, 0xd7, 0xea, 0xc3, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0xdf, 0x67, 0x3c, 0x6e,
|
||||
0xce, 0x0a, 0x00, 0x00,
|
||||
// 872 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x51, 0x8f, 0xdb, 0x44,
|
||||
0x10, 0x3e, 0x27, 0xb1, 0x93, 0x9b, 0xc4, 0x77, 0xd1, 0xf6, 0x5a, 0xac, 0x94, 0x6b, 0xaf, 0x2e,
|
||||
0x82, 0xa3, 0x82, 0x1c, 0x4a, 0x5f, 0x0a, 0x7d, 0xe1, 0xd4, 0x44, 0xa1, 0x85, 0x06, 0x61, 0x15,
|
||||
0x21, 0x90, 0x50, 0x65, 0x9c, 0x81, 0xb3, 0x2e, 0x67, 0x9b, 0xdd, 0xf5, 0x89, 0xbc, 0x20, 0xf1,
|
||||
0xc6, 0x8f, 0xe1, 0x27, 0xf1, 0xce, 0x1f, 0xe0, 0x07, 0x20, 0xef, 0xce, 0xba, 0xb1, 0xe3, 0x54,
|
||||
0x15, 0x88, 0x37, 0xcf, 0xec, 0xb7, 0xb3, 0xf3, 0x7d, 0x3b, 0x33, 0x6b, 0x38, 0x0e, 0x73, 0x79,
|
||||
0x71, 0x26, 0x90, 0x5f, 0xc7, 0x11, 0x9e, 0x65, 0x3c, 0x95, 0xe9, 0x59, 0xe1, 0x1a, 0xab, 0x4f,
|
||||
0xe6, 0xfe, 0x94, 0x8e, 0xaf, 0xe2, 0x88, 0xa7, 0xe3, 0xc2, 0xe9, 0xdf, 0x84, 0x1b, 0x5f, 0xc4,
|
||||
0x42, 0x9e, 0x47, 0x51, 0x9a, 0x27, 0x52, 0x04, 0xf8, 0x73, 0x8e, 0x42, 0xfa, 0xcf, 0xe0, 0xa8,
|
||||
0xea, 0x16, 0x59, 0x9a, 0x08, 0x64, 0x13, 0xe8, 0x85, 0xe4, 0xf3, 0xac, 0x93, 0xf6, 0x69, 0x7f,
|
||||
0x72, 0x6b, 0x5c, 0x09, 0x38, 0xa6, 0x2d, 0x41, 0x89, 0xf3, 0x7f, 0xb3, 0xc0, 0x7e, 0x91, 0x5e,
|
||||
0x62, 0xc2, 0xee, 0xc1, 0x20, 0x8c, 0x22, 0x14, 0xe2, 0xa5, 0x2c, 0x6c, 0xcf, 0x3a, 0xb1, 0x4e,
|
||||
0xf7, 0x83, 0xbe, 0xf6, 0x69, 0xc8, 0x7d, 0x70, 0x39, 0xfe, 0xc8, 0x51, 0x5c, 0x10, 0xa6, 0xa5,
|
||||
0x30, 0x03, 0x72, 0x6a, 0x90, 0x07, 0xdd, 0x88, 0x63, 0x28, 0x71, 0xe9, 0xb5, 0x4f, 0xac, 0xd3,
|
||||
0x76, 0x60, 0x4c, 0x76, 0x0b, 0x1c, 0xfc, 0x25, 0x8b, 0xf9, 0xda, 0xeb, 0xa8, 0x05, 0xb2, 0xfc,
|
||||
0xbf, 0x2d, 0xe8, 0x52, 0x66, 0xec, 0x00, 0x5a, 0xf1, 0x92, 0xce, 0x6e, 0xc5, 0x4b, 0xc6, 0xa0,
|
||||
0x23, 0xd7, 0x19, 0xd2, 0x49, 0xea, 0x9b, 0x7d, 0x0a, 0xbd, 0x2b, 0x94, 0xe1, 0x32, 0x94, 0xa1,
|
||||
0xd7, 0x51, 0x3c, 0xdf, 0x69, 0xe6, 0x39, 0x7e, 0x4e, 0xb0, 0x59, 0x22, 0xf9, 0x3a, 0x28, 0x77,
|
||||
0x15, 0x99, 0x88, 0x28, 0xcd, 0x50, 0x78, 0xf6, 0x49, 0xfb, 0x74, 0x3f, 0x20, 0xab, 0xf0, 0xc7,
|
||||
0x42, 0xe4, 0xc8, 0x3d, 0x47, 0x9d, 0x47, 0x96, 0xc2, 0x63, 0xc4, 0x51, 0x7a, 0x5d, 0xed, 0xd7,
|
||||
0xd6, 0xe8, 0x31, 0xb8, 0x95, 0x23, 0xd8, 0x10, 0xda, 0x97, 0xb8, 0xa6, 0xfc, 0x8b, 0x4f, 0x76,
|
||||
0x04, 0xf6, 0x75, 0xb8, 0xca, 0x0d, 0x03, 0x6d, 0x7c, 0xd2, 0x7a, 0x64, 0xf9, 0x0b, 0xe8, 0x05,
|
||||
0x28, 0xd2, 0x9c, 0x47, 0x58, 0xd0, 0x4c, 0xc2, 0x2b, 0xa4, 0x8d, 0xea, 0xbb, 0x91, 0xfa, 0x08,
|
||||
0x7a, 0x98, 0x2c, 0xb3, 0x34, 0x4e, 0xa4, 0x52, 0x77, 0x3f, 0x28, 0x6d, 0xff, 0xf7, 0x16, 0x1c,
|
||||
0xce, 0x31, 0x41, 0x1e, 0x4a, 0xa4, 0x52, 0xd9, 0x92, 0xf3, 0xb3, 0x0d, 0xe9, 0xda, 0x4a, 0xba,
|
||||
0x0f, 0x6a, 0xd2, 0xd5, 0x22, 0xbc, 0x81, 0x84, 0x9d, 0xba, 0x84, 0x24, 0x95, 0xbd, 0x29, 0x55,
|
||||
0xc9, 0xc6, 0xa9, 0xb2, 0xc9, 0x78, 0x7a, 0x1d, 0x2f, 0x91, 0x93, 0xb0, 0xa5, 0xfd, 0xdf, 0xa4,
|
||||
0x9d, 0xc2, 0xf0, 0x15, 0x0f, 0xea, 0x8e, 0x8f, 0xa0, 0x4b, 0x55, 0xaf, 0x62, 0xec, 0x6e, 0x0e,
|
||||
0x03, 0xf3, 0xbf, 0x85, 0xc1, 0x9c, 0x87, 0x89, 0x34, 0x62, 0x1e, 0x81, 0xad, 0x48, 0x52, 0x0e,
|
||||
0xda, 0x60, 0x0f, 0xa1, 0xc7, 0xe9, 0x1a, 0x55, 0x22, 0xfd, 0xc9, 0x5b, 0xb5, 0xc0, 0xe6, 0x96,
|
||||
0x83, 0x12, 0xe8, 0x1f, 0x82, 0x4b, 0xa1, 0x75, 0x76, 0xfe, 0x77, 0xe0, 0x06, 0x78, 0x9d, 0x5e,
|
||||
0xe2, 0xff, 0x70, 0xd8, 0x10, 0x0e, 0x4c, 0x6c, 0x3a, 0xed, 0x5d, 0x38, 0x78, 0x9a, 0x88, 0x0c,
|
||||
0xa3, 0x4d, 0x6e, 0x9b, 0x6d, 0xaf, 0x0d, 0xff, 0x09, 0x1c, 0x96, 0xb8, 0x7f, 0x2d, 0xe3, 0xaf,
|
||||
0x30, 0x50, 0x93, 0x61, 0x57, 0x4d, 0xbe, 0xaa, 0x98, 0x56, 0xa5, 0x62, 0xb6, 0xa6, 0x4d, 0xbb,
|
||||
0x61, 0xda, 0xdc, 0x83, 0x81, 0x5a, 0x7c, 0x59, 0x99, 0x2c, 0x7d, 0xe5, 0x9b, 0xe9, 0xf1, 0xf2,
|
||||
0x18, 0x5c, 0x3a, 0x9f, 0x28, 0x3c, 0xd8, 0xe4, 0xda, 0x9f, 0x1c, 0xd5, 0x08, 0x68, 0x30, 0x29,
|
||||
0xf0, 0x87, 0x05, 0x9d, 0x20, 0x5f, 0xe1, 0x56, 0xd6, 0xe5, 0xfd, 0xb4, 0x76, 0xdd, 0x4f, 0xfb,
|
||||
0x0d, 0xef, 0x87, 0x7d, 0x08, 0x8e, 0x9e, 0xb2, 0x2a, 0xfb, 0x83, 0xc9, 0xcd, 0x6d, 0x45, 0x51,
|
||||
0x88, 0x80, 0x40, 0xba, 0x6b, 0xe2, 0x94, 0xc7, 0x72, 0xad, 0x7a, 0xcc, 0x0e, 0x4a, 0xdb, 0x7f,
|
||||
0x04, 0xee, 0x13, 0x35, 0x6d, 0x8d, 0xd8, 0xef, 0x41, 0x87, 0xe7, 0x2b, 0x24, 0xaa, 0x37, 0xea,
|
||||
0xc9, 0xe4, 0x2b, 0x0c, 0x14, 0xa0, 0x28, 0x12, 0xb3, 0x93, 0x8a, 0xe4, 0x2e, 0xb8, 0x53, 0x5c,
|
||||
0xe1, 0xce, 0x61, 0x52, 0x6c, 0x31, 0x00, 0xda, 0xe2, 0x42, 0xbf, 0x78, 0x99, 0xcc, 0x43, 0xf5,
|
||||
0x31, 0x0c, 0xb4, 0x49, 0xc2, 0xbf, 0x0f, 0x76, 0x71, 0x96, 0x79, 0x9d, 0x1a, 0xb3, 0xd1, 0x88,
|
||||
0x07, 0x63, 0x70, 0x34, 0x6d, 0xd6, 0x87, 0xee, 0xd7, 0x8b, 0xcf, 0x17, 0x5f, 0x7e, 0xb3, 0x18,
|
||||
0xee, 0x15, 0xc6, 0x3c, 0x38, 0x5f, 0xbc, 0x98, 0x4d, 0x87, 0x16, 0x03, 0x70, 0xa6, 0xb3, 0xc5,
|
||||
0xd3, 0xd9, 0x74, 0xd8, 0x9a, 0xfc, 0x65, 0x41, 0xe7, 0x3c, 0x97, 0x17, 0xec, 0x39, 0xf4, 0x4c,
|
||||
0xeb, 0xb3, 0x3b, 0xaf, 0x9f, 0x6d, 0xa3, 0xbb, 0x3b, 0xd7, 0x89, 0xcf, 0x1e, 0x7b, 0x06, 0x5d,
|
||||
0xea, 0x00, 0x76, 0x5c, 0x43, 0x57, 0x3b, 0x68, 0x74, 0x67, 0xd7, 0x72, 0x19, 0x6b, 0x6a, 0x9e,
|
||||
0xda, 0xdb, 0x8d, 0x15, 0x47, 0x71, 0xde, 0x6e, 0x5e, 0x34, 0x51, 0x26, 0xdf, 0x43, 0xcf, 0xbc,
|
||||
0xfc, 0xec, 0x2b, 0xe8, 0x14, 0x02, 0x33, 0xbf, 0xb6, 0xa7, 0xe1, 0xaf, 0x61, 0x74, 0xff, 0xb5,
|
||||
0x98, 0x32, 0xfc, 0x9f, 0x16, 0xd8, 0xc5, 0x45, 0x08, 0x36, 0x07, 0x47, 0x57, 0x04, 0xab, 0xa7,
|
||||
0x54, 0x29, 0xb1, 0xd1, 0xf1, 0x8e, 0xd5, 0x92, 0xf7, 0x1c, 0x1c, 0x5d, 0x27, 0x5b, 0x81, 0x2a,
|
||||
0xf5, 0xb5, 0x15, 0xa8, 0x56, 0x5c, 0x7b, 0xec, 0x9c, 0xe8, 0x8e, 0x1a, 0xa8, 0x98, 0x20, 0xb7,
|
||||
0x1b, 0xd7, 0x4c, 0x88, 0x1f, 0x1c, 0xf5, 0xa3, 0xf5, 0xf0, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff,
|
||||
0x52, 0x12, 0xc2, 0xdb, 0x89, 0x09, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
@@ -35,10 +35,9 @@ message Token {
|
||||
message Account {
|
||||
string id = 1;
|
||||
string type = 2;
|
||||
repeated string roles = 3;
|
||||
map<string, string> metadata = 4;
|
||||
string namespace = 5;
|
||||
string provider = 6;
|
||||
repeated string scopes = 5;
|
||||
string issuer = 6;
|
||||
string secret = 7;
|
||||
}
|
||||
|
||||
@@ -46,14 +45,12 @@ message Resource{
|
||||
string name = 1;
|
||||
string type = 2;
|
||||
string endpoint = 3;
|
||||
string namespace = 4;
|
||||
}
|
||||
|
||||
message GenerateRequest {
|
||||
string id = 1;
|
||||
repeated string roles = 2;
|
||||
map<string, string> metadata = 3;
|
||||
string namespace = 4;
|
||||
repeated string scopes = 4;
|
||||
string secret = 5;
|
||||
string type = 6;
|
||||
string provider = 7;
|
||||
@@ -64,14 +61,14 @@ message GenerateResponse {
|
||||
}
|
||||
|
||||
message GrantRequest {
|
||||
string role = 1;
|
||||
string scope = 1;
|
||||
Resource resource = 2;
|
||||
}
|
||||
|
||||
message GrantResponse {}
|
||||
|
||||
message RevokeRequest {
|
||||
string role = 1;
|
||||
string scope = 1;
|
||||
Resource resource = 2;
|
||||
}
|
||||
|
||||
@@ -104,26 +101,20 @@ enum Access {
|
||||
|
||||
message Rule {
|
||||
string id = 1;
|
||||
string role = 2;
|
||||
string scope = 2;
|
||||
Resource resource = 3;
|
||||
Access access = 4;
|
||||
int32 priority = 5;
|
||||
}
|
||||
|
||||
message CreateRequest {
|
||||
string role = 1;
|
||||
Resource resource = 2;
|
||||
Access access = 3;
|
||||
int32 priority = 4;
|
||||
Rule rule = 1;
|
||||
}
|
||||
|
||||
message CreateResponse {}
|
||||
|
||||
message DeleteRequest {
|
||||
string role = 1;
|
||||
Resource resource = 2;
|
||||
Access access = 3;
|
||||
int32 priority = 4;
|
||||
string id = 1;
|
||||
}
|
||||
|
||||
message DeleteResponse {}
|
||||
|
@@ -2,35 +2,23 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
"github.com/micro/go-micro/v2/auth/rules"
|
||||
pb "github.com/micro/go-micro/v2/auth/service/proto"
|
||||
"github.com/micro/go-micro/v2/auth/token"
|
||||
"github.com/micro/go-micro/v2/auth/token/jwt"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
log "github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/util/jitter"
|
||||
)
|
||||
|
||||
// NewAuth returns a new instance of the Auth service
|
||||
func NewAuth(opts ...auth.Option) auth.Auth {
|
||||
return &svc{options: auth.NewOptions(opts...)}
|
||||
}
|
||||
|
||||
// svc is the service implementation of the Auth interface
|
||||
type svc struct {
|
||||
options auth.Options
|
||||
auth pb.AuthService
|
||||
rule pb.RulesService
|
||||
rules pb.RulesService
|
||||
jwt token.Provider
|
||||
|
||||
rules []*pb.Rule
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
func (s *svc) String() string {
|
||||
@@ -42,9 +30,12 @@ func (s *svc) Init(opts ...auth.Option) {
|
||||
o(&s.options)
|
||||
}
|
||||
|
||||
dc := client.DefaultClient
|
||||
s.auth = pb.NewAuthService("go.micro.auth", dc)
|
||||
s.rule = pb.NewRulesService("go.micro.auth", dc)
|
||||
if s.options.Client == nil {
|
||||
s.options.Client = client.DefaultClient
|
||||
}
|
||||
|
||||
s.auth = pb.NewAuthService("go.micro.auth", s.options.Client)
|
||||
s.rules = pb.NewRulesService("go.micro.auth", s.options.Client)
|
||||
|
||||
// if we have a JWT public key passed as an option,
|
||||
// we can decode tokens with the type "JWT" locally
|
||||
@@ -52,29 +43,9 @@ func (s *svc) Init(opts ...auth.Option) {
|
||||
if key := s.options.PublicKey; len(key) > 0 {
|
||||
s.jwt = jwt.NewTokenProvider(token.WithPublicKey(key))
|
||||
}
|
||||
|
||||
// load rules periodically from the auth service
|
||||
go func() {
|
||||
ruleTimer := time.NewTicker(time.Second * 30)
|
||||
|
||||
// load rules immediately on startup
|
||||
s.loadRules()
|
||||
|
||||
for {
|
||||
<-ruleTimer.C
|
||||
|
||||
// jitter for up to 5 seconds, this stops
|
||||
// all the services calling the auth service
|
||||
// at the exact same time
|
||||
time.Sleep(jitter.Do(time.Second * 5))
|
||||
s.loadRules()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (s *svc) Options() auth.Options {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
return s.options
|
||||
}
|
||||
|
||||
@@ -83,13 +54,12 @@ func (s *svc) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, e
|
||||
options := auth.NewGenerateOptions(opts...)
|
||||
|
||||
rsp, err := s.auth.Generate(context.TODO(), &pb.GenerateRequest{
|
||||
Id: id,
|
||||
Type: options.Type,
|
||||
Secret: options.Secret,
|
||||
Roles: options.Roles,
|
||||
Metadata: options.Metadata,
|
||||
Provider: options.Provider,
|
||||
Namespace: options.Namespace,
|
||||
Id: id,
|
||||
Type: options.Type,
|
||||
Secret: options.Secret,
|
||||
Scopes: options.Scopes,
|
||||
Metadata: options.Metadata,
|
||||
Provider: options.Provider,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -99,87 +69,75 @@ func (s *svc) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, e
|
||||
}
|
||||
|
||||
// Grant access to a resource
|
||||
func (s *svc) Grant(role string, res *auth.Resource) error {
|
||||
_, err := s.rule.Create(context.TODO(), &pb.CreateRequest{
|
||||
Role: role,
|
||||
Access: pb.Access_GRANTED,
|
||||
Resource: &pb.Resource{
|
||||
Namespace: res.Namespace,
|
||||
Type: res.Type,
|
||||
Name: res.Name,
|
||||
Endpoint: res.Endpoint,
|
||||
func (s *svc) Grant(rule *auth.Rule) error {
|
||||
access := pb.Access_UNKNOWN
|
||||
if rule.Access == auth.AccessGranted {
|
||||
access = pb.Access_GRANTED
|
||||
} else if rule.Access == auth.AccessDenied {
|
||||
access = pb.Access_DENIED
|
||||
}
|
||||
|
||||
_, err := s.rules.Create(context.TODO(), &pb.CreateRequest{
|
||||
Rule: &pb.Rule{
|
||||
Id: rule.ID,
|
||||
Scope: rule.Scope,
|
||||
Priority: rule.Priority,
|
||||
Access: access,
|
||||
Resource: &pb.Resource{
|
||||
Type: rule.Resource.Type,
|
||||
Name: rule.Resource.Name,
|
||||
Endpoint: rule.Resource.Endpoint,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Revoke access to a resource
|
||||
func (s *svc) Revoke(role string, res *auth.Resource) error {
|
||||
_, err := s.rule.Delete(context.TODO(), &pb.DeleteRequest{
|
||||
Role: role,
|
||||
Access: pb.Access_GRANTED,
|
||||
Resource: &pb.Resource{
|
||||
Namespace: res.Namespace,
|
||||
Type: res.Type,
|
||||
Name: res.Name,
|
||||
Endpoint: res.Endpoint,
|
||||
},
|
||||
func (s *svc) Revoke(rule *auth.Rule) error {
|
||||
_, err := s.rules.Delete(context.TODO(), &pb.DeleteRequest{
|
||||
Id: rule.ID,
|
||||
})
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *svc) Rules(opts ...auth.RulesOption) ([]*auth.Rule, error) {
|
||||
var options auth.RulesOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
if options.Context == nil {
|
||||
options.Context = context.TODO()
|
||||
}
|
||||
|
||||
rsp, err := s.rules.List(options.Context, &pb.ListRequest{}, client.WithCache(time.Second*30))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rules := make([]*auth.Rule, len(rsp.Rules))
|
||||
for i, r := range rsp.Rules {
|
||||
rules[i] = serializeRule(r)
|
||||
}
|
||||
|
||||
return rules, nil
|
||||
}
|
||||
|
||||
// Verify an account has access to a resource
|
||||
func (s *svc) Verify(acc *auth.Account, res *auth.Resource) error {
|
||||
// set the namespace on the resource
|
||||
if len(res.Namespace) == 0 {
|
||||
res.Namespace = s.Options().Namespace
|
||||
func (s *svc) Verify(acc *auth.Account, res *auth.Resource, opts ...auth.VerifyOption) error {
|
||||
var options auth.VerifyOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
queries := [][]string{
|
||||
{res.Namespace, res.Type, res.Name, res.Endpoint}, // check for specific role, e.g. service.foo.ListFoo:admin (role is checked in accessForRule)
|
||||
{res.Namespace, res.Type, res.Name, "*"}, // check for wildcard endpoint, e.g. service.foo*
|
||||
{res.Namespace, res.Type, "*"}, // check for wildcard name, e.g. service.*
|
||||
{res.Namespace, "*"}, // check for wildcard type, e.g. *
|
||||
{"*"}, // check for wildcard namespace
|
||||
rs, err := s.Rules(auth.RulesContext(options.Context))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// endpoint is a url which can have wildcard excludes, e.g.
|
||||
// "/foo/*" will allow "/foo/bar"
|
||||
if comps := strings.Split(res.Endpoint, "/"); len(comps) > 1 {
|
||||
for i := 1; i < len(comps); i++ {
|
||||
wildcard := fmt.Sprintf("%v/*", strings.Join(comps[0:i], "/"))
|
||||
queries = append(queries, []string{res.Type, res.Name, wildcard})
|
||||
}
|
||||
}
|
||||
|
||||
// set a default account id / namespace to log
|
||||
logID := acc.ID
|
||||
if len(logID) == 0 {
|
||||
logID = "[no account]"
|
||||
}
|
||||
logNamespace := acc.Namespace
|
||||
if len(logNamespace) == 0 {
|
||||
logNamespace = "[no namespace]"
|
||||
}
|
||||
|
||||
for _, q := range queries {
|
||||
for _, rule := range s.listRules(q...) {
|
||||
switch accessForRule(rule, acc, res) {
|
||||
case pb.Access_UNKNOWN:
|
||||
continue // rule did not specify access, check the next rule
|
||||
case pb.Access_GRANTED:
|
||||
log.Tracef("%v:%v granted access to %v:%v:%v:%v by rule %v", logNamespace, logID, res.Namespace, res.Type, res.Name, res.Endpoint, rule.Id)
|
||||
return nil // rule grants the account access to the resource
|
||||
case pb.Access_DENIED:
|
||||
log.Tracef("%v:%v denied access to %v:%v:%v:%v by rule %v", logNamespace, logID, res.Namespace, res.Type, res.Name, res.Endpoint, rule.Id)
|
||||
return auth.ErrForbidden // rule denies access to the resource
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no rules were found for the resource, default to denying access
|
||||
log.Tracef("%v:%v denied access to %v:%v:%v:%v by lack of rule (%v rules found for namespace)", logNamespace, logID, res.Namespace, res.Type, res.Name, res.Endpoint, len(s.listRules(res.Namespace)))
|
||||
return auth.ErrForbidden
|
||||
return rules.Verify(rs, acc, res)
|
||||
}
|
||||
|
||||
// Inspect a token
|
||||
@@ -215,75 +173,6 @@ func (s *svc) Token(opts ...auth.TokenOption) (*auth.Token, error) {
|
||||
return serializeToken(rsp.Token), nil
|
||||
}
|
||||
|
||||
var ruleJoinKey = ":"
|
||||
|
||||
// accessForRule returns a rule status, indicating if a rule permits access to a
|
||||
// resource for a given account
|
||||
func accessForRule(rule *pb.Rule, acc *auth.Account, res *auth.Resource) pb.Access {
|
||||
if rule.Role == "*" {
|
||||
return rule.Access
|
||||
}
|
||||
|
||||
for _, role := range acc.Roles {
|
||||
if rule.Role == role {
|
||||
return rule.Access
|
||||
}
|
||||
|
||||
// allow user.anything if role is user.*
|
||||
if strings.HasSuffix(rule.Role, ".*") && strings.HasPrefix(rule.Role, role+".") {
|
||||
return rule.Access
|
||||
}
|
||||
}
|
||||
|
||||
return pb.Access_UNKNOWN
|
||||
}
|
||||
|
||||
// listRules gets all the rules from the store which match the filters.
|
||||
// filters are namespace, type, name and then endpoint.
|
||||
func (s *svc) listRules(filters ...string) []*pb.Rule {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
var rules []*pb.Rule
|
||||
for _, r := range s.rules {
|
||||
if len(filters) > 0 && r.Resource.Namespace != filters[0] {
|
||||
continue
|
||||
}
|
||||
if len(filters) > 1 && r.Resource.Type != filters[1] {
|
||||
continue
|
||||
}
|
||||
if len(filters) > 2 && r.Resource.Name != filters[2] {
|
||||
continue
|
||||
}
|
||||
if len(filters) > 3 && r.Resource.Endpoint != filters[3] {
|
||||
continue
|
||||
}
|
||||
|
||||
rules = append(rules, r)
|
||||
}
|
||||
|
||||
// sort rules by priority
|
||||
sort.Slice(rules, func(i, j int) bool {
|
||||
return rules[i].Priority < rules[j].Priority
|
||||
})
|
||||
|
||||
return rules
|
||||
}
|
||||
|
||||
// loadRules retrieves the rules from the auth service
|
||||
func (s *svc) loadRules() {
|
||||
rsp, err := s.rule.List(context.TODO(), &pb.ListRequest{})
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Error listing rules: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
s.rules = rsp.Rules
|
||||
}
|
||||
|
||||
func serializeToken(t *pb.Token) *auth.Token {
|
||||
return &auth.Token{
|
||||
AccessToken: t.AccessToken,
|
||||
@@ -295,11 +184,45 @@ func serializeToken(t *pb.Token) *auth.Token {
|
||||
|
||||
func serializeAccount(a *pb.Account) *auth.Account {
|
||||
return &auth.Account{
|
||||
ID: a.Id,
|
||||
Roles: a.Roles,
|
||||
Secret: a.Secret,
|
||||
Metadata: a.Metadata,
|
||||
Provider: a.Provider,
|
||||
Namespace: a.Namespace,
|
||||
ID: a.Id,
|
||||
Secret: a.Secret,
|
||||
Issuer: a.Issuer,
|
||||
Metadata: a.Metadata,
|
||||
Scopes: a.Scopes,
|
||||
}
|
||||
}
|
||||
|
||||
func serializeRule(r *pb.Rule) *auth.Rule {
|
||||
var access auth.Access
|
||||
if r.Access == pb.Access_GRANTED {
|
||||
access = auth.AccessGranted
|
||||
} else {
|
||||
access = auth.AccessDenied
|
||||
}
|
||||
|
||||
return &auth.Rule{
|
||||
ID: r.Id,
|
||||
Scope: r.Scope,
|
||||
Access: access,
|
||||
Priority: r.Priority,
|
||||
Resource: &auth.Resource{
|
||||
Type: r.Resource.Type,
|
||||
Name: r.Resource.Name,
|
||||
Endpoint: r.Resource.Endpoint,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewAuth returns a new instance of the Auth service
|
||||
func NewAuth(opts ...auth.Option) auth.Auth {
|
||||
options := auth.NewOptions(opts...)
|
||||
if options.Client == nil {
|
||||
options.Client = client.DefaultClient
|
||||
}
|
||||
|
||||
return &svc{
|
||||
auth: pb.NewAuthService("go.micro.auth", options.Client),
|
||||
rules: pb.NewRulesService("go.micro.auth", options.Client),
|
||||
options: options,
|
||||
}
|
||||
}
|
||||
|
@@ -1,26 +0,0 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
pb "github.com/micro/go-micro/v2/auth/service/proto"
|
||||
)
|
||||
|
||||
func TestListRulesSorting(t *testing.T) {
|
||||
s := &svc{
|
||||
rules: []*pb.Rule{
|
||||
&pb.Rule{Priority: 1},
|
||||
&pb.Rule{Priority: 3},
|
||||
&pb.Rule{Priority: 2},
|
||||
},
|
||||
}
|
||||
|
||||
var priorities []int32
|
||||
for _, r := range s.listRules() {
|
||||
priorities = append(priorities, r.Priority)
|
||||
}
|
||||
|
||||
if priorities[0] != 1 || priorities[1] != 2 || priorities[2] != 3 {
|
||||
t.Errorf("Incorrect Rule Sequence")
|
||||
}
|
||||
}
|
@@ -32,10 +32,10 @@ func TestInspect(t *testing.T) {
|
||||
|
||||
t.Run("Valid token", func(t *testing.T) {
|
||||
md := map[string]string{"foo": "bar"}
|
||||
roles := []string{"admin"}
|
||||
scopes := []string{"admin"}
|
||||
subject := "test"
|
||||
|
||||
tok, err := b.Generate(&auth.Account{ID: subject, Roles: roles, Metadata: md})
|
||||
tok, err := b.Generate(&auth.Account{ID: subject, Scopes: scopes, Metadata: md})
|
||||
if err != nil {
|
||||
t.Fatalf("Generate returned %v error, expected nil", err)
|
||||
}
|
||||
@@ -47,8 +47,8 @@ func TestInspect(t *testing.T) {
|
||||
if tok2.ID != subject {
|
||||
t.Errorf("Inspect returned %v as the token subject, expected %v", tok2.ID, subject)
|
||||
}
|
||||
if len(tok2.Roles) != len(roles) {
|
||||
t.Errorf("Inspect returned %v roles, expected %v", len(tok2.Roles), len(roles))
|
||||
if len(tok2.Scopes) != len(scopes) {
|
||||
t.Errorf("Inspect returned %v scopes, expected %v", len(tok2.Scopes), len(scopes))
|
||||
}
|
||||
if len(tok2.Metadata) != len(md) {
|
||||
t.Errorf("Inspect returned %v as the token metadata, expected %v", tok2.Metadata, md)
|
||||
|
@@ -11,11 +11,9 @@ import (
|
||||
|
||||
// authClaims to be encoded in the JWT
|
||||
type authClaims struct {
|
||||
Type string `json:"type"`
|
||||
Roles []string `json:"roles"`
|
||||
Provider string `json:"provider"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
Namespace string `json:"namespace"`
|
||||
Type string `json:"type"`
|
||||
Scopes []string `json:"scopes"`
|
||||
Metadata map[string]string `json:"metadata"`
|
||||
|
||||
jwt.StandardClaims
|
||||
}
|
||||
@@ -52,8 +50,9 @@ func (j *JWT) Generate(acc *auth.Account, opts ...token.GenerateOption) (*token.
|
||||
// generate the JWT
|
||||
expiry := time.Now().Add(options.Expiry)
|
||||
t := jwt.NewWithClaims(jwt.SigningMethodRS256, authClaims{
|
||||
acc.Type, acc.Roles, acc.Provider, acc.Metadata, acc.Namespace, jwt.StandardClaims{
|
||||
acc.Type, acc.Scopes, acc.Metadata, jwt.StandardClaims{
|
||||
Subject: acc.ID,
|
||||
Issuer: acc.Issuer,
|
||||
ExpiresAt: expiry.Unix(),
|
||||
},
|
||||
})
|
||||
@@ -97,12 +96,11 @@ func (j *JWT) Inspect(t string) (*auth.Account, error) {
|
||||
|
||||
// return the token
|
||||
return &auth.Account{
|
||||
ID: claims.Subject,
|
||||
Type: claims.Type,
|
||||
Roles: claims.Roles,
|
||||
Provider: claims.Provider,
|
||||
Metadata: claims.Metadata,
|
||||
Namespace: claims.Namespace,
|
||||
ID: claims.Subject,
|
||||
Issuer: claims.Issuer,
|
||||
Type: claims.Type,
|
||||
Scopes: claims.Scopes,
|
||||
Metadata: claims.Metadata,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
@@ -42,10 +42,10 @@ func TestInspect(t *testing.T) {
|
||||
|
||||
t.Run("Valid token", func(t *testing.T) {
|
||||
md := map[string]string{"foo": "bar"}
|
||||
roles := []string{"admin"}
|
||||
scopes := []string{"admin"}
|
||||
subject := "test"
|
||||
|
||||
acc := &auth.Account{ID: subject, Roles: roles, Metadata: md}
|
||||
acc := &auth.Account{ID: subject, Scopes: scopes, Metadata: md}
|
||||
tok, err := j.Generate(acc)
|
||||
if err != nil {
|
||||
t.Fatalf("Generate returned %v error, expected nil", err)
|
||||
@@ -58,8 +58,8 @@ func TestInspect(t *testing.T) {
|
||||
if acc.ID != subject {
|
||||
t.Errorf("Inspect returned %v as the token subject, expected %v", acc.ID, subject)
|
||||
}
|
||||
if len(tok2.Roles) != len(roles) {
|
||||
t.Errorf("Inspect returned %v roles, expected %v", len(tok2.Roles), len(roles))
|
||||
if len(tok2.Scopes) != len(scopes) {
|
||||
t.Errorf("Inspect returned %v scopes, expected %v", len(tok2.Scopes), len(scopes))
|
||||
}
|
||||
if len(tok2.Metadata) != len(md) {
|
||||
t.Errorf("Inspect returned %v as the token metadata, expected %v", tok2.Metadata, md)
|
||||
|
66
client/cache.go
Normal file
66
client/cache.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/metadata"
|
||||
cache "github.com/patrickmn/go-cache"
|
||||
)
|
||||
|
||||
// NewCache returns an initialised cache.
|
||||
func NewCache() *Cache {
|
||||
return &Cache{
|
||||
cache: cache.New(cache.NoExpiration, 30*time.Second),
|
||||
}
|
||||
}
|
||||
|
||||
// Cache for responses
|
||||
type Cache struct {
|
||||
cache *cache.Cache
|
||||
}
|
||||
|
||||
// Get a response from the cache
|
||||
func (c *Cache) Get(ctx context.Context, req *Request) (interface{}, bool) {
|
||||
return c.cache.Get(key(ctx, req))
|
||||
}
|
||||
|
||||
// Set a response in the cache
|
||||
func (c *Cache) Set(ctx context.Context, req *Request, rsp interface{}, expiry time.Duration) {
|
||||
c.cache.Set(key(ctx, req), rsp, expiry)
|
||||
}
|
||||
|
||||
// List the key value pairs in the cache
|
||||
func (c *Cache) List() map[string]string {
|
||||
items := c.cache.Items()
|
||||
|
||||
rsp := make(map[string]string, len(items))
|
||||
for k, v := range items {
|
||||
bytes, _ := json.Marshal(v.Object)
|
||||
rsp[k] = string(bytes)
|
||||
}
|
||||
|
||||
return rsp
|
||||
}
|
||||
|
||||
// key returns a hash for the context and request
|
||||
func key(ctx context.Context, req *Request) string {
|
||||
ns, _ := metadata.Get(ctx, "Micro-Namespace")
|
||||
|
||||
bytes, _ := json.Marshal(map[string]interface{}{
|
||||
"namespace": ns,
|
||||
"request": map[string]interface{}{
|
||||
"service": (*req).Service(),
|
||||
"endpoint": (*req).Endpoint(),
|
||||
"method": (*req).Method(),
|
||||
"body": (*req).Body(),
|
||||
},
|
||||
})
|
||||
|
||||
h := fnv.New64()
|
||||
h.Write(bytes)
|
||||
return fmt.Sprintf("%x", h.Sum(nil))
|
||||
}
|
76
client/cache_test.go
Normal file
76
client/cache_test.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/metadata"
|
||||
)
|
||||
|
||||
func TestCache(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
req := NewRequest("go.micro.service.foo", "Foo.Bar", nil)
|
||||
|
||||
t.Run("CacheMiss", func(t *testing.T) {
|
||||
if _, ok := NewCache().Get(ctx, &req); ok {
|
||||
t.Errorf("Expected to get no result from Get")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("CacheHit", func(t *testing.T) {
|
||||
c := NewCache()
|
||||
|
||||
rsp := "theresponse"
|
||||
c.Set(ctx, &req, rsp, time.Minute)
|
||||
|
||||
if res, ok := c.Get(ctx, &req); !ok {
|
||||
t.Errorf("Expected a result, got nothing")
|
||||
} else if res != rsp {
|
||||
t.Errorf("Expected '%v' result, got '%v'", rsp, res)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestCacheKey(t *testing.T) {
|
||||
ctx := context.TODO()
|
||||
req1 := NewRequest("go.micro.service.foo", "Foo.Bar", nil)
|
||||
req2 := NewRequest("go.micro.service.foo", "Foo.Baz", nil)
|
||||
req3 := NewRequest("go.micro.service.foo", "Foo.Baz", "customquery")
|
||||
|
||||
t.Run("IdenticalRequests", func(t *testing.T) {
|
||||
key1 := key(ctx, &req1)
|
||||
key2 := key(ctx, &req1)
|
||||
if key1 != key2 {
|
||||
t.Errorf("Expected the keys to match for identical requests and context")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DifferentRequestEndpoints", func(t *testing.T) {
|
||||
key1 := key(ctx, &req1)
|
||||
key2 := key(ctx, &req2)
|
||||
|
||||
if key1 == key2 {
|
||||
t.Errorf("Expected the keys to differ for different request endpoints")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DifferentRequestBody", func(t *testing.T) {
|
||||
key1 := key(ctx, &req2)
|
||||
key2 := key(ctx, &req3)
|
||||
|
||||
if key1 == key2 {
|
||||
t.Errorf("Expected the keys to differ for different request bodies")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("DifferentMetadata", func(t *testing.T) {
|
||||
mdCtx := metadata.Set(context.TODO(), "Micro-Namespace", "bar")
|
||||
key1 := key(mdCtx, &req1)
|
||||
key2 := key(ctx, &req1)
|
||||
|
||||
if key1 == key2 {
|
||||
t.Errorf("Expected the keys to differ for different metadata")
|
||||
}
|
||||
})
|
||||
}
|
@@ -6,6 +6,7 @@ import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
@@ -173,7 +174,7 @@ func (g *grpcClient) call(ctx context.Context, node *registry.Node, req client.R
|
||||
return grr
|
||||
}
|
||||
|
||||
func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client.Request, opts client.CallOptions) (client.Stream, error) {
|
||||
func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client.Request, rsp interface{}, opts client.CallOptions) error {
|
||||
var header map[string]string
|
||||
|
||||
address := node.Address
|
||||
@@ -199,7 +200,7 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
|
||||
|
||||
cf, err := g.newGRPCCodec(req.ContentType())
|
||||
if err != nil {
|
||||
return nil, errors.InternalServerError("go.micro.client", err.Error())
|
||||
return errors.InternalServerError("go.micro.client", err.Error())
|
||||
}
|
||||
|
||||
var dialCtx context.Context
|
||||
@@ -224,7 +225,7 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
|
||||
|
||||
cc, err := grpc.DialContext(dialCtx, address, grpcDialOptions...)
|
||||
if err != nil {
|
||||
return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
|
||||
return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error sending request: %v", err))
|
||||
}
|
||||
|
||||
desc := &grpc.StreamDesc{
|
||||
@@ -252,7 +253,7 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
|
||||
// close the connection
|
||||
cc.Close()
|
||||
// now return the error
|
||||
return nil, errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err))
|
||||
return errors.InternalServerError("go.micro.client", fmt.Sprintf("Error creating stream: %v", err))
|
||||
}
|
||||
|
||||
codec := &grpcCodec{
|
||||
@@ -265,21 +266,25 @@ func (g *grpcClient) stream(ctx context.Context, node *registry.Node, req client
|
||||
r.codec = codec
|
||||
}
|
||||
|
||||
rsp := &response{
|
||||
conn: cc,
|
||||
// setup the stream response
|
||||
stream := &grpcStream{
|
||||
context: ctx,
|
||||
request: req,
|
||||
response: &response{
|
||||
conn: cc,
|
||||
stream: st,
|
||||
codec: cf,
|
||||
gcodec: codec,
|
||||
},
|
||||
stream: st,
|
||||
codec: cf,
|
||||
gcodec: codec,
|
||||
conn: cc,
|
||||
cancel: cancel,
|
||||
}
|
||||
|
||||
return &grpcStream{
|
||||
context: ctx,
|
||||
request: req,
|
||||
response: rsp,
|
||||
stream: st,
|
||||
conn: cc,
|
||||
cancel: cancel,
|
||||
}, nil
|
||||
// set the stream as the response
|
||||
val := reflect.ValueOf(rsp).Elem()
|
||||
val.Set(reflect.ValueOf(stream).Elem())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (g *grpcClient) poolMaxStreams() int {
|
||||
@@ -506,6 +511,14 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli
|
||||
default:
|
||||
}
|
||||
|
||||
// make a copy of stream
|
||||
gstream := g.stream
|
||||
|
||||
// wrap the call in reverse
|
||||
for i := len(callOpts.CallWrappers); i > 0; i-- {
|
||||
gstream = callOpts.CallWrappers[i-1](gstream)
|
||||
}
|
||||
|
||||
call := func(i int) (client.Stream, error) {
|
||||
// call backoff first. Someone may want an initial start delay
|
||||
t, err := callOpts.Backoff(ctx, req, i)
|
||||
@@ -527,7 +540,10 @@ func (g *grpcClient) Stream(ctx context.Context, req client.Request, opts ...cli
|
||||
return nil, errors.InternalServerError("go.micro.client", "error selecting %s node: %s", service, err.Error())
|
||||
}
|
||||
|
||||
stream, err := g.stream(ctx, node, req, callOpts)
|
||||
// make the call
|
||||
stream := &grpcStream{}
|
||||
err = g.stream(ctx, node, req, stream, callOpts)
|
||||
|
||||
g.opts.Selector.Mark(service, node, err)
|
||||
return stream, err
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/client/selector"
|
||||
"github.com/micro/go-micro/v2/codec"
|
||||
@@ -17,7 +16,6 @@ type Options struct {
|
||||
ContentType string
|
||||
|
||||
// Plugged interfaces
|
||||
Auth auth.Auth
|
||||
Broker broker.Broker
|
||||
Codecs map[string]codec.NewCodec
|
||||
Registry registry.Registry
|
||||
@@ -31,6 +29,9 @@ type Options struct {
|
||||
PoolSize int
|
||||
PoolTTL time.Duration
|
||||
|
||||
// Response cache
|
||||
Cache *Cache
|
||||
|
||||
// Middleware for client
|
||||
Wrappers []Wrapper
|
||||
|
||||
@@ -61,6 +62,8 @@ type CallOptions struct {
|
||||
StreamTimeout time.Duration
|
||||
// Use the services own auth token
|
||||
ServiceToken bool
|
||||
// Duration to cache the response for
|
||||
CacheExpiry time.Duration
|
||||
|
||||
// Middleware for low level call func
|
||||
CallWrappers []CallWrapper
|
||||
@@ -93,6 +96,7 @@ type RequestOptions struct {
|
||||
|
||||
func NewOptions(options ...Option) Options {
|
||||
opts := Options{
|
||||
Cache: NewCache(),
|
||||
Context: context.Background(),
|
||||
ContentType: DefaultContentType,
|
||||
Codecs: make(map[string]codec.NewCodec),
|
||||
@@ -105,7 +109,6 @@ func NewOptions(options ...Option) Options {
|
||||
},
|
||||
PoolSize: DefaultPoolSize,
|
||||
PoolTTL: DefaultPoolTTL,
|
||||
Auth: auth.DefaultAuth,
|
||||
Broker: broker.DefaultBroker,
|
||||
Selector: selector.DefaultSelector,
|
||||
Registry: registry.DefaultRegistry,
|
||||
@@ -126,13 +129,6 @@ func Broker(b broker.Broker) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// Auth to be used when making a request
|
||||
func Auth(a auth.Auth) Option {
|
||||
return func(o *Options) {
|
||||
o.Auth = a
|
||||
}
|
||||
}
|
||||
|
||||
// Codec to be used to encode/decode requests for a given content type
|
||||
func Codec(contentType string, c codec.NewCodec) Option {
|
||||
return func(o *Options) {
|
||||
@@ -334,6 +330,14 @@ func WithServiceToken() CallOption {
|
||||
}
|
||||
}
|
||||
|
||||
// WithCache is a CallOption which sets the duration the response
|
||||
// shoull be cached for
|
||||
func WithCache(c time.Duration) CallOption {
|
||||
return func(o *CallOptions) {
|
||||
o.CacheExpiry = c
|
||||
}
|
||||
}
|
||||
|
||||
func WithMessageContentType(ct string) MessageOption {
|
||||
return func(o *MessageOptions) {
|
||||
o.ContentType = ct
|
||||
|
@@ -114,8 +114,7 @@ func (r *rpcClient) call(ctx context.Context, node *registry.Node, req Request,
|
||||
return errors.InternalServerError("go.micro.client", "connection error: %v", err)
|
||||
}
|
||||
|
||||
seq := atomic.LoadUint64(&r.seq)
|
||||
atomic.AddUint64(&r.seq, 1)
|
||||
seq := atomic.AddUint64(&r.seq, 1) - 1
|
||||
codec := newRpcCodec(msg, c, cf, "")
|
||||
|
||||
rsp := &rpcResponse{
|
||||
@@ -232,8 +231,7 @@ func (r *rpcClient) stream(ctx context.Context, node *registry.Node, req Request
|
||||
}
|
||||
|
||||
// increment the sequence number
|
||||
seq := atomic.LoadUint64(&r.seq)
|
||||
atomic.AddUint64(&r.seq, 1)
|
||||
seq := atomic.AddUint64(&r.seq, 1) - 1
|
||||
id := fmt.Sprintf("%v", seq)
|
||||
|
||||
// create codec with stream id
|
||||
|
@@ -130,15 +130,15 @@ func (r *rpcStream) Error() error {
|
||||
}
|
||||
|
||||
func (r *rpcStream) Close() error {
|
||||
r.RLock()
|
||||
r.Lock()
|
||||
|
||||
select {
|
||||
case <-r.closed:
|
||||
r.RUnlock()
|
||||
r.Unlock()
|
||||
return nil
|
||||
default:
|
||||
close(r.closed)
|
||||
r.RUnlock()
|
||||
r.Unlock()
|
||||
|
||||
// send the end of stream message
|
||||
if r.sendEOS {
|
||||
|
@@ -11,8 +11,10 @@ import (
|
||||
"github.com/micro/go-micro/v2/auth/provider"
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/client/grpc"
|
||||
"github.com/micro/go-micro/v2/client/selector"
|
||||
"github.com/micro/go-micro/v2/config"
|
||||
configSrc "github.com/micro/go-micro/v2/config/source"
|
||||
configSrv "github.com/micro/go-micro/v2/config/source/service"
|
||||
"github.com/micro/go-micro/v2/debug/profile"
|
||||
"github.com/micro/go-micro/v2/debug/profile/http"
|
||||
@@ -20,10 +22,13 @@ import (
|
||||
"github.com/micro/go-micro/v2/debug/trace"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
registrySrv "github.com/micro/go-micro/v2/registry/service"
|
||||
"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"
|
||||
authutil "github.com/micro/go-micro/v2/util/auth"
|
||||
"github.com/micro/go-micro/v2/util/wrapper"
|
||||
|
||||
// clients
|
||||
cgrpc "github.com/micro/go-micro/v2/client/grpc"
|
||||
@@ -270,6 +275,12 @@ var (
|
||||
EnvVars: []string{"MICRO_AUTH_SECRET"},
|
||||
Usage: "Account secret used for client authentication",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_namespace",
|
||||
EnvVars: []string{"MICRO_AUTH_NAMESPACE"},
|
||||
Usage: "Namespace for the services auth account",
|
||||
Value: "go.micro",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "auth_public_key",
|
||||
EnvVars: []string{"MICRO_AUTH_PUBLIC_KEY"},
|
||||
@@ -458,10 +469,17 @@ func (c *cmd) Options() Options {
|
||||
|
||||
func (c *cmd) Before(ctx *cli.Context) error {
|
||||
// If flags are set then use them otherwise do nothing
|
||||
var authOpts []auth.Option
|
||||
var serverOpts []server.Option
|
||||
var clientOpts []client.Option
|
||||
|
||||
// setup a client to use when calling the runtime. It is important the auth client is wrapped
|
||||
// after the cache client since the wrappers are applied in reverse order and the cache will use
|
||||
// some of the headers set by the auth client.
|
||||
authFn := func() auth.Auth { return *c.opts.Auth }
|
||||
cacheFn := func() *client.Cache { return (*c.opts.Client).Options().Cache }
|
||||
microClient := wrapper.CacheClient(cacheFn, grpc.NewClient())
|
||||
microClient = wrapper.AuthClient(authFn, microClient)
|
||||
|
||||
// Set the store
|
||||
if name := ctx.String("store"); len(name) > 0 {
|
||||
s, ok := c.opts.Stores[name]
|
||||
@@ -469,7 +487,7 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
return fmt.Errorf("Unsupported store: %s", name)
|
||||
}
|
||||
|
||||
*c.opts.Store = s()
|
||||
*c.opts.Store = s(store.WithClient(microClient))
|
||||
}
|
||||
|
||||
// Set the runtime
|
||||
@@ -479,7 +497,7 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
return fmt.Errorf("Unsupported runtime: %s", name)
|
||||
}
|
||||
|
||||
*c.opts.Runtime = r()
|
||||
*c.opts.Runtime = r(runtime.WithClient(microClient))
|
||||
}
|
||||
|
||||
// Set the tracer
|
||||
@@ -492,28 +510,6 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
*c.opts.Tracer = r()
|
||||
}
|
||||
|
||||
// Set the auth
|
||||
if name := ctx.String("auth"); len(name) > 0 {
|
||||
a, ok := c.opts.Auths[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Unsupported auth: %s", name)
|
||||
}
|
||||
|
||||
*c.opts.Auth = a()
|
||||
clientOpts = append(clientOpts, client.Auth(*c.opts.Auth))
|
||||
serverOpts = append(serverOpts, server.Auth(*c.opts.Auth))
|
||||
}
|
||||
|
||||
// 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
|
||||
@@ -530,16 +526,58 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Set the broker
|
||||
if name := ctx.String("broker"); len(name) > 0 && (*c.opts.Broker).String() != name {
|
||||
b, ok := c.opts.Brokers[name]
|
||||
// Setup auth
|
||||
authOpts := []auth.Option{auth.WithClient(microClient)}
|
||||
|
||||
if len(ctx.String("auth_id")) > 0 || len(ctx.String("auth_secret")) > 0 {
|
||||
authOpts = append(authOpts, auth.Credentials(
|
||||
ctx.String("auth_id"), ctx.String("auth_secret"),
|
||||
))
|
||||
}
|
||||
if len(ctx.String("auth_public_key")) > 0 {
|
||||
authOpts = append(authOpts, auth.PublicKey(ctx.String("auth_public_key")))
|
||||
}
|
||||
if len(ctx.String("auth_private_key")) > 0 {
|
||||
authOpts = append(authOpts, auth.PrivateKey(ctx.String("auth_private_key")))
|
||||
}
|
||||
if len(ctx.String("auth_namespace")) > 0 {
|
||||
authOpts = append(authOpts, auth.Namespace(ctx.String("auth_namespace")))
|
||||
}
|
||||
if name := ctx.String("auth_provider"); len(name) > 0 {
|
||||
p, ok := DefaultAuthProviders[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Broker %s not found", name)
|
||||
return fmt.Errorf("AuthProvider %s not found", name)
|
||||
}
|
||||
|
||||
*c.opts.Broker = b()
|
||||
serverOpts = append(serverOpts, server.Broker(*c.opts.Broker))
|
||||
clientOpts = append(clientOpts, client.Broker(*c.opts.Broker))
|
||||
var provOpts []provider.Option
|
||||
clientID := ctx.String("auth_provider_client_id")
|
||||
clientSecret := ctx.String("auth_provider_client_secret")
|
||||
if len(clientID) > 0 || len(clientSecret) > 0 {
|
||||
provOpts = append(provOpts, provider.Credentials(clientID, clientSecret))
|
||||
}
|
||||
if e := ctx.String("auth_provider_endpoint"); len(e) > 0 {
|
||||
provOpts = append(provOpts, provider.Endpoint(e))
|
||||
}
|
||||
if r := ctx.String("auth_provider_redirect"); len(r) > 0 {
|
||||
provOpts = append(provOpts, provider.Redirect(r))
|
||||
}
|
||||
if s := ctx.String("auth_provider_scope"); len(s) > 0 {
|
||||
provOpts = append(provOpts, provider.Scope(s))
|
||||
}
|
||||
|
||||
authOpts = append(authOpts, auth.Provider(p(provOpts...)))
|
||||
}
|
||||
|
||||
// Set the auth
|
||||
if name := ctx.String("auth"); len(name) > 0 {
|
||||
a, ok := c.opts.Auths[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Unsupported auth: %s", name)
|
||||
}
|
||||
*c.opts.Auth = a(authOpts...)
|
||||
serverOpts = append(serverOpts, server.Auth(*c.opts.Auth))
|
||||
} else {
|
||||
(*c.opts.Auth).Init(authOpts...)
|
||||
}
|
||||
|
||||
// Set the registry
|
||||
@@ -549,7 +587,7 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
return fmt.Errorf("Registry %s not found", name)
|
||||
}
|
||||
|
||||
*c.opts.Registry = r()
|
||||
*c.opts.Registry = r(registrySrv.WithClient(microClient))
|
||||
serverOpts = append(serverOpts, server.Registry(*c.opts.Registry))
|
||||
clientOpts = append(clientOpts, client.Registry(*c.opts.Registry))
|
||||
|
||||
@@ -564,6 +602,34 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
// generate the services auth account
|
||||
serverID := (*c.opts.Server).Options().Id
|
||||
if err := authutil.Generate(serverID, c.App().Name, (*c.opts.Auth)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 broker
|
||||
if name := ctx.String("broker"); len(name) > 0 && (*c.opts.Broker).String() != name {
|
||||
b, ok := c.opts.Brokers[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Broker %s not found", name)
|
||||
}
|
||||
|
||||
*c.opts.Broker = b()
|
||||
serverOpts = append(serverOpts, server.Broker(*c.opts.Broker))
|
||||
clientOpts = append(clientOpts, client.Broker(*c.opts.Broker))
|
||||
}
|
||||
|
||||
// Set the selector
|
||||
if name := ctx.String("selector"); len(name) > 0 && (*c.opts.Selector).String() != name {
|
||||
s, ok := c.opts.Selectors[name]
|
||||
@@ -675,48 +741,8 @@ func (c *cmd) Before(ctx *cli.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
if len(ctx.String("auth_id")) > 0 || len(ctx.String("auth_secret")) > 0 {
|
||||
authOpts = append(authOpts, auth.Credentials(
|
||||
ctx.String("auth_id"), ctx.String("auth_secret"),
|
||||
))
|
||||
}
|
||||
|
||||
if len(ctx.String("auth_public_key")) > 0 {
|
||||
authOpts = append(authOpts, auth.PublicKey(ctx.String("auth_public_key")))
|
||||
}
|
||||
if len(ctx.String("auth_private_key")) > 0 {
|
||||
authOpts = append(authOpts, auth.PrivateKey(ctx.String("auth_private_key")))
|
||||
}
|
||||
|
||||
if name := ctx.String("auth_provider"); len(name) > 0 {
|
||||
p, ok := DefaultAuthProviders[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("AuthProvider %s not found", name)
|
||||
}
|
||||
|
||||
var provOpts []provider.Option
|
||||
|
||||
clientID := ctx.String("auth_provider_client_id")
|
||||
clientSecret := ctx.String("auth_provider_client_secret")
|
||||
if len(clientID) > 0 || len(clientSecret) > 0 {
|
||||
provOpts = append(provOpts, provider.Credentials(clientID, clientSecret))
|
||||
}
|
||||
if e := ctx.String("auth_provider_endpoint"); len(e) > 0 {
|
||||
provOpts = append(provOpts, provider.Endpoint(e))
|
||||
}
|
||||
if r := ctx.String("auth_provider_redirect"); len(r) > 0 {
|
||||
provOpts = append(provOpts, provider.Redirect(r))
|
||||
}
|
||||
if s := ctx.String("auth_provider_scope"); len(s) > 0 {
|
||||
provOpts = append(provOpts, provider.Scope(s))
|
||||
}
|
||||
|
||||
authOpts = append(authOpts, auth.Provider(p(provOpts...)))
|
||||
}
|
||||
(*c.opts.Auth).Init(authOpts...)
|
||||
|
||||
if ctx.String("config") == "service" {
|
||||
opt := config.WithSource(configSrv.NewSource())
|
||||
opt := config.WithSource(configSrv.NewSource(configSrc.WithClient(microClient)))
|
||||
if err := (*c.opts.Config).Init(opt); err != nil {
|
||||
logger.Fatalf("Error configuring config: %v", err)
|
||||
}
|
||||
|
@@ -100,6 +100,12 @@ func Registry(r *registry.Registry) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func Runtime(r *runtime.Runtime) Option {
|
||||
return func(o *Options) {
|
||||
o.Runtime = r
|
||||
}
|
||||
}
|
||||
|
||||
func Transport(t *transport.Transport) Option {
|
||||
return func(o *Options) {
|
||||
o.Transport = t
|
||||
|
@@ -3,6 +3,7 @@ package source
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/config/encoder"
|
||||
"github.com/micro/go-micro/v2/config/encoder/json"
|
||||
)
|
||||
@@ -13,6 +14,9 @@ type Options struct {
|
||||
|
||||
// for alternative data
|
||||
Context context.Context
|
||||
|
||||
// Client to use for RPC
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
type Option func(o *Options)
|
||||
@@ -21,6 +25,7 @@ func NewOptions(opts ...Option) Options {
|
||||
options := Options{
|
||||
Encoder: json.NewEncoder(),
|
||||
Context: context.Background(),
|
||||
Client: client.DefaultClient,
|
||||
}
|
||||
|
||||
for _, o := range opts {
|
||||
@@ -36,3 +41,10 @@ func WithEncoder(e encoder.Encoder) Option {
|
||||
o.Encoder = e
|
||||
}
|
||||
}
|
||||
|
||||
// WithClient sets the source client
|
||||
func WithClient(c client.Client) Option {
|
||||
return func(o *Options) {
|
||||
o.Client = c
|
||||
}
|
||||
}
|
||||
|
@@ -2,10 +2,12 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"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/errors"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
@@ -24,12 +26,14 @@ type service struct {
|
||||
}
|
||||
|
||||
func (m *service) Read() (set *source.ChangeSet, err error) {
|
||||
client := proto.NewConfigService(m.serviceName, client.DefaultClient)
|
||||
client := proto.NewConfigService(m.serviceName, m.opts.Client)
|
||||
req, err := client.Read(context.Background(), &proto.ReadRequest{
|
||||
Namespace: m.namespace,
|
||||
Path: m.path,
|
||||
})
|
||||
if err != nil {
|
||||
if verr, ok := err.(*errors.Error); ok && verr.Code == http.StatusNotFound {
|
||||
return nil, nil
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -37,7 +41,7 @@ func (m *service) Read() (set *source.ChangeSet, err error) {
|
||||
}
|
||||
|
||||
func (m *service) Watch() (w source.Watcher, err error) {
|
||||
client := proto.NewConfigService(m.serviceName, client.DefaultClient)
|
||||
client := proto.NewConfigService(m.serviceName, m.opts.Client)
|
||||
stream, err := client.Watch(context.Background(), &proto.WatchRequest{
|
||||
Namespace: m.namespace,
|
||||
Path: m.path,
|
||||
@@ -87,6 +91,10 @@ func NewSource(opts ...source.Option) source.Source {
|
||||
}
|
||||
}
|
||||
|
||||
if options.Client == nil {
|
||||
options.Client = client.DefaultClient
|
||||
}
|
||||
|
||||
s := &service{
|
||||
serviceName: addr,
|
||||
opts: options,
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/debug/log"
|
||||
proto "github.com/micro/go-micro/v2/debug/service/proto"
|
||||
"github.com/micro/go-micro/v2/debug/stats"
|
||||
@@ -13,11 +14,12 @@ import (
|
||||
)
|
||||
|
||||
// NewHandler returns an instance of the Debug Handler
|
||||
func NewHandler() *Debug {
|
||||
func NewHandler(c client.Client) *Debug {
|
||||
return &Debug{
|
||||
log: log.DefaultLog,
|
||||
stats: stats.DefaultStats,
|
||||
trace: trace.DefaultTracer,
|
||||
cache: c.Options().Cache,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +32,8 @@ type Debug struct {
|
||||
stats stats.Stats
|
||||
// the tracer
|
||||
trace trace.Tracer
|
||||
// the cache
|
||||
cache *client.Cache
|
||||
}
|
||||
|
||||
func (d *Debug) Health(ctx context.Context, req *proto.HealthRequest, rsp *proto.HealthResponse) error {
|
||||
@@ -164,3 +168,9 @@ func (d *Debug) Log(ctx context.Context, stream server.Stream) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Cache returns all the key value pairs in the client cache
|
||||
func (d *Debug) Cache(ctx context.Context, req *proto.CacheRequest, rsp *proto.CacheResponse) error {
|
||||
rsp.Values = d.cache.List()
|
||||
return nil
|
||||
}
|
||||
|
@@ -582,6 +582,76 @@ func (m *Span) GetType() SpanType {
|
||||
return SpanType_INBOUND
|
||||
}
|
||||
|
||||
type CacheRequest struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CacheRequest) Reset() { *m = CacheRequest{} }
|
||||
func (m *CacheRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*CacheRequest) ProtoMessage() {}
|
||||
func (*CacheRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_df91f41a5db378e6, []int{9}
|
||||
}
|
||||
|
||||
func (m *CacheRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CacheRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *CacheRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CacheRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *CacheRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CacheRequest.Merge(m, src)
|
||||
}
|
||||
func (m *CacheRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_CacheRequest.Size(m)
|
||||
}
|
||||
func (m *CacheRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CacheRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CacheRequest proto.InternalMessageInfo
|
||||
|
||||
type CacheResponse struct {
|
||||
Values map[string]string `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CacheResponse) Reset() { *m = CacheResponse{} }
|
||||
func (m *CacheResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*CacheResponse) ProtoMessage() {}
|
||||
func (*CacheResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_df91f41a5db378e6, []int{10}
|
||||
}
|
||||
|
||||
func (m *CacheResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CacheResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *CacheResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CacheResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *CacheResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CacheResponse.Merge(m, src)
|
||||
}
|
||||
func (m *CacheResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_CacheResponse.Size(m)
|
||||
}
|
||||
func (m *CacheResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CacheResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CacheResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *CacheResponse) GetValues() map[string]string {
|
||||
if m != nil {
|
||||
return m.Values
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterEnum("SpanType", SpanType_name, SpanType_value)
|
||||
proto.RegisterType((*HealthRequest)(nil), "HealthRequest")
|
||||
@@ -595,50 +665,56 @@ func init() {
|
||||
proto.RegisterType((*TraceResponse)(nil), "TraceResponse")
|
||||
proto.RegisterType((*Span)(nil), "Span")
|
||||
proto.RegisterMapType((map[string]string)(nil), "Span.MetadataEntry")
|
||||
proto.RegisterType((*CacheRequest)(nil), "CacheRequest")
|
||||
proto.RegisterType((*CacheResponse)(nil), "CacheResponse")
|
||||
proto.RegisterMapType((map[string]string)(nil), "CacheResponse.ValuesEntry")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("debug/service/proto/debug.proto", fileDescriptor_df91f41a5db378e6) }
|
||||
|
||||
var fileDescriptor_df91f41a5db378e6 = []byte{
|
||||
// 594 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xdb, 0x6e, 0xd3, 0x40,
|
||||
0x10, 0x8d, 0xed, 0x38, 0xb1, 0xa7, 0x8d, 0xa9, 0x96, 0x8b, 0x2c, 0x73, 0x69, 0x65, 0x09, 0x29,
|
||||
0x5c, 0xe4, 0x40, 0x79, 0x41, 0xf0, 0x86, 0x8a, 0x04, 0x52, 0x69, 0xa5, 0x6d, 0xfb, 0x01, 0x5b,
|
||||
0x7b, 0xe4, 0x1a, 0xea, 0x0b, 0xbb, 0xeb, 0x4a, 0xf9, 0x16, 0xbe, 0x80, 0x37, 0x7e, 0x86, 0xff,
|
||||
0x41, 0x7b, 0x71, 0x1b, 0x0b, 0xa1, 0x3e, 0xf0, 0xb6, 0xe7, 0xec, 0xec, 0xc9, 0xcc, 0xc9, 0xf1,
|
||||
0xc0, 0x6e, 0x81, 0xe7, 0x7d, 0xb9, 0x12, 0xc8, 0xaf, 0xaa, 0x1c, 0x57, 0x1d, 0x6f, 0x65, 0xbb,
|
||||
0xd2, 0x5c, 0xa6, 0xcf, 0xe9, 0x33, 0x58, 0x7c, 0x42, 0x76, 0x29, 0x2f, 0x28, 0x7e, 0xef, 0x51,
|
||||
0x48, 0x12, 0xc3, 0xdc, 0x56, 0xc7, 0xce, 0x9e, 0xb3, 0x0c, 0xe9, 0x00, 0xd3, 0x25, 0x44, 0x43,
|
||||
0xa9, 0xe8, 0xda, 0x46, 0x20, 0x79, 0x00, 0x33, 0x21, 0x99, 0xec, 0x85, 0x2d, 0xb5, 0x28, 0x5d,
|
||||
0xc2, 0xf6, 0x89, 0x64, 0x52, 0xdc, 0xae, 0xf9, 0xdb, 0x81, 0x85, 0x2d, 0xb5, 0x9a, 0x8f, 0x20,
|
||||
0x94, 0x55, 0x8d, 0x42, 0xb2, 0xba, 0xd3, 0xd5, 0x53, 0x7a, 0x43, 0x68, 0x25, 0xc9, 0xb8, 0xc4,
|
||||
0x22, 0x76, 0xf5, 0xdd, 0x00, 0x55, 0x2f, 0x7d, 0xa7, 0x0a, 0x63, 0x4f, 0x5f, 0x58, 0xa4, 0xf8,
|
||||
0x1a, 0xeb, 0x96, 0xaf, 0xe3, 0xa9, 0xe1, 0x0d, 0x52, 0x4a, 0xf2, 0x82, 0x23, 0x2b, 0x44, 0xec,
|
||||
0x1b, 0x25, 0x0b, 0x49, 0x04, 0x6e, 0x99, 0xc7, 0x33, 0x4d, 0xba, 0x65, 0x4e, 0x12, 0x08, 0xb8,
|
||||
0x19, 0x44, 0xc4, 0x73, 0xcd, 0x5e, 0x63, 0xa5, 0x8e, 0x9c, 0xb7, 0x5c, 0xc4, 0x81, 0x51, 0x37,
|
||||
0x28, 0xfd, 0x0a, 0x70, 0xd8, 0x96, 0xb7, 0xce, 0x6f, 0x1c, 0xe4, 0xc8, 0x6a, 0x3d, 0x4e, 0x40,
|
||||
0x2d, 0x22, 0xf7, 0xc0, 0xcf, 0xdb, 0xbe, 0x91, 0x7a, 0x18, 0x8f, 0x1a, 0xa0, 0x58, 0x51, 0x35,
|
||||
0x39, 0xea, 0x51, 0x3c, 0x6a, 0x40, 0xfa, 0xcb, 0x81, 0x19, 0xc5, 0xbc, 0xe5, 0xc5, 0xdf, 0xe6,
|
||||
0x79, 0x9b, 0xe6, 0xbd, 0x86, 0xa0, 0x46, 0xc9, 0x0a, 0x26, 0x59, 0xec, 0xee, 0x79, 0xcb, 0xad,
|
||||
0xfd, 0xfb, 0x99, 0x79, 0x98, 0x7d, 0xb1, 0xfc, 0xc7, 0x46, 0xf2, 0x35, 0xbd, 0x2e, 0x53, 0x9d,
|
||||
0xd7, 0x28, 0x04, 0x2b, 0x8d, 0xad, 0x21, 0x1d, 0x60, 0xf2, 0x1e, 0x16, 0xa3, 0x47, 0x64, 0x07,
|
||||
0xbc, 0x6f, 0xb8, 0xb6, 0x03, 0xaa, 0xa3, 0x6a, 0xf7, 0x8a, 0x5d, 0xf6, 0xa8, 0x67, 0x0b, 0xa9,
|
||||
0x01, 0xef, 0xdc, 0xb7, 0x4e, 0xfa, 0x04, 0xb6, 0x4f, 0x39, 0xcb, 0x71, 0x30, 0x28, 0x02, 0xb7,
|
||||
0x2a, 0xec, 0x53, 0xb7, 0x2a, 0xd2, 0x97, 0xb0, 0xb0, 0xf7, 0x36, 0x15, 0x0f, 0xc1, 0x17, 0x1d,
|
||||
0x6b, 0x54, 0xd0, 0x54, 0xdf, 0x7e, 0x76, 0xd2, 0xb1, 0x86, 0x1a, 0x2e, 0xfd, 0xe1, 0xc2, 0x54,
|
||||
0x61, 0xf5, 0x83, 0x52, 0x3d, 0xb3, 0x4a, 0x06, 0x58, 0x71, 0x77, 0x10, 0x57, 0x9e, 0x77, 0x8c,
|
||||
0xa3, 0x35, 0x37, 0xa4, 0x16, 0x11, 0x02, 0xd3, 0x86, 0xd5, 0xc6, 0xdc, 0x90, 0xea, 0xf3, 0x66,
|
||||
0xde, 0xfc, 0x71, 0xde, 0x12, 0x08, 0x8a, 0x9e, 0x33, 0x59, 0xb5, 0x8d, 0xcd, 0xca, 0x35, 0x26,
|
||||
0xab, 0x0d, 0xa3, 0xe7, 0xba, 0xe1, 0xbb, 0xba, 0xe1, 0x7f, 0xda, 0xfc, 0x18, 0xa6, 0x72, 0xdd,
|
||||
0xa1, 0x0e, 0x51, 0xb4, 0x1f, 0xea, 0xe2, 0xd3, 0x75, 0x87, 0x54, 0xd3, 0xff, 0xe5, 0xf5, 0xf3,
|
||||
0xa7, 0x10, 0x0c, 0x72, 0x64, 0x0b, 0xe6, 0x9f, 0x8f, 0x3e, 0x1c, 0x9f, 0x1d, 0x1d, 0xec, 0x4c,
|
||||
0xc8, 0x36, 0x04, 0xc7, 0x67, 0xa7, 0x06, 0x39, 0xfb, 0x3f, 0x1d, 0xf0, 0x0f, 0xd4, 0x62, 0x20,
|
||||
0xbb, 0xe0, 0x1d, 0xb6, 0x25, 0xd9, 0xca, 0x6e, 0x12, 0x9c, 0xcc, 0x6d, 0x50, 0xd2, 0xc9, 0x2b,
|
||||
0x87, 0xbc, 0x80, 0x99, 0x59, 0x04, 0x24, 0xca, 0x46, 0xcb, 0x23, 0xb9, 0x93, 0x8d, 0x37, 0x44,
|
||||
0x3a, 0x21, 0x4b, 0xf0, 0xf5, 0x07, 0x4e, 0x16, 0xd9, 0xe6, 0x4e, 0x48, 0xa2, 0x6c, 0xf4, 0xdd,
|
||||
0x9b, 0x4a, 0xfd, 0xa7, 0x93, 0x45, 0xb6, 0x19, 0x8e, 0x24, 0xca, 0x46, 0x59, 0x48, 0x27, 0xe7,
|
||||
0x33, 0xbd, 0xbb, 0xde, 0xfc, 0x09, 0x00, 0x00, 0xff, 0xff, 0x6e, 0x42, 0x7f, 0x05, 0xde, 0x04,
|
||||
0x00, 0x00,
|
||||
// 646 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x54, 0xdb, 0x6e, 0xd3, 0x4a,
|
||||
0x14, 0x8d, 0xed, 0x38, 0xb1, 0x77, 0x62, 0x9f, 0x6a, 0xce, 0x45, 0x96, 0x0f, 0xd0, 0xca, 0x12,
|
||||
0x52, 0xb8, 0x68, 0x02, 0xe1, 0x85, 0xcb, 0x1b, 0x14, 0x09, 0xa4, 0xd2, 0x4a, 0xd3, 0x96, 0xf7,
|
||||
0xa9, 0x3d, 0x4a, 0x03, 0xf5, 0x85, 0x99, 0x71, 0xa5, 0xbc, 0xf0, 0x23, 0xfc, 0x04, 0xff, 0x82,
|
||||
0xf8, 0x1f, 0x34, 0x17, 0xb7, 0xb6, 0x10, 0xaa, 0x10, 0x6f, 0x5e, 0x6b, 0xaf, 0xd9, 0xd9, 0x7b,
|
||||
0x69, 0x65, 0xc3, 0x6e, 0xc1, 0xce, 0xda, 0xf5, 0x52, 0x30, 0x7e, 0xb9, 0xc9, 0xd9, 0xb2, 0xe1,
|
||||
0xb5, 0xac, 0x97, 0x9a, 0xc3, 0xfa, 0x3b, 0xbb, 0x07, 0xd1, 0x1b, 0x46, 0x2f, 0xe4, 0x39, 0x61,
|
||||
0x9f, 0x5a, 0x26, 0x24, 0x4a, 0x60, 0x6a, 0xd5, 0x89, 0xb3, 0xe7, 0x2c, 0x42, 0xd2, 0xc1, 0x6c,
|
||||
0x01, 0x71, 0x27, 0x15, 0x4d, 0x5d, 0x09, 0x86, 0xfe, 0x83, 0x89, 0x90, 0x54, 0xb6, 0xc2, 0x4a,
|
||||
0x2d, 0xca, 0x16, 0x30, 0x3f, 0x96, 0x54, 0x8a, 0x9b, 0x7b, 0x7e, 0x77, 0x20, 0xb2, 0x52, 0xdb,
|
||||
0xf3, 0x16, 0x84, 0x72, 0x53, 0x32, 0x21, 0x69, 0xd9, 0x68, 0xf5, 0x98, 0x5c, 0x13, 0xba, 0x93,
|
||||
0xa4, 0x5c, 0xb2, 0x22, 0x71, 0x75, 0xad, 0x83, 0x6a, 0x96, 0xb6, 0x51, 0xc2, 0xc4, 0xd3, 0x05,
|
||||
0x8b, 0x14, 0x5f, 0xb2, 0xb2, 0xe6, 0xdb, 0x64, 0x6c, 0x78, 0x83, 0x54, 0x27, 0x79, 0xce, 0x19,
|
||||
0x2d, 0x44, 0xe2, 0x9b, 0x4e, 0x16, 0xa2, 0x18, 0xdc, 0x75, 0x9e, 0x4c, 0x34, 0xe9, 0xae, 0x73,
|
||||
0x94, 0x42, 0xc0, 0xcd, 0x22, 0x22, 0x99, 0x6a, 0xf6, 0x0a, 0xab, 0xee, 0x8c, 0xf3, 0x9a, 0x8b,
|
||||
0x24, 0x30, 0xdd, 0x0d, 0xca, 0x3e, 0x00, 0x1c, 0xd4, 0xeb, 0x1b, 0xf7, 0x37, 0x0e, 0x72, 0x46,
|
||||
0x4b, 0xbd, 0x4e, 0x40, 0x2c, 0x42, 0xff, 0x80, 0x9f, 0xd7, 0x6d, 0x25, 0xf5, 0x32, 0x1e, 0x31,
|
||||
0x40, 0xb1, 0x62, 0x53, 0xe5, 0x4c, 0xaf, 0xe2, 0x11, 0x03, 0xb2, 0xaf, 0x0e, 0x4c, 0x08, 0xcb,
|
||||
0x6b, 0x5e, 0xfc, 0x6c, 0x9e, 0xd7, 0x37, 0xef, 0x31, 0x04, 0x25, 0x93, 0xb4, 0xa0, 0x92, 0x26,
|
||||
0xee, 0x9e, 0xb7, 0x98, 0xad, 0xfe, 0xc5, 0xe6, 0x21, 0x7e, 0x67, 0xf9, 0xd7, 0x95, 0xe4, 0x5b,
|
||||
0x72, 0x25, 0x53, 0x93, 0x97, 0x4c, 0x08, 0xba, 0x36, 0xb6, 0x86, 0xa4, 0x83, 0xe9, 0x0b, 0x88,
|
||||
0x06, 0x8f, 0xd0, 0x0e, 0x78, 0x1f, 0xd9, 0xd6, 0x2e, 0xa8, 0x3e, 0xd5, 0xb8, 0x97, 0xf4, 0xa2,
|
||||
0x65, 0x7a, 0xb7, 0x90, 0x18, 0xf0, 0xdc, 0x7d, 0xea, 0x64, 0x77, 0x60, 0x7e, 0xc2, 0x69, 0xce,
|
||||
0x3a, 0x83, 0x62, 0x70, 0x37, 0x85, 0x7d, 0xea, 0x6e, 0x8a, 0xec, 0x21, 0x44, 0xb6, 0x6e, 0x53,
|
||||
0xf1, 0x3f, 0xf8, 0xa2, 0xa1, 0x95, 0x0a, 0x9a, 0x9a, 0xdb, 0xc7, 0xc7, 0x0d, 0xad, 0x88, 0xe1,
|
||||
0xb2, 0x2f, 0x2e, 0x8c, 0x15, 0x56, 0x3f, 0x28, 0xd5, 0x33, 0xdb, 0xc9, 0x00, 0xdb, 0xdc, 0xed,
|
||||
0x9a, 0x2b, 0xcf, 0x1b, 0xca, 0x99, 0x35, 0x37, 0x24, 0x16, 0x21, 0x04, 0xe3, 0x8a, 0x96, 0xc6,
|
||||
0xdc, 0x90, 0xe8, 0xef, 0x7e, 0xde, 0xfc, 0x61, 0xde, 0x52, 0x08, 0x8a, 0x96, 0x53, 0xb9, 0xa9,
|
||||
0x2b, 0x9b, 0x95, 0x2b, 0x8c, 0x96, 0x3d, 0xa3, 0xa7, 0x7a, 0xe0, 0xbf, 0xf5, 0xc0, 0xbf, 0xb4,
|
||||
0xf9, 0x36, 0x8c, 0xe5, 0xb6, 0x61, 0x3a, 0x44, 0xf1, 0x2a, 0xd4, 0xe2, 0x93, 0x6d, 0xc3, 0x88,
|
||||
0xa6, 0xff, 0xcc, 0xeb, 0x18, 0xe6, 0xaf, 0x68, 0x7e, 0xde, 0x79, 0x9d, 0x7d, 0x86, 0xc8, 0x62,
|
||||
0xeb, 0xed, 0x0a, 0x26, 0x5a, 0xdd, 0x99, 0x9b, 0xe2, 0x41, 0x1d, 0xbf, 0xd7, 0x45, 0x33, 0xb2,
|
||||
0x55, 0xa6, 0xcf, 0x60, 0xd6, 0xa3, 0x7f, 0x67, 0x9e, 0xfb, 0x77, 0x21, 0xe8, 0xd6, 0x43, 0x33,
|
||||
0x98, 0xbe, 0x3d, 0x7c, 0x79, 0x74, 0x7a, 0xb8, 0xbf, 0x33, 0x42, 0x73, 0x08, 0x8e, 0x4e, 0x4f,
|
||||
0x0c, 0x72, 0x56, 0xdf, 0x1c, 0xf0, 0xf7, 0xd5, 0xa1, 0x42, 0xbb, 0xe0, 0x1d, 0xd4, 0x6b, 0x34,
|
||||
0xc3, 0xd7, 0xff, 0xa8, 0x74, 0x6a, 0x83, 0x9b, 0x8d, 0x1e, 0x39, 0xe8, 0x01, 0x4c, 0xcc, 0x61,
|
||||
0x42, 0x31, 0x1e, 0x1c, 0xb3, 0xf4, 0x2f, 0x3c, 0xbc, 0x58, 0xd9, 0x08, 0x2d, 0xc0, 0xd7, 0x07,
|
||||
0x07, 0x45, 0xb8, 0x7f, 0xa3, 0xd2, 0x18, 0x0f, 0xee, 0x90, 0x51, 0xea, 0x10, 0xa2, 0x08, 0xf7,
|
||||
0xc3, 0x9a, 0xc6, 0x78, 0x90, 0x4d, 0xa3, 0xd4, 0x96, 0xa1, 0x08, 0xf7, 0xad, 0x4e, 0xe3, 0xa1,
|
||||
0x93, 0xd9, 0xe8, 0x6c, 0xa2, 0xaf, 0xee, 0x93, 0x1f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x22, 0x65,
|
||||
0x99, 0x10, 0x98, 0x05, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
@@ -657,6 +733,7 @@ type DebugClient interface {
|
||||
Health(ctx context.Context, in *HealthRequest, opts ...grpc.CallOption) (*HealthResponse, error)
|
||||
Stats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (*StatsResponse, error)
|
||||
Trace(ctx context.Context, in *TraceRequest, opts ...grpc.CallOption) (*TraceResponse, error)
|
||||
Cache(ctx context.Context, in *CacheRequest, opts ...grpc.CallOption) (*CacheResponse, error)
|
||||
}
|
||||
|
||||
type debugClient struct {
|
||||
@@ -726,12 +803,22 @@ func (c *debugClient) Trace(ctx context.Context, in *TraceRequest, opts ...grpc.
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *debugClient) Cache(ctx context.Context, in *CacheRequest, opts ...grpc.CallOption) (*CacheResponse, error) {
|
||||
out := new(CacheResponse)
|
||||
err := c.cc.Invoke(ctx, "/Debug/Cache", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// DebugServer is the server API for Debug service.
|
||||
type DebugServer interface {
|
||||
Log(*LogRequest, Debug_LogServer) error
|
||||
Health(context.Context, *HealthRequest) (*HealthResponse, error)
|
||||
Stats(context.Context, *StatsRequest) (*StatsResponse, error)
|
||||
Trace(context.Context, *TraceRequest) (*TraceResponse, error)
|
||||
Cache(context.Context, *CacheRequest) (*CacheResponse, error)
|
||||
}
|
||||
|
||||
// UnimplementedDebugServer can be embedded to have forward compatible implementations.
|
||||
@@ -750,6 +837,9 @@ func (*UnimplementedDebugServer) Stats(ctx context.Context, req *StatsRequest) (
|
||||
func (*UnimplementedDebugServer) Trace(ctx context.Context, req *TraceRequest) (*TraceResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Trace not implemented")
|
||||
}
|
||||
func (*UnimplementedDebugServer) Cache(ctx context.Context, req *CacheRequest) (*CacheResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Cache not implemented")
|
||||
}
|
||||
|
||||
func RegisterDebugServer(s *grpc.Server, srv DebugServer) {
|
||||
s.RegisterService(&_Debug_serviceDesc, srv)
|
||||
@@ -830,6 +920,24 @@ func _Debug_Trace_Handler(srv interface{}, ctx context.Context, dec func(interfa
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Debug_Cache_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CacheRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(DebugServer).Cache(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/Debug/Cache",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(DebugServer).Cache(ctx, req.(*CacheRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Debug_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "Debug",
|
||||
HandlerType: (*DebugServer)(nil),
|
||||
@@ -846,6 +954,10 @@ var _Debug_serviceDesc = grpc.ServiceDesc{
|
||||
MethodName: "Trace",
|
||||
Handler: _Debug_Trace_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Cache",
|
||||
Handler: _Debug_Cache_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{
|
||||
{
|
||||
|
@@ -46,6 +46,7 @@ type DebugService interface {
|
||||
Health(ctx context.Context, in *HealthRequest, opts ...client.CallOption) (*HealthResponse, error)
|
||||
Stats(ctx context.Context, in *StatsRequest, opts ...client.CallOption) (*StatsResponse, error)
|
||||
Trace(ctx context.Context, in *TraceRequest, opts ...client.CallOption) (*TraceResponse, error)
|
||||
Cache(ctx context.Context, in *CacheRequest, opts ...client.CallOption) (*CacheResponse, error)
|
||||
}
|
||||
|
||||
type debugService struct {
|
||||
@@ -139,6 +140,16 @@ func (c *debugService) Trace(ctx context.Context, in *TraceRequest, opts ...clie
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *debugService) Cache(ctx context.Context, in *CacheRequest, opts ...client.CallOption) (*CacheResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "Debug.Cache", in)
|
||||
out := new(CacheResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for Debug service
|
||||
|
||||
type DebugHandler interface {
|
||||
@@ -146,6 +157,7 @@ type DebugHandler interface {
|
||||
Health(context.Context, *HealthRequest, *HealthResponse) error
|
||||
Stats(context.Context, *StatsRequest, *StatsResponse) error
|
||||
Trace(context.Context, *TraceRequest, *TraceResponse) error
|
||||
Cache(context.Context, *CacheRequest, *CacheResponse) error
|
||||
}
|
||||
|
||||
func RegisterDebugHandler(s server.Server, hdlr DebugHandler, opts ...server.HandlerOption) error {
|
||||
@@ -154,6 +166,7 @@ func RegisterDebugHandler(s server.Server, hdlr DebugHandler, opts ...server.Han
|
||||
Health(ctx context.Context, in *HealthRequest, out *HealthResponse) error
|
||||
Stats(ctx context.Context, in *StatsRequest, out *StatsResponse) error
|
||||
Trace(ctx context.Context, in *TraceRequest, out *TraceResponse) error
|
||||
Cache(ctx context.Context, in *CacheRequest, out *CacheResponse) error
|
||||
}
|
||||
type Debug struct {
|
||||
debug
|
||||
@@ -217,3 +230,7 @@ func (h *debugHandler) Stats(ctx context.Context, in *StatsRequest, out *StatsRe
|
||||
func (h *debugHandler) Trace(ctx context.Context, in *TraceRequest, out *TraceResponse) error {
|
||||
return h.DebugHandler.Trace(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *debugHandler) Cache(ctx context.Context, in *CacheRequest, out *CacheResponse) error {
|
||||
return h.DebugHandler.Cache(ctx, in, out)
|
||||
}
|
||||
|
@@ -1,10 +1,11 @@
|
||||
syntax = "proto3";
|
||||
|
||||
service Debug {
|
||||
rpc Log(LogRequest) returns (stream Record) {};
|
||||
rpc Health(HealthRequest) returns (HealthResponse) {};
|
||||
rpc Stats(StatsRequest) returns (StatsResponse) {};
|
||||
rpc Log(LogRequest) returns (stream Record) {};
|
||||
rpc Health(HealthRequest) returns (HealthResponse) {};
|
||||
rpc Stats(StatsRequest) returns (StatsResponse) {};
|
||||
rpc Trace(TraceRequest) returns (TraceResponse) {};
|
||||
rpc Cache(CacheRequest) returns (CacheResponse) {};
|
||||
}
|
||||
|
||||
message HealthRequest {
|
||||
@@ -97,3 +98,9 @@ message Span {
|
||||
map<string,string> metadata = 7;
|
||||
SpanType type = 8;
|
||||
}
|
||||
|
||||
message CacheRequest {}
|
||||
|
||||
message CacheResponse {
|
||||
map<string, string> values = 1;
|
||||
}
|
20
go.mod
20
go.mod
@@ -2,11 +2,14 @@ module github.com/micro/go-micro/v2
|
||||
|
||||
go 1.13
|
||||
|
||||
replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.8
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/bitly/go-simplejson v0.5.0
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
|
||||
github.com/bwmarrin/discordgo v0.20.2
|
||||
github.com/caddyserver/certmagic v0.10.6
|
||||
github.com/coreos/bbolt v1.3.3 // indirect
|
||||
github.com/coreos/etcd v3.3.18+incompatible
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
@@ -21,15 +24,14 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.4.7
|
||||
github.com/fsouza/go-dockerclient v1.6.0
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/go-acme/lego/v3 v3.3.0
|
||||
github.com/go-git/go-git/v5 v5.0.0
|
||||
github.com/go-acme/lego/v3 v3.4.0
|
||||
github.com/go-git/go-git/v5 v5.1.0
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect
|
||||
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee
|
||||
github.com/gobwas/pool v0.2.0 // indirect
|
||||
github.com/gobwas/ws v1.0.3
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect
|
||||
github.com/golang/protobuf v1.3.5
|
||||
github.com/google/go-cmp v0.4.0 // indirect
|
||||
github.com/golang/protobuf v1.4.0
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gorilla/handlers v1.4.2
|
||||
github.com/gorilla/websocket v1.4.1 // indirect
|
||||
@@ -38,13 +40,12 @@ require (
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.5 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0
|
||||
github.com/hpcloud/tail v1.0.0
|
||||
github.com/imdario/mergo v0.3.8
|
||||
github.com/imdario/mergo v0.3.9
|
||||
github.com/jonboulle/clockwork v0.1.0 // indirect
|
||||
github.com/json-iterator/go v1.1.9 // indirect
|
||||
github.com/kr/pretty v0.1.0
|
||||
github.com/lib/pq v1.3.0
|
||||
github.com/lucas-clemente/quic-go v0.14.1
|
||||
github.com/mholt/certmagic v0.9.3
|
||||
github.com/micro/cli/v2 v2.1.2
|
||||
github.com/miekg/dns v1.1.27
|
||||
github.com/mitchellh/hashstructure v1.0.0
|
||||
@@ -61,12 +62,13 @@ require (
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
|
||||
go.etcd.io/bbolt v1.3.4
|
||||
go.uber.org/zap v1.13.0
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121 // indirect
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1
|
||||
google.golang.org/grpc v1.26.0
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1
|
||||
google.golang.org/protobuf v1.22.0
|
||||
gopkg.in/telegram-bot-api.v4 v4.6.4
|
||||
sigs.k8s.io/yaml v1.1.0 // indirect
|
||||
)
|
||||
|
57
go.sum
57
go.sum
@@ -64,8 +64,10 @@ github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4Yn
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
|
||||
github.com/bwmarrin/discordgo v0.20.2 h1:nA7jiTtqUA9lT93WL2jPjUp8ZTEInRujBdx1C9gkr20=
|
||||
github.com/bwmarrin/discordgo v0.20.2/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q=
|
||||
github.com/cenkalti/backoff/v3 v3.0.0 h1:ske+9nBpD9qZsTBoF41nW5L+AIuFBKMeze18XQ3eG1c=
|
||||
github.com/cenkalti/backoff/v3 v3.0.0/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
|
||||
github.com/caddyserver/certmagic v0.10.6 h1:sCya6FmfaN74oZE46kqfaFOVoROD/mF36rTQfjN7TZc=
|
||||
github.com/caddyserver/certmagic v0.10.6/go.mod h1:Y8jcUBctgk/IhpAzlHKfimZNyXCkfGgRTC0orl8gROQ=
|
||||
github.com/cenkalti/backoff/v4 v4.0.0 h1:6VeaLF9aI+MAUQ95106HwWzYZgJJpZ4stumjj6RFYAU=
|
||||
github.com/cenkalti/backoff/v4 v4.0.0/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cheekybits/genny v1.0.0 h1:uGGa4nei+j20rOSeDeP5Of12XVm7TGUd4dJA9RDitfE=
|
||||
@@ -100,7 +102,6 @@ github.com/cpu/goacmedns v0.0.1/go.mod h1:sesf/pNnCYwUevQEQfEwY0Y3DydlQWSGZbaMEl
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
@@ -143,8 +144,8 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
|
||||
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
|
||||
github.com/go-acme/lego/v3 v3.3.0 h1:6BePZsOiYA4/w+M7QDytxQtMfCipMPGnWAHs9pWks98=
|
||||
github.com/go-acme/lego/v3 v3.3.0/go.mod h1:iGSY2vQrvQs3WezicSB/oVbO2eCrD88dpWPwb1qLqu0=
|
||||
github.com/go-acme/lego/v3 v3.4.0 h1:deB9NkelA+TfjGHVw8J7iKl/rMtffcGMWSMmptvMv0A=
|
||||
github.com/go-acme/lego/v3 v3.4.0/go.mod h1:xYbLDuxq3Hy4bMUT1t9JIuz6GWIWb3m5X+TeTHYaT7M=
|
||||
github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s=
|
||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||
github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
|
||||
@@ -153,8 +154,8 @@ github.com/go-git/go-billy/v5 v5.0.0 h1:7NQHvd9FVid8VL4qVUMm8XifBK+2xCoZ2lSk0agR
|
||||
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.1 h1:q+IFMfLx200Q3scvt2hN79JsEzy4AmBTp/pqnefH+Bc=
|
||||
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
|
||||
github.com/go-git/go-git/v5 v5.0.0 h1:k5RWPm4iJwYtfWoxIJy4wJX9ON7ihPeZZYC1fLYDnpg=
|
||||
github.com/go-git/go-git/v5 v5.0.0/go.mod h1:oYD8y9kWsGINPFJoLdaScGCN6dlKg23blmClfZwtUVA=
|
||||
github.com/go-git/go-git/v5 v5.1.0 h1:HxJn9g/E7eYvKW3Fm7Jt4ee8LXfPOm/H1cdDu8vEssk=
|
||||
github.com/go-git/go-git/v5 v5.1.0/go.mod h1:ZKfuPUoY1ZqIG4QG9BDBh3G4gLM5zvPuSJAozQrZuyM=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-ini/ini v1.44.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
@@ -191,6 +192,12 @@ github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0 h1:oOuy+ugB+P/kBdUnG5QaMXSIyJ1q38wWSojYCb3z5VQ=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
||||
@@ -259,8 +266,8 @@ github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v
|
||||
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/cpuid v1.2.0 h1:NMpwD2G9JSFOE1/TJjGSo5zG7Yb2bTe7eq1jH+irmeE=
|
||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.2.3 h1:CCtW0xUnWGVINKvE/WWOYKdsPV6mawAtvQuSl8guwQs=
|
||||
github.com/klauspost/cpuid v1.2.3/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/kolo/xmlrpc v0.0.0-20190717152603-07c4ee3fd181/go.mod h1:o03bZfuBwAXHetKXuInt4S7omeXUu62/A845kiycsSQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||
@@ -269,7 +276,6 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -293,8 +299,6 @@ 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.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/miekg/dns v1.1.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
@@ -333,7 +337,7 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA
|
||||
github.com/nlopes/slack v0.6.1-0.20191106133607-d06c2a2b3249 h1:Pr5gZa2VcmktVwq0lyC39MsN5tz356vC/pQHKvq+QBo=
|
||||
github.com/nlopes/slack v0.6.1-0.20191106133607-d06c2a2b3249/go.mod h1:JzQ9m3PMAqcpeCam7UaHSuBuupz7CmpjehYMayT6YOk=
|
||||
github.com/nrdcg/auroradns v1.0.0/go.mod h1:6JPXKzIRzZzMqtTDgueIhTi6rFf1QvYE/HzqidhOhjw=
|
||||
github.com/nrdcg/dnspod-go v0.3.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
|
||||
github.com/nrdcg/dnspod-go v0.4.0/go.mod h1:vZSoFSFeQVm2gWLMkyX61LZ8HI3BaqtHZWgPTGKr6KQ=
|
||||
github.com/nrdcg/goinwx v0.6.1/go.mod h1:XPiut7enlbEdntAqalBIqcYcTEVhpv/dKWgDCX2SwKQ=
|
||||
github.com/nrdcg/namesilo v0.2.1/go.mod h1:lwMvfQTyYq+BbjJd30ylEG4GPSS6PII0Tia4rRpRiyw=
|
||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
@@ -360,7 +364,6 @@ github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgF
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
||||
github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtbSNq5BcowyYOWdKo=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -396,8 +399,6 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sacloud/libsacloud v1.26.1/go.mod h1:79ZwATmHLIFZIMd7sxA3LwzVy/B77uj3LDoToVTxDoQ=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
@@ -411,11 +412,8 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1
|
||||
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/src-d/gcfg v1.4.0 h1:xXbNR5AlLSA315x2UO+fTSSAXCDf+Ar38/6oyGbDKQ4=
|
||||
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
@@ -474,6 +472,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59 h1:3zb4D3T4G8jdExgVU/95+vQXfpEPiMdCaZgmGVxjNHM=
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw=
|
||||
golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/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=
|
||||
@@ -518,6 +518,8 @@ golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLL
|
||||
golang.org/x/net v0.0.0-20191027093000-83d349e8ac1a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a h1:GuSPYbZzB5/dcLNCwLQLsg3obCJtX9IJhpXkvY7kzk0=
|
||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2 h1:eDrdRpKgkcCqKZQwyZRyeFZgfqt37SL7Kv3tok06cKE=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
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=
|
||||
@@ -557,6 +559,9 @@ golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5 h1:LfCXLvNmTYH9kEmVgqbnsWfru
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527 h1:uYVVQ9WP/Ds2ROhcaGPeIdVq0RIXVLwsHlnvJ+cT1So=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
@@ -582,7 +587,6 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
@@ -626,6 +630,13 @@ google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0 h1:cJv5/xdbk1NnMPR1VP9+HU6gupuG9MLBoH1r6RHZ2MY=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
|
||||
@@ -644,12 +655,6 @@ gopkg.in/resty.v1 v1.9.1/go.mod h1:vo52Hzryw9PnPHcJfPsBiFW62XhNx5OczbV9y+IMpgc=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
|
||||
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
|
||||
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
|
||||
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
|
||||
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
|
||||
gopkg.in/telegram-bot-api.v4 v4.6.4 h1:hpHWhzn4jTCsAJZZ2loNKfy2QWyPDRJVl3aTFXeMW8g=
|
||||
gopkg.in/telegram-bot-api.v4 v4.6.4/go.mod h1:5DpGO5dbumb40px+dXcwCpcjmeHNYLpk0bp3XRNvWDM=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
|
@@ -4,7 +4,6 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -55,9 +54,28 @@ func copyFields(src map[string]interface{}) map[string]interface{} {
|
||||
return dst
|
||||
}
|
||||
|
||||
// logCallerfilePath returns a package/file:line description of the caller,
|
||||
// preserving only the leaf directory name and file name.
|
||||
func logCallerfilePath(loggingFilePath string) string {
|
||||
parts := strings.Split(loggingFilePath, string(filepath.Separator))
|
||||
return parts[len(parts)-1]
|
||||
// To make sure we trim the path correctly on Windows too, we
|
||||
// counter-intuitively need to use '/' and *not* os.PathSeparator here,
|
||||
// because the path given originates from Go stdlib, specifically
|
||||
// runtime.Caller() which (as of Mar/17) returns forward slashes even on
|
||||
// Windows.
|
||||
//
|
||||
// See https://github.com/golang/go/issues/3335
|
||||
// and https://github.com/golang/go/issues/18151
|
||||
//
|
||||
// for discussion on the issue on Go side.
|
||||
idx := strings.LastIndexByte(loggingFilePath, '/')
|
||||
if idx == -1 {
|
||||
return loggingFilePath
|
||||
}
|
||||
idx = strings.LastIndexByte(loggingFilePath[:idx], '/')
|
||||
if idx == -1 {
|
||||
return loggingFilePath
|
||||
}
|
||||
return loggingFilePath[idx+1:]
|
||||
}
|
||||
|
||||
func (l *defaultLogger) Log(level Level, v ...interface{}) {
|
||||
|
11
options.go
11
options.go
@@ -14,6 +14,7 @@ import (
|
||||
"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"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
"github.com/micro/go-micro/v2/store"
|
||||
"github.com/micro/go-micro/v2/transport"
|
||||
@@ -29,6 +30,7 @@ type Options struct {
|
||||
Server server.Server
|
||||
Store store.Store
|
||||
Registry registry.Registry
|
||||
Runtime runtime.Runtime
|
||||
Transport transport.Transport
|
||||
Profile profile.Profile
|
||||
|
||||
@@ -55,6 +57,7 @@ func newOptions(opts ...Option) Options {
|
||||
Server: server.DefaultServer,
|
||||
Store: store.DefaultStore,
|
||||
Registry: registry.DefaultRegistry,
|
||||
Runtime: runtime.DefaultRuntime,
|
||||
Transport: transport.DefaultTransport,
|
||||
Context: context.Background(),
|
||||
Signal: true,
|
||||
@@ -152,7 +155,6 @@ func Tracer(t trace.Tracer) Option {
|
||||
func Auth(a auth.Auth) Option {
|
||||
return func(o *Options) {
|
||||
o.Auth = a
|
||||
o.Client.Init(client.Auth(a))
|
||||
o.Server.Init(server.Auth(a))
|
||||
}
|
||||
}
|
||||
@@ -182,6 +184,13 @@ func Transport(t transport.Transport) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// Runtime sets the runtime
|
||||
func Runtime(r runtime.Runtime) Option {
|
||||
return func(o *Options) {
|
||||
o.Runtime = r
|
||||
}
|
||||
}
|
||||
|
||||
// Convenience options
|
||||
|
||||
// Address sets the address of the server
|
||||
|
@@ -353,10 +353,10 @@ func (m *mdnsRegistry) GetService(service string, opts ...GetOption) ([]*Service
|
||||
}
|
||||
addr := ""
|
||||
// prefer ipv4 addrs
|
||||
if e.AddrV4 != nil {
|
||||
if len(e.AddrV4) > 0 {
|
||||
addr = e.AddrV4.String()
|
||||
// else use ipv6
|
||||
} else if e.AddrV6 != nil {
|
||||
} else if len(e.AddrV6) > 0 {
|
||||
addr = "[" + e.AddrV6.String() + "]"
|
||||
} else {
|
||||
if logger.V(logger.InfoLevel, logger.DefaultLogger) {
|
||||
|
21
registry/service/options.go
Normal file
21
registry/service/options.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
)
|
||||
|
||||
type clientKey struct{}
|
||||
|
||||
// WithClient sets the RPC client
|
||||
func WithClient(c client.Client) registry.Option {
|
||||
return func(o *registry.Options) {
|
||||
if o.Context == nil {
|
||||
o.Context = context.Background()
|
||||
}
|
||||
|
||||
o.Context = context.WithValue(o.Context, clientKey{}, c)
|
||||
}
|
||||
}
|
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/client/grpc"
|
||||
"github.com/micro/go-micro/v2/errors"
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
pb "github.com/micro/go-micro/v2/registry/service/proto"
|
||||
)
|
||||
@@ -46,6 +47,21 @@ func (s *serviceRegistry) Init(opts ...registry.Option) error {
|
||||
for _, o := range opts {
|
||||
o(&s.opts)
|
||||
}
|
||||
|
||||
if len(s.opts.Addrs) > 0 {
|
||||
s.address = s.opts.Addrs
|
||||
}
|
||||
|
||||
// extract the client from the context, fallback to grpc
|
||||
var cli client.Client
|
||||
if c, ok := s.opts.Context.Value(clientKey{}).(client.Client); ok {
|
||||
cli = c
|
||||
} else {
|
||||
cli = grpc.NewClient()
|
||||
}
|
||||
|
||||
s.client = pb.NewRegistryService(DefaultService, cli)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -105,7 +121,9 @@ func (s *serviceRegistry) GetService(name string, opts ...registry.GetOption) ([
|
||||
Service: name,
|
||||
}, s.callOpts()...)
|
||||
|
||||
if err != nil {
|
||||
if verr, ok := err.(*errors.Error); ok && verr.Code == 404 {
|
||||
return nil, registry.ErrNotFound
|
||||
} else if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -171,21 +189,23 @@ func NewRegistry(opts ...registry.Option) registry.Registry {
|
||||
|
||||
// the registry address
|
||||
addrs := options.Addrs
|
||||
|
||||
if len(addrs) == 0 {
|
||||
addrs = []string{"127.0.0.1:8000"}
|
||||
}
|
||||
|
||||
// use mdns as a fall back in case its used
|
||||
mReg := registry.NewRegistry()
|
||||
if options.Context == nil {
|
||||
options.Context = context.TODO()
|
||||
}
|
||||
|
||||
// create new client with mdns
|
||||
cli := grpc.NewClient(
|
||||
client.Registry(mReg),
|
||||
)
|
||||
// extract the client from the context, fallback to grpc
|
||||
var cli client.Client
|
||||
if c, ok := options.Context.Value(clientKey{}).(client.Client); ok {
|
||||
cli = c
|
||||
} else {
|
||||
cli = grpc.NewClient()
|
||||
}
|
||||
|
||||
// service name
|
||||
// TODO: accept option
|
||||
// service name. TODO: accept option
|
||||
name := DefaultService
|
||||
|
||||
return &serviceRegistry{
|
||||
|
@@ -3,7 +3,6 @@ package router
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
@@ -19,18 +18,6 @@ var (
|
||||
AdvertiseEventsTick = 10 * time.Second
|
||||
// DefaultAdvertTTL is default advertisement TTL
|
||||
DefaultAdvertTTL = 2 * time.Minute
|
||||
// AdvertSuppress is advert suppression threshold
|
||||
AdvertSuppress = 200.0
|
||||
// AdvertRecover is advert recovery threshold
|
||||
AdvertRecover = 20.0
|
||||
// Penalty for routes processed multiple times
|
||||
Penalty = 100.0
|
||||
// PenaltyHalfLife is the time the advert penalty decays to half its value
|
||||
PenaltyHalfLife = 30.0
|
||||
// MaxSuppressTime defines time after which the suppressed advert is deleted
|
||||
MaxSuppressTime = 90 * time.Second
|
||||
// PenaltyDecay is a coefficient which controls the speed the advert penalty decays
|
||||
PenaltyDecay = math.Log(2) / PenaltyHalfLife
|
||||
)
|
||||
|
||||
// router implements default router
|
||||
@@ -269,68 +256,8 @@ func (r *router) publishAdvert(advType AdvertType, events []*Event) {
|
||||
r.sub.RUnlock()
|
||||
}
|
||||
|
||||
// advert contains a route event to be advertised
|
||||
type advert struct {
|
||||
// event received from routing table
|
||||
event *Event
|
||||
// lastSeen records the time of the last advert update
|
||||
lastSeen time.Time
|
||||
// penalty is current advert penalty
|
||||
penalty float64
|
||||
// isSuppressed flags the advert suppression
|
||||
isSuppressed bool
|
||||
// suppressTime records the time interval the advert has been suppressed for
|
||||
suppressTime time.Time
|
||||
}
|
||||
|
||||
// adverts maintains a map of router adverts
|
||||
type adverts map[uint64]*advert
|
||||
|
||||
// process processes advert
|
||||
// It updates advert timestamp, increments its penalty and
|
||||
// marks upresses or recovers it if it reaches configured thresholds
|
||||
func (m adverts) process(a *advert) error {
|
||||
// lookup advert in adverts
|
||||
hash := a.event.Route.Hash()
|
||||
a, ok := m[hash]
|
||||
if !ok {
|
||||
return fmt.Errorf("advert not found")
|
||||
}
|
||||
|
||||
// decay the event penalty
|
||||
delta := time.Since(a.lastSeen).Seconds()
|
||||
|
||||
// decay advert penalty
|
||||
a.penalty = a.penalty * math.Exp(-delta*PenaltyDecay)
|
||||
service := a.event.Route.Service
|
||||
address := a.event.Route.Address
|
||||
|
||||
// suppress/recover the event based on its penalty level
|
||||
switch {
|
||||
case a.penalty > AdvertSuppress && !a.isSuppressed:
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router suppressing advert %d %.2f for route %s %s", hash, a.penalty, service, address)
|
||||
}
|
||||
a.isSuppressed = true
|
||||
a.suppressTime = time.Now()
|
||||
case a.penalty < AdvertRecover && a.isSuppressed:
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router recovering advert %d %.2f for route %s %s", hash, a.penalty, service, address)
|
||||
}
|
||||
a.isSuppressed = false
|
||||
}
|
||||
|
||||
// if suppressed, checked how long has it been suppressed for
|
||||
if a.isSuppressed {
|
||||
// max suppression time threshold has been reached, delete the advert
|
||||
if time.Since(a.suppressTime) > MaxSuppressTime {
|
||||
delete(m, hash)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
type adverts map[uint64]*Event
|
||||
|
||||
// advertiseEvents advertises routing table events
|
||||
// It suppresses unhealthy flapping events and advertises healthy events upstream.
|
||||
@@ -396,21 +323,9 @@ func (r *router) advertiseEvents() error {
|
||||
var events []*Event
|
||||
|
||||
// collect all events which are not flapping
|
||||
for key, advert := range adverts {
|
||||
// process the advert
|
||||
if err := adverts.process(advert); err != nil {
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router failed processing advert %d: %v", key, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// if suppressed go to the next advert
|
||||
if advert.isSuppressed {
|
||||
continue
|
||||
}
|
||||
|
||||
for key, event := range adverts {
|
||||
// if we only advertise local routes skip processing anything not link local
|
||||
if r.options.Advertise == AdvertiseLocal && advert.event.Route.Link != "local" {
|
||||
if r.options.Advertise == AdvertiseLocal && event.Route.Link != "local" {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -418,7 +333,7 @@ func (r *router) advertiseEvents() error {
|
||||
e := new(Event)
|
||||
// this is ok, because router.Event only contains builtin types
|
||||
// and no references so this creates a deep copy of struct Event
|
||||
*e = *(advert.event)
|
||||
*e = *event
|
||||
events = append(events, e)
|
||||
// delete the advert from adverts
|
||||
delete(adverts, key)
|
||||
@@ -447,44 +362,22 @@ func (r *router) advertiseEvents() error {
|
||||
continue
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router processing table event %s for service %s %s", e.Type, e.Route.Service, e.Route.Address)
|
||||
}
|
||||
|
||||
// check if we have already registered the route
|
||||
hash := e.Route.Hash()
|
||||
a, ok := adverts[hash]
|
||||
ev, ok := adverts[hash]
|
||||
if !ok {
|
||||
a = &advert{
|
||||
event: e,
|
||||
penalty: Penalty,
|
||||
lastSeen: now,
|
||||
}
|
||||
adverts[hash] = a
|
||||
ev = e
|
||||
adverts[hash] = e
|
||||
continue
|
||||
}
|
||||
|
||||
// override the route event only if the previous event was different
|
||||
if a.event.Type != e.Type {
|
||||
a.event = e
|
||||
}
|
||||
|
||||
// process the advert
|
||||
if err := adverts.process(a); err != nil {
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router error processing advert %d: %v", hash, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// update event penalty and timestamp
|
||||
a.lastSeen = now
|
||||
// increment the penalty
|
||||
a.penalty += Penalty
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Router advert %d for route %s %s event penalty: %f", hash, a.event.Route.Service, a.event.Route.Address, a.penalty)
|
||||
if ev.Type != e.Type {
|
||||
ev = e
|
||||
}
|
||||
case <-r.exit:
|
||||
if w != nil {
|
||||
|
@@ -1,6 +1,8 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -16,6 +18,9 @@ import (
|
||||
"github.com/micro/go-micro/v2/runtime/local/git"
|
||||
)
|
||||
|
||||
// defaultNamespace to use if not provided as an option
|
||||
const defaultNamespace = "default"
|
||||
|
||||
type runtime struct {
|
||||
sync.RWMutex
|
||||
// options configure runtime
|
||||
@@ -26,9 +31,9 @@ type runtime struct {
|
||||
start chan *service
|
||||
// indicates if we're running
|
||||
running bool
|
||||
// the service map
|
||||
// TODO: track different versions of the same service
|
||||
services map[string]*service
|
||||
// namespaces stores services grouped by namespace, e.g. namespaces["foo"]["go.micro.auth:latest"]
|
||||
// would return the latest version of go.micro.auth from the foo namespace
|
||||
namespaces map[string]map[string]*service
|
||||
}
|
||||
|
||||
// NewRuntime creates new local runtime and returns it
|
||||
@@ -46,10 +51,10 @@ func NewRuntime(opts ...Option) Runtime {
|
||||
_ = os.MkdirAll(path, 0755)
|
||||
|
||||
return &runtime{
|
||||
options: options,
|
||||
closed: make(chan bool),
|
||||
start: make(chan *service, 128),
|
||||
services: make(map[string]*service),
|
||||
options: options,
|
||||
closed: make(chan bool),
|
||||
start: make(chan *service, 128),
|
||||
namespaces: make(map[string]map[string]*service),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,6 +65,25 @@ func (r *runtime) checkoutSourceIfNeeded(s *Service) error {
|
||||
if len(s.Source) == 0 {
|
||||
return nil
|
||||
}
|
||||
// @todo make this come from config
|
||||
cpath := filepath.Join(os.TempDir(), "micro", "uploads", s.Source)
|
||||
path := strings.ReplaceAll(cpath, ".tar.gz", "")
|
||||
if ex, _ := exists(cpath); ex {
|
||||
err := os.RemoveAll(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.MkdirAll(path, 0777)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = uncompress(cpath, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.Source = path
|
||||
return nil
|
||||
}
|
||||
source, err := git.ParseSourceLocal("", s.Source)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -74,6 +98,83 @@ func (r *runtime) checkoutSourceIfNeeded(s *Service) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// modified version of: https://gist.github.com/mimoo/25fc9716e0f1353791f5908f94d6e726
|
||||
func uncompress(src string, dst string) error {
|
||||
file, err := os.OpenFile(src, os.O_RDWR|os.O_CREATE, 0666)
|
||||
defer file.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// ungzip
|
||||
zr, err := gzip.NewReader(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// untar
|
||||
tr := tar.NewReader(zr)
|
||||
|
||||
// uncompress each element
|
||||
for {
|
||||
header, err := tr.Next()
|
||||
if err == io.EOF {
|
||||
break // End of archive
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
target := header.Name
|
||||
|
||||
// validate name against path traversal
|
||||
if !validRelPath(header.Name) {
|
||||
return fmt.Errorf("tar contained invalid name error %q\n", target)
|
||||
}
|
||||
|
||||
// add dst + re-format slashes according to system
|
||||
target = filepath.Join(dst, header.Name)
|
||||
// if no join is needed, replace with ToSlash:
|
||||
// target = filepath.ToSlash(header.Name)
|
||||
|
||||
// check the type
|
||||
switch header.Typeflag {
|
||||
|
||||
// if its a dir and it doesn't exist create it (with 0755 permission)
|
||||
case tar.TypeDir:
|
||||
if _, err := os.Stat(target); err != nil {
|
||||
// @todo think about this:
|
||||
// if we don't nuke the folder, we might end up with files from
|
||||
// the previous decompress.
|
||||
if err := os.MkdirAll(target, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// if it's a file create it (with same permission)
|
||||
case tar.TypeReg:
|
||||
// the truncating is probably unnecessary due to the `RemoveAll` of folders
|
||||
// above
|
||||
fileToWrite, err := os.OpenFile(target, os.O_TRUNC|os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// copy over contents
|
||||
if _, err := io.Copy(fileToWrite, tr); err != nil {
|
||||
return err
|
||||
}
|
||||
// manually close here after each file operation; defering would cause each file close
|
||||
// to wait until all operations have completed.
|
||||
fileToWrite.Close()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// check for path traversal and correct forward slashes
|
||||
func validRelPath(p string) bool {
|
||||
if p == "" || strings.Contains(p, `\`) || strings.HasPrefix(p, "/") || strings.Contains(p, "../") {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Init initializes runtime options
|
||||
func (r *runtime) Init(opts ...Option) error {
|
||||
r.Lock()
|
||||
@@ -92,7 +193,7 @@ func (r *runtime) run(events <-chan Event) {
|
||||
defer t.Stop()
|
||||
|
||||
// process event processes an incoming event
|
||||
processEvent := func(event Event, service *service) error {
|
||||
processEvent := func(event Event, service *service, ns string) error {
|
||||
// get current vals
|
||||
r.RLock()
|
||||
name := service.Name
|
||||
@@ -105,11 +206,11 @@ func (r *runtime) run(events <-chan Event) {
|
||||
}
|
||||
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime updating service %s", name)
|
||||
logger.Debugf("Runtime updating service %s in %v namespace", name, ns)
|
||||
}
|
||||
|
||||
// this will cause a delete followed by created
|
||||
if err := r.Update(service.Service); err != nil {
|
||||
if err := r.Update(service.Service, UpdateNamespace(ns)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -126,18 +227,20 @@ func (r *runtime) run(events <-chan Event) {
|
||||
case <-t.C:
|
||||
// check running services
|
||||
r.RLock()
|
||||
for _, service := range r.services {
|
||||
if !service.ShouldStart() {
|
||||
continue
|
||||
}
|
||||
for _, sevices := range r.namespaces {
|
||||
for _, service := range sevices {
|
||||
if !service.ShouldStart() {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO: check service error
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime starting %s", service.Name)
|
||||
}
|
||||
if err := service.Start(); err != nil {
|
||||
// TODO: check service error
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime error starting %s: %v", service.Name, err)
|
||||
logger.Debugf("Runtime starting %s", service.Name)
|
||||
}
|
||||
if err := service.Start(); err != nil {
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime error starting %s: %v", service.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,17 +265,27 @@ func (r *runtime) run(events <-chan Event) {
|
||||
// NOTE: we only handle Update events for now
|
||||
switch event.Type {
|
||||
case Update:
|
||||
if len(event.Service) > 0 {
|
||||
if event.Service != nil {
|
||||
ns := defaultNamespace
|
||||
if event.Options != nil && len(event.Options.Namespace) > 0 {
|
||||
ns = event.Options.Namespace
|
||||
}
|
||||
|
||||
r.RLock()
|
||||
service, ok := r.services[fmt.Sprintf("%v:%v", event.Service, event.Version)]
|
||||
r.RUnlock()
|
||||
if !ok {
|
||||
if _, ok := r.namespaces[ns]; !ok {
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime unknown service: %s", event.Service)
|
||||
logger.Debugf("Runtime unknown namespace: %s", ns)
|
||||
}
|
||||
r.RUnlock()
|
||||
continue
|
||||
}
|
||||
if err := processEvent(event, service); err != nil {
|
||||
service, ok := r.namespaces[ns][fmt.Sprintf("%v:%v", event.Service.Name, event.Service.Version)]
|
||||
r.RUnlock()
|
||||
if !ok {
|
||||
logger.Debugf("Runtime unknown service: %s", event.Service)
|
||||
}
|
||||
|
||||
if err := processEvent(event, service, ns); err != nil {
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime error updating service %s: %v", event.Service, err)
|
||||
}
|
||||
@@ -181,14 +294,16 @@ func (r *runtime) run(events <-chan Event) {
|
||||
}
|
||||
|
||||
r.RLock()
|
||||
services := r.services
|
||||
namespaces := r.namespaces
|
||||
r.RUnlock()
|
||||
|
||||
// if blank service was received we update all services
|
||||
for _, service := range services {
|
||||
if err := processEvent(event, service); err != nil {
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime error updating service %s: %v", service.Name, err)
|
||||
for ns, services := range namespaces {
|
||||
for _, service := range services {
|
||||
if err := processEvent(event, service, ns); err != nil {
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime error updating service %s: %v", service.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,20 +337,25 @@ func (r *runtime) Create(s *Service, opts ...CreateOption) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if _, ok := r.services[serviceKey(s)]; ok {
|
||||
return errors.New("service already running")
|
||||
}
|
||||
|
||||
var options CreateOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
if len(options.Namespace) == 0 {
|
||||
options.Namespace = defaultNamespace
|
||||
}
|
||||
if len(options.Command) == 0 {
|
||||
options.Command = []string{"go"}
|
||||
options.Args = []string{"run", "."}
|
||||
}
|
||||
|
||||
if _, ok := r.namespaces[options.Namespace]; !ok {
|
||||
r.namespaces[options.Namespace] = make(map[string]*service)
|
||||
}
|
||||
if _, ok := r.namespaces[options.Namespace][serviceKey(s)]; ok {
|
||||
return errors.New("service already running")
|
||||
}
|
||||
|
||||
// create new service
|
||||
service := newService(s, options)
|
||||
|
||||
@@ -253,9 +373,8 @@ func (r *runtime) Create(s *Service, opts ...CreateOption) error {
|
||||
if err := service.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// save service
|
||||
r.services[serviceKey(s)] = service
|
||||
r.namespaces[options.Namespace][serviceKey(s)] = service
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -383,6 +502,9 @@ func (r *runtime) Read(opts ...ReadOption) ([]*Service, error) {
|
||||
for _, o := range opts {
|
||||
o(&gopts)
|
||||
}
|
||||
if len(gopts.Namespace) == 0 {
|
||||
gopts.Namespace = defaultNamespace
|
||||
}
|
||||
|
||||
save := func(k, v string) bool {
|
||||
if len(k) == 0 {
|
||||
@@ -394,7 +516,11 @@ func (r *runtime) Read(opts ...ReadOption) ([]*Service, error) {
|
||||
//nolint:prealloc
|
||||
var services []*Service
|
||||
|
||||
for _, service := range r.services {
|
||||
if _, ok := r.namespaces[gopts.Namespace]; !ok {
|
||||
return make([]*Service, 0), nil
|
||||
}
|
||||
|
||||
for _, service := range r.namespaces[gopts.Namespace] {
|
||||
if !save(gopts.Service, service.Name) {
|
||||
continue
|
||||
}
|
||||
@@ -409,22 +535,40 @@ func (r *runtime) Read(opts ...ReadOption) ([]*Service, error) {
|
||||
return services, nil
|
||||
}
|
||||
|
||||
// Update attemps to update the service
|
||||
// Update attempts to update the service
|
||||
func (r *runtime) Update(s *Service, opts ...UpdateOption) error {
|
||||
var options UpdateOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
if len(options.Namespace) == 0 {
|
||||
options.Namespace = defaultNamespace
|
||||
}
|
||||
|
||||
err := r.checkoutSourceIfNeeded(s)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
r.Lock()
|
||||
service, ok := r.services[serviceKey(s)]
|
||||
srvs, ok := r.namespaces[options.Namespace]
|
||||
r.Unlock()
|
||||
if !ok {
|
||||
return errors.New("Service not found")
|
||||
}
|
||||
err = service.Stop()
|
||||
if err != nil {
|
||||
|
||||
r.Lock()
|
||||
service, ok := srvs[serviceKey(s)]
|
||||
r.Unlock()
|
||||
if !ok {
|
||||
return errors.New("Service not found")
|
||||
}
|
||||
|
||||
if err := service.Stop(); err != nil && err.Error() != "no such process" {
|
||||
logger.Errorf("Error stopping service %s: %s", service.Name, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return service.Start()
|
||||
}
|
||||
|
||||
@@ -433,24 +577,41 @@ func (r *runtime) Delete(s *Service, opts ...DeleteOption) error {
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime deleting service %s", s.Name)
|
||||
var options DeleteOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
if s, ok := r.services[serviceKey(s)]; ok {
|
||||
// check if running
|
||||
if s.Running() {
|
||||
delete(r.services, s.key())
|
||||
return nil
|
||||
}
|
||||
// otherwise stop it
|
||||
if err := s.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
// delete it
|
||||
delete(r.services, s.key())
|
||||
if len(options.Namespace) == 0 {
|
||||
options.Namespace = defaultNamespace
|
||||
}
|
||||
|
||||
srvs, ok := r.namespaces[options.Namespace]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime deleting service %s", s.Name)
|
||||
}
|
||||
|
||||
service, ok := srvs[serviceKey(s)]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
// check if running
|
||||
if !service.Running() {
|
||||
delete(srvs, service.key())
|
||||
r.namespaces[options.Namespace] = srvs
|
||||
return nil
|
||||
}
|
||||
// otherwise stop it
|
||||
if err := service.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
// delete it
|
||||
delete(srvs, service.key())
|
||||
r.namespaces[options.Namespace] = srvs
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -504,12 +665,15 @@ func (r *runtime) Stop() error {
|
||||
r.running = false
|
||||
|
||||
// stop all the services
|
||||
for _, service := range r.services {
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime stopping %s", service.Name)
|
||||
for _, services := range r.namespaces {
|
||||
for _, service := range services {
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
logger.Debugf("Runtime stopping %s", service.Name)
|
||||
}
|
||||
service.Stop()
|
||||
}
|
||||
service.Stop()
|
||||
}
|
||||
|
||||
// stop the scheduler
|
||||
if r.options.Scheduler != nil {
|
||||
return r.options.Scheduler.Close()
|
||||
|
@@ -167,11 +167,10 @@ func (k *kubernetes) getService(labels map[string]string, opts ...client.GetOpti
|
||||
|
||||
// parse out deployment status and inject into service metadata
|
||||
if len(kdep.Status.Conditions) > 0 {
|
||||
svc.Metadata["status"] = kdep.Status.Conditions[0].Type
|
||||
svc.Status(kdep.Status.Conditions[0].Type, nil)
|
||||
svc.Metadata["started"] = kdep.Status.Conditions[0].LastUpdateTime
|
||||
delete(svc.Metadata, "error")
|
||||
} else {
|
||||
svc.Metadata["status"] = "n/a"
|
||||
svc.Status("n/a", nil)
|
||||
}
|
||||
|
||||
// get the real status
|
||||
@@ -214,8 +213,7 @@ func (k *kubernetes) getService(labels map[string]string, opts ...client.GetOpti
|
||||
}
|
||||
}
|
||||
// TODO: set from terminated
|
||||
|
||||
svc.Metadata["status"] = status
|
||||
svc.Status(status, nil)
|
||||
}
|
||||
|
||||
// save deployment
|
||||
@@ -252,12 +250,12 @@ func (k *kubernetes) run(events <-chan runtime.Event) {
|
||||
case runtime.Update:
|
||||
// only process if there's an actual service
|
||||
// we do not update all the things individually
|
||||
if len(event.Service) == 0 {
|
||||
if event.Service == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
// format the name
|
||||
name := client.Format(event.Service)
|
||||
name := client.Format(event.Service.Name)
|
||||
|
||||
// set the default labels
|
||||
labels := map[string]string{
|
||||
@@ -265,8 +263,8 @@ func (k *kubernetes) run(events <-chan runtime.Event) {
|
||||
"name": name,
|
||||
}
|
||||
|
||||
if len(event.Version) > 0 {
|
||||
labels["version"] = event.Version
|
||||
if len(event.Service.Version) > 0 {
|
||||
labels["version"] = event.Service.Version
|
||||
}
|
||||
|
||||
// get the deployment status
|
||||
|
@@ -3,6 +3,7 @@ package kubernetes
|
||||
import (
|
||||
"encoding/json"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/runtime"
|
||||
@@ -185,8 +186,10 @@ func (s *service) Update(k client.Client, opts ...client.UpdateOption) error {
|
||||
}
|
||||
|
||||
func (s *service) Status(status string, err error) {
|
||||
s.Metadata["lastStatusUpdate"] = time.Now().Format(time.RFC3339)
|
||||
if err == nil {
|
||||
s.Metadata["status"] = status
|
||||
delete(s.Metadata, "error")
|
||||
return
|
||||
}
|
||||
s.Metadata["status"] = "error"
|
||||
|
@@ -74,27 +74,18 @@ func (g libGitter) Checkout(repo, branchOrCommit string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
isCommit := func(s string) bool {
|
||||
return strings.ContainsAny(s, "0123456789") && len(s) == 40
|
||||
}
|
||||
if isCommit(branchOrCommit) {
|
||||
err = worktree.Checkout(&git.CheckoutOptions{
|
||||
|
||||
if plumbing.IsHash(branchOrCommit) {
|
||||
return worktree.Checkout(&git.CheckoutOptions{
|
||||
Hash: plumbing.NewHash(branchOrCommit),
|
||||
Force: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = worktree.Checkout(&git.CheckoutOptions{
|
||||
Branch: plumbing.NewBranchReferenceName(branchOrCommit),
|
||||
Force: true,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
return worktree.Checkout(&git.CheckoutOptions{
|
||||
Branch: plumbing.NewBranchReferenceName(branchOrCommit),
|
||||
Force: true,
|
||||
})
|
||||
}
|
||||
|
||||
func (g libGitter) RepoDir(repo string) string {
|
||||
|
@@ -20,6 +20,7 @@ func (p *Process) Exec(exe *process.Executable) error {
|
||||
}
|
||||
|
||||
func (p *Process) Fork(exe *process.Executable) (*process.PID, error) {
|
||||
|
||||
// create command
|
||||
cmd := exec.Command(exe.Package.Path, exe.Args...)
|
||||
|
||||
@@ -43,7 +44,6 @@ func (p *Process) Fork(exe *process.Executable) (*process.PID, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// start the process
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, err
|
||||
@@ -62,22 +62,13 @@ func (p *Process) Kill(pid *process.PID) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pr, err := os.FindProcess(id)
|
||||
if err != nil {
|
||||
if _, err := os.FindProcess(id); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// now kill it
|
||||
err = pr.Kill()
|
||||
|
||||
// kill the group
|
||||
if pgid, err := syscall.Getpgid(id); err == nil {
|
||||
syscall.Kill(-pgid, syscall.SIGKILL)
|
||||
}
|
||||
|
||||
// return the kill error
|
||||
return err
|
||||
// using -ve PID kills the process group which we created in Fork()
|
||||
return syscall.Kill(-id, syscall.SIGTERM)
|
||||
}
|
||||
|
||||
func (p *Process) Wait(pid *process.PID) error {
|
||||
|
@@ -6,8 +6,8 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/go-git/go-git/v5"
|
||||
"github.com/micro/go-micro/v2/runtime/local/source"
|
||||
git "gopkg.in/src-d/go-git.v4"
|
||||
)
|
||||
|
||||
// Source retrieves source code
|
||||
|
@@ -3,6 +3,8 @@ package runtime
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
)
|
||||
|
||||
type Option func(o *Options)
|
||||
@@ -17,6 +19,8 @@ type Options struct {
|
||||
Source string
|
||||
// Base image to use
|
||||
Image string
|
||||
// Client to use when making requests
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
// WithSource sets the base image / repository
|
||||
@@ -47,6 +51,13 @@ func WithImage(t string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithClient sets the client to use
|
||||
func WithClient(c client.Client) Option {
|
||||
return func(o *Options) {
|
||||
o.Client = c
|
||||
}
|
||||
}
|
||||
|
||||
type CreateOption func(o *CreateOptions)
|
||||
|
||||
type ReadOption func(o *ReadOptions)
|
||||
|
@@ -85,14 +85,16 @@ func (t EventType) String() string {
|
||||
|
||||
// Event is notification event
|
||||
type Event struct {
|
||||
// ID of the event
|
||||
ID string
|
||||
// Type is event type
|
||||
Type EventType
|
||||
// Timestamp is event timestamp
|
||||
Timestamp time.Time
|
||||
// Service is the name of the service
|
||||
Service string
|
||||
// Version of the build
|
||||
Version string
|
||||
// Service the event relates to
|
||||
Service *Service
|
||||
// Options to use when processing the event
|
||||
Options *CreateOptions
|
||||
}
|
||||
|
||||
// Service is runtime service
|
||||
|
@@ -93,7 +93,7 @@ func (s *service) Running() bool {
|
||||
return s.running
|
||||
}
|
||||
|
||||
// Start stars the service
|
||||
// Start starts the service
|
||||
func (s *service) Start() error {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
@@ -110,10 +110,7 @@ func (s *service) Start() error {
|
||||
if s.Metadata == nil {
|
||||
s.Metadata = make(map[string]string)
|
||||
}
|
||||
|
||||
s.Metadata["status"] = "starting"
|
||||
// delete any existing error
|
||||
delete(s.Metadata, "error")
|
||||
s.Status("starting", nil)
|
||||
|
||||
// TODO: pull source & build binary
|
||||
if logger.V(logger.DebugLevel, logger.DefaultLogger) {
|
||||
@@ -122,17 +119,15 @@ func (s *service) Start() error {
|
||||
|
||||
p, err := s.Process.Fork(s.Exec)
|
||||
if err != nil {
|
||||
s.Metadata["status"] = "error"
|
||||
s.Metadata["error"] = err.Error()
|
||||
s.Status("error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// set the pid
|
||||
s.PID = p
|
||||
// set to running
|
||||
s.running = true
|
||||
// set status
|
||||
s.Metadata["status"] = "running"
|
||||
s.Status("running", nil)
|
||||
// set started
|
||||
s.Metadata["started"] = time.Now().Format(time.RFC3339)
|
||||
|
||||
@@ -146,6 +141,18 @@ func (s *service) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Status updates the status of the service. Assumes it's called under a lock as it mutates state
|
||||
func (s *service) Status(status string, err error) {
|
||||
s.Metadata["lastStatusUpdate"] = time.Now().Format(time.RFC3339)
|
||||
s.Metadata["status"] = status
|
||||
if err == nil {
|
||||
delete(s.Metadata, "error")
|
||||
return
|
||||
}
|
||||
s.Metadata["error"] = err.Error()
|
||||
|
||||
}
|
||||
|
||||
// Stop stops the service
|
||||
func (s *service) Stop() error {
|
||||
s.Lock()
|
||||
@@ -163,18 +170,17 @@ func (s *service) Stop() error {
|
||||
}
|
||||
|
||||
// set status
|
||||
s.Metadata["status"] = "stopping"
|
||||
s.Status("stopping", nil)
|
||||
|
||||
// kill the process
|
||||
err := s.Process.Kill(s.PID)
|
||||
if err != nil {
|
||||
return err
|
||||
if err == nil {
|
||||
// wait for it to exit
|
||||
s.Process.Wait(s.PID)
|
||||
}
|
||||
// wait for it to exit
|
||||
s.Process.Wait(s.PID)
|
||||
|
||||
// set status
|
||||
s.Metadata["status"] = "stopped"
|
||||
s.Status("stopped", err)
|
||||
|
||||
// return the kill error
|
||||
return err
|
||||
@@ -191,21 +197,32 @@ func (s *service) Error() error {
|
||||
// Wait waits for the service to finish running
|
||||
func (s *service) Wait() {
|
||||
// wait for process to exit
|
||||
err := s.Process.Wait(s.PID)
|
||||
s.RLock()
|
||||
thisPID := s.PID
|
||||
s.RUnlock()
|
||||
err := s.Process.Wait(thisPID)
|
||||
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if s.PID.ID != thisPID.ID {
|
||||
// trying to update when it's already been switched out, ignore
|
||||
logger.Warnf("Trying to update a process status but PID doesn't match. Old %s, New %s. Skipping update.", thisPID.ID, s.PID.ID)
|
||||
return
|
||||
}
|
||||
|
||||
// save the error
|
||||
if err != nil {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Errorf("Service %s terminated with error %s", s.Name, err)
|
||||
}
|
||||
s.retries++
|
||||
s.Metadata["status"] = "error"
|
||||
s.Metadata["error"] = err.Error()
|
||||
s.Status("error", err)
|
||||
s.Metadata["retries"] = strconv.Itoa(s.retries)
|
||||
|
||||
s.err = err
|
||||
} else {
|
||||
s.Metadata["status"] = "done"
|
||||
s.Status("done", nil)
|
||||
}
|
||||
|
||||
// no longer running
|
||||
|
@@ -453,18 +453,50 @@ func (m *ReadResponse) GetServices() []*Service {
|
||||
return nil
|
||||
}
|
||||
|
||||
type DeleteRequest struct {
|
||||
Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
type DeleteOptions struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *DeleteOptions) Reset() { *m = DeleteOptions{} }
|
||||
func (m *DeleteOptions) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteOptions) ProtoMessage() {}
|
||||
func (*DeleteOptions) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{8}
|
||||
}
|
||||
|
||||
func (m *DeleteOptions) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_DeleteOptions.Unmarshal(m, b)
|
||||
}
|
||||
func (m *DeleteOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_DeleteOptions.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *DeleteOptions) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_DeleteOptions.Merge(m, src)
|
||||
}
|
||||
func (m *DeleteOptions) XXX_Size() int {
|
||||
return xxx_messageInfo_DeleteOptions.Size(m)
|
||||
}
|
||||
func (m *DeleteOptions) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_DeleteOptions.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_DeleteOptions proto.InternalMessageInfo
|
||||
|
||||
type DeleteRequest struct {
|
||||
Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
Options *DeleteOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *DeleteRequest) Reset() { *m = DeleteRequest{} }
|
||||
func (m *DeleteRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteRequest) ProtoMessage() {}
|
||||
func (*DeleteRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{8}
|
||||
return fileDescriptor_2434d8152598889b, []int{9}
|
||||
}
|
||||
|
||||
func (m *DeleteRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -492,6 +524,13 @@ func (m *DeleteRequest) GetService() *Service {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *DeleteRequest) GetOptions() *DeleteOptions {
|
||||
if m != nil {
|
||||
return m.Options
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type DeleteResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
@@ -502,7 +541,7 @@ func (m *DeleteResponse) Reset() { *m = DeleteResponse{} }
|
||||
func (m *DeleteResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*DeleteResponse) ProtoMessage() {}
|
||||
func (*DeleteResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{9}
|
||||
return fileDescriptor_2434d8152598889b, []int{10}
|
||||
}
|
||||
|
||||
func (m *DeleteResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -523,18 +562,50 @@ func (m *DeleteResponse) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_DeleteResponse proto.InternalMessageInfo
|
||||
|
||||
type UpdateRequest struct {
|
||||
Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
type UpdateOptions struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *UpdateOptions) Reset() { *m = UpdateOptions{} }
|
||||
func (m *UpdateOptions) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateOptions) ProtoMessage() {}
|
||||
func (*UpdateOptions) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{11}
|
||||
}
|
||||
|
||||
func (m *UpdateOptions) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_UpdateOptions.Unmarshal(m, b)
|
||||
}
|
||||
func (m *UpdateOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_UpdateOptions.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *UpdateOptions) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_UpdateOptions.Merge(m, src)
|
||||
}
|
||||
func (m *UpdateOptions) XXX_Size() int {
|
||||
return xxx_messageInfo_UpdateOptions.Size(m)
|
||||
}
|
||||
func (m *UpdateOptions) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_UpdateOptions.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_UpdateOptions proto.InternalMessageInfo
|
||||
|
||||
type UpdateRequest struct {
|
||||
Service *Service `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
Options *UpdateOptions `protobuf:"bytes,2,opt,name=options,proto3" json:"options,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *UpdateRequest) Reset() { *m = UpdateRequest{} }
|
||||
func (m *UpdateRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateRequest) ProtoMessage() {}
|
||||
func (*UpdateRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{10}
|
||||
return fileDescriptor_2434d8152598889b, []int{12}
|
||||
}
|
||||
|
||||
func (m *UpdateRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -562,6 +633,13 @@ func (m *UpdateRequest) GetService() *Service {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *UpdateRequest) GetOptions() *UpdateOptions {
|
||||
if m != nil {
|
||||
return m.Options
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type UpdateResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
@@ -572,7 +650,7 @@ func (m *UpdateResponse) Reset() { *m = UpdateResponse{} }
|
||||
func (m *UpdateResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateResponse) ProtoMessage() {}
|
||||
func (*UpdateResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{11}
|
||||
return fileDescriptor_2434d8152598889b, []int{13}
|
||||
}
|
||||
|
||||
func (m *UpdateResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -593,17 +671,49 @@ func (m *UpdateResponse) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_UpdateResponse proto.InternalMessageInfo
|
||||
|
||||
type ListRequest struct {
|
||||
type ListOptions struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ListOptions) Reset() { *m = ListOptions{} }
|
||||
func (m *ListOptions) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListOptions) ProtoMessage() {}
|
||||
func (*ListOptions) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{14}
|
||||
}
|
||||
|
||||
func (m *ListOptions) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ListOptions.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ListOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ListOptions.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ListOptions) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ListOptions.Merge(m, src)
|
||||
}
|
||||
func (m *ListOptions) XXX_Size() int {
|
||||
return xxx_messageInfo_ListOptions.Size(m)
|
||||
}
|
||||
func (m *ListOptions) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ListOptions.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ListOptions proto.InternalMessageInfo
|
||||
|
||||
type ListRequest struct {
|
||||
Options *ListOptions `protobuf:"bytes,1,opt,name=options,proto3" json:"options,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ListRequest) Reset() { *m = ListRequest{} }
|
||||
func (m *ListRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListRequest) ProtoMessage() {}
|
||||
func (*ListRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{12}
|
||||
return fileDescriptor_2434d8152598889b, []int{15}
|
||||
}
|
||||
|
||||
func (m *ListRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -624,6 +734,13 @@ func (m *ListRequest) XXX_DiscardUnknown() {
|
||||
|
||||
var xxx_messageInfo_ListRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *ListRequest) GetOptions() *ListOptions {
|
||||
if m != nil {
|
||||
return m.Options
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ListResponse struct {
|
||||
Services []*Service `protobuf:"bytes,1,rep,name=services,proto3" json:"services,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
@@ -635,7 +752,7 @@ func (m *ListResponse) Reset() { *m = ListResponse{} }
|
||||
func (m *ListResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ListResponse) ProtoMessage() {}
|
||||
func (*ListResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{13}
|
||||
return fileDescriptor_2434d8152598889b, []int{16}
|
||||
}
|
||||
|
||||
func (m *ListResponse) XXX_Unmarshal(b []byte) error {
|
||||
@@ -663,6 +780,37 @@ func (m *ListResponse) GetServices() []*Service {
|
||||
return nil
|
||||
}
|
||||
|
||||
type LogsOptions struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *LogsOptions) Reset() { *m = LogsOptions{} }
|
||||
func (m *LogsOptions) String() string { return proto.CompactTextString(m) }
|
||||
func (*LogsOptions) ProtoMessage() {}
|
||||
func (*LogsOptions) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{17}
|
||||
}
|
||||
|
||||
func (m *LogsOptions) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_LogsOptions.Unmarshal(m, b)
|
||||
}
|
||||
func (m *LogsOptions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_LogsOptions.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *LogsOptions) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_LogsOptions.Merge(m, src)
|
||||
}
|
||||
func (m *LogsOptions) XXX_Size() int {
|
||||
return xxx_messageInfo_LogsOptions.Size(m)
|
||||
}
|
||||
func (m *LogsOptions) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_LogsOptions.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_LogsOptions proto.InternalMessageInfo
|
||||
|
||||
type LogsRequest struct {
|
||||
// service to request logs for
|
||||
Service string `protobuf:"bytes,1,opt,name=service,proto3" json:"service,omitempty"`
|
||||
@@ -673,17 +821,19 @@ type LogsRequest struct {
|
||||
// relative time in seconds
|
||||
// before the current time
|
||||
// from which to show logs
|
||||
Since int64 `protobuf:"varint,4,opt,name=since,proto3" json:"since,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
Since int64 `protobuf:"varint,4,opt,name=since,proto3" json:"since,omitempty"`
|
||||
// options to use
|
||||
Options *LogsOptions `protobuf:"bytes,5,opt,name=options,proto3" json:"options,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *LogsRequest) Reset() { *m = LogsRequest{} }
|
||||
func (m *LogsRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*LogsRequest) ProtoMessage() {}
|
||||
func (*LogsRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{14}
|
||||
return fileDescriptor_2434d8152598889b, []int{18}
|
||||
}
|
||||
|
||||
func (m *LogsRequest) XXX_Unmarshal(b []byte) error {
|
||||
@@ -732,6 +882,13 @@ func (m *LogsRequest) GetSince() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *LogsRequest) GetOptions() *LogsOptions {
|
||||
if m != nil {
|
||||
return m.Options
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type LogRecord struct {
|
||||
// timestamp of log record
|
||||
Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"`
|
||||
@@ -748,7 +905,7 @@ func (m *LogRecord) Reset() { *m = LogRecord{} }
|
||||
func (m *LogRecord) String() string { return proto.CompactTextString(m) }
|
||||
func (*LogRecord) ProtoMessage() {}
|
||||
func (*LogRecord) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_2434d8152598889b, []int{15}
|
||||
return fileDescriptor_2434d8152598889b, []int{19}
|
||||
}
|
||||
|
||||
func (m *LogRecord) XXX_Unmarshal(b []byte) error {
|
||||
@@ -800,12 +957,16 @@ func init() {
|
||||
proto.RegisterType((*ReadOptions)(nil), "go.micro.runtime.ReadOptions")
|
||||
proto.RegisterType((*ReadRequest)(nil), "go.micro.runtime.ReadRequest")
|
||||
proto.RegisterType((*ReadResponse)(nil), "go.micro.runtime.ReadResponse")
|
||||
proto.RegisterType((*DeleteOptions)(nil), "go.micro.runtime.DeleteOptions")
|
||||
proto.RegisterType((*DeleteRequest)(nil), "go.micro.runtime.DeleteRequest")
|
||||
proto.RegisterType((*DeleteResponse)(nil), "go.micro.runtime.DeleteResponse")
|
||||
proto.RegisterType((*UpdateOptions)(nil), "go.micro.runtime.UpdateOptions")
|
||||
proto.RegisterType((*UpdateRequest)(nil), "go.micro.runtime.UpdateRequest")
|
||||
proto.RegisterType((*UpdateResponse)(nil), "go.micro.runtime.UpdateResponse")
|
||||
proto.RegisterType((*ListOptions)(nil), "go.micro.runtime.ListOptions")
|
||||
proto.RegisterType((*ListRequest)(nil), "go.micro.runtime.ListRequest")
|
||||
proto.RegisterType((*ListResponse)(nil), "go.micro.runtime.ListResponse")
|
||||
proto.RegisterType((*LogsOptions)(nil), "go.micro.runtime.LogsOptions")
|
||||
proto.RegisterType((*LogsRequest)(nil), "go.micro.runtime.LogsRequest")
|
||||
proto.RegisterType((*LogRecord)(nil), "go.micro.runtime.LogRecord")
|
||||
proto.RegisterMapType((map[string]string)(nil), "go.micro.runtime.LogRecord.MetadataEntry")
|
||||
@@ -816,48 +977,50 @@ func init() {
|
||||
}
|
||||
|
||||
var fileDescriptor_2434d8152598889b = []byte{
|
||||
// 645 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xa4, 0x55, 0xc9, 0x6e, 0xdb, 0x30,
|
||||
0x10, 0x8d, 0x2c, 0x2f, 0xc9, 0xa8, 0x2e, 0x02, 0x22, 0x28, 0xd4, 0x74, 0x33, 0xd4, 0x43, 0xd3,
|
||||
0x8b, 0x52, 0x38, 0x28, 0xba, 0x1d, 0x63, 0xa7, 0x17, 0x1b, 0x05, 0x54, 0xe4, 0x03, 0x58, 0x79,
|
||||
0x60, 0x08, 0x89, 0x44, 0x55, 0xa4, 0x0c, 0xf8, 0xd4, 0x63, 0xcf, 0xfd, 0xaa, 0x9e, 0xfb, 0x47,
|
||||
0x05, 0x17, 0x6d, 0xb6, 0x94, 0x8b, 0x6f, 0x9c, 0x11, 0xf9, 0xf8, 0xde, 0x9b, 0x19, 0x0a, 0x5e,
|
||||
0x67, 0x79, 0x22, 0xa2, 0x18, 0x2f, 0x39, 0x66, 0x9b, 0x28, 0xc4, 0xcb, 0x34, 0x63, 0x82, 0x5d,
|
||||
0x9a, 0xac, 0xaf, 0x22, 0x72, 0xba, 0x66, 0x7e, 0x1c, 0x85, 0x19, 0xf3, 0x4d, 0xde, 0xfb, 0x67,
|
||||
0xc1, 0xe8, 0xbb, 0x3e, 0x41, 0x08, 0xf4, 0x13, 0x1a, 0xa3, 0x6b, 0x4d, 0xac, 0x8b, 0x93, 0x40,
|
||||
0xad, 0x89, 0x0b, 0xa3, 0x0d, 0x66, 0x3c, 0x62, 0x89, 0xdb, 0x53, 0xe9, 0x22, 0x24, 0x4f, 0x60,
|
||||
0xc8, 0x59, 0x9e, 0x85, 0xe8, 0xda, 0xea, 0x83, 0x89, 0xc8, 0x35, 0x1c, 0xc7, 0x28, 0xe8, 0x8a,
|
||||
0x0a, 0xea, 0xf6, 0x27, 0xf6, 0x85, 0x33, 0x7d, 0xe3, 0xef, 0x5e, 0xeb, 0x9b, 0x2b, 0xfd, 0xa5,
|
||||
0xd9, 0x39, 0x4f, 0x44, 0xb6, 0x0d, 0xca, 0x83, 0xe7, 0x5f, 0x60, 0xdc, 0xf8, 0x44, 0x4e, 0xc1,
|
||||
0xbe, 0xc3, 0xad, 0xa1, 0x26, 0x97, 0xe4, 0x0c, 0x06, 0x1b, 0x7a, 0x9f, 0xa3, 0xe1, 0xa5, 0x83,
|
||||
0xcf, 0xbd, 0x8f, 0x96, 0x17, 0xc3, 0x60, 0xbe, 0xc1, 0x44, 0x48, 0x41, 0x62, 0x9b, 0x96, 0x82,
|
||||
0xe4, 0x9a, 0x3c, 0x87, 0x13, 0xc9, 0x80, 0x0b, 0x1a, 0xa7, 0xea, 0xa8, 0x1d, 0x54, 0x09, 0x29,
|
||||
0xd7, 0xf8, 0x67, 0x54, 0x15, 0x61, 0xdd, 0x88, 0x7e, 0xc3, 0x08, 0xef, 0x8f, 0x05, 0xe3, 0xeb,
|
||||
0x0c, 0xa9, 0xc0, 0x6f, 0xa9, 0x88, 0x58, 0xc2, 0xe5, 0xde, 0x90, 0xc5, 0x31, 0x4d, 0x56, 0xae,
|
||||
0x35, 0xb1, 0xe5, 0x5e, 0x13, 0x4a, 0x46, 0x34, 0x5b, 0x73, 0xb7, 0xa7, 0xd2, 0x6a, 0x2d, 0xa5,
|
||||
0x61, 0xb2, 0x71, 0x6d, 0x95, 0x92, 0x4b, 0x69, 0x2d, 0xcb, 0x45, 0x9a, 0x0b, 0x73, 0x95, 0x89,
|
||||
0x4a, 0x3d, 0x83, 0x9a, 0x9e, 0x33, 0x18, 0x44, 0x31, 0x5d, 0xa3, 0x3b, 0xd4, 0x36, 0xa8, 0xc0,
|
||||
0xfb, 0x55, 0x50, 0x0a, 0xf0, 0x67, 0x8e, 0x5c, 0x90, 0xab, 0x4a, 0x98, 0x74, 0xc3, 0x99, 0x3e,
|
||||
0xed, 0x2c, 0x4a, 0xa5, 0xf9, 0x13, 0x8c, 0x98, 0x96, 0xa4, 0x9c, 0x72, 0xa6, 0xaf, 0xf6, 0x0f,
|
||||
0x35, 0x94, 0x07, 0xc5, 0x7e, 0xef, 0x14, 0x1e, 0x17, 0x04, 0x78, 0xca, 0x12, 0x8e, 0xde, 0x2d,
|
||||
0x38, 0x01, 0xd2, 0x55, 0xcd, 0xa3, 0x3a, 0xa1, 0x76, 0xa7, 0x77, 0x5a, 0xae, 0xd0, 0x6f, 0x57,
|
||||
0xfa, 0xbd, 0x1b, 0x0d, 0x5b, 0xe8, 0xfc, 0x50, 0x51, 0xd6, 0x3a, 0x5f, 0xec, 0x53, 0xae, 0xd1,
|
||||
0xa8, 0x08, 0xcf, 0xe1, 0x91, 0xc6, 0xd1, 0x74, 0xc9, 0x7b, 0x38, 0x36, 0x84, 0xb8, 0x2a, 0xe2,
|
||||
0x83, 0x8e, 0x95, 0x5b, 0xbd, 0x19, 0x8c, 0x67, 0x78, 0x8f, 0x87, 0x19, 0x2f, 0xdd, 0x2b, 0x50,
|
||||
0x8c, 0x7b, 0x33, 0x18, 0xdf, 0xa6, 0x2b, 0x7a, 0x38, 0x6e, 0x81, 0x62, 0x70, 0xc7, 0xe0, 0x2c,
|
||||
0x22, 0x2e, 0x0c, 0xaa, 0x74, 0x41, 0x87, 0x87, 0xb9, 0x70, 0x07, 0xce, 0x82, 0xad, 0x79, 0xc1,
|
||||
0xb5, 0xbb, 0xd6, 0xf2, 0x11, 0x11, 0x19, 0xd2, 0x58, 0x95, 0xfa, 0x38, 0x30, 0x91, 0xec, 0xea,
|
||||
0x90, 0xe5, 0x89, 0x50, 0xa5, 0xb6, 0x03, 0x1d, 0xc8, 0x2c, 0x8f, 0x92, 0x10, 0xd5, 0x58, 0xd8,
|
||||
0x81, 0x0e, 0xbc, 0xbf, 0x16, 0x9c, 0x2c, 0xd8, 0x3a, 0xc0, 0x90, 0x65, 0xab, 0xe6, 0x7c, 0x5b,
|
||||
0xbb, 0xf3, 0x3d, 0xaf, 0x3d, 0x4e, 0x3d, 0xa5, 0xe7, 0xed, 0xbe, 0x9e, 0x12, 0xac, 0xeb, 0x79,
|
||||
0x92, 0x82, 0x62, 0xe4, 0x5c, 0x8e, 0x9d, 0x79, 0x26, 0x4c, 0x78, 0xd0, 0xc3, 0x35, 0xfd, 0x6d,
|
||||
0xc3, 0x28, 0xd0, 0x24, 0xc8, 0x12, 0x86, 0x7a, 0x80, 0x48, 0xe7, 0xd0, 0x19, 0x7b, 0xcf, 0x27,
|
||||
0xdd, 0x1b, 0x4c, 0x95, 0x8f, 0xc8, 0x57, 0xe8, 0xcb, 0xf6, 0x26, 0x1d, 0xe3, 0x50, 0x40, 0xbd,
|
||||
0xec, 0xfa, 0x5c, 0x02, 0x2d, 0x61, 0xa8, 0x5b, 0xb3, 0x8d, 0x57, 0xa3, 0xf5, 0xdb, 0x78, 0xed,
|
||||
0x74, 0xb5, 0x82, 0xd3, 0x1d, 0xd9, 0x06, 0xd7, 0xe8, 0xf8, 0x36, 0xb8, 0x9d, 0x66, 0x3e, 0x22,
|
||||
0x37, 0xd0, 0x97, 0x8d, 0xd7, 0x26, 0xb3, 0xd6, 0x90, 0xe7, 0xcf, 0x1e, 0x28, 0xba, 0x77, 0xf4,
|
||||
0xce, 0xfa, 0x31, 0x54, 0xff, 0xcb, 0xab, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x20, 0x0e, 0x37,
|
||||
0xf1, 0x56, 0x07, 0x00, 0x00,
|
||||
// 683 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xcb, 0x6e, 0xd3, 0x40,
|
||||
0x14, 0xad, 0xe3, 0x3c, 0xda, 0x1b, 0x42, 0xab, 0x51, 0x85, 0x4c, 0x79, 0x45, 0x66, 0x41, 0xd9,
|
||||
0x38, 0x28, 0x15, 0xe2, 0xb5, 0x2c, 0x09, 0x9b, 0x46, 0x48, 0x46, 0xfd, 0x80, 0xc1, 0xb9, 0x8a,
|
||||
0x2c, 0x6a, 0x8f, 0xf1, 0x8c, 0x23, 0x65, 0xc5, 0x92, 0x35, 0xff, 0xc0, 0xbf, 0xb0, 0xe6, 0x8f,
|
||||
0xd0, 0xbc, 0xfc, 0x48, 0xeb, 0x48, 0xa8, 0xea, 0x6e, 0xce, 0xf5, 0xcc, 0x9d, 0x73, 0xce, 0x9d,
|
||||
0x7b, 0x65, 0x78, 0x9e, 0x17, 0xa9, 0x88, 0x13, 0x9c, 0x70, 0xcc, 0xd7, 0x71, 0x84, 0x93, 0x2c,
|
||||
0x67, 0x82, 0x4d, 0x4c, 0x34, 0x50, 0x88, 0x1c, 0xad, 0x58, 0x90, 0xc4, 0x51, 0xce, 0x02, 0x13,
|
||||
0xf7, 0xff, 0x3a, 0x30, 0xf8, 0xa2, 0x4f, 0x10, 0x02, 0xdd, 0x94, 0x26, 0xe8, 0x39, 0x63, 0xe7,
|
||||
0xf4, 0x20, 0x54, 0x6b, 0xe2, 0xc1, 0x60, 0x8d, 0x39, 0x8f, 0x59, 0xea, 0x75, 0x54, 0xd8, 0x42,
|
||||
0xf2, 0x00, 0xfa, 0x9c, 0x15, 0x79, 0x84, 0x9e, 0xab, 0x3e, 0x18, 0x44, 0xce, 0x61, 0x3f, 0x41,
|
||||
0x41, 0x97, 0x54, 0x50, 0xaf, 0x3b, 0x76, 0x4f, 0x87, 0xd3, 0x17, 0xc1, 0xf6, 0xb5, 0x81, 0xb9,
|
||||
0x32, 0x58, 0x98, 0x9d, 0xb3, 0x54, 0xe4, 0x9b, 0xb0, 0x3c, 0x78, 0xf2, 0x01, 0x46, 0x8d, 0x4f,
|
||||
0xe4, 0x08, 0xdc, 0x6f, 0xb8, 0x31, 0xd4, 0xe4, 0x92, 0x1c, 0x43, 0x6f, 0x4d, 0xaf, 0x0a, 0x34,
|
||||
0xbc, 0x34, 0x78, 0xdf, 0x79, 0xeb, 0xf8, 0x09, 0xf4, 0x66, 0x6b, 0x4c, 0x85, 0x14, 0x24, 0x36,
|
||||
0x59, 0x29, 0x48, 0xae, 0xc9, 0x63, 0x38, 0x90, 0x0c, 0xb8, 0xa0, 0x49, 0xa6, 0x8e, 0xba, 0x61,
|
||||
0x15, 0x90, 0x72, 0x8d, 0x7f, 0x46, 0x95, 0x85, 0x75, 0x23, 0xba, 0x0d, 0x23, 0xfc, 0x5f, 0x0e,
|
||||
0x8c, 0xce, 0x73, 0xa4, 0x02, 0x3f, 0x67, 0x22, 0x66, 0x29, 0x97, 0x7b, 0x23, 0x96, 0x24, 0x34,
|
||||
0x5d, 0x7a, 0xce, 0xd8, 0x95, 0x7b, 0x0d, 0x94, 0x8c, 0x68, 0xbe, 0xe2, 0x5e, 0x47, 0x85, 0xd5,
|
||||
0x5a, 0x4a, 0xc3, 0x74, 0xed, 0xb9, 0x2a, 0x24, 0x97, 0xd2, 0x5a, 0x56, 0x88, 0xac, 0x10, 0xe6,
|
||||
0x2a, 0x83, 0x4a, 0x3d, 0xbd, 0x9a, 0x9e, 0x63, 0xe8, 0xc5, 0x09, 0x5d, 0xa1, 0xd7, 0xd7, 0x36,
|
||||
0x28, 0xe0, 0xff, 0xb0, 0x94, 0x42, 0xfc, 0x5e, 0x20, 0x17, 0xe4, 0xac, 0x12, 0x26, 0xdd, 0x18,
|
||||
0x4e, 0x1f, 0xb6, 0x16, 0xa5, 0xd2, 0xfc, 0x0e, 0x06, 0x4c, 0x4b, 0x52, 0x4e, 0x0d, 0xa7, 0xcf,
|
||||
0xae, 0x1f, 0x6a, 0x28, 0x0f, 0xed, 0x7e, 0xff, 0x08, 0xee, 0x5b, 0x02, 0x3c, 0x63, 0x29, 0x47,
|
||||
0xff, 0x12, 0x86, 0x21, 0xd2, 0x65, 0xcd, 0xa3, 0x3a, 0xa1, 0x9b, 0x9d, 0xde, 0x7a, 0x72, 0x56,
|
||||
0xbf, 0x5b, 0xe9, 0xf7, 0xe7, 0x3a, 0xad, 0xd5, 0xf9, 0xa6, 0xa2, 0xac, 0x75, 0x3e, 0xb9, 0x4e,
|
||||
0xb9, 0x46, 0xa3, 0x22, 0x3c, 0x83, 0x7b, 0x3a, 0x8f, 0xa6, 0x4b, 0x5e, 0xc3, 0xbe, 0x21, 0xc4,
|
||||
0x55, 0x11, 0x77, 0x3a, 0x56, 0x6e, 0xf5, 0x0f, 0x61, 0xf4, 0x11, 0xaf, 0xb0, 0x74, 0x44, 0x56,
|
||||
0x42, 0x07, 0xee, 0xbc, 0x12, 0x8d, 0x7b, 0x1b, 0x95, 0xb0, 0x04, 0x4c, 0x25, 0x0e, 0x61, 0x74,
|
||||
0x99, 0x2d, 0x69, 0x83, 0xa3, 0x0e, 0xdc, 0x39, 0xc7, 0xc6, 0xbd, 0x0d, 0x8e, 0x96, 0x80, 0xe1,
|
||||
0x38, 0x82, 0xe1, 0x45, 0xcc, 0x85, 0x65, 0x38, 0xd7, 0xf0, 0x7f, 0xaa, 0x5c, 0x3b, 0xde, 0xa8,
|
||||
0xb2, 0xce, 0x73, 0xbb, 0x2a, 0x4b, 0x76, 0x6c, 0xc5, 0x2d, 0xbb, 0xdf, 0x8e, 0xc6, 0x96, 0x5e,
|
||||
0xfb, 0xdb, 0x96, 0x43, 0x53, 0xe4, 0x48, 0x13, 0x65, 0xd1, 0x7e, 0x68, 0x90, 0xec, 0xe2, 0x88,
|
||||
0x15, 0xa9, 0x50, 0x4f, 0xdb, 0x0d, 0x35, 0x90, 0x51, 0x1e, 0xa7, 0x11, 0xaa, 0x31, 0xe0, 0x86,
|
||||
0x1a, 0xd4, 0xc5, 0xf7, 0x5a, 0xc5, 0x57, 0xec, 0x2a, 0xf1, 0x7f, 0x1c, 0x38, 0xb8, 0x60, 0xab,
|
||||
0x10, 0x23, 0x96, 0x2f, 0x9b, 0x83, 0xd0, 0xd9, 0x1e, 0x84, 0xb3, 0xda, 0x14, 0xef, 0x28, 0x63,
|
||||
0x5e, 0xde, 0x78, 0x8b, 0x4e, 0xd6, 0x36, 0xc7, 0xa5, 0x13, 0x09, 0x72, 0x2e, 0xe7, 0x93, 0x99,
|
||||
0xa7, 0x06, 0xde, 0x6a, 0xc2, 0x4f, 0x7f, 0xba, 0x30, 0x08, 0x35, 0x09, 0xb2, 0x80, 0xbe, 0x9e,
|
||||
0x34, 0xa4, 0x75, 0x3a, 0x99, 0xba, 0x9c, 0x8c, 0xdb, 0x37, 0x98, 0x67, 0xb7, 0x47, 0x3e, 0x41,
|
||||
0x57, 0xce, 0x01, 0xd2, 0x32, 0x37, 0x6c, 0xaa, 0xa7, 0x6d, 0x9f, 0xcb, 0x44, 0x0b, 0xe8, 0xeb,
|
||||
0xbe, 0x23, 0xad, 0xbd, 0xba, 0x83, 0xd7, 0x56, 0xcb, 0xaa, 0x74, 0xba, 0x45, 0x48, 0x6b, 0x5b,
|
||||
0xed, 0x48, 0xb7, 0xd5, 0x5d, 0x7b, 0x64, 0x0e, 0x5d, 0xf9, 0x46, 0x48, 0xcb, 0xdb, 0xb1, 0xa9,
|
||||
0x1e, 0xed, 0x28, 0xba, 0xbf, 0xf7, 0xca, 0xf9, 0xda, 0x57, 0x3f, 0x16, 0x67, 0xff, 0x02, 0x00,
|
||||
0x00, 0xff, 0xff, 0xe1, 0x5b, 0x52, 0x93, 0x7f, 0x08, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
@@ -67,24 +67,40 @@ message ReadResponse {
|
||||
repeated Service services = 1;
|
||||
}
|
||||
|
||||
message DeleteOptions {
|
||||
}
|
||||
|
||||
message DeleteRequest {
|
||||
Service service = 1;
|
||||
DeleteOptions options = 2;
|
||||
}
|
||||
|
||||
message DeleteResponse {}
|
||||
|
||||
message UpdateOptions {
|
||||
}
|
||||
|
||||
message UpdateRequest {
|
||||
Service service = 1;
|
||||
UpdateOptions options = 2;
|
||||
}
|
||||
|
||||
message UpdateResponse {}
|
||||
|
||||
message ListRequest {}
|
||||
message ListOptions {
|
||||
}
|
||||
|
||||
message ListRequest {
|
||||
ListOptions options = 1;
|
||||
}
|
||||
|
||||
message ListResponse {
|
||||
repeated Service services = 1;
|
||||
}
|
||||
|
||||
message LogsOptions {
|
||||
}
|
||||
|
||||
message LogsRequest{
|
||||
// service to request logs for
|
||||
string service = 1;
|
||||
@@ -96,6 +112,8 @@ message LogsRequest{
|
||||
// before the current time
|
||||
// from which to show logs
|
||||
int64 since = 4;
|
||||
// options to use
|
||||
LogsOptions options = 5;
|
||||
}
|
||||
|
||||
message LogRecord {
|
||||
|
@@ -24,6 +24,9 @@ func (s *svc) Init(opts ...runtime.Option) error {
|
||||
o(&s.options)
|
||||
}
|
||||
|
||||
// reset the runtime as the client could have changed
|
||||
s.runtime = pb.NewRuntimeService(runtime.DefaultName, s.options.Client)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -267,19 +270,17 @@ func (s *svc) String() string {
|
||||
|
||||
// NewRuntime creates new service runtime and returns it
|
||||
func NewRuntime(opts ...runtime.Option) runtime.Runtime {
|
||||
// get default options
|
||||
options := runtime.Options{}
|
||||
var options runtime.Options
|
||||
|
||||
// apply requested options
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
// create default client
|
||||
cli := client.DefaultClient
|
||||
if options.Client == nil {
|
||||
options.Client = client.DefaultClient
|
||||
}
|
||||
|
||||
return &svc{
|
||||
options: options,
|
||||
runtime: pb.NewRuntimeService(runtime.DefaultName, cli),
|
||||
runtime: pb.NewRuntimeService(runtime.DefaultName, options.Client),
|
||||
}
|
||||
}
|
||||
|
@@ -22,6 +22,7 @@ import (
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
"github.com/micro/go-micro/v2/util/addr"
|
||||
"github.com/micro/go-micro/v2/util/backoff"
|
||||
mgrpc "github.com/micro/go-micro/v2/util/grpc"
|
||||
mnet "github.com/micro/go-micro/v2/util/net"
|
||||
"golang.org/x/net/netutil"
|
||||
@@ -566,16 +567,36 @@ func (g *grpcServer) Subscribe(sb server.Subscriber) error {
|
||||
}
|
||||
|
||||
func (g *grpcServer) Register() error {
|
||||
|
||||
g.RLock()
|
||||
rsvc := g.rsvc
|
||||
config := g.opts
|
||||
g.RUnlock()
|
||||
|
||||
regFunc := func(service *registry.Service) error {
|
||||
var regErr error
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
// set the ttl
|
||||
rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}
|
||||
// attempt to register
|
||||
if err := config.Registry.Register(service, rOpts...); err != nil {
|
||||
// set the error
|
||||
regErr = err
|
||||
// backoff then retry
|
||||
time.Sleep(backoff.Do(i + 1))
|
||||
continue
|
||||
}
|
||||
// success so nil error
|
||||
regErr = nil
|
||||
break
|
||||
}
|
||||
|
||||
return regErr
|
||||
}
|
||||
|
||||
// if service already filled, reuse it and return early
|
||||
if rsvc != nil {
|
||||
rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}
|
||||
if err := config.Registry.Register(rsvc, rOpts...); err != nil {
|
||||
if err := regFunc(rsvc); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
@@ -677,10 +698,8 @@ func (g *grpcServer) Register() error {
|
||||
}
|
||||
}
|
||||
|
||||
// create registry options
|
||||
rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}
|
||||
|
||||
if err := config.Registry.Register(service, rOpts...); err != nil {
|
||||
// register the service
|
||||
if err := regFunc(service); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@@ -120,23 +120,23 @@ func init() { proto.RegisterFile("server/grpc/proto/test.proto", fileDescriptor_
|
||||
|
||||
var fileDescriptor_bb9c685b7640cf1e = []byte{
|
||||
// 261 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x74, 0xd0, 0xcf, 0x4a, 0x03, 0x31,
|
||||
0x10, 0x06, 0x70, 0xb6, 0x2e, 0xba, 0xcd, 0x45, 0xc9, 0x69, 0x59, 0x56, 0x2c, 0xd1, 0x82, 0x54,
|
||||
0xd8, 0xf1, 0xcf, 0xad, 0x97, 0x0a, 0x82, 0xe0, 0x4d, 0x56, 0xcf, 0x42, 0xdc, 0x0e, 0x4b, 0x20,
|
||||
0x4d, 0x62, 0x92, 0xdd, 0x8b, 0x78, 0xf1, 0x15, 0x7c, 0x34, 0x5f, 0x41, 0xdf, 0x43, 0x92, 0x6d,
|
||||
0x4f, 0xb6, 0xb7, 0x8f, 0x09, 0xdf, 0x6f, 0x86, 0x90, 0xd2, 0xa1, 0xed, 0xd1, 0x42, 0x6b, 0x4d,
|
||||
0x03, 0xc6, 0x6a, 0xaf, 0xc1, 0xa3, 0xf3, 0x55, 0x8c, 0x45, 0xd9, 0x6a, 0xdd, 0x4a, 0x04, 0x6e,
|
||||
0x04, 0x70, 0xa5, 0xb4, 0xe7, 0x5e, 0x68, 0xe5, 0x86, 0x57, 0x76, 0x45, 0x0e, 0x6a, 0x7c, 0xeb,
|
||||
0xd0, 0x79, 0x4a, 0x49, 0xda, 0x75, 0x62, 0x99, 0x27, 0x93, 0xe4, 0x7c, 0x5c, 0xc7, 0x1c, 0x66,
|
||||
0x8a, 0xaf, 0x30, 0x1f, 0x0d, 0xb3, 0x90, 0x59, 0x49, 0xb2, 0x1a, 0x9d, 0xd1, 0xca, 0x21, 0x3d,
|
||||
0x22, 0x7b, 0x2b, 0xd7, 0xae, 0x2b, 0x21, 0x5e, 0xff, 0x26, 0x24, 0x7d, 0x0e, 0xdc, 0x2d, 0x49,
|
||||
0xef, 0xb8, 0x94, 0x34, 0xab, 0xd6, 0x0b, 0x8a, 0x71, 0xb5, 0xe9, 0xb1, 0xd3, 0xcf, 0xef, 0x9f,
|
||||
0xaf, 0xd1, 0x31, 0xcb, 0xe3, 0x59, 0xfd, 0x65, 0x3c, 0x18, 0x1a, 0x2e, 0x25, 0xbc, 0x87, 0xc5,
|
||||
0x1f, 0xf3, 0x64, 0x46, 0xef, 0x49, 0x16, 0x84, 0xc7, 0xc6, 0xe2, 0x76, 0x65, 0x1a, 0x95, 0x13,
|
||||
0x56, 0xbc, 0xfc, 0x67, 0x4c, 0x63, 0x11, 0x16, 0x67, 0xc1, 0x79, 0x22, 0x87, 0x1b, 0xe7, 0x41,
|
||||
0xf5, 0x5c, 0x8a, 0xe5, 0x76, 0xee, 0x22, 0x72, 0x53, 0x36, 0xd9, 0xa1, 0x89, 0xa1, 0x0c, 0x8b,
|
||||
0x79, 0x32, 0x7b, 0xdd, 0x8f, 0xff, 0x77, 0xf3, 0x17, 0x00, 0x00, 0xff, 0xff, 0xd3, 0x25, 0x7a,
|
||||
0x7d, 0x7d, 0x01, 0x00, 0x00,
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe2, 0x92, 0x29, 0x4e, 0x2d, 0x2a,
|
||||
0x4b, 0x2d, 0xd2, 0x4f, 0x2f, 0x2a, 0x48, 0xd6, 0x2f, 0x28, 0xca, 0x2f, 0xc9, 0xd7, 0x2f, 0x49,
|
||||
0x2d, 0x2e, 0xd1, 0x03, 0x33, 0xa5, 0x64, 0xd2, 0xf3, 0xf3, 0xd3, 0x73, 0x52, 0xf5, 0x13, 0x0b,
|
||||
0x32, 0xf5, 0x13, 0xf3, 0xf2, 0xf2, 0x4b, 0x12, 0x4b, 0x32, 0xf3, 0xf3, 0x8a, 0x21, 0xb2, 0x4a,
|
||||
0x86, 0x5c, 0xec, 0x41, 0xa9, 0x85, 0xa5, 0xa9, 0xc5, 0x25, 0x42, 0x42, 0x5c, 0x2c, 0xa5, 0xa5,
|
||||
0x99, 0x29, 0x12, 0x8c, 0x0a, 0x8c, 0x1a, 0x9c, 0x41, 0x60, 0x36, 0x48, 0x2c, 0x2f, 0x31, 0x37,
|
||||
0x55, 0x82, 0x09, 0x22, 0x06, 0x62, 0x2b, 0xc9, 0x70, 0x71, 0x04, 0xa5, 0x16, 0x17, 0xe4, 0xe7,
|
||||
0x15, 0xa7, 0x0a, 0x09, 0x70, 0x31, 0xe7, 0x16, 0xa7, 0x43, 0xb5, 0x80, 0x98, 0x46, 0xcf, 0x18,
|
||||
0xb9, 0x58, 0x42, 0x40, 0xc6, 0x39, 0x70, 0xb1, 0x38, 0x27, 0xe6, 0xe4, 0x08, 0x71, 0xe8, 0x41,
|
||||
0x2d, 0x90, 0xe2, 0xd4, 0x83, 0xe9, 0x53, 0x52, 0x6e, 0xba, 0xfc, 0x64, 0x32, 0x93, 0xac, 0x92,
|
||||
0x04, 0xd8, 0x59, 0x65, 0x06, 0x60, 0x07, 0xeb, 0x27, 0x27, 0xe6, 0xe4, 0xe8, 0x57, 0x83, 0x2c,
|
||||
0xae, 0xb5, 0x62, 0xd4, 0x12, 0x72, 0xe3, 0xe2, 0x00, 0x99, 0x10, 0x90, 0x5c, 0x94, 0x8a, 0xdd,
|
||||
0x14, 0x55, 0xb0, 0x29, 0xf2, 0x4a, 0x52, 0x71, 0x98, 0xc6, 0x14, 0x24, 0x17, 0xa5, 0xea, 0xdb,
|
||||
0xab, 0x80, 0xcc, 0x09, 0xe1, 0xe2, 0x87, 0x99, 0xe3, 0x99, 0x57, 0x96, 0x98, 0x93, 0x99, 0x82,
|
||||
0xdd, 0x38, 0x1d, 0xb0, 0x71, 0x6a, 0x4a, 0x8a, 0xb8, 0x8c, 0xcb, 0x84, 0xe8, 0xd6, 0xb7, 0xb7,
|
||||
0x62, 0xd4, 0x4a, 0x62, 0x03, 0x07, 0xa0, 0x31, 0x20, 0x00, 0x00, 0xff, 0xff, 0xf6, 0x32, 0x18,
|
||||
0x0f, 0x7e, 0x01, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
|
@@ -54,7 +54,7 @@ func NewTestEndpoints() []*api.Endpoint {
|
||||
},
|
||||
&api.Endpoint{
|
||||
Name: "Test.CallPcreInvalid",
|
||||
Path: []string{"/api/v0/test/call/pcre/invalid/?"},
|
||||
Path: []string{"^/api/v0/test/call/pcre/invalid/?"},
|
||||
Method: []string{"POST"},
|
||||
Body: "*",
|
||||
Handler: "rpc",
|
||||
@@ -146,7 +146,7 @@ func RegisterTestHandler(s server.Server, hdlr TestHandler, opts ...server.Handl
|
||||
}))
|
||||
opts = append(opts, api.WithEndpoint(&api.Endpoint{
|
||||
Name: "Test.CallPcreInvalid",
|
||||
Path: []string{"/api/v0/test/call/pcre/invalid/?"},
|
||||
Path: []string{"^/api/v0/test/call/pcre/invalid/?"},
|
||||
Method: []string{"POST"},
|
||||
Body: "*",
|
||||
Handler: "rpc",
|
||||
|
@@ -87,7 +87,7 @@ func prepareEndpoint(method reflect.Method) *methodType {
|
||||
contextType = mtype.In(1)
|
||||
default:
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
|
||||
logger.Errorf("method %v of %v has wrong number of ins: %v", mname, mtype, mtype.NumIn())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -97,7 +97,7 @@ func prepareEndpoint(method reflect.Method) *methodType {
|
||||
streamType := reflect.TypeOf((*server.Stream)(nil)).Elem()
|
||||
if !argType.Implements(streamType) {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(mname, "argument does not implement Streamer interface:", argType)
|
||||
logger.Errorf("%v argument does not implement Streamer interface: %v", mname, argType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -107,14 +107,14 @@ func prepareEndpoint(method reflect.Method) *methodType {
|
||||
// First arg need not be a pointer.
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error(mname, "argument type not exported:", argType)
|
||||
logger.Errorf("%v argument type not exported: %v", mname, argType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
if replyType.Kind() != reflect.Ptr {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("method", mname, "reply type not a pointer:", replyType)
|
||||
logger.Errorf("method %v reply type not a pointer: %v", mname, replyType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -122,7 +122,7 @@ func prepareEndpoint(method reflect.Method) *methodType {
|
||||
// Reply type must be exported.
|
||||
if !isExportedOrBuiltinType(replyType) {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("method", mname, "reply type not exported:", replyType)
|
||||
logger.Errorf("method %v reply type not exported: %v", mname, replyType)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -131,14 +131,14 @@ func prepareEndpoint(method reflect.Method) *methodType {
|
||||
// Endpoint() needs one out.
|
||||
if mtype.NumOut() != 1 {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("method", mname, "has wrong number of outs:", mtype.NumOut())
|
||||
logger.Errorf("method %v has wrong number of outs: %v", mname, mtype.NumOut())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
// The return type of the method must be error.
|
||||
if returnType := mtype.Out(0); returnType != typeOfError {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("method", mname, "returns", returnType.String(), "not error")
|
||||
logger.Errorf("method %v returns %v not error", mname, returnType.String())
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -156,7 +156,7 @@ func (server *rServer) register(rcvr interface{}) error {
|
||||
s.rcvr = reflect.ValueOf(rcvr)
|
||||
sname := reflect.Indirect(s.rcvr).Type().Name()
|
||||
if sname == "" {
|
||||
logger.Fatal("rpc: no service name for type", s.typ.String())
|
||||
logger.Fatalf("rpc: no service name for type %v", s.typ.String())
|
||||
}
|
||||
if !isExported(sname) {
|
||||
s := "rpc Register: type " + sname + " is not exported"
|
||||
|
@@ -140,7 +140,7 @@ func prepareMethod(method reflect.Method) *methodType {
|
||||
replyType = mtype.In(3)
|
||||
contextType = mtype.In(1)
|
||||
default:
|
||||
log.Error("method", mname, "of", mtype, "has wrong number of ins:", mtype.NumIn())
|
||||
log.Errorf("method %v of %v has wrong number of ins: %v", mname, mtype, mtype.NumIn())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ func prepareMethod(method reflect.Method) *methodType {
|
||||
// check stream type
|
||||
streamType := reflect.TypeOf((*Stream)(nil)).Elem()
|
||||
if !argType.Implements(streamType) {
|
||||
log.Error(mname, "argument does not implement Stream interface:", argType)
|
||||
log.Errorf("%v argument does not implement Stream interface: %v", mname, argType)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
@@ -156,30 +156,30 @@ func prepareMethod(method reflect.Method) *methodType {
|
||||
|
||||
// First arg need not be a pointer.
|
||||
if !isExportedOrBuiltinType(argType) {
|
||||
log.Error(mname, "argument type not exported:", argType)
|
||||
log.Errorf("%v argument type not exported: %v", mname, argType)
|
||||
return nil
|
||||
}
|
||||
|
||||
if replyType.Kind() != reflect.Ptr {
|
||||
log.Error("method", mname, "reply type not a pointer:", replyType)
|
||||
log.Errorf("method %v reply type not a pointer: %v", mname, replyType)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Reply type must be exported.
|
||||
if !isExportedOrBuiltinType(replyType) {
|
||||
log.Error("method", mname, "reply type not exported:", replyType)
|
||||
log.Errorf("method %v reply type not exported: %v", mname, replyType)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Method needs one out.
|
||||
if mtype.NumOut() != 1 {
|
||||
log.Error("method", mname, "has wrong number of outs:", mtype.NumOut())
|
||||
log.Errorf("method %v has wrong number of outs: %v", mname, mtype.NumOut())
|
||||
return nil
|
||||
}
|
||||
// The return type of the method must be error.
|
||||
if returnType := mtype.Out(0); returnType != typeOfError {
|
||||
log.Error("method", mname, "returns", returnType.String(), "not error")
|
||||
log.Errorf("method %v returns %v not error", mname, returnType.String())
|
||||
return nil
|
||||
}
|
||||
return &methodType{method: method, ArgType: argType, ReplyType: replyType, ContextType: contextType, stream: stream}
|
||||
@@ -508,7 +508,7 @@ func (router *router) ProcessMessage(ctx context.Context, msg Message) (err erro
|
||||
defer func() {
|
||||
// recover any panics
|
||||
if r := recover(); r != nil {
|
||||
log.Error("panic recovered: ", r)
|
||||
log.Errorf("panic recovered: %v", r)
|
||||
log.Error(string(debug.Stack()))
|
||||
err = merrors.InternalServerError("go.micro.server", "panic recovered: %v", r)
|
||||
}
|
||||
|
@@ -20,6 +20,7 @@ import (
|
||||
"github.com/micro/go-micro/v2/registry"
|
||||
"github.com/micro/go-micro/v2/transport"
|
||||
"github.com/micro/go-micro/v2/util/addr"
|
||||
"github.com/micro/go-micro/v2/util/backoff"
|
||||
mnet "github.com/micro/go-micro/v2/util/net"
|
||||
"github.com/micro/go-micro/v2/util/socket"
|
||||
)
|
||||
@@ -514,18 +515,39 @@ func (s *rpcServer) Subscribe(sb Subscriber) error {
|
||||
}
|
||||
|
||||
func (s *rpcServer) Register() error {
|
||||
|
||||
s.RLock()
|
||||
rsvc := s.rsvc
|
||||
config := s.Options()
|
||||
s.RUnlock()
|
||||
|
||||
if rsvc != nil {
|
||||
regFunc := func(service *registry.Service) error {
|
||||
// create registry options
|
||||
rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}
|
||||
if err := config.Registry.Register(rsvc, rOpts...); err != nil {
|
||||
return err
|
||||
|
||||
var regErr error
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
// attempt to register
|
||||
if err := config.Registry.Register(service, rOpts...); err != nil {
|
||||
// set the error
|
||||
regErr = err
|
||||
// backoff then retry
|
||||
time.Sleep(backoff.Do(i + 1))
|
||||
continue
|
||||
}
|
||||
// success so nil error
|
||||
regErr = nil
|
||||
break
|
||||
}
|
||||
|
||||
return regErr
|
||||
}
|
||||
|
||||
// have we registered before?
|
||||
if rsvc != nil {
|
||||
if err := regFunc(rsvc); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -635,10 +657,8 @@ func (s *rpcServer) Register() error {
|
||||
}
|
||||
}
|
||||
|
||||
// create registry options
|
||||
rOpts := []registry.RegisterOption{registry.RegisterTTL(config.RegisterTTL)}
|
||||
|
||||
if err := config.Registry.Register(service, rOpts...); err != nil {
|
||||
// register the service
|
||||
if err := regFunc(service); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@@ -16,14 +16,23 @@ import (
|
||||
|
||||
// Server is a simple micro server abstraction
|
||||
type Server interface {
|
||||
Options() Options
|
||||
// Initialise options
|
||||
Init(...Option) error
|
||||
// Retrieve the options
|
||||
Options() Options
|
||||
// Register a handler
|
||||
Handle(Handler) error
|
||||
// Create a new handler
|
||||
NewHandler(interface{}, ...HandlerOption) Handler
|
||||
// Create a new subscriber
|
||||
NewSubscriber(string, interface{}, ...SubscriberOption) Subscriber
|
||||
// Register a subscriber
|
||||
Subscribe(Subscriber) error
|
||||
// Start the server
|
||||
Start() error
|
||||
// Stop the server
|
||||
Stop() error
|
||||
// Server implementation
|
||||
String() string
|
||||
}
|
||||
|
||||
@@ -116,7 +125,8 @@ type Handler interface {
|
||||
}
|
||||
|
||||
// Subscriber interface represents a subscription to a given topic using
|
||||
// a specific subscriber function or object with endpoints.
|
||||
// a specific subscriber function or object with endpoints. It mirrors
|
||||
// the handler in its behaviour.
|
||||
type Subscriber interface {
|
||||
Topic() string
|
||||
Subscriber() interface{}
|
||||
@@ -135,7 +145,7 @@ var (
|
||||
DefaultRouter = newRpcRouter()
|
||||
DefaultRegisterCheck = func(context.Context) error { return nil }
|
||||
DefaultRegisterInterval = time.Second * 30
|
||||
DefaultRegisterTTL = time.Minute
|
||||
DefaultRegisterTTL = time.Second * 90
|
||||
|
||||
// NewServer creates a new server
|
||||
NewServer func(...Option) Server = newRpcServer
|
||||
|
24
service.go
24
service.go
@@ -3,7 +3,7 @@ package micro
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
rtime "runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@@ -34,14 +34,15 @@ func newService(opts ...Option) Service {
|
||||
// service name
|
||||
serviceName := options.Server.Options().Name
|
||||
|
||||
// authFn returns the auth, we pass as a function since auth
|
||||
// has not yet been set at this point.
|
||||
// we pass functions to the wrappers since the values can change during initialisation
|
||||
authFn := func() auth.Auth { return options.Server.Options().Auth }
|
||||
cacheFn := func() *client.Cache { return options.Client.Options().Cache }
|
||||
|
||||
// wrap client to inject From-Service header on any calls
|
||||
options.Client = wrapper.FromService(serviceName, options.Client)
|
||||
options.Client = wrapper.TraceCall(serviceName, trace.DefaultTracer, options.Client)
|
||||
options.Client = wrapper.AuthClient(serviceName, options.Server.Options().Id, authFn, options.Client)
|
||||
options.Client = wrapper.CacheClient(cacheFn, options.Client)
|
||||
options.Client = wrapper.AuthClient(authFn, options.Client)
|
||||
|
||||
// wrap the server to provide handler stats
|
||||
options.Server.Init(
|
||||
@@ -98,6 +99,7 @@ func (s *service) Init(opts ...Option) {
|
||||
cmd.Auth(&s.opts.Auth),
|
||||
cmd.Broker(&s.opts.Broker),
|
||||
cmd.Registry(&s.opts.Registry),
|
||||
cmd.Runtime(&s.opts.Runtime),
|
||||
cmd.Transport(&s.opts.Transport),
|
||||
cmd.Client(&s.opts.Client),
|
||||
cmd.Config(&s.opts.Config),
|
||||
@@ -111,14 +113,6 @@ func (s *service) Init(opts ...Option) {
|
||||
// Explicitly set the table name to the service name
|
||||
name := s.opts.Cmd.App().Name
|
||||
s.opts.Store.Init(store.Table(name))
|
||||
|
||||
// TODO: replace Cmd.Init with config.Load
|
||||
// Right now we're just going to load a token
|
||||
// May need to re-read value on change
|
||||
// TODO: should be scoped to micro/auth/token
|
||||
// if tk, _ := config.Get("token"); len(tk) > 0 {
|
||||
// s.opts.Auth.Init(auth.ServiceToken(tk))
|
||||
// }
|
||||
})
|
||||
}
|
||||
|
||||
@@ -184,7 +178,7 @@ func (s *service) Run() error {
|
||||
// register the debug handler
|
||||
s.opts.Server.Handle(
|
||||
s.opts.Server.NewHandler(
|
||||
handler.NewHandler(),
|
||||
handler.NewHandler(s.opts.Client),
|
||||
server.InternalHandler(true),
|
||||
),
|
||||
)
|
||||
@@ -192,9 +186,9 @@ func (s *service) Run() error {
|
||||
// start the profiler
|
||||
if s.opts.Profile != nil {
|
||||
// to view mutex contention
|
||||
runtime.SetMutexProfileFraction(5)
|
||||
rtime.SetMutexProfileFraction(5)
|
||||
// to view blocking profile
|
||||
runtime.SetBlockProfileRate(1)
|
||||
rtime.SetBlockProfileRate(1)
|
||||
|
||||
if err := s.opts.Profile.Start(); err != nil {
|
||||
return err
|
||||
|
15
store/cache/cache_test.go
vendored
15
store/cache/cache_test.go
vendored
@@ -28,16 +28,19 @@ func TestCache(t *testing.T) {
|
||||
_, err := cachedStore.Read("test")
|
||||
assert.Equal(store.ErrNotFound, err, "Read non existant key")
|
||||
r1 := &store.Record{
|
||||
Key: "aaa",
|
||||
Value: []byte("bbb"),
|
||||
Key: "aaa",
|
||||
Value: []byte("bbb"),
|
||||
Metadata: map[string]interface{}{},
|
||||
}
|
||||
r2 := &store.Record{
|
||||
Key: "aaaa",
|
||||
Value: []byte("bbbb"),
|
||||
Key: "aaaa",
|
||||
Value: []byte("bbbb"),
|
||||
Metadata: map[string]interface{}{},
|
||||
}
|
||||
r3 := &store.Record{
|
||||
Key: "aaaaa",
|
||||
Value: []byte("bbbbb"),
|
||||
Key: "aaaaa",
|
||||
Value: []byte("bbbbb"),
|
||||
Metadata: map[string]interface{}{},
|
||||
}
|
||||
// Write 3 records directly to l2
|
||||
l2.Write(r1)
|
||||
|
@@ -11,6 +11,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/store"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -26,11 +27,11 @@ var (
|
||||
re = regexp.MustCompile("[^a-zA-Z0-9]+")
|
||||
|
||||
statements = map[string]string{
|
||||
"list": "SELECT key, value, expiry FROM %s.%s;",
|
||||
"read": "SELECT key, value, expiry FROM %s.%s WHERE key = $1;",
|
||||
"readMany": "SELECT key, value, expiry FROM %s.%s WHERE key LIKE $1;",
|
||||
"readOffset": "SELECT key, value, expiry FROM %s.%s WHERE key LIKE $1 ORDER BY key DESC LIMIT $2 OFFSET $3;",
|
||||
"write": "INSERT INTO %s.%s(key, value, expiry) VALUES ($1, $2::bytea, $3) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, expiry = EXCLUDED.expiry;",
|
||||
"list": "SELECT key, value, metadata, expiry FROM %s.%s;",
|
||||
"read": "SELECT key, value, metadata, expiry FROM %s.%s WHERE key = $1;",
|
||||
"readMany": "SELECT key, value, metadata, expiry FROM %s.%s WHERE key LIKE $1;",
|
||||
"readOffset": "SELECT key, value, metadata, expiry FROM %s.%s WHERE key LIKE $1 ORDER BY key DESC LIMIT $2 OFFSET $3;",
|
||||
"write": "INSERT INTO %s.%s(key, value, metadata, expiry) VALUES ($1, $2::bytea, $3, $4) ON CONFLICT (key) DO UPDATE SET value = EXCLUDED.value, metadata = EXCLUDED.metadata, expiry = EXCLUDED.expiry;",
|
||||
"delete": "DELETE FROM %s.%s WHERE key = $1;",
|
||||
}
|
||||
)
|
||||
@@ -68,19 +69,29 @@ func (s *sqlStore) getDB(database, table string) (string, string) {
|
||||
return database, table
|
||||
}
|
||||
|
||||
func (s *sqlStore) createDB(database, table string) {
|
||||
func (s *sqlStore) createDB(database, table string) error {
|
||||
database, table = s.getDB(database, table)
|
||||
|
||||
s.Lock()
|
||||
_, ok := s.databases[database+":"+table]
|
||||
if !ok {
|
||||
s.initDB(database, table)
|
||||
s.databases[database+":"+table] = true
|
||||
defer s.Unlock()
|
||||
|
||||
if _, ok := s.databases[database+":"+table]; ok {
|
||||
return nil
|
||||
}
|
||||
s.Unlock()
|
||||
|
||||
if err := s.initDB(database, table); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.databases[database+":"+table] = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *sqlStore) initDB(database, table string) error {
|
||||
if s.db == nil {
|
||||
return errors.New("Database connection not initialised")
|
||||
}
|
||||
|
||||
// Create the namespace's database
|
||||
_, err := s.db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s;", database))
|
||||
if err != nil {
|
||||
@@ -97,6 +108,7 @@ func (s *sqlStore) initDB(database, table string) error {
|
||||
(
|
||||
key text NOT NULL,
|
||||
value bytea,
|
||||
metadata JSONB,
|
||||
expiry timestamp with time zone,
|
||||
CONSTRAINT %s_pkey PRIMARY KEY (key)
|
||||
);`, table, table))
|
||||
@@ -110,6 +122,12 @@ func (s *sqlStore) initDB(database, table string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create Metadata Index
|
||||
_, err = s.db.Exec(fmt.Sprintf(`CREATE INDEX IF NOT EXISTS "%s" ON %s.%s USING GIN ("metadata");`, "metadata_index_"+table, database, table))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -192,7 +210,9 @@ func (s *sqlStore) List(opts ...store.ListOption) ([]string, error) {
|
||||
}
|
||||
|
||||
// create the db if not exists
|
||||
s.createDB(options.Database, options.Table)
|
||||
if err := s.createDB(options.Database, options.Table); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
st, err := s.prepare(options.Database, options.Table, "list")
|
||||
if err != nil {
|
||||
@@ -214,9 +234,15 @@ func (s *sqlStore) List(opts ...store.ListOption) ([]string, error) {
|
||||
|
||||
for rows.Next() {
|
||||
record := &store.Record{}
|
||||
if err := rows.Scan(&record.Key, &record.Value, &timehelper); err != nil {
|
||||
metadata := make(Metadata)
|
||||
|
||||
if err := rows.Scan(&record.Key, &record.Value, &metadata, &timehelper); err != nil {
|
||||
return keys, err
|
||||
}
|
||||
|
||||
// set the metadata
|
||||
record.Metadata = toMetadata(&metadata)
|
||||
|
||||
if timehelper.Valid {
|
||||
if timehelper.Time.Before(time.Now()) {
|
||||
// record has expired
|
||||
@@ -249,7 +275,9 @@ func (s *sqlStore) Read(key string, opts ...store.ReadOption) ([]*store.Record,
|
||||
}
|
||||
|
||||
// create the db if not exists
|
||||
s.createDB(options.Database, options.Table)
|
||||
if err := s.createDB(options.Database, options.Table); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if options.Prefix || options.Suffix {
|
||||
return s.read(key, options)
|
||||
@@ -266,12 +294,18 @@ func (s *sqlStore) Read(key string, opts ...store.ReadOption) ([]*store.Record,
|
||||
|
||||
row := st.QueryRow(key)
|
||||
record := &store.Record{}
|
||||
if err := row.Scan(&record.Key, &record.Value, &timehelper); err != nil {
|
||||
metadata := make(Metadata)
|
||||
|
||||
if err := row.Scan(&record.Key, &record.Value, &metadata, &timehelper); err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return records, store.ErrNotFound
|
||||
}
|
||||
return records, err
|
||||
}
|
||||
|
||||
// set the metadata
|
||||
record.Metadata = toMetadata(&metadata)
|
||||
|
||||
if timehelper.Valid {
|
||||
if timehelper.Time.Before(time.Now()) {
|
||||
// record has expired
|
||||
@@ -331,9 +365,15 @@ func (s *sqlStore) read(key string, options store.ReadOptions) ([]*store.Record,
|
||||
|
||||
for rows.Next() {
|
||||
record := &store.Record{}
|
||||
if err := rows.Scan(&record.Key, &record.Value, &timehelper); err != nil {
|
||||
metadata := make(Metadata)
|
||||
|
||||
if err := rows.Scan(&record.Key, &record.Value, &metadata, &timehelper); err != nil {
|
||||
return records, err
|
||||
}
|
||||
|
||||
// set the metadata
|
||||
record.Metadata = toMetadata(&metadata)
|
||||
|
||||
if timehelper.Valid {
|
||||
if timehelper.Time.Before(time.Now()) {
|
||||
// record has expired
|
||||
@@ -366,7 +406,9 @@ func (s *sqlStore) Write(r *store.Record, opts ...store.WriteOption) error {
|
||||
}
|
||||
|
||||
// create the db if not exists
|
||||
s.createDB(options.Database, options.Table)
|
||||
if err := s.createDB(options.Database, options.Table); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
st, err := s.prepare(options.Database, options.Table, "write")
|
||||
if err != nil {
|
||||
@@ -374,10 +416,15 @@ func (s *sqlStore) Write(r *store.Record, opts ...store.WriteOption) error {
|
||||
}
|
||||
defer st.Close()
|
||||
|
||||
metadata := make(Metadata)
|
||||
for k, v := range r.Metadata {
|
||||
metadata[k] = v
|
||||
}
|
||||
|
||||
if r.Expiry != 0 {
|
||||
_, err = st.Exec(r.Key, r.Value, time.Now().Add(r.Expiry))
|
||||
_, err = st.Exec(r.Key, r.Value, metadata, time.Now().Add(r.Expiry))
|
||||
} else {
|
||||
_, err = st.Exec(r.Key, r.Value, nil)
|
||||
_, err = st.Exec(r.Key, r.Value, metadata, nil)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@@ -395,7 +442,9 @@ func (s *sqlStore) Delete(key string, opts ...store.DeleteOption) error {
|
||||
}
|
||||
|
||||
// create the db if not exists
|
||||
s.createDB(options.Database, options.Table)
|
||||
if err := s.createDB(options.Database, options.Table); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
st, err := s.prepare(options.Database, options.Table, "delete")
|
||||
if err != nil {
|
||||
@@ -442,7 +491,11 @@ func NewStore(opts ...store.Option) store.Store {
|
||||
// mark known databases
|
||||
s.databases = make(map[string]bool)
|
||||
// best-effort configure the store
|
||||
s.configure()
|
||||
if err := s.configure(); err != nil {
|
||||
if logger.V(logger.ErrorLevel, logger.DefaultLogger) {
|
||||
logger.Error("Error configuring store ", err)
|
||||
}
|
||||
}
|
||||
|
||||
// return store
|
||||
return s
|
||||
|
45
store/cockroach/metadata.go
Normal file
45
store/cockroach/metadata.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package cockroach
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// https://github.com/upper/db/blob/master/postgresql/custom_types.go#L43
|
||||
type Metadata map[string]interface{}
|
||||
|
||||
// Scan satisfies the sql.Scanner interface.
|
||||
func (m *Metadata) Scan(src interface{}) error {
|
||||
source, ok := src.([]byte)
|
||||
if !ok {
|
||||
return errors.New("Type assertion .([]byte) failed.")
|
||||
}
|
||||
|
||||
var i interface{}
|
||||
err := json.Unmarshal(source, &i)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*m, ok = i.(map[string]interface{})
|
||||
if !ok {
|
||||
return errors.New("Type assertion .(map[string]interface{}) failed.")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Value satisfies the driver.Valuer interface.
|
||||
func (m Metadata) Value() (driver.Value, error) {
|
||||
j, err := json.Marshal(m)
|
||||
return j, err
|
||||
}
|
||||
|
||||
func toMetadata(m *Metadata) map[string]interface{} {
|
||||
md := make(map[string]interface{})
|
||||
for k, v := range *m {
|
||||
md[k] = v
|
||||
}
|
||||
return md
|
||||
}
|
@@ -54,6 +54,7 @@ type fileHandle struct {
|
||||
type record struct {
|
||||
Key string
|
||||
Value []byte
|
||||
Metadata map[string]interface{}
|
||||
ExpiresAt time.Time
|
||||
}
|
||||
|
||||
@@ -104,7 +105,6 @@ func (f *fileStore) getDB(database, table string) (*fileHandle, error) {
|
||||
}
|
||||
|
||||
k := key(database, table)
|
||||
|
||||
f.RLock()
|
||||
fd, ok := f.handles[k]
|
||||
f.RUnlock()
|
||||
@@ -114,6 +114,13 @@ func (f *fileStore) getDB(database, table string) (*fileHandle, error) {
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// double check locking
|
||||
f.Lock()
|
||||
defer f.Unlock()
|
||||
if fd, ok := f.handles[k]; ok {
|
||||
return fd, nil
|
||||
}
|
||||
|
||||
// create a directory /tmp/micro
|
||||
dir := filepath.Join(DefaultDir, database)
|
||||
// create the database handle
|
||||
@@ -124,18 +131,16 @@ func (f *fileStore) getDB(database, table string) (*fileHandle, error) {
|
||||
dbPath := filepath.Join(dir, fname)
|
||||
|
||||
// create new db handle
|
||||
// Bolt DB only allows one process to open the file R/W so make sure we're doing this under a lock
|
||||
db, err := bolt.Open(dbPath, 0700, &bolt.Options{Timeout: 5 * time.Second})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
f.Lock()
|
||||
fd = &fileHandle{
|
||||
key: k,
|
||||
db: db,
|
||||
}
|
||||
f.handles[k] = fd
|
||||
f.Unlock()
|
||||
|
||||
return fd, nil
|
||||
}
|
||||
@@ -221,6 +226,11 @@ func (m *fileStore) get(fd *fileHandle, k string) (*store.Record, error) {
|
||||
newRecord := &store.Record{}
|
||||
newRecord.Key = storedRecord.Key
|
||||
newRecord.Value = storedRecord.Value
|
||||
newRecord.Metadata = make(map[string]interface{})
|
||||
|
||||
for k, v := range storedRecord.Metadata {
|
||||
newRecord.Metadata[k] = v
|
||||
}
|
||||
|
||||
if !storedRecord.ExpiresAt.IsZero() {
|
||||
if storedRecord.ExpiresAt.Before(time.Now()) {
|
||||
@@ -238,10 +248,16 @@ func (m *fileStore) set(fd *fileHandle, r *store.Record) error {
|
||||
item := &record{}
|
||||
item.Key = r.Key
|
||||
item.Value = r.Value
|
||||
item.Metadata = make(map[string]interface{})
|
||||
|
||||
if r.Expiry != 0 {
|
||||
item.ExpiresAt = time.Now().Add(r.Expiry)
|
||||
}
|
||||
|
||||
for k, v := range r.Metadata {
|
||||
item.Metadata[k] = v
|
||||
}
|
||||
|
||||
// marshal the data
|
||||
data, _ := json.Marshal(item)
|
||||
|
||||
@@ -348,6 +364,7 @@ func (m *fileStore) Write(r *store.Record, opts ...store.WriteOption) error {
|
||||
newRecord := store.Record{}
|
||||
newRecord.Key = r.Key
|
||||
newRecord.Value = r.Value
|
||||
newRecord.Metadata = make(map[string]interface{})
|
||||
newRecord.Expiry = r.Expiry
|
||||
|
||||
if !writeOpts.Expiry.IsZero() {
|
||||
@@ -357,6 +374,10 @@ func (m *fileStore) Write(r *store.Record, opts ...store.WriteOption) error {
|
||||
newRecord.Expiry = writeOpts.TTL
|
||||
}
|
||||
|
||||
for k, v := range r.Metadata {
|
||||
newRecord.Metadata[k] = v
|
||||
}
|
||||
|
||||
return m.set(fd, &newRecord)
|
||||
}
|
||||
|
||||
|
@@ -33,9 +33,10 @@ type memoryStore struct {
|
||||
store *cache.Cache
|
||||
}
|
||||
|
||||
type internalRecord struct {
|
||||
type storeRecord struct {
|
||||
key string
|
||||
value []byte
|
||||
metadata map[string]interface{}
|
||||
expiresAt time.Time
|
||||
}
|
||||
|
||||
@@ -56,26 +57,36 @@ func (m *memoryStore) prefix(database, table string) string {
|
||||
func (m *memoryStore) get(prefix, key string) (*store.Record, error) {
|
||||
key = m.key(prefix, key)
|
||||
|
||||
var storedRecord *internalRecord
|
||||
var storedRecord *storeRecord
|
||||
r, found := m.store.Get(key)
|
||||
if !found {
|
||||
return nil, store.ErrNotFound
|
||||
}
|
||||
|
||||
storedRecord, ok := r.(*internalRecord)
|
||||
storedRecord, ok := r.(*storeRecord)
|
||||
if !ok {
|
||||
return nil, errors.New("Retrieved a non *internalRecord from the cache")
|
||||
return nil, errors.New("Retrieved a non *storeRecord from the cache")
|
||||
}
|
||||
|
||||
// Copy the record on the way out
|
||||
newRecord := &store.Record{}
|
||||
newRecord.Key = strings.TrimPrefix(storedRecord.key, prefix+"/")
|
||||
newRecord.Value = make([]byte, len(storedRecord.value))
|
||||
newRecord.Metadata = make(map[string]interface{})
|
||||
|
||||
// copy the value into the new record
|
||||
copy(newRecord.Value, storedRecord.value)
|
||||
|
||||
// check if we need to set the expiry
|
||||
if !storedRecord.expiresAt.IsZero() {
|
||||
newRecord.Expiry = time.Until(storedRecord.expiresAt)
|
||||
}
|
||||
|
||||
// copy in the metadata
|
||||
for k, v := range storedRecord.metadata {
|
||||
newRecord.Metadata[k] = v
|
||||
}
|
||||
|
||||
return newRecord, nil
|
||||
}
|
||||
|
||||
@@ -84,15 +95,24 @@ func (m *memoryStore) set(prefix string, r *store.Record) {
|
||||
|
||||
// copy the incoming record and then
|
||||
// convert the expiry in to a hard timestamp
|
||||
i := &internalRecord{}
|
||||
i := &storeRecord{}
|
||||
i.key = r.Key
|
||||
i.value = make([]byte, len(r.Value))
|
||||
i.metadata = make(map[string]interface{})
|
||||
|
||||
// copy the the value
|
||||
copy(i.value, r.Value)
|
||||
|
||||
// set the expiry
|
||||
if r.Expiry != 0 {
|
||||
i.expiresAt = time.Now().Add(r.Expiry)
|
||||
}
|
||||
|
||||
// set the metadata
|
||||
for k, v := range r.Metadata {
|
||||
i.metadata[k] = v
|
||||
}
|
||||
|
||||
m.store.Set(key, i, r.Expiry)
|
||||
}
|
||||
|
||||
@@ -134,7 +154,6 @@ func (m *memoryStore) Close() error {
|
||||
}
|
||||
|
||||
func (m *memoryStore) Init(opts ...store.Option) error {
|
||||
m.store.Flush()
|
||||
for _, o := range opts {
|
||||
o(&m.options)
|
||||
}
|
||||
@@ -200,6 +219,7 @@ func (m *memoryStore) Write(r *store.Record, opts ...store.WriteOption) error {
|
||||
newRecord := store.Record{}
|
||||
newRecord.Key = r.Key
|
||||
newRecord.Value = make([]byte, len(r.Value))
|
||||
newRecord.Metadata = make(map[string]interface{})
|
||||
copy(newRecord.Value, r.Value)
|
||||
newRecord.Expiry = r.Expiry
|
||||
|
||||
@@ -209,6 +229,11 @@ func (m *memoryStore) Write(r *store.Record, opts ...store.WriteOption) error {
|
||||
if writeOpts.TTL != 0 {
|
||||
newRecord.Expiry = writeOpts.TTL
|
||||
}
|
||||
|
||||
for k, v := range r.Metadata {
|
||||
newRecord.Metadata[k] = v
|
||||
}
|
||||
|
||||
m.set(prefix, &newRecord)
|
||||
return nil
|
||||
}
|
||||
|
@@ -248,7 +248,7 @@ func basictest(s store.Store, t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
s.Init()
|
||||
s.Close() // reset the store
|
||||
for i := 0; i < 10; i++ {
|
||||
s.Write(&store.Record{
|
||||
Key: fmt.Sprintf("a%d", i),
|
||||
|
@@ -3,6 +3,8 @@ package store
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
)
|
||||
|
||||
// Options contains configuration for the Store
|
||||
@@ -17,6 +19,8 @@ type Options struct {
|
||||
Table string
|
||||
// Context should contain all implementation specific options, using context.WithValue.
|
||||
Context context.Context
|
||||
// Client to use for RPC
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
// Option sets values in Options
|
||||
@@ -52,6 +56,13 @@ func WithContext(c context.Context) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithClient sets the stores client to use for RPC
|
||||
func WithClient(c client.Client) Option {
|
||||
return func(o *Options) {
|
||||
o.Client = c
|
||||
}
|
||||
}
|
||||
|
||||
// ReadOptions configures an individual Read operation
|
||||
type ReadOptions struct {
|
||||
Database, Table string
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,13 @@ service Store {
|
||||
rpc Tables(TablesRequest) returns (TablesResponse) {};
|
||||
}
|
||||
|
||||
message Field {
|
||||
// type of value e.g string, int, int64, bool, float64
|
||||
string type = 1;
|
||||
// the actual value
|
||||
string value = 2;
|
||||
}
|
||||
|
||||
message Record {
|
||||
// key of the record
|
||||
string key = 1;
|
||||
@@ -18,6 +25,8 @@ message Record {
|
||||
bytes value = 2;
|
||||
// time.Duration (signed int64 nanoseconds)
|
||||
int64 expiry = 3;
|
||||
// the associated metadata
|
||||
map<string,Field> metadata = 4;
|
||||
}
|
||||
|
||||
message ReadOptions {
|
||||
|
@@ -3,7 +3,9 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
@@ -137,10 +139,21 @@ func (s *serviceStore) Read(key string, opts ...store.ReadOption) ([]*store.Reco
|
||||
records := make([]*store.Record, 0, len(rsp.Records))
|
||||
|
||||
for _, val := range rsp.Records {
|
||||
metadata := make(map[string]interface{})
|
||||
|
||||
for k, v := range val.Metadata {
|
||||
switch v.Type {
|
||||
// TODO: parse all types
|
||||
default:
|
||||
metadata[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
records = append(records, &store.Record{
|
||||
Key: val.Key,
|
||||
Value: val.Value,
|
||||
Expiry: time.Duration(val.Expiry) * time.Second,
|
||||
Key: val.Key,
|
||||
Value: val.Value,
|
||||
Expiry: time.Duration(val.Expiry) * time.Second,
|
||||
Metadata: metadata,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -163,11 +176,21 @@ func (s *serviceStore) Write(record *store.Record, opts ...store.WriteOption) er
|
||||
Table: options.Table,
|
||||
}
|
||||
|
||||
metadata := make(map[string]*pb.Field)
|
||||
|
||||
for k, v := range record.Metadata {
|
||||
metadata[k] = &pb.Field{
|
||||
Type: reflect.TypeOf(v).String(),
|
||||
Value: fmt.Sprintf("%v", v),
|
||||
}
|
||||
}
|
||||
|
||||
_, err := s.Client.Write(s.Context(), &pb.WriteRequest{
|
||||
Record: &pb.Record{
|
||||
Key: record.Key,
|
||||
Value: record.Value,
|
||||
Expiry: int64(record.Expiry.Seconds()),
|
||||
Key: record.Key,
|
||||
Value: record.Value,
|
||||
Expiry: int64(record.Expiry.Seconds()),
|
||||
Metadata: metadata,
|
||||
},
|
||||
Options: writeOpts}, client.WithAddress(s.Nodes...))
|
||||
if err != nil && errors.Equal(err, errors.NotFound("", "")) {
|
||||
@@ -219,12 +242,16 @@ func NewStore(opts ...store.Option) store.Store {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
if options.Client == nil {
|
||||
options.Client = client.DefaultClient
|
||||
}
|
||||
|
||||
service := &serviceStore{
|
||||
options: options,
|
||||
Database: options.Database,
|
||||
Table: options.Table,
|
||||
Nodes: options.Nodes,
|
||||
Client: pb.NewStoreService("go.micro.store", client.DefaultClient),
|
||||
Client: pb.NewStoreService("go.micro.store", options.Client),
|
||||
}
|
||||
|
||||
return service
|
||||
|
@@ -36,7 +36,12 @@ type Store interface {
|
||||
|
||||
// Record is an item stored or retrieved from a Store
|
||||
type Record struct {
|
||||
Key string `json:"key"`
|
||||
Value []byte `json:"value"`
|
||||
// The key to store the record
|
||||
Key string `json:"key"`
|
||||
// The value within the record
|
||||
Value []byte `json:"value"`
|
||||
// Any associated metadata for indexing
|
||||
Metadata map[string]interface{} `json:"metadata"`
|
||||
// Time to expire a record: TODO: change to timestamp
|
||||
Expiry time.Duration `json:"expiry,omitempty"`
|
||||
}
|
||||
|
@@ -68,7 +68,7 @@ func Extract(addr string) (string, error) {
|
||||
for _, iface := range ifaces {
|
||||
ifaceAddrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
// ignore error, interface can dissapear from system
|
||||
// ignore error, interface can disappear from system
|
||||
continue
|
||||
}
|
||||
if iface.Flags&net.FlagLoopback != 0 {
|
||||
|
81
util/auth/auth.go
Normal file
81
util/auth/auth.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
// Generate generates a service account for and continually
|
||||
// refreshes the access token.
|
||||
func Generate(id string, name string, a auth.Auth) error {
|
||||
// extract the account creds from options, these can be set by flags
|
||||
accID := a.Options().ID
|
||||
accSecret := a.Options().Secret
|
||||
|
||||
// if no credentials were provided, generate an account
|
||||
if len(accID) == 0 || len(accSecret) == 0 {
|
||||
name := fmt.Sprintf("%v-%v", name, id)
|
||||
|
||||
opts := []auth.GenerateOption{
|
||||
auth.WithType("service"),
|
||||
auth.WithScopes("service"),
|
||||
}
|
||||
|
||||
acc, err := a.Generate(name, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Debugf("Auth [%v] Authenticated as %v issued by %v", a, name, acc.Issuer)
|
||||
|
||||
accID = acc.ID
|
||||
accSecret = acc.Secret
|
||||
}
|
||||
|
||||
// generate the first token
|
||||
token, err := a.Token(
|
||||
auth.WithCredentials(accID, accSecret),
|
||||
auth.WithExpiry(time.Minute*10),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the credentials and token in auth options
|
||||
a.Init(
|
||||
auth.ClientToken(token),
|
||||
auth.Credentials(accID, accSecret),
|
||||
)
|
||||
|
||||
// periodically check to see if the token needs refreshing
|
||||
go func() {
|
||||
timer := time.NewTicker(time.Second * 15)
|
||||
|
||||
for {
|
||||
<-timer.C
|
||||
|
||||
// don't refresh the token if it's not close to expiring
|
||||
tok := a.Options().Token
|
||||
if tok.Expiry.Unix() > time.Now().Add(time.Minute).Unix() {
|
||||
continue
|
||||
}
|
||||
|
||||
// generate the first token
|
||||
tok, err := a.Token(
|
||||
auth.WithToken(tok.RefreshToken),
|
||||
auth.WithExpiry(time.Minute*10),
|
||||
)
|
||||
if err != nil {
|
||||
logger.Warnf("[Auth] Error refreshing token: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// set the token
|
||||
a.Init(auth.ClientToken(tok))
|
||||
}
|
||||
}()
|
||||
|
||||
return nil
|
||||
}
|
@@ -1,90 +0,0 @@
|
||||
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(path ...string) (string, error) {
|
||||
tk := config.Get(path...).String("")
|
||||
return strings.TrimSpace(tk), nil
|
||||
}
|
||||
|
||||
// Set a value in the .micro file
|
||||
func Set(value string, path ...string) error {
|
||||
// get the filepath
|
||||
fp, err := filePath()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the value
|
||||
config.Set(value, path...)
|
||||
|
||||
// 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
|
||||
}
|
191
util/file/client.go
Normal file
191
util/file/client.go
Normal file
@@ -0,0 +1,191 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
proto "github.com/micro/go-micro/v2/util/file/proto"
|
||||
)
|
||||
|
||||
// Client is the client interface to access files
|
||||
type File interface {
|
||||
Open(filename string, truncate bool) (int64, error)
|
||||
Stat(filename string) (*proto.StatResponse, error)
|
||||
GetBlock(sessionId, blockId int64) ([]byte, error)
|
||||
ReadAt(sessionId, offset, size int64) ([]byte, error)
|
||||
Read(sessionId int64, buf []byte) (int, error)
|
||||
Write(sessionId, offset int64, data []byte) error
|
||||
Close(sessionId int64) error
|
||||
Download(filename, saveFile string) error
|
||||
Upload(filename, localFile string) error
|
||||
DownloadAt(filename, saveFile string, blockId int) error
|
||||
}
|
||||
|
||||
// NewClient returns a new Client which uses a micro Client
|
||||
func New(service string, c client.Client) File {
|
||||
return &fc{proto.NewFileService(service, c)}
|
||||
}
|
||||
|
||||
const (
|
||||
blockSize = 512 * 1024
|
||||
)
|
||||
|
||||
type fc struct {
|
||||
c proto.FileService
|
||||
}
|
||||
|
||||
func (c *fc) Open(filename string, truncate bool) (int64, error) {
|
||||
rsp, err := c.c.Open(context.TODO(), &proto.OpenRequest{
|
||||
Filename: filename,
|
||||
Truncate: truncate,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return rsp.Id, nil
|
||||
}
|
||||
|
||||
func (c *fc) Stat(filename string) (*proto.StatResponse, error) {
|
||||
return c.c.Stat(context.TODO(), &proto.StatRequest{Filename: filename})
|
||||
}
|
||||
|
||||
func (c *fc) GetBlock(sessionId, blockId int64) ([]byte, error) {
|
||||
return c.ReadAt(sessionId, blockId*blockSize, blockSize)
|
||||
}
|
||||
|
||||
func (c *fc) ReadAt(sessionId, offset, size int64) ([]byte, error) {
|
||||
rsp, err := c.c.Read(context.TODO(), &proto.ReadRequest{Id: sessionId, Size: size, Offset: offset})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if rsp.Eof {
|
||||
err = io.EOF
|
||||
}
|
||||
|
||||
if rsp.Data == nil {
|
||||
rsp.Data = make([]byte, size)
|
||||
}
|
||||
|
||||
if size != rsp.Size {
|
||||
return rsp.Data[:rsp.Size], err
|
||||
}
|
||||
|
||||
return rsp.Data, nil
|
||||
}
|
||||
|
||||
func (c *fc) Read(sessionId int64, buf []byte) (int, error) {
|
||||
b, err := c.ReadAt(sessionId, 0, int64(cap(buf)))
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
copy(buf, b)
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func (c *fc) Write(sessionId, offset int64, data []byte) error {
|
||||
_, err := c.c.Write(context.TODO(), &proto.WriteRequest{
|
||||
Id: sessionId,
|
||||
Offset: offset,
|
||||
Data: data})
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *fc) Close(sessionId int64) error {
|
||||
_, err := c.c.Close(context.TODO(), &proto.CloseRequest{Id: sessionId})
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *fc) Download(filename, saveFile string) error {
|
||||
return c.DownloadAt(filename, saveFile, 0)
|
||||
}
|
||||
|
||||
func (c *fc) Upload(filename, localFile string) error {
|
||||
file, err := os.Open(localFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
offset := 0
|
||||
sessionId, err := c.Open(filename, true)
|
||||
defer c.Close(sessionId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
reader := bufio.NewReader(file)
|
||||
part := make([]byte, blockSize)
|
||||
|
||||
for {
|
||||
count, err := reader.Read(part)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
err = c.Write(sessionId, int64(offset), part)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
offset += count
|
||||
}
|
||||
if err != nil && err != io.EOF {
|
||||
return fmt.Errorf("Error reading %v: %v", localFile, err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fc) DownloadAt(filename, saveFile string, blockId int) error {
|
||||
stat, err := c.Stat(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if stat.Type == "Directory" {
|
||||
return errors.New(fmt.Sprintf("%s is directory.", filename))
|
||||
}
|
||||
|
||||
blocks := int(stat.Size / blockSize)
|
||||
if stat.Size%blockSize != 0 {
|
||||
blocks += 1
|
||||
}
|
||||
|
||||
log.Printf("Download %s in %d blocks\n", filename, blocks-blockId)
|
||||
|
||||
file, err := os.OpenFile(saveFile, os.O_CREATE|os.O_WRONLY, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
sessionId, err := c.Open(filename, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := blockId; i < blocks; i++ {
|
||||
buf, rerr := c.GetBlock(sessionId, int64(i))
|
||||
if rerr != nil && rerr != io.EOF {
|
||||
return rerr
|
||||
}
|
||||
if _, werr := file.WriteAt(buf, int64(i)*blockSize); werr != nil {
|
||||
return werr
|
||||
}
|
||||
|
||||
if i%((blocks-blockId)/100+1) == 0 {
|
||||
log.Printf("Downloading %s [%d/%d] blocks", filename, i-blockId+1, blocks-blockId)
|
||||
}
|
||||
|
||||
if rerr == io.EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
log.Printf("Download %s completed", filename)
|
||||
|
||||
c.Close(sessionId)
|
||||
|
||||
return nil
|
||||
}
|
154
util/file/handler.go
Normal file
154
util/file/handler.go
Normal file
@@ -0,0 +1,154 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/micro/go-micro/v2/errors"
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
proto "github.com/micro/go-micro/v2/util/file/proto"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// NewHandler is a handler that can be registered with a micro Server
|
||||
func NewHandler(readDir string) proto.FileHandler {
|
||||
return &handler{
|
||||
readDir: readDir,
|
||||
session: &session{
|
||||
files: make(map[int64]*os.File),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterHandler is a convenience method for registering a handler
|
||||
func RegisterHandler(s server.Server, readDir string) {
|
||||
proto.RegisterFileHandler(s, NewHandler(readDir))
|
||||
}
|
||||
|
||||
type handler struct {
|
||||
readDir string
|
||||
session *session
|
||||
}
|
||||
|
||||
func (h *handler) Open(ctx context.Context, req *proto.OpenRequest, rsp *proto.OpenResponse) error {
|
||||
path := filepath.Join(h.readDir, req.Filename)
|
||||
flags := os.O_CREATE | os.O_RDWR
|
||||
if req.GetTruncate() {
|
||||
flags = flags | os.O_TRUNC
|
||||
}
|
||||
file, err := os.OpenFile(path, flags, 0666)
|
||||
if err != nil {
|
||||
return errors.InternalServerError("go.micro.server", err.Error())
|
||||
}
|
||||
|
||||
rsp.Id = h.session.Add(file)
|
||||
rsp.Result = true
|
||||
|
||||
logger.Debugf("Open %s, sessionId=%d", req.Filename, rsp.Id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *handler) Close(ctx context.Context, req *proto.CloseRequest, rsp *proto.CloseResponse) error {
|
||||
h.session.Delete(req.Id)
|
||||
logger.Debugf("Close sessionId=%d", req.Id)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *handler) Stat(ctx context.Context, req *proto.StatRequest, rsp *proto.StatResponse) error {
|
||||
path := filepath.Join(h.readDir, req.Filename)
|
||||
fi, err := os.Stat(path)
|
||||
if os.IsNotExist(err) {
|
||||
return errors.InternalServerError("go.micro.srv.file", err.Error())
|
||||
}
|
||||
|
||||
if fi.IsDir() {
|
||||
rsp.Type = "Directory"
|
||||
} else {
|
||||
rsp.Type = "File"
|
||||
rsp.Size = fi.Size()
|
||||
}
|
||||
|
||||
rsp.LastModified = fi.ModTime().Unix()
|
||||
logger.Debugf("Stat %s, %#v", req.Filename, rsp)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *handler) Read(ctx context.Context, req *proto.ReadRequest, rsp *proto.ReadResponse) error {
|
||||
file := h.session.Get(req.Id)
|
||||
if file == nil {
|
||||
return errors.InternalServerError("go.micro.srv.file", "You must call open first.")
|
||||
}
|
||||
|
||||
rsp.Data = make([]byte, req.Size)
|
||||
n, err := file.ReadAt(rsp.Data, req.Offset)
|
||||
if err != nil && err != io.EOF {
|
||||
return errors.InternalServerError("go.micro.srv.file", err.Error())
|
||||
}
|
||||
|
||||
if err == io.EOF {
|
||||
rsp.Eof = true
|
||||
}
|
||||
|
||||
rsp.Size = int64(n)
|
||||
rsp.Data = rsp.Data[:n]
|
||||
|
||||
logger.Debugf("Read sessionId=%d, Offset=%d, n=%d", req.Id, req.Offset, rsp.Size)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *handler) Write(ctx context.Context, req *proto.WriteRequest, rsp *proto.WriteResponse) error {
|
||||
file := h.session.Get(req.Id)
|
||||
if file == nil {
|
||||
return errors.InternalServerError("go.micro.srv.file", "You must call open first.")
|
||||
}
|
||||
|
||||
if _, err := file.WriteAt(req.GetData(), req.GetOffset()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Debugf("Write sessionId=%d, Offset=%d, n=%d", req.Id, req.Offset)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type session struct {
|
||||
sync.Mutex
|
||||
files map[int64]*os.File
|
||||
counter int64
|
||||
}
|
||||
|
||||
func (s *session) Add(file *os.File) int64 {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
s.counter += 1
|
||||
s.files[s.counter] = file
|
||||
|
||||
return s.counter
|
||||
}
|
||||
|
||||
func (s *session) Get(id int64) *os.File {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
return s.files[id]
|
||||
}
|
||||
|
||||
func (s *session) Delete(id int64) {
|
||||
s.Lock()
|
||||
defer s.Unlock()
|
||||
|
||||
if file, exist := s.files[id]; exist {
|
||||
file.Close()
|
||||
delete(s.files, id)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *session) Len() int {
|
||||
return len(s.files)
|
||||
}
|
854
util/file/proto/file.pb.go
Normal file
854
util/file/proto/file.pb.go
Normal file
@@ -0,0 +1,854 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: util/file/proto/file.proto
|
||||
|
||||
package go_micro_server
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type OpenRequest struct {
|
||||
Filename string `protobuf:"bytes,1,opt,name=filename,proto3" json:"filename,omitempty"`
|
||||
Truncate bool `protobuf:"varint,2,opt,name=truncate,proto3" json:"truncate,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *OpenRequest) Reset() { *m = OpenRequest{} }
|
||||
func (m *OpenRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*OpenRequest) ProtoMessage() {}
|
||||
func (*OpenRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c90a6c4a93f92bf4, []int{0}
|
||||
}
|
||||
|
||||
func (m *OpenRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_OpenRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *OpenRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_OpenRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *OpenRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_OpenRequest.Merge(m, src)
|
||||
}
|
||||
func (m *OpenRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_OpenRequest.Size(m)
|
||||
}
|
||||
func (m *OpenRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_OpenRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_OpenRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *OpenRequest) GetFilename() string {
|
||||
if m != nil {
|
||||
return m.Filename
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *OpenRequest) GetTruncate() bool {
|
||||
if m != nil {
|
||||
return m.Truncate
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type OpenResponse struct {
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Result bool `protobuf:"varint,2,opt,name=result,proto3" json:"result,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *OpenResponse) Reset() { *m = OpenResponse{} }
|
||||
func (m *OpenResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*OpenResponse) ProtoMessage() {}
|
||||
func (*OpenResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c90a6c4a93f92bf4, []int{1}
|
||||
}
|
||||
|
||||
func (m *OpenResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_OpenResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *OpenResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_OpenResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *OpenResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_OpenResponse.Merge(m, src)
|
||||
}
|
||||
func (m *OpenResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_OpenResponse.Size(m)
|
||||
}
|
||||
func (m *OpenResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_OpenResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_OpenResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *OpenResponse) GetId() int64 {
|
||||
if m != nil {
|
||||
return m.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *OpenResponse) GetResult() bool {
|
||||
if m != nil {
|
||||
return m.Result
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type CloseRequest struct {
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CloseRequest) Reset() { *m = CloseRequest{} }
|
||||
func (m *CloseRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*CloseRequest) ProtoMessage() {}
|
||||
func (*CloseRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c90a6c4a93f92bf4, []int{2}
|
||||
}
|
||||
|
||||
func (m *CloseRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CloseRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *CloseRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CloseRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *CloseRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CloseRequest.Merge(m, src)
|
||||
}
|
||||
func (m *CloseRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_CloseRequest.Size(m)
|
||||
}
|
||||
func (m *CloseRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CloseRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CloseRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *CloseRequest) GetId() int64 {
|
||||
if m != nil {
|
||||
return m.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type CloseResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CloseResponse) Reset() { *m = CloseResponse{} }
|
||||
func (m *CloseResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*CloseResponse) ProtoMessage() {}
|
||||
func (*CloseResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c90a6c4a93f92bf4, []int{3}
|
||||
}
|
||||
|
||||
func (m *CloseResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CloseResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *CloseResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CloseResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *CloseResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CloseResponse.Merge(m, src)
|
||||
}
|
||||
func (m *CloseResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_CloseResponse.Size(m)
|
||||
}
|
||||
func (m *CloseResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CloseResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CloseResponse proto.InternalMessageInfo
|
||||
|
||||
type StatRequest struct {
|
||||
Filename string `protobuf:"bytes,1,opt,name=filename,proto3" json:"filename,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *StatRequest) Reset() { *m = StatRequest{} }
|
||||
func (m *StatRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*StatRequest) ProtoMessage() {}
|
||||
func (*StatRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c90a6c4a93f92bf4, []int{4}
|
||||
}
|
||||
|
||||
func (m *StatRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StatRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *StatRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_StatRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *StatRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_StatRequest.Merge(m, src)
|
||||
}
|
||||
func (m *StatRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_StatRequest.Size(m)
|
||||
}
|
||||
func (m *StatRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_StatRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_StatRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *StatRequest) GetFilename() string {
|
||||
if m != nil {
|
||||
return m.Filename
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type StatResponse struct {
|
||||
Type string `protobuf:"bytes,1,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Size int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"`
|
||||
LastModified int64 `protobuf:"varint,3,opt,name=last_modified,json=lastModified,proto3" json:"last_modified,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *StatResponse) Reset() { *m = StatResponse{} }
|
||||
func (m *StatResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*StatResponse) ProtoMessage() {}
|
||||
func (*StatResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c90a6c4a93f92bf4, []int{5}
|
||||
}
|
||||
|
||||
func (m *StatResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StatResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *StatResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_StatResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *StatResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_StatResponse.Merge(m, src)
|
||||
}
|
||||
func (m *StatResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_StatResponse.Size(m)
|
||||
}
|
||||
func (m *StatResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_StatResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_StatResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *StatResponse) GetType() string {
|
||||
if m != nil {
|
||||
return m.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *StatResponse) GetSize() int64 {
|
||||
if m != nil {
|
||||
return m.Size
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *StatResponse) GetLastModified() int64 {
|
||||
if m != nil {
|
||||
return m.LastModified
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ReadRequest struct {
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Offset int64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"`
|
||||
Size int64 `protobuf:"varint,3,opt,name=size,proto3" json:"size,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ReadRequest) Reset() { *m = ReadRequest{} }
|
||||
func (m *ReadRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ReadRequest) ProtoMessage() {}
|
||||
func (*ReadRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c90a6c4a93f92bf4, []int{6}
|
||||
}
|
||||
|
||||
func (m *ReadRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ReadRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ReadRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ReadRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ReadRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ReadRequest.Merge(m, src)
|
||||
}
|
||||
func (m *ReadRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_ReadRequest.Size(m)
|
||||
}
|
||||
func (m *ReadRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ReadRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ReadRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *ReadRequest) GetId() int64 {
|
||||
if m != nil {
|
||||
return m.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *ReadRequest) GetOffset() int64 {
|
||||
if m != nil {
|
||||
return m.Offset
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *ReadRequest) GetSize() int64 {
|
||||
if m != nil {
|
||||
return m.Size
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type ReadResponse struct {
|
||||
Size int64 `protobuf:"varint,1,opt,name=size,proto3" json:"size,omitempty"`
|
||||
Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
|
||||
Eof bool `protobuf:"varint,3,opt,name=eof,proto3" json:"eof,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *ReadResponse) Reset() { *m = ReadResponse{} }
|
||||
func (m *ReadResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ReadResponse) ProtoMessage() {}
|
||||
func (*ReadResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c90a6c4a93f92bf4, []int{7}
|
||||
}
|
||||
|
||||
func (m *ReadResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ReadResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *ReadResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_ReadResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *ReadResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_ReadResponse.Merge(m, src)
|
||||
}
|
||||
func (m *ReadResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_ReadResponse.Size(m)
|
||||
}
|
||||
func (m *ReadResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_ReadResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_ReadResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *ReadResponse) GetSize() int64 {
|
||||
if m != nil {
|
||||
return m.Size
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *ReadResponse) GetData() []byte {
|
||||
if m != nil {
|
||||
return m.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ReadResponse) GetEof() bool {
|
||||
if m != nil {
|
||||
return m.Eof
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type GetRequest struct {
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
BlockId int64 `protobuf:"varint,2,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *GetRequest) Reset() { *m = GetRequest{} }
|
||||
func (m *GetRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*GetRequest) ProtoMessage() {}
|
||||
func (*GetRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c90a6c4a93f92bf4, []int{8}
|
||||
}
|
||||
|
||||
func (m *GetRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_GetRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *GetRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_GetRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *GetRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_GetRequest.Merge(m, src)
|
||||
}
|
||||
func (m *GetRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_GetRequest.Size(m)
|
||||
}
|
||||
func (m *GetRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_GetRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_GetRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *GetRequest) GetId() int64 {
|
||||
if m != nil {
|
||||
return m.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *GetRequest) GetBlockId() int64 {
|
||||
if m != nil {
|
||||
return m.BlockId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type GetResponse struct {
|
||||
BlockId int64 `protobuf:"varint,1,opt,name=block_id,json=blockId,proto3" json:"block_id,omitempty"`
|
||||
Size int64 `protobuf:"varint,2,opt,name=size,proto3" json:"size,omitempty"`
|
||||
Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *GetResponse) Reset() { *m = GetResponse{} }
|
||||
func (m *GetResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*GetResponse) ProtoMessage() {}
|
||||
func (*GetResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c90a6c4a93f92bf4, []int{9}
|
||||
}
|
||||
|
||||
func (m *GetResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_GetResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *GetResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_GetResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *GetResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_GetResponse.Merge(m, src)
|
||||
}
|
||||
func (m *GetResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_GetResponse.Size(m)
|
||||
}
|
||||
func (m *GetResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_GetResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_GetResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *GetResponse) GetBlockId() int64 {
|
||||
if m != nil {
|
||||
return m.BlockId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *GetResponse) GetSize() int64 {
|
||||
if m != nil {
|
||||
return m.Size
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *GetResponse) GetData() []byte {
|
||||
if m != nil {
|
||||
return m.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type WriteRequest struct {
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Offset int64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"`
|
||||
Data []byte `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *WriteRequest) Reset() { *m = WriteRequest{} }
|
||||
func (m *WriteRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*WriteRequest) ProtoMessage() {}
|
||||
func (*WriteRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c90a6c4a93f92bf4, []int{10}
|
||||
}
|
||||
|
||||
func (m *WriteRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_WriteRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *WriteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_WriteRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *WriteRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_WriteRequest.Merge(m, src)
|
||||
}
|
||||
func (m *WriteRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_WriteRequest.Size(m)
|
||||
}
|
||||
func (m *WriteRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_WriteRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_WriteRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *WriteRequest) GetId() int64 {
|
||||
if m != nil {
|
||||
return m.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *WriteRequest) GetOffset() int64 {
|
||||
if m != nil {
|
||||
return m.Offset
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *WriteRequest) GetData() []byte {
|
||||
if m != nil {
|
||||
return m.Data
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type WriteResponse struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *WriteResponse) Reset() { *m = WriteResponse{} }
|
||||
func (m *WriteResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*WriteResponse) ProtoMessage() {}
|
||||
func (*WriteResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_c90a6c4a93f92bf4, []int{11}
|
||||
}
|
||||
|
||||
func (m *WriteResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_WriteResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *WriteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_WriteResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *WriteResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_WriteResponse.Merge(m, src)
|
||||
}
|
||||
func (m *WriteResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_WriteResponse.Size(m)
|
||||
}
|
||||
func (m *WriteResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_WriteResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_WriteResponse proto.InternalMessageInfo
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*OpenRequest)(nil), "go.micro.server.OpenRequest")
|
||||
proto.RegisterType((*OpenResponse)(nil), "go.micro.server.OpenResponse")
|
||||
proto.RegisterType((*CloseRequest)(nil), "go.micro.server.CloseRequest")
|
||||
proto.RegisterType((*CloseResponse)(nil), "go.micro.server.CloseResponse")
|
||||
proto.RegisterType((*StatRequest)(nil), "go.micro.server.StatRequest")
|
||||
proto.RegisterType((*StatResponse)(nil), "go.micro.server.StatResponse")
|
||||
proto.RegisterType((*ReadRequest)(nil), "go.micro.server.ReadRequest")
|
||||
proto.RegisterType((*ReadResponse)(nil), "go.micro.server.ReadResponse")
|
||||
proto.RegisterType((*GetRequest)(nil), "go.micro.server.GetRequest")
|
||||
proto.RegisterType((*GetResponse)(nil), "go.micro.server.GetResponse")
|
||||
proto.RegisterType((*WriteRequest)(nil), "go.micro.server.WriteRequest")
|
||||
proto.RegisterType((*WriteResponse)(nil), "go.micro.server.WriteResponse")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("util/file/proto/file.proto", fileDescriptor_c90a6c4a93f92bf4) }
|
||||
|
||||
var fileDescriptor_c90a6c4a93f92bf4 = []byte{
|
||||
// 447 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x94, 0xcf, 0x8e, 0xd3, 0x30,
|
||||
0x10, 0xc6, 0x9b, 0x3f, 0x2c, 0x61, 0x92, 0x52, 0xe4, 0x03, 0x2a, 0x11, 0xac, 0x56, 0xe6, 0xb2,
|
||||
0x5c, 0xb2, 0x12, 0x48, 0xf0, 0x00, 0x68, 0x61, 0x17, 0x09, 0x81, 0xcc, 0x81, 0x03, 0x87, 0x55,
|
||||
0xb6, 0x9e, 0x20, 0x8b, 0x34, 0x0e, 0xb1, 0x83, 0x04, 0x2f, 0xcd, 0x2b, 0x20, 0x3b, 0x6e, 0xeb,
|
||||
0xb6, 0x89, 0x84, 0xf6, 0x36, 0xe3, 0x19, 0xff, 0xfc, 0xd9, 0xf9, 0x26, 0x90, 0xf7, 0x5a, 0xd4,
|
||||
0x17, 0x95, 0xa8, 0xf1, 0xa2, 0xed, 0xa4, 0x96, 0x36, 0x2c, 0x6c, 0x48, 0x16, 0xdf, 0x65, 0xb1,
|
||||
0x16, 0xab, 0x4e, 0x16, 0x0a, 0xbb, 0x5f, 0xd8, 0xd1, 0x4b, 0x48, 0x3f, 0xb5, 0xd8, 0x30, 0xfc,
|
||||
0xd9, 0xa3, 0xd2, 0x24, 0x87, 0xc4, 0x74, 0x37, 0xe5, 0x1a, 0x97, 0xc1, 0x59, 0x70, 0xfe, 0x80,
|
||||
0x6d, 0x73, 0x53, 0xd3, 0x5d, 0xdf, 0xac, 0x4a, 0x8d, 0xcb, 0xf0, 0x2c, 0x38, 0x4f, 0xd8, 0x36,
|
||||
0xa7, 0xaf, 0x21, 0x1b, 0x30, 0xaa, 0x95, 0x8d, 0x42, 0xf2, 0x10, 0x42, 0xc1, 0x2d, 0x21, 0x62,
|
||||
0xa1, 0xe0, 0xe4, 0x31, 0x9c, 0x74, 0xa8, 0xfa, 0x5a, 0xbb, 0x9d, 0x2e, 0xa3, 0xa7, 0x90, 0xbd,
|
||||
0xad, 0xa5, 0xc2, 0xcd, 0xf9, 0x07, 0xfb, 0xe8, 0x02, 0xe6, 0xae, 0x3e, 0x80, 0xe9, 0x0b, 0x48,
|
||||
0xbf, 0xe8, 0x52, 0xff, 0x87, 0x5e, 0xfa, 0x0d, 0xb2, 0xa1, 0xd5, 0x69, 0x22, 0x10, 0xeb, 0xdf,
|
||||
0xed, 0xa6, 0xcf, 0xc6, 0x66, 0x4d, 0x89, 0x3f, 0xc3, 0x7d, 0x22, 0x66, 0x63, 0xf2, 0x1c, 0xe6,
|
||||
0x75, 0xa9, 0xf4, 0xcd, 0x5a, 0x72, 0x51, 0x09, 0xe4, 0xcb, 0xc8, 0x16, 0x33, 0xb3, 0xf8, 0xd1,
|
||||
0xad, 0xd1, 0x6b, 0x48, 0x19, 0x96, 0x7c, 0x42, 0xb7, 0xb9, 0xaf, 0xac, 0x2a, 0x85, 0xda, 0x91,
|
||||
0x5d, 0xb6, 0x3d, 0x2f, 0xda, 0x9d, 0x47, 0xaf, 0x20, 0x1b, 0x50, 0x3b, 0x9d, 0xb6, 0x27, 0xf0,
|
||||
0x34, 0x11, 0x88, 0x79, 0xa9, 0x4b, 0x4b, 0xcb, 0x98, 0x8d, 0xc9, 0x23, 0x88, 0x50, 0x56, 0x16,
|
||||
0x95, 0x30, 0x13, 0xd2, 0x37, 0x00, 0xef, 0x51, 0x4f, 0x69, 0x7a, 0x02, 0xc9, 0x6d, 0x2d, 0x57,
|
||||
0x3f, 0x6e, 0x04, 0x77, 0xaa, 0xee, 0xdb, 0xfc, 0x9a, 0xd3, 0xcf, 0x90, 0xda, 0x8d, 0x4e, 0x81,
|
||||
0xdf, 0x19, 0xec, 0x75, 0x8e, 0x3e, 0xd8, 0x46, 0x5c, 0xb4, 0x13, 0x47, 0x3f, 0x40, 0xf6, 0xb5,
|
||||
0x13, 0x1a, 0xef, 0xf0, 0x40, 0x47, 0xac, 0x05, 0xcc, 0x1d, 0x6b, 0xd0, 0xf7, 0xf2, 0x6f, 0x08,
|
||||
0xf1, 0x3b, 0x51, 0x23, 0xb9, 0x84, 0xd8, 0xd8, 0x8e, 0x3c, 0x2d, 0x0e, 0x7c, 0x5d, 0x78, 0xa6,
|
||||
0xce, 0x9f, 0x4d, 0x54, 0x9d, 0xa5, 0x66, 0x06, 0x63, 0x9c, 0x32, 0x82, 0xf1, 0xbc, 0x36, 0x82,
|
||||
0xf1, 0xed, 0x35, 0x60, 0xcc, 0x87, 0x1c, 0xc1, 0x78, 0x56, 0x19, 0xc1, 0xf8, 0x5f, 0x9f, 0xce,
|
||||
0xc8, 0x15, 0xdc, 0xb3, 0xd7, 0x25, 0xc7, 0x9d, 0xfe, 0x93, 0xe6, 0xa7, 0x53, 0x65, 0x9f, 0x64,
|
||||
0xa7, 0x67, 0x84, 0xe4, 0x4f, 0xdd, 0x08, 0x69, 0x7f, 0xe8, 0x66, 0xb7, 0x27, 0xf6, 0xf7, 0xf1,
|
||||
0xea, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xaf, 0x08, 0x7e, 0x74, 0x5c, 0x04, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConn
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion4
|
||||
|
||||
// FileClient is the client API for File service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type FileClient interface {
|
||||
Open(ctx context.Context, in *OpenRequest, opts ...grpc.CallOption) (*OpenResponse, error)
|
||||
Stat(ctx context.Context, in *StatRequest, opts ...grpc.CallOption) (*StatResponse, error)
|
||||
Read(ctx context.Context, in *ReadRequest, opts ...grpc.CallOption) (*ReadResponse, error)
|
||||
Write(ctx context.Context, in *WriteRequest, opts ...grpc.CallOption) (*WriteResponse, error)
|
||||
Close(ctx context.Context, in *CloseRequest, opts ...grpc.CallOption) (*CloseResponse, error)
|
||||
}
|
||||
|
||||
type fileClient struct {
|
||||
cc *grpc.ClientConn
|
||||
}
|
||||
|
||||
func NewFileClient(cc *grpc.ClientConn) FileClient {
|
||||
return &fileClient{cc}
|
||||
}
|
||||
|
||||
func (c *fileClient) Open(ctx context.Context, in *OpenRequest, opts ...grpc.CallOption) (*OpenResponse, error) {
|
||||
out := new(OpenResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.server.File/Open", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *fileClient) Stat(ctx context.Context, in *StatRequest, opts ...grpc.CallOption) (*StatResponse, error) {
|
||||
out := new(StatResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.server.File/Stat", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *fileClient) Read(ctx context.Context, in *ReadRequest, opts ...grpc.CallOption) (*ReadResponse, error) {
|
||||
out := new(ReadResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.server.File/Read", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *fileClient) Write(ctx context.Context, in *WriteRequest, opts ...grpc.CallOption) (*WriteResponse, error) {
|
||||
out := new(WriteResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.server.File/Write", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *fileClient) Close(ctx context.Context, in *CloseRequest, opts ...grpc.CallOption) (*CloseResponse, error) {
|
||||
out := new(CloseResponse)
|
||||
err := c.cc.Invoke(ctx, "/go.micro.server.File/Close", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// FileServer is the server API for File service.
|
||||
type FileServer interface {
|
||||
Open(context.Context, *OpenRequest) (*OpenResponse, error)
|
||||
Stat(context.Context, *StatRequest) (*StatResponse, error)
|
||||
Read(context.Context, *ReadRequest) (*ReadResponse, error)
|
||||
Write(context.Context, *WriteRequest) (*WriteResponse, error)
|
||||
Close(context.Context, *CloseRequest) (*CloseResponse, error)
|
||||
}
|
||||
|
||||
// UnimplementedFileServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedFileServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedFileServer) Open(ctx context.Context, req *OpenRequest) (*OpenResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Open not implemented")
|
||||
}
|
||||
func (*UnimplementedFileServer) Stat(ctx context.Context, req *StatRequest) (*StatResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Stat not implemented")
|
||||
}
|
||||
func (*UnimplementedFileServer) Read(ctx context.Context, req *ReadRequest) (*ReadResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Read not implemented")
|
||||
}
|
||||
func (*UnimplementedFileServer) Write(ctx context.Context, req *WriteRequest) (*WriteResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Write not implemented")
|
||||
}
|
||||
func (*UnimplementedFileServer) Close(ctx context.Context, req *CloseRequest) (*CloseResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Close not implemented")
|
||||
}
|
||||
|
||||
func RegisterFileServer(s *grpc.Server, srv FileServer) {
|
||||
s.RegisterService(&_File_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _File_Open_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(OpenRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(FileServer).Open(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.server.File/Open",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(FileServer).Open(ctx, req.(*OpenRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _File_Stat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(StatRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(FileServer).Stat(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.server.File/Stat",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(FileServer).Stat(ctx, req.(*StatRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _File_Read_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ReadRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(FileServer).Read(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.server.File/Read",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(FileServer).Read(ctx, req.(*ReadRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _File_Write_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(WriteRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(FileServer).Write(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.server.File/Write",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(FileServer).Write(ctx, req.(*WriteRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _File_Close_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CloseRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(FileServer).Close(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/go.micro.server.File/Close",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(FileServer).Close(ctx, req.(*CloseRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _File_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "go.micro.server.File",
|
||||
HandlerType: (*FileServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Open",
|
||||
Handler: _File_Open_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Stat",
|
||||
Handler: _File_Stat_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Read",
|
||||
Handler: _File_Read_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Write",
|
||||
Handler: _File_Write_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Close",
|
||||
Handler: _File_Close_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "util/file/proto/file.proto",
|
||||
}
|
161
util/file/proto/file.pb.micro.go
Normal file
161
util/file/proto/file.pb.micro.go
Normal file
@@ -0,0 +1,161 @@
|
||||
// Code generated by protoc-gen-micro. DO NOT EDIT.
|
||||
// source: util/file/proto/file.proto
|
||||
|
||||
package go_micro_server
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
math "math"
|
||||
)
|
||||
|
||||
import (
|
||||
context "context"
|
||||
api "github.com/micro/go-micro/v2/api"
|
||||
client "github.com/micro/go-micro/v2/client"
|
||||
server "github.com/micro/go-micro/v2/server"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ api.Endpoint
|
||||
var _ context.Context
|
||||
var _ client.Option
|
||||
var _ server.Option
|
||||
|
||||
// Api Endpoints for File service
|
||||
|
||||
func NewFileEndpoints() []*api.Endpoint {
|
||||
return []*api.Endpoint{}
|
||||
}
|
||||
|
||||
// Client API for File service
|
||||
|
||||
type FileService interface {
|
||||
Open(ctx context.Context, in *OpenRequest, opts ...client.CallOption) (*OpenResponse, error)
|
||||
Stat(ctx context.Context, in *StatRequest, opts ...client.CallOption) (*StatResponse, error)
|
||||
Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error)
|
||||
Write(ctx context.Context, in *WriteRequest, opts ...client.CallOption) (*WriteResponse, error)
|
||||
Close(ctx context.Context, in *CloseRequest, opts ...client.CallOption) (*CloseResponse, error)
|
||||
}
|
||||
|
||||
type fileService struct {
|
||||
c client.Client
|
||||
name string
|
||||
}
|
||||
|
||||
func NewFileService(name string, c client.Client) FileService {
|
||||
return &fileService{
|
||||
c: c,
|
||||
name: name,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *fileService) Open(ctx context.Context, in *OpenRequest, opts ...client.CallOption) (*OpenResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "File.Open", in)
|
||||
out := new(OpenResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *fileService) Stat(ctx context.Context, in *StatRequest, opts ...client.CallOption) (*StatResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "File.Stat", in)
|
||||
out := new(StatResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *fileService) Read(ctx context.Context, in *ReadRequest, opts ...client.CallOption) (*ReadResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "File.Read", in)
|
||||
out := new(ReadResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *fileService) Write(ctx context.Context, in *WriteRequest, opts ...client.CallOption) (*WriteResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "File.Write", in)
|
||||
out := new(WriteResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *fileService) Close(ctx context.Context, in *CloseRequest, opts ...client.CallOption) (*CloseResponse, error) {
|
||||
req := c.c.NewRequest(c.name, "File.Close", in)
|
||||
out := new(CloseResponse)
|
||||
err := c.c.Call(ctx, req, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// Server API for File service
|
||||
|
||||
type FileHandler interface {
|
||||
Open(context.Context, *OpenRequest, *OpenResponse) error
|
||||
Stat(context.Context, *StatRequest, *StatResponse) error
|
||||
Read(context.Context, *ReadRequest, *ReadResponse) error
|
||||
Write(context.Context, *WriteRequest, *WriteResponse) error
|
||||
Close(context.Context, *CloseRequest, *CloseResponse) error
|
||||
}
|
||||
|
||||
func RegisterFileHandler(s server.Server, hdlr FileHandler, opts ...server.HandlerOption) error {
|
||||
type file interface {
|
||||
Open(ctx context.Context, in *OpenRequest, out *OpenResponse) error
|
||||
Stat(ctx context.Context, in *StatRequest, out *StatResponse) error
|
||||
Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error
|
||||
Write(ctx context.Context, in *WriteRequest, out *WriteResponse) error
|
||||
Close(ctx context.Context, in *CloseRequest, out *CloseResponse) error
|
||||
}
|
||||
type File struct {
|
||||
file
|
||||
}
|
||||
h := &fileHandler{hdlr}
|
||||
return s.Handle(s.NewHandler(&File{h}, opts...))
|
||||
}
|
||||
|
||||
type fileHandler struct {
|
||||
FileHandler
|
||||
}
|
||||
|
||||
func (h *fileHandler) Open(ctx context.Context, in *OpenRequest, out *OpenResponse) error {
|
||||
return h.FileHandler.Open(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *fileHandler) Stat(ctx context.Context, in *StatRequest, out *StatResponse) error {
|
||||
return h.FileHandler.Stat(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *fileHandler) Read(ctx context.Context, in *ReadRequest, out *ReadResponse) error {
|
||||
return h.FileHandler.Read(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *fileHandler) Write(ctx context.Context, in *WriteRequest, out *WriteResponse) error {
|
||||
return h.FileHandler.Write(ctx, in, out)
|
||||
}
|
||||
|
||||
func (h *fileHandler) Close(ctx context.Context, in *CloseRequest, out *CloseResponse) error {
|
||||
return h.FileHandler.Close(ctx, in, out)
|
||||
}
|
69
util/file/proto/file.proto
Normal file
69
util/file/proto/file.proto
Normal file
@@ -0,0 +1,69 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package go.micro.server;
|
||||
|
||||
service File {
|
||||
rpc Open(OpenRequest) returns(OpenResponse) {};
|
||||
rpc Stat(StatRequest) returns(StatResponse) {};
|
||||
rpc Read(ReadRequest) returns(ReadResponse) {};
|
||||
rpc Write(WriteRequest) returns(WriteResponse) {};
|
||||
rpc Close(CloseRequest) returns(CloseResponse) {};
|
||||
}
|
||||
|
||||
message OpenRequest {
|
||||
string filename = 1;
|
||||
bool truncate = 2;
|
||||
}
|
||||
|
||||
message OpenResponse {
|
||||
int64 id = 1;
|
||||
bool result = 2;
|
||||
}
|
||||
|
||||
message CloseRequest {
|
||||
int64 id = 1;
|
||||
}
|
||||
|
||||
message CloseResponse {
|
||||
}
|
||||
|
||||
message StatRequest {
|
||||
string filename = 1;
|
||||
}
|
||||
|
||||
message StatResponse {
|
||||
string type = 1;
|
||||
int64 size = 2;
|
||||
int64 last_modified = 3;
|
||||
}
|
||||
|
||||
message ReadRequest {
|
||||
int64 id = 1;
|
||||
int64 offset = 2;
|
||||
int64 size = 3;
|
||||
}
|
||||
|
||||
message ReadResponse {
|
||||
int64 size = 1;
|
||||
bytes data = 2;
|
||||
bool eof = 3;
|
||||
}
|
||||
|
||||
message GetRequest {
|
||||
int64 id = 1;
|
||||
int64 block_id = 2;
|
||||
}
|
||||
|
||||
message GetResponse {
|
||||
int64 block_id = 1;
|
||||
int64 size = 2;
|
||||
bytes data = 3;
|
||||
}
|
||||
|
||||
message WriteRequest {
|
||||
int64 id = 1;
|
||||
int64 offset = 2;
|
||||
bytes data = 3;
|
||||
}
|
||||
|
||||
message WriteResponse {}
|
@@ -9,6 +9,8 @@ import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/micro/go-micro/v2/logger"
|
||||
)
|
||||
|
||||
// Request is used to construct a http request for the k8s API.
|
||||
@@ -30,7 +32,7 @@ type Request struct {
|
||||
err error
|
||||
}
|
||||
|
||||
// Params is the object to pass in to set paramaters
|
||||
// Params is the object to pass in to set parameters
|
||||
// on a request.
|
||||
type Params struct {
|
||||
LabelSelector map[string]string
|
||||
@@ -217,6 +219,7 @@ func (r *Request) Do() *Response {
|
||||
}
|
||||
}
|
||||
|
||||
logger.Debugf("[Kubernetes] %v %v", req.Method, req.URL.String())
|
||||
res, err := r.client.Do(req)
|
||||
if err != nil {
|
||||
return &Response{
|
||||
|
@@ -129,6 +129,7 @@ metadata:
|
||||
var secretTmpl = `
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
type: "{{ .Type }}"
|
||||
metadata:
|
||||
name: "{{ .Metadata.Name }}"
|
||||
namespace: "{{ .Metadata.Namespace }}"
|
||||
@@ -139,11 +140,11 @@ metadata:
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
data:
|
||||
{{- with .Data }}
|
||||
{{- range $key, $value := . }}
|
||||
{{ $key }}: "{{ $value }}"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Data }}
|
||||
{{- range $key, $value := . }}
|
||||
{{ $key }}: "{{ $value }}"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
`
|
||||
|
||||
var serviceAccountTmpl = `
|
||||
|
@@ -34,7 +34,7 @@ type ServiceEntry struct {
|
||||
|
||||
// complete is used to check if we have all the info we need
|
||||
func (s *ServiceEntry) complete() bool {
|
||||
return (s.AddrV4 != nil || s.AddrV6 != nil || s.Addr != nil) && s.Port != 0 && s.hasTXT
|
||||
return (len(s.AddrV4) > 0 || len(s.AddrV6) > 0 || len(s.Addr) > 0) && s.Port != 0 && s.hasTXT
|
||||
}
|
||||
|
||||
// QueryParam is used to customize how a Lookup is performed
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"context"
|
||||
"sync"
|
||||
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
"github.com/micro/go-micro/v2/debug/service/handler"
|
||||
"github.com/micro/go-micro/v2/proxy"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
@@ -42,7 +43,7 @@ func New(name string, p proxy.Proxy) *Server {
|
||||
server.DefaultRouter.Handle(
|
||||
// inject the debug handler
|
||||
server.DefaultRouter.NewHandler(
|
||||
handler.NewHandler(),
|
||||
handler.NewHandler(client.DefaultClient),
|
||||
server.InternalHandler(true),
|
||||
),
|
||||
)
|
||||
|
@@ -83,20 +83,23 @@ func Listen(addr string, fn func(string) (net.Listener, error)) (net.Listener, e
|
||||
func Proxy(service string, address []string) (string, []string, bool) {
|
||||
var hasProxy bool
|
||||
|
||||
// get proxy
|
||||
// get proxy. we parse out address if present
|
||||
if prx := os.Getenv("MICRO_PROXY"); len(prx) > 0 {
|
||||
// default name
|
||||
if prx == "service" {
|
||||
prx = "go.micro.proxy"
|
||||
address = nil
|
||||
}
|
||||
|
||||
// check if its an address
|
||||
if v := strings.Split(prx, ":"); len(v) > 1 {
|
||||
address = []string{prx}
|
||||
}
|
||||
|
||||
service = prx
|
||||
hasProxy = true
|
||||
}
|
||||
|
||||
// get proxy address
|
||||
if prx := os.Getenv("MICRO_PROXY_ADDRESS"); len(prx) > 0 {
|
||||
address = []string{prx}
|
||||
hasProxy = true
|
||||
return service, address, hasProxy
|
||||
}
|
||||
|
||||
if prx := os.Getenv("MICRO_NETWORK"); len(prx) > 0 {
|
||||
|
@@ -57,7 +57,6 @@ func TestProxyEnv(t *testing.T) {
|
||||
}
|
||||
|
||||
test("MICRO_PROXY", "service", "go.micro.proxy", "")
|
||||
test("MICRO_PROXY_ADDRESS", "10.0.0.1:8080", "", "10.0.0.1:8080")
|
||||
test("MICRO_NETWORK", "service", "go.micro.network", "")
|
||||
test("MICRO_NETWORK_ADDRESS", "10.0.0.1:8081", "", "10.0.0.1:8081")
|
||||
}
|
||||
|
@@ -67,17 +67,12 @@ func (b *Buffer) Get(n int) []*Entry {
|
||||
defer b.RUnlock()
|
||||
|
||||
// reset any invalid values
|
||||
if n > b.size || n < 0 {
|
||||
n = b.size
|
||||
if n > len(b.vals) || n < 0 {
|
||||
n = len(b.vals)
|
||||
}
|
||||
|
||||
// create a delta
|
||||
delta := b.size - n
|
||||
|
||||
// if all the values are less than delta
|
||||
if len(b.vals) < delta {
|
||||
return b.vals
|
||||
}
|
||||
delta := len(b.vals) - n
|
||||
|
||||
// return the delta set
|
||||
return b.vals[delta:]
|
||||
|
@@ -19,12 +19,18 @@ func (p *Pool) Get(id string) (*Socket, bool) {
|
||||
}
|
||||
p.RUnlock()
|
||||
|
||||
// create new socket
|
||||
socket = New(id)
|
||||
// save socket
|
||||
p.Lock()
|
||||
defer p.Unlock()
|
||||
// double checked locking
|
||||
socket, ok = p.pool[id]
|
||||
if ok {
|
||||
return socket, ok
|
||||
}
|
||||
// create new socket
|
||||
socket = New(id)
|
||||
p.pool[id] = socket
|
||||
p.Unlock()
|
||||
|
||||
// return socket
|
||||
return socket, false
|
||||
}
|
||||
|
@@ -2,9 +2,8 @@ package wrapper
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/micro/go-micro/v2/auth"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
@@ -13,7 +12,6 @@ import (
|
||||
"github.com/micro/go-micro/v2/errors"
|
||||
"github.com/micro/go-micro/v2/metadata"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
"github.com/micro/go-micro/v2/util/config"
|
||||
)
|
||||
|
||||
type fromServiceWrapper struct {
|
||||
@@ -134,8 +132,6 @@ func TraceHandler(t trace.Tracer) server.HandlerWrapper {
|
||||
|
||||
type authWrapper struct {
|
||||
client.Client
|
||||
name string
|
||||
id string
|
||||
auth func() auth.Auth
|
||||
}
|
||||
|
||||
@@ -156,78 +152,29 @@ func (a *authWrapper) Call(ctx context.Context, req client.Request, rsp interfac
|
||||
// if auth is nil we won't be able to get an access token, so we execute
|
||||
// the request without one.
|
||||
aa := a.auth()
|
||||
if a == nil {
|
||||
if aa == nil {
|
||||
return a.Client.Call(ctx, req, rsp, opts...)
|
||||
}
|
||||
|
||||
// performs the call with the authorization token provided
|
||||
callWithToken := func(token string) error {
|
||||
ctx := metadata.Set(ctx, "Authorization", auth.BearerScheme+token)
|
||||
return a.Client.Call(ctx, req, rsp, opts...)
|
||||
// set the namespace header if it has not been set (e.g. on a service to service request)
|
||||
if _, ok := metadata.Get(ctx, "Micro-Namespace"); !ok {
|
||||
ctx = metadata.Set(ctx, "Micro-Namespace", aa.Options().Namespace)
|
||||
}
|
||||
|
||||
// check to see if we have a valid access token
|
||||
aaOpts := aa.Options()
|
||||
if aaOpts.Token != nil && aaOpts.Token.Expiry.Unix() > time.Now().Unix() {
|
||||
return callWithToken(aaOpts.Token.AccessToken)
|
||||
if aaOpts.Token != nil && !aaOpts.Token.Expired() {
|
||||
ctx = metadata.Set(ctx, "Authorization", auth.BearerScheme+aaOpts.Token.AccessToken)
|
||||
return a.Client.Call(ctx, req, rsp, opts...)
|
||||
}
|
||||
|
||||
// if we have a refresh token we can use this to generate another access token
|
||||
if aaOpts.Token != nil {
|
||||
tok, err := aa.Token(auth.WithToken(aaOpts.Token.RefreshToken))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
aa.Init(auth.ClientToken(tok))
|
||||
return callWithToken(tok.AccessToken)
|
||||
}
|
||||
|
||||
// if we have credentials we can generate a new token for the account
|
||||
if len(aaOpts.ID) > 0 && len(aaOpts.Secret) > 0 {
|
||||
tok, err := aa.Token(auth.WithCredentials(aaOpts.ID, aaOpts.Secret))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
aa.Init(auth.ClientToken(tok))
|
||||
return callWithToken(tok.AccessToken)
|
||||
}
|
||||
|
||||
// check to see if a token was provided in config, this is normally used for
|
||||
// setting the token when calling via the cli
|
||||
if token, err := config.Get("micro", "auth", "token"); err == nil && len(token) > 0 {
|
||||
return callWithToken(token)
|
||||
}
|
||||
|
||||
// determine the type of service from the name. we do this so we can allocate
|
||||
// different roles depending on the type of services. e.g. we don't want web
|
||||
// services talking directly to the runtime. TODO: find a better way to determine
|
||||
// the type of service
|
||||
serviceType := "service"
|
||||
if strings.Contains(a.name, "api") {
|
||||
serviceType = "api"
|
||||
} else if strings.Contains(a.name, "web") {
|
||||
serviceType = "web"
|
||||
}
|
||||
|
||||
// generate a new auth account for the service
|
||||
name := fmt.Sprintf("%v-%v", a.name, a.id)
|
||||
acc, err := aa.Generate(name, auth.WithNamespace(aaOpts.Namespace), auth.WithRoles(serviceType))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
token, err := aa.Token(auth.WithCredentials(acc.ID, acc.Secret))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
aa.Init(auth.ClientToken(token))
|
||||
|
||||
// use the token to execute the request
|
||||
return callWithToken(token.AccessToken)
|
||||
// call without an auth token
|
||||
return a.Client.Call(ctx, req, rsp, opts...)
|
||||
}
|
||||
|
||||
// AuthClient wraps requests with the auth header
|
||||
func AuthClient(name string, id string, auth func() auth.Auth, c client.Client) client.Client {
|
||||
return &authWrapper{c, name, id, auth}
|
||||
func AuthClient(auth func() auth.Auth, c client.Client) client.Client {
|
||||
return &authWrapper{c, auth}
|
||||
}
|
||||
|
||||
// AuthHandler wraps a server handler to perform auth
|
||||
@@ -244,20 +191,28 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper {
|
||||
|
||||
// Extract the token if present. Note: if noop is being used
|
||||
// then the token can be blank without erroring
|
||||
var token string
|
||||
var account *auth.Account
|
||||
if header, ok := metadata.Get(ctx, "Authorization"); ok {
|
||||
// Ensure the correct scheme is being used
|
||||
if !strings.HasPrefix(header, auth.BearerScheme) {
|
||||
return errors.Unauthorized(req.Service(), "invalid authorization header. expected Bearer schema")
|
||||
}
|
||||
|
||||
token = header[len(auth.BearerScheme):]
|
||||
// Strip the prefix and inspect the resulting token
|
||||
account, _ = a.Inspect(strings.TrimPrefix(header, auth.BearerScheme))
|
||||
}
|
||||
|
||||
// Inspect the token and get the account
|
||||
account, err := a.Inspect(token)
|
||||
if err != nil {
|
||||
account = &auth.Account{Namespace: a.Options().Namespace}
|
||||
// Extract the namespace header
|
||||
ns, ok := metadata.Get(ctx, "Micro-Namespace")
|
||||
if !ok {
|
||||
ns = a.Options().Namespace
|
||||
ctx = metadata.Set(ctx, "Micro-Namespace", ns)
|
||||
}
|
||||
|
||||
// Check the issuer matches the services namespace. TODO: Stop allowing go.micro to access
|
||||
// any namespace and instead check for the server issuer.
|
||||
if account != nil && account.Issuer != ns && account.Issuer != "go.micro" {
|
||||
return errors.Forbidden(req.Service(), "Account was not issued by %v", ns)
|
||||
}
|
||||
|
||||
// construct the resource
|
||||
@@ -268,18 +223,90 @@ func AuthHandler(fn func() auth.Auth) server.HandlerWrapper {
|
||||
}
|
||||
|
||||
// Verify the caller has access to the resource
|
||||
err = a.Verify(account, res)
|
||||
if err != nil && len(account.ID) > 0 {
|
||||
err := a.Verify(account, res, auth.VerifyContext(ctx))
|
||||
if err != nil && account != nil {
|
||||
return errors.Forbidden(req.Service(), "Forbidden call made to %v:%v by %v", req.Service(), req.Endpoint(), account.ID)
|
||||
} else if err != nil {
|
||||
return errors.Unauthorized(req.Service(), "Unauthorised call made to %v:%v", req.Service(), req.Endpoint())
|
||||
return errors.Unauthorized(req.Service(), "Unauthorized call made to %v:%v", req.Service(), req.Endpoint())
|
||||
}
|
||||
|
||||
// There is an account, set it in the context
|
||||
ctx = auth.ContextWithAccount(ctx, account)
|
||||
if account != nil {
|
||||
ctx = auth.ContextWithAccount(ctx, account)
|
||||
}
|
||||
|
||||
// The user is authorised, allow the call
|
||||
return h(ctx, req, rsp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type cacheWrapper struct {
|
||||
cacheFn func() *client.Cache
|
||||
client.Client
|
||||
}
|
||||
|
||||
// Call executes the request. If the CacheExpiry option was set, the response will be cached using
|
||||
// a hash of the metadata and request as the key.
|
||||
func (c *cacheWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
||||
// parse the options
|
||||
var options client.CallOptions
|
||||
for _, o := range opts {
|
||||
o(&options)
|
||||
}
|
||||
|
||||
// if the client doesn't have a cacbe setup don't continue
|
||||
cache := c.cacheFn()
|
||||
if cache == nil {
|
||||
return c.Client.Call(ctx, req, rsp, opts...)
|
||||
}
|
||||
|
||||
// if the cache expiry is not set, execute the call without the cache
|
||||
if options.CacheExpiry == 0 {
|
||||
return c.Client.Call(ctx, req, rsp, opts...)
|
||||
}
|
||||
|
||||
// if the response is nil don't call the cache since we can't assign the response
|
||||
if rsp == nil {
|
||||
return c.Client.Call(ctx, req, rsp, opts...)
|
||||
}
|
||||
|
||||
// check to see if there is a response cached, if there is assign it
|
||||
if r, ok := cache.Get(ctx, &req); ok {
|
||||
val := reflect.ValueOf(rsp).Elem()
|
||||
val.Set(reflect.ValueOf(r).Elem())
|
||||
return nil
|
||||
}
|
||||
|
||||
// don't cache the result if there was an error
|
||||
if err := c.Client.Call(ctx, req, rsp, opts...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// set the result in the cache
|
||||
cache.Set(ctx, &req, rsp, options.CacheExpiry)
|
||||
return nil
|
||||
}
|
||||
|
||||
// CacheClient wraps requests with the cache wrapper
|
||||
func CacheClient(cacheFn func() *client.Cache, c client.Client) client.Client {
|
||||
return &cacheWrapper{cacheFn, c}
|
||||
}
|
||||
|
||||
type staticClient struct {
|
||||
address string
|
||||
client.Client
|
||||
}
|
||||
|
||||
func (s *staticClient) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
|
||||
return s.Client.Call(ctx, req, rsp, append(opts, client.WithAddress(s.address))...)
|
||||
}
|
||||
|
||||
func (s *staticClient) Stream(ctx context.Context, req client.Request, opts ...client.CallOption) (client.Stream, error) {
|
||||
return s.Client.Stream(ctx, req, append(opts, client.WithAddress(s.address))...)
|
||||
}
|
||||
|
||||
// StaticClient sets an address on every call
|
||||
func StaticClient(address string, c client.Client) client.Client {
|
||||
return &staticClient{address, c}
|
||||
}
|
||||
|
72
util/wrapper/wrapper_static_client_test.go
Normal file
72
util/wrapper/wrapper_static_client_test.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package wrapper_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/micro/go-micro/v2/broker"
|
||||
bmemory "github.com/micro/go-micro/v2/broker/memory"
|
||||
"github.com/micro/go-micro/v2/client"
|
||||
rmemory "github.com/micro/go-micro/v2/registry/memory"
|
||||
"github.com/micro/go-micro/v2/server"
|
||||
tmemory "github.com/micro/go-micro/v2/transport/memory"
|
||||
wrapper "github.com/micro/go-micro/v2/util/wrapper"
|
||||
)
|
||||
|
||||
type TestFoo struct {
|
||||
}
|
||||
|
||||
type TestReq struct{}
|
||||
|
||||
type TestRsp struct {
|
||||
Data string
|
||||
}
|
||||
|
||||
func (h *TestFoo) Bar(ctx context.Context, req *TestReq, rsp *TestRsp) error {
|
||||
rsp.Data = "pass"
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestStaticClientWrapper(t *testing.T) {
|
||||
var err error
|
||||
|
||||
req := client.NewRequest("go.micro.service.foo", "TestFoo.Bar", &TestReq{}, client.WithContentType("application/json"))
|
||||
rsp := &TestRsp{}
|
||||
|
||||
reg := rmemory.NewRegistry()
|
||||
brk := bmemory.NewBroker(broker.Registry(reg))
|
||||
tr := tmemory.NewTransport()
|
||||
|
||||
srv := server.NewServer(
|
||||
server.Broker(brk),
|
||||
server.Registry(reg),
|
||||
server.Name("go.micro.service.foo"),
|
||||
server.Address("127.0.0.1:0"),
|
||||
server.Transport(tr),
|
||||
)
|
||||
if err = srv.Handle(srv.NewHandler(&TestFoo{})); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err = srv.Start(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
cli := client.NewClient(
|
||||
client.Registry(reg),
|
||||
client.Broker(brk),
|
||||
client.Transport(tr),
|
||||
)
|
||||
|
||||
w1 := wrapper.StaticClient("xxx_localhost:12345", cli)
|
||||
if err = w1.Call(context.TODO(), req, nil); err == nil {
|
||||
t.Fatal("address xxx_#localhost:12345 must not exists and call must be failed")
|
||||
}
|
||||
|
||||
w2 := wrapper.StaticClient(srv.Options().Address, cli)
|
||||
if err = w2.Call(context.TODO(), req, rsp); err != nil {
|
||||
t.Fatal(err)
|
||||
} else if rsp.Data != "pass" {
|
||||
t.Fatalf("something wrong with response: %#+v", rsp)
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user