add web ui
3
.dockerignore
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Dockerfile
|
||||
**/node_modules
|
||||
webui-build
|
||||
4
.gitignore
vendored
|
|
@ -1,3 +1,3 @@
|
|||
/circuitbreaker
|
||||
/circuitbreaker.db
|
||||
/webui/node_modules
|
||||
|
||||
**/node_modules
|
||||
34
Dockerfile
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
### Build frontend
|
||||
FROM node:15.4 as build_frontend
|
||||
|
||||
WORKDIR /react-app
|
||||
|
||||
COPY webui/package*.json .
|
||||
|
||||
RUN npm install
|
||||
|
||||
COPY webui .
|
||||
|
||||
RUN npm run build
|
||||
|
||||
### Build backend
|
||||
FROM golang:1.18-alpine AS build_backend
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
COPY *.go go.mod go.sum ./
|
||||
COPY circuitbreakerrpc circuitbreakerrpc/
|
||||
COPY --from=build_frontend /webui-build/ webui-build/
|
||||
|
||||
RUN go install .
|
||||
|
||||
### Build an Alpine image
|
||||
FROM alpine:3.16 as alpine
|
||||
|
||||
# Update CA certs
|
||||
RUN apk add --no-cache ca-certificates && rm -rf /var/cache/apk/*
|
||||
|
||||
# Copy over app binary
|
||||
COPY --from=build_backend /go/bin/circuitbreaker /usr/bin/circuitbreaker
|
||||
|
||||
ENTRYPOINT [ "circuitbreaker" ]
|
||||
36
README.md
|
|
@ -12,12 +12,14 @@ Furthermore it is possible to apply rate limits to the number of forwarded
|
|||
htlcs. This offers protection against DoS/spam attacks that rely on large
|
||||
numbers of fast-resolving htlcs. Rate limiting is implemented with a [Token
|
||||
bucket](https://en.wikipedia.org/wiki/Token_bucket). In configuration the
|
||||
minimum interval between htlcs and a burst size can be specified.
|
||||
minimum interval between htlcs can be specified.
|
||||
|
||||
Large numbers of htlcs are also required for probing channel balances. Reducing the
|
||||
information leakage through probing could be another reason to put in place a
|
||||
rate limit for untrusted peers.
|
||||
|
||||

|
||||
|
||||
## Why are limits needed?
|
||||
|
||||
In today's Lighting Network payments are routed via a series of hops. Each of
|
||||
|
|
@ -41,23 +43,38 @@ This is where `circuitbreaker` comes in. It puts up a defense around that
|
|||
valuable channel liquidity and helps to keep the locked coins at work to
|
||||
maximize routing revenue.
|
||||
|
||||
## Insights
|
||||
|
||||
In addition to firewall functionality, `circuitbreaker` also provides counters
|
||||
for the number of htlcs that settled, failed and were rejected in the last hour
|
||||
and day on a peer-by-peer basis.
|
||||
|
||||
## How to use
|
||||
|
||||
### Requirements
|
||||
* `go` 1.13
|
||||
* `lnd` version 0.11.0-beta or above.
|
||||
* `go` 1.18
|
||||
* `lnd` version 0.15.4-beta or above.
|
||||
|
||||
### Configuration
|
||||
`circuitbreaker` by default reads its configuration from `~/.circuitbreaker/circuitbreaker.yaml`.
|
||||
An example configuration can be found [here](circuitbreaker-example.yaml)
|
||||
`circuitbreaker` can be configured through a web ui. The configuration is stored
|
||||
in a sqlite database located at `~/.circuitbreaker/circuitbreaker.db` (on
|
||||
linux).
|
||||
|
||||
### Run
|
||||
### Run locally
|
||||
|
||||
* Clone this repository
|
||||
* `cd circuitbreaker/`
|
||||
* `go install`
|
||||
* Execute `circuitbreaker` with the correct command line flags to connect to
|
||||
`lnd`. See `circuitbreaker --help` for details.
|
||||
* Open http://127.0.0.1:9235 in a browser.
|
||||
|
||||
### Run using Docker
|
||||
|
||||
* Start docker container:
|
||||
|
||||
`docker run -v <lnd_tls_cert_path>:/root/.lnd/tls.cert -v <lnd_macaroon_path>:/root/.lnd/data/chain/bitcoin/mainnet/admin.macaroon -p 9235:9235 ghcr.io/lightningequipment/circuitbreaker:latest --rpcserver host.docker.internal:10009 --httplisten 0.0.0.0:9235`
|
||||
* Open http://127.0.0.1:9235 in a browser.
|
||||
|
||||
## Operating modes
|
||||
|
||||
|
|
@ -90,6 +107,13 @@ configured globally and per peer in the configuration file.
|
|||
|
||||
WARNING: See `queue` mode warning.
|
||||
|
||||
## Stub/demo
|
||||
|
||||
For a quick try out or demo, it is possible to run circuitbreaker in stub mode.
|
||||
In this mode, fake traffic is generated and no lnd instance is required.
|
||||
|
||||
`docker run -p 9235:9235 ghcr.io/lightningequipment/circuitbreaker:latest --httplisten 0.0.0.0:9235 --stub`
|
||||
|
||||
## Limitations
|
||||
* This software is alpha quality. Use at your own risk and be careful in particular on mainnet.
|
||||
* The interfaces on `lnd` aren't optimized for this purpose. Therefore the use
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
# Default max pendings htlcs. Limit the number of pending htlcs to five by
|
||||
# default. Set to zero for no limit.
|
||||
maxPendingHtlcs: 5
|
||||
|
||||
# Default minimum interval between htlcs that is enforced per peer. If htlcs
|
||||
# come in faster than that, they are cancelled back. Leave unset for no limit.
|
||||
htlcMinInterval: 1s
|
||||
|
||||
# Default htlc burst size per peer. This many htlcs are allowed through in a
|
||||
# burst, but longer delays will be enforced afterwards to keep true to the
|
||||
# minimum interval defined above. If not set, a burst size of 1 will be used.
|
||||
# For more info, see the Token Bucket Algorithm
|
||||
# https://en.wikipedia.org/wiki/Token_bucket.
|
||||
htlcBurstSize: 10
|
||||
|
||||
# Default mode setting for peers. If set to 'queue', htlcs that exceed limits
|
||||
# are queued and forwarded later. If set to `queue_peer_initiated`, only htlcs
|
||||
# on channels that we didn't initiate are queued. On other channels, htlcs are
|
||||
# failed. If set to 'fail', all htlcs exceeding limits are failed back
|
||||
# instantly. If not set, mode defaults to 'fail'.
|
||||
mode: queue_peer_initiated
|
||||
|
||||
# Define exception groups. Note that the configuration of the exception group
|
||||
# does not inherit from the defaults above. So for example not setting a rate
|
||||
# limit really means no rate limit, even if there is a default configured.
|
||||
groups:
|
||||
# For two peers, the pending and rate limits are
|
||||
# lowered.
|
||||
- maxPendingHtlcs: 2
|
||||
htlcMinInterval: 5s
|
||||
htlcBurstSize: 3
|
||||
peers:
|
||||
- 03901a1fcfbf621245d859fe4b8bfd93c9e8191a93612db3db0efd11af64e226a2
|
||||
- 03670eff2ccfd3a469536d8e3d38825313d266fa3c2d22b1f841beca30414586d0
|
||||
|
||||
# A last peer is allowed to have more pending htlcs and no rate limit.
|
||||
- maxPendingHtlcs: 25
|
||||
peers:
|
||||
- 035cb74e3232e98ba6a866c485f1076dca5e42147dc1e3fbf9ea7241d359988e4d
|
||||
9
circuitbreakerrpc/Dockerfile
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
FROM golang:1.16
|
||||
|
||||
RUN apt-get update && \
|
||||
apt-get install -y wget make unzip && \
|
||||
ls
|
||||
|
||||
COPY Makefile .
|
||||
|
||||
RUN make protoc-buf protoc-tools protoc-go-tools
|
||||
32
circuitbreakerrpc/Makefile
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
protoc_os = linux
|
||||
ifeq ($(shell uname -s),Darwin)
|
||||
protoc_os = osx
|
||||
endif
|
||||
|
||||
protoc_arch = $(shell uname -m)
|
||||
ifeq (protoc_arch,aarch64)
|
||||
protoc_arch = aarch_64
|
||||
else
|
||||
protoc_arch = x86_64
|
||||
endif
|
||||
|
||||
protoc-go-docker:
|
||||
docker build . -t circuitbreaker-protobuf-builder
|
||||
docker run --rm -it -v "$(shell pwd):/app" circuitbreaker-protobuf-builder sh -c 'cd /app && make buf-gen'
|
||||
|
||||
protoc-tools:
|
||||
wget https://github.com/protocolbuffers/protobuf/releases/download/v3.18.0/protoc-3.18.0-${protoc_os}-${protoc_arch}.zip -O /tmp/protoc.zip
|
||||
unzip -d /usr/local /tmp/protoc.zip
|
||||
|
||||
protoc-buf:
|
||||
curl -sSL "https://github.com/bufbuild/buf/releases/download/v1.11.0/buf-$(shell uname -s)-$(shell uname -m).tar.gz" | tar -xvzf - -C /usr/local --strip-components 1
|
||||
|
||||
protoc-go-tools:
|
||||
go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.27.1
|
||||
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.1
|
||||
go install github.com/envoyproxy/protoc-gen-validate@v0.6.1
|
||||
go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.5.0
|
||||
|
||||
buf-gen:
|
||||
buf mod update
|
||||
buf generate
|
||||
15
circuitbreakerrpc/buf.gen.yaml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
version: v1
|
||||
plugins:
|
||||
- name: go
|
||||
out: .
|
||||
opt: paths=source_relative
|
||||
strategy: directory
|
||||
- name: go-grpc
|
||||
out: .
|
||||
opt: paths=source_relative
|
||||
- name: grpc-gateway
|
||||
out: .
|
||||
opt: logtostderr=true,paths=source_relative
|
||||
- name: validate
|
||||
out: .
|
||||
opt: lang=go,paths=source_relative
|
||||
7
circuitbreakerrpc/buf.lock
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# Generated by buf. DO NOT EDIT.
|
||||
version: v1
|
||||
deps:
|
||||
- remote: buf.build
|
||||
owner: googleapis
|
||||
repository: googleapis
|
||||
commit: 75b4300737fb4efca0831636be94e517
|
||||
3
circuitbreakerrpc/buf.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
version: v1
|
||||
deps:
|
||||
- buf.build/googleapis/googleapis
|
||||
1092
circuitbreakerrpc/circuitbreaker.pb.go
Normal file
511
circuitbreakerrpc/circuitbreaker.pb.gw.go
Normal file
|
|
@ -0,0 +1,511 @@
|
|||
// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT.
|
||||
// source: circuitbreaker.proto
|
||||
|
||||
/*
|
||||
Package circuitbreakerrpc is a reverse proxy.
|
||||
|
||||
It translates gRPC into RESTful JSON APIs.
|
||||
*/
|
||||
package circuitbreakerrpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
// Suppress "imported and not used" errors
|
||||
var _ codes.Code
|
||||
var _ io.Reader
|
||||
var _ status.Status
|
||||
var _ = runtime.String
|
||||
var _ = utilities.NewDoubleArray
|
||||
var _ = metadata.Join
|
||||
|
||||
func request_Service_GetInfo_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetInfoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := client.GetInfo(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_GetInfo_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq GetInfoRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.GetInfo(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_Service_UpdateLimit_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq UpdateLimitRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["node"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "node")
|
||||
}
|
||||
|
||||
protoReq.Node, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node", err)
|
||||
}
|
||||
|
||||
msg, err := client.UpdateLimit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_UpdateLimit_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq UpdateLimitRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["node"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "node")
|
||||
}
|
||||
|
||||
protoReq.Node, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node", err)
|
||||
}
|
||||
|
||||
msg, err := server.UpdateLimit(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_Service_ClearLimit_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ClearLimitRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["node"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "node")
|
||||
}
|
||||
|
||||
protoReq.Node, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node", err)
|
||||
}
|
||||
|
||||
msg, err := client.ClearLimit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_ClearLimit_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ClearLimitRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
var (
|
||||
val string
|
||||
ok bool
|
||||
err error
|
||||
_ = err
|
||||
)
|
||||
|
||||
val, ok = pathParams["node"]
|
||||
if !ok {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "node")
|
||||
}
|
||||
|
||||
protoReq.Node, err = runtime.String(val)
|
||||
if err != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "node", err)
|
||||
}
|
||||
|
||||
msg, err := server.ClearLimit(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_Service_UpdateDefaultLimit_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq UpdateDefaultLimitRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.UpdateDefaultLimit(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_UpdateDefaultLimit_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq UpdateDefaultLimitRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := server.UpdateDefaultLimit(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func request_Service_ListLimits_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ListLimitsRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := client.ListLimits(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func local_request_Service_ListLimits_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq ListLimitsRequest
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
msg, err := server.ListLimits(ctx, &protoReq)
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
// RegisterServiceHandlerServer registers the http handlers for service Service to "mux".
|
||||
// UnaryRPC :call ServiceServer directly.
|
||||
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
|
||||
// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterServiceHandlerFromEndpoint instead.
|
||||
func RegisterServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server ServiceServer) error {
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/circuitbreaker.Service/GetInfo", runtime.WithHTTPPathPattern("/info"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Service_GetInfo_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_GetInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Service_UpdateLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/circuitbreaker.Service/UpdateLimit", runtime.WithHTTPPathPattern("/updatelimit/{node}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Service_UpdateLimit_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_UpdateLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Service_ClearLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/circuitbreaker.Service/ClearLimit", runtime.WithHTTPPathPattern("/clearlimit/{node}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Service_ClearLimit_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_ClearLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Service_UpdateDefaultLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/circuitbreaker.Service/UpdateDefaultLimit", runtime.WithHTTPPathPattern("/updatedefaultlimit"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Service_UpdateDefaultLimit_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_UpdateDefaultLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Service_ListLimits_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
var stream runtime.ServerTransportStream
|
||||
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/circuitbreaker.Service/ListLimits", runtime.WithHTTPPathPattern("/limits"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := local_request_Service_ListLimits_0(rctx, inboundMarshaler, server, req, pathParams)
|
||||
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_ListLimits_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RegisterServiceHandlerFromEndpoint is same as RegisterServiceHandler but
|
||||
// automatically dials to "endpoint" and closes the connection when "ctx" gets done.
|
||||
func RegisterServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
conn, err := grpc.Dial(endpoint, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
|
||||
return RegisterServiceHandler(ctx, mux, conn)
|
||||
}
|
||||
|
||||
// RegisterServiceHandler registers the http handlers for service Service to "mux".
|
||||
// The handlers forward requests to the grpc endpoint over "conn".
|
||||
func RegisterServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||
return RegisterServiceHandlerClient(ctx, mux, NewServiceClient(conn))
|
||||
}
|
||||
|
||||
// RegisterServiceHandlerClient registers the http handlers for service Service
|
||||
// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "ServiceClient".
|
||||
// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "ServiceClient"
|
||||
// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in
|
||||
// "ServiceClient" to call the correct interceptors.
|
||||
func RegisterServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client ServiceClient) error {
|
||||
|
||||
mux.Handle("GET", pattern_Service_GetInfo_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/circuitbreaker.Service/GetInfo", runtime.WithHTTPPathPattern("/info"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Service_GetInfo_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_GetInfo_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Service_UpdateLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/circuitbreaker.Service/UpdateLimit", runtime.WithHTTPPathPattern("/updatelimit/{node}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Service_UpdateLimit_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_UpdateLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Service_ClearLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/circuitbreaker.Service/ClearLimit", runtime.WithHTTPPathPattern("/clearlimit/{node}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Service_ClearLimit_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_ClearLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("POST", pattern_Service_UpdateDefaultLimit_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/circuitbreaker.Service/UpdateDefaultLimit", runtime.WithHTTPPathPattern("/updatedefaultlimit"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Service_UpdateDefaultLimit_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_UpdateDefaultLimit_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
mux.Handle("GET", pattern_Service_ListLimits_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
rctx, err := runtime.AnnotateContext(ctx, mux, req, "/circuitbreaker.Service/ListLimits", runtime.WithHTTPPathPattern("/limits"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_Service_ListLimits_0(rctx, inboundMarshaler, client, req, pathParams)
|
||||
ctx = runtime.NewServerMetadataContext(ctx, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_Service_ListLimits_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
pattern_Service_GetInfo_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"info"}, ""))
|
||||
|
||||
pattern_Service_UpdateLimit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"updatelimit", "node"}, ""))
|
||||
|
||||
pattern_Service_ClearLimit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 1, 0, 4, 1, 5, 1}, []string{"clearlimit", "node"}, ""))
|
||||
|
||||
pattern_Service_UpdateDefaultLimit_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"updatedefaultlimit"}, ""))
|
||||
|
||||
pattern_Service_ListLimits_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"limits"}, ""))
|
||||
)
|
||||
|
||||
var (
|
||||
forward_Service_GetInfo_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Service_UpdateLimit_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Service_ClearLimit_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Service_UpdateDefaultLimit_0 = runtime.ForwardResponseMessage
|
||||
|
||||
forward_Service_ListLimits_0 = runtime.ForwardResponseMessage
|
||||
)
|
||||
993
circuitbreakerrpc/circuitbreaker.pb.validate.go
Normal file
|
|
@ -0,0 +1,993 @@
|
|||
// Code generated by protoc-gen-validate. DO NOT EDIT.
|
||||
// source: circuitbreaker.proto
|
||||
|
||||
package circuitbreakerrpc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/mail"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
|
||||
"google.golang.org/protobuf/types/known/anypb"
|
||||
)
|
||||
|
||||
// ensure the imports are used
|
||||
var (
|
||||
_ = bytes.MinRead
|
||||
_ = errors.New("")
|
||||
_ = fmt.Print
|
||||
_ = utf8.UTFMax
|
||||
_ = (*regexp.Regexp)(nil)
|
||||
_ = (*strings.Reader)(nil)
|
||||
_ = net.IPv4len
|
||||
_ = time.Duration(0)
|
||||
_ = (*url.URL)(nil)
|
||||
_ = (*mail.Address)(nil)
|
||||
_ = anypb.Any{}
|
||||
)
|
||||
|
||||
// Validate checks the field values on GetInfoRequest with the rules defined in
|
||||
// the proto definition for this message. If any rules are violated, an error
|
||||
// is returned.
|
||||
func (m *GetInfoRequest) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetInfoRequestValidationError is the validation error returned by
|
||||
// GetInfoRequest.Validate if the designated constraints aren't met.
|
||||
type GetInfoRequestValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e GetInfoRequestValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e GetInfoRequestValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e GetInfoRequestValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e GetInfoRequestValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e GetInfoRequestValidationError) ErrorName() string { return "GetInfoRequestValidationError" }
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e GetInfoRequestValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sGetInfoRequest.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = GetInfoRequestValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = GetInfoRequestValidationError{}
|
||||
|
||||
// Validate checks the field values on GetInfoResponse with the rules defined
|
||||
// in the proto definition for this message. If any rules are violated, an
|
||||
// error is returned.
|
||||
func (m *GetInfoResponse) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// no validation rules for ConnectedNode
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetInfoResponseValidationError is the validation error returned by
|
||||
// GetInfoResponse.Validate if the designated constraints aren't met.
|
||||
type GetInfoResponseValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e GetInfoResponseValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e GetInfoResponseValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e GetInfoResponseValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e GetInfoResponseValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e GetInfoResponseValidationError) ErrorName() string { return "GetInfoResponseValidationError" }
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e GetInfoResponseValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sGetInfoResponse.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = GetInfoResponseValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = GetInfoResponseValidationError{}
|
||||
|
||||
// Validate checks the field values on ClearLimitRequest with the rules defined
|
||||
// in the proto definition for this message. If any rules are violated, an
|
||||
// error is returned.
|
||||
func (m *ClearLimitRequest) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// no validation rules for Node
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearLimitRequestValidationError is the validation error returned by
|
||||
// ClearLimitRequest.Validate if the designated constraints aren't met.
|
||||
type ClearLimitRequestValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e ClearLimitRequestValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e ClearLimitRequestValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e ClearLimitRequestValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e ClearLimitRequestValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e ClearLimitRequestValidationError) ErrorName() string {
|
||||
return "ClearLimitRequestValidationError"
|
||||
}
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e ClearLimitRequestValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sClearLimitRequest.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = ClearLimitRequestValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = ClearLimitRequestValidationError{}
|
||||
|
||||
// Validate checks the field values on ClearLimitResponse with the rules
|
||||
// defined in the proto definition for this message. If any rules are
|
||||
// violated, an error is returned.
|
||||
func (m *ClearLimitResponse) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClearLimitResponseValidationError is the validation error returned by
|
||||
// ClearLimitResponse.Validate if the designated constraints aren't met.
|
||||
type ClearLimitResponseValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e ClearLimitResponseValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e ClearLimitResponseValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e ClearLimitResponseValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e ClearLimitResponseValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e ClearLimitResponseValidationError) ErrorName() string {
|
||||
return "ClearLimitResponseValidationError"
|
||||
}
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e ClearLimitResponseValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sClearLimitResponse.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = ClearLimitResponseValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = ClearLimitResponseValidationError{}
|
||||
|
||||
// Validate checks the field values on UpdateLimitRequest with the rules
|
||||
// defined in the proto definition for this message. If any rules are
|
||||
// violated, an error is returned.
|
||||
func (m *UpdateLimitRequest) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// no validation rules for Node
|
||||
|
||||
if v, ok := interface{}(m.GetLimit()).(interface{ Validate() error }); ok {
|
||||
if err := v.Validate(); err != nil {
|
||||
return UpdateLimitRequestValidationError{
|
||||
field: "Limit",
|
||||
reason: "embedded message failed validation",
|
||||
cause: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateLimitRequestValidationError is the validation error returned by
|
||||
// UpdateLimitRequest.Validate if the designated constraints aren't met.
|
||||
type UpdateLimitRequestValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e UpdateLimitRequestValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e UpdateLimitRequestValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e UpdateLimitRequestValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e UpdateLimitRequestValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e UpdateLimitRequestValidationError) ErrorName() string {
|
||||
return "UpdateLimitRequestValidationError"
|
||||
}
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e UpdateLimitRequestValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sUpdateLimitRequest.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = UpdateLimitRequestValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = UpdateLimitRequestValidationError{}
|
||||
|
||||
// Validate checks the field values on UpdateLimitResponse with the rules
|
||||
// defined in the proto definition for this message. If any rules are
|
||||
// violated, an error is returned.
|
||||
func (m *UpdateLimitResponse) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateLimitResponseValidationError is the validation error returned by
|
||||
// UpdateLimitResponse.Validate if the designated constraints aren't met.
|
||||
type UpdateLimitResponseValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e UpdateLimitResponseValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e UpdateLimitResponseValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e UpdateLimitResponseValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e UpdateLimitResponseValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e UpdateLimitResponseValidationError) ErrorName() string {
|
||||
return "UpdateLimitResponseValidationError"
|
||||
}
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e UpdateLimitResponseValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sUpdateLimitResponse.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = UpdateLimitResponseValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = UpdateLimitResponseValidationError{}
|
||||
|
||||
// Validate checks the field values on UpdateDefaultLimitRequest with the rules
|
||||
// defined in the proto definition for this message. If any rules are
|
||||
// violated, an error is returned.
|
||||
func (m *UpdateDefaultLimitRequest) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if v, ok := interface{}(m.GetLimit()).(interface{ Validate() error }); ok {
|
||||
if err := v.Validate(); err != nil {
|
||||
return UpdateDefaultLimitRequestValidationError{
|
||||
field: "Limit",
|
||||
reason: "embedded message failed validation",
|
||||
cause: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateDefaultLimitRequestValidationError is the validation error returned by
|
||||
// UpdateDefaultLimitRequest.Validate if the designated constraints aren't met.
|
||||
type UpdateDefaultLimitRequestValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e UpdateDefaultLimitRequestValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e UpdateDefaultLimitRequestValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e UpdateDefaultLimitRequestValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e UpdateDefaultLimitRequestValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e UpdateDefaultLimitRequestValidationError) ErrorName() string {
|
||||
return "UpdateDefaultLimitRequestValidationError"
|
||||
}
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e UpdateDefaultLimitRequestValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sUpdateDefaultLimitRequest.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = UpdateDefaultLimitRequestValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = UpdateDefaultLimitRequestValidationError{}
|
||||
|
||||
// Validate checks the field values on UpdateDefaultLimitResponse with the
|
||||
// rules defined in the proto definition for this message. If any rules are
|
||||
// violated, an error is returned.
|
||||
func (m *UpdateDefaultLimitResponse) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateDefaultLimitResponseValidationError is the validation error returned
|
||||
// by UpdateDefaultLimitResponse.Validate if the designated constraints aren't met.
|
||||
type UpdateDefaultLimitResponseValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e UpdateDefaultLimitResponseValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e UpdateDefaultLimitResponseValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e UpdateDefaultLimitResponseValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e UpdateDefaultLimitResponseValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e UpdateDefaultLimitResponseValidationError) ErrorName() string {
|
||||
return "UpdateDefaultLimitResponseValidationError"
|
||||
}
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e UpdateDefaultLimitResponseValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sUpdateDefaultLimitResponse.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = UpdateDefaultLimitResponseValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = UpdateDefaultLimitResponseValidationError{}
|
||||
|
||||
// Validate checks the field values on ListLimitsRequest with the rules defined
|
||||
// in the proto definition for this message. If any rules are violated, an
|
||||
// error is returned.
|
||||
func (m *ListLimitsRequest) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListLimitsRequestValidationError is the validation error returned by
|
||||
// ListLimitsRequest.Validate if the designated constraints aren't met.
|
||||
type ListLimitsRequestValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e ListLimitsRequestValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e ListLimitsRequestValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e ListLimitsRequestValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e ListLimitsRequestValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e ListLimitsRequestValidationError) ErrorName() string {
|
||||
return "ListLimitsRequestValidationError"
|
||||
}
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e ListLimitsRequestValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sListLimitsRequest.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = ListLimitsRequestValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = ListLimitsRequestValidationError{}
|
||||
|
||||
// Validate checks the field values on ListLimitsResponse with the rules
|
||||
// defined in the proto definition for this message. If any rules are
|
||||
// violated, an error is returned.
|
||||
func (m *ListLimitsResponse) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for idx, item := range m.GetLimits() {
|
||||
_, _ = idx, item
|
||||
|
||||
if v, ok := interface{}(item).(interface{ Validate() error }); ok {
|
||||
if err := v.Validate(); err != nil {
|
||||
return ListLimitsResponseValidationError{
|
||||
field: fmt.Sprintf("Limits[%v]", idx),
|
||||
reason: "embedded message failed validation",
|
||||
cause: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if v, ok := interface{}(m.GetDefaultLimit()).(interface{ Validate() error }); ok {
|
||||
if err := v.Validate(); err != nil {
|
||||
return ListLimitsResponseValidationError{
|
||||
field: "DefaultLimit",
|
||||
reason: "embedded message failed validation",
|
||||
cause: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListLimitsResponseValidationError is the validation error returned by
|
||||
// ListLimitsResponse.Validate if the designated constraints aren't met.
|
||||
type ListLimitsResponseValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e ListLimitsResponseValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e ListLimitsResponseValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e ListLimitsResponseValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e ListLimitsResponseValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e ListLimitsResponseValidationError) ErrorName() string {
|
||||
return "ListLimitsResponseValidationError"
|
||||
}
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e ListLimitsResponseValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sListLimitsResponse.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = ListLimitsResponseValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = ListLimitsResponseValidationError{}
|
||||
|
||||
// Validate checks the field values on NodeLimit with the rules defined in the
|
||||
// proto definition for this message. If any rules are violated, an error is returned.
|
||||
func (m *NodeLimit) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// no validation rules for Node
|
||||
|
||||
// no validation rules for Alias
|
||||
|
||||
if v, ok := interface{}(m.GetLimit()).(interface{ Validate() error }); ok {
|
||||
if err := v.Validate(); err != nil {
|
||||
return NodeLimitValidationError{
|
||||
field: "Limit",
|
||||
reason: "embedded message failed validation",
|
||||
cause: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := interface{}(m.GetCounter_1H()).(interface{ Validate() error }); ok {
|
||||
if err := v.Validate(); err != nil {
|
||||
return NodeLimitValidationError{
|
||||
field: "Counter_1H",
|
||||
reason: "embedded message failed validation",
|
||||
cause: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := interface{}(m.GetCounter_24H()).(interface{ Validate() error }); ok {
|
||||
if err := v.Validate(); err != nil {
|
||||
return NodeLimitValidationError{
|
||||
field: "Counter_24H",
|
||||
reason: "embedded message failed validation",
|
||||
cause: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no validation rules for QueueLen
|
||||
|
||||
// no validation rules for PendingHtlcCount
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NodeLimitValidationError is the validation error returned by
|
||||
// NodeLimit.Validate if the designated constraints aren't met.
|
||||
type NodeLimitValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e NodeLimitValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e NodeLimitValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e NodeLimitValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e NodeLimitValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e NodeLimitValidationError) ErrorName() string { return "NodeLimitValidationError" }
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e NodeLimitValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sNodeLimit.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = NodeLimitValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = NodeLimitValidationError{}
|
||||
|
||||
// Validate checks the field values on Limit with the rules defined in the
|
||||
// proto definition for this message. If any rules are violated, an error is returned.
|
||||
func (m *Limit) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// no validation rules for MaxHourlyRate
|
||||
|
||||
// no validation rules for MaxPending
|
||||
|
||||
// no validation rules for Mode
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LimitValidationError is the validation error returned by Limit.Validate if
|
||||
// the designated constraints aren't met.
|
||||
type LimitValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e LimitValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e LimitValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e LimitValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e LimitValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e LimitValidationError) ErrorName() string { return "LimitValidationError" }
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e LimitValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sLimit.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = LimitValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = LimitValidationError{}
|
||||
|
||||
// Validate checks the field values on Counter with the rules defined in the
|
||||
// proto definition for this message. If any rules are violated, an error is returned.
|
||||
func (m *Counter) Validate() error {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// no validation rules for Fail
|
||||
|
||||
// no validation rules for Success
|
||||
|
||||
// no validation rules for Reject
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CounterValidationError is the validation error returned by Counter.Validate
|
||||
// if the designated constraints aren't met.
|
||||
type CounterValidationError struct {
|
||||
field string
|
||||
reason string
|
||||
cause error
|
||||
key bool
|
||||
}
|
||||
|
||||
// Field function returns field value.
|
||||
func (e CounterValidationError) Field() string { return e.field }
|
||||
|
||||
// Reason function returns reason value.
|
||||
func (e CounterValidationError) Reason() string { return e.reason }
|
||||
|
||||
// Cause function returns cause value.
|
||||
func (e CounterValidationError) Cause() error { return e.cause }
|
||||
|
||||
// Key function returns key value.
|
||||
func (e CounterValidationError) Key() bool { return e.key }
|
||||
|
||||
// ErrorName returns error name.
|
||||
func (e CounterValidationError) ErrorName() string { return "CounterValidationError" }
|
||||
|
||||
// Error satisfies the builtin error interface
|
||||
func (e CounterValidationError) Error() string {
|
||||
cause := ""
|
||||
if e.cause != nil {
|
||||
cause = fmt.Sprintf(" | caused by: %v", e.cause)
|
||||
}
|
||||
|
||||
key := ""
|
||||
if e.key {
|
||||
key = "key for "
|
||||
}
|
||||
|
||||
return fmt.Sprintf(
|
||||
"invalid %sCounter.%s: %s%s",
|
||||
key,
|
||||
e.field,
|
||||
e.reason,
|
||||
cause)
|
||||
}
|
||||
|
||||
var _ error = CounterValidationError{}
|
||||
|
||||
var _ interface {
|
||||
Field() string
|
||||
Reason() string
|
||||
Key() bool
|
||||
Cause() error
|
||||
ErrorName() string
|
||||
} = CounterValidationError{}
|
||||
108
circuitbreakerrpc/circuitbreaker.proto
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package circuitbreaker;
|
||||
|
||||
import "google/api/annotations.proto";
|
||||
|
||||
option go_package = "github.com/lightningequipment/circuitbreaker/circuitbreakerrpc";
|
||||
|
||||
service Service {
|
||||
rpc GetInfo (GetInfoRequest) returns (GetInfoResponse) {
|
||||
option (google.api.http) = {
|
||||
get:"/info"
|
||||
};
|
||||
}
|
||||
|
||||
rpc UpdateLimit (UpdateLimitRequest) returns (UpdateLimitResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/updatelimit/{node}"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
// Clear specific limit and use default.
|
||||
rpc ClearLimit (ClearLimitRequest) returns (ClearLimitResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/clearlimit/{node}"
|
||||
};
|
||||
}
|
||||
|
||||
rpc UpdateDefaultLimit (UpdateDefaultLimitRequest) returns (UpdateDefaultLimitResponse) {
|
||||
option (google.api.http) = {
|
||||
post: "/updatedefaultlimit"
|
||||
body: "*"
|
||||
};
|
||||
}
|
||||
|
||||
rpc ListLimits (ListLimitsRequest) returns (ListLimitsResponse) {
|
||||
option (google.api.http) = {
|
||||
get:"/limits"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
message GetInfoRequest {}
|
||||
|
||||
message GetInfoResponse {
|
||||
string connected_node = 1;
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
MODE_FAIL = 0;
|
||||
MODE_QUEUE = 1;
|
||||
MODE_QUEUE_PEER_INITIATED = 2;
|
||||
}
|
||||
|
||||
|
||||
message ClearLimitRequest {
|
||||
string node = 1;
|
||||
}
|
||||
|
||||
message ClearLimitResponse {}
|
||||
|
||||
message UpdateLimitRequest {
|
||||
string node = 1;
|
||||
Limit limit = 2;
|
||||
}
|
||||
|
||||
message UpdateLimitResponse {}
|
||||
|
||||
|
||||
message UpdateDefaultLimitRequest {
|
||||
Limit limit = 1;
|
||||
}
|
||||
|
||||
message UpdateDefaultLimitResponse {}
|
||||
|
||||
message ListLimitsRequest {}
|
||||
|
||||
message ListLimitsResponse {
|
||||
repeated NodeLimit limits = 5;
|
||||
|
||||
Limit default_limit = 2;
|
||||
}
|
||||
|
||||
message NodeLimit {
|
||||
string node = 1;
|
||||
string alias = 5;
|
||||
|
||||
// The default limit applies if limit is not set.
|
||||
Limit limit = 2;
|
||||
|
||||
Counter counter_1h = 3;
|
||||
Counter counter_24h = 4;
|
||||
int64 queue_len = 6;
|
||||
int64 pending_htlc_count = 7;
|
||||
}
|
||||
|
||||
message Limit {
|
||||
int64 max_hourly_rate = 3;
|
||||
int64 max_pending = 5;
|
||||
Mode mode = 6;
|
||||
}
|
||||
|
||||
message Counter {
|
||||
int64 fail = 1;
|
||||
int64 success = 2;
|
||||
int64 reject = 3;
|
||||
}
|
||||
247
circuitbreakerrpc/circuitbreaker_grpc.pb.go
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
|
||||
package circuitbreakerrpc
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
// ServiceClient is the client API for Service service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type ServiceClient interface {
|
||||
GetInfo(ctx context.Context, in *GetInfoRequest, opts ...grpc.CallOption) (*GetInfoResponse, error)
|
||||
UpdateLimit(ctx context.Context, in *UpdateLimitRequest, opts ...grpc.CallOption) (*UpdateLimitResponse, error)
|
||||
// Clear specific limit and use default.
|
||||
ClearLimit(ctx context.Context, in *ClearLimitRequest, opts ...grpc.CallOption) (*ClearLimitResponse, error)
|
||||
UpdateDefaultLimit(ctx context.Context, in *UpdateDefaultLimitRequest, opts ...grpc.CallOption) (*UpdateDefaultLimitResponse, error)
|
||||
ListLimits(ctx context.Context, in *ListLimitsRequest, opts ...grpc.CallOption) (*ListLimitsResponse, error)
|
||||
}
|
||||
|
||||
type serviceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewServiceClient(cc grpc.ClientConnInterface) ServiceClient {
|
||||
return &serviceClient{cc}
|
||||
}
|
||||
|
||||
func (c *serviceClient) GetInfo(ctx context.Context, in *GetInfoRequest, opts ...grpc.CallOption) (*GetInfoResponse, error) {
|
||||
out := new(GetInfoResponse)
|
||||
err := c.cc.Invoke(ctx, "/circuitbreaker.Service/GetInfo", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *serviceClient) UpdateLimit(ctx context.Context, in *UpdateLimitRequest, opts ...grpc.CallOption) (*UpdateLimitResponse, error) {
|
||||
out := new(UpdateLimitResponse)
|
||||
err := c.cc.Invoke(ctx, "/circuitbreaker.Service/UpdateLimit", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *serviceClient) ClearLimit(ctx context.Context, in *ClearLimitRequest, opts ...grpc.CallOption) (*ClearLimitResponse, error) {
|
||||
out := new(ClearLimitResponse)
|
||||
err := c.cc.Invoke(ctx, "/circuitbreaker.Service/ClearLimit", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *serviceClient) UpdateDefaultLimit(ctx context.Context, in *UpdateDefaultLimitRequest, opts ...grpc.CallOption) (*UpdateDefaultLimitResponse, error) {
|
||||
out := new(UpdateDefaultLimitResponse)
|
||||
err := c.cc.Invoke(ctx, "/circuitbreaker.Service/UpdateDefaultLimit", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *serviceClient) ListLimits(ctx context.Context, in *ListLimitsRequest, opts ...grpc.CallOption) (*ListLimitsResponse, error) {
|
||||
out := new(ListLimitsResponse)
|
||||
err := c.cc.Invoke(ctx, "/circuitbreaker.Service/ListLimits", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ServiceServer is the server API for Service service.
|
||||
// All implementations must embed UnimplementedServiceServer
|
||||
// for forward compatibility
|
||||
type ServiceServer interface {
|
||||
GetInfo(context.Context, *GetInfoRequest) (*GetInfoResponse, error)
|
||||
UpdateLimit(context.Context, *UpdateLimitRequest) (*UpdateLimitResponse, error)
|
||||
// Clear specific limit and use default.
|
||||
ClearLimit(context.Context, *ClearLimitRequest) (*ClearLimitResponse, error)
|
||||
UpdateDefaultLimit(context.Context, *UpdateDefaultLimitRequest) (*UpdateDefaultLimitResponse, error)
|
||||
ListLimits(context.Context, *ListLimitsRequest) (*ListLimitsResponse, error)
|
||||
mustEmbedUnimplementedServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedServiceServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedServiceServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedServiceServer) GetInfo(context.Context, *GetInfoRequest) (*GetInfoResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetInfo not implemented")
|
||||
}
|
||||
func (UnimplementedServiceServer) UpdateLimit(context.Context, *UpdateLimitRequest) (*UpdateLimitResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateLimit not implemented")
|
||||
}
|
||||
func (UnimplementedServiceServer) ClearLimit(context.Context, *ClearLimitRequest) (*ClearLimitResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ClearLimit not implemented")
|
||||
}
|
||||
func (UnimplementedServiceServer) UpdateDefaultLimit(context.Context, *UpdateDefaultLimitRequest) (*UpdateDefaultLimitResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateDefaultLimit not implemented")
|
||||
}
|
||||
func (UnimplementedServiceServer) ListLimits(context.Context, *ListLimitsRequest) (*ListLimitsResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListLimits not implemented")
|
||||
}
|
||||
func (UnimplementedServiceServer) mustEmbedUnimplementedServiceServer() {}
|
||||
|
||||
// UnsafeServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to ServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeServiceServer interface {
|
||||
mustEmbedUnimplementedServiceServer()
|
||||
}
|
||||
|
||||
func RegisterServiceServer(s grpc.ServiceRegistrar, srv ServiceServer) {
|
||||
s.RegisterService(&Service_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Service_GetInfo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetInfoRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ServiceServer).GetInfo(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/circuitbreaker.Service/GetInfo",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ServiceServer).GetInfo(ctx, req.(*GetInfoRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Service_UpdateLimit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateLimitRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ServiceServer).UpdateLimit(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/circuitbreaker.Service/UpdateLimit",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ServiceServer).UpdateLimit(ctx, req.(*UpdateLimitRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Service_ClearLimit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ClearLimitRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ServiceServer).ClearLimit(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/circuitbreaker.Service/ClearLimit",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ServiceServer).ClearLimit(ctx, req.(*ClearLimitRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Service_UpdateDefaultLimit_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateDefaultLimitRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ServiceServer).UpdateDefaultLimit(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/circuitbreaker.Service/UpdateDefaultLimit",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ServiceServer).UpdateDefaultLimit(ctx, req.(*UpdateDefaultLimitRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Service_ListLimits_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListLimitsRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ServiceServer).ListLimits(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/circuitbreaker.Service/ListLimits",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ServiceServer).ListLimits(ctx, req.(*ListLimitsRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Service_ServiceDesc is the grpc.ServiceDesc for Service service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Service_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "circuitbreaker.Service",
|
||||
HandlerType: (*ServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GetInfo",
|
||||
Handler: _Service_GetInfo_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateLimit",
|
||||
Handler: _Service_UpdateLimit_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ClearLimit",
|
||||
Handler: _Service_ClearLimit_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateDefaultLimit",
|
||||
Handler: _Service_UpdateDefaultLimit_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListLimits",
|
||||
Handler: _Service_ListLimits_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "circuitbreaker.proto",
|
||||
}
|
||||
16
circuitbreakerrpc/go.mod
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
module github.com/lightningequipment/circuitbreaker/circuitbreakerrpc
|
||||
|
||||
go 1.18
|
||||
|
||||
require (
|
||||
google.golang.org/grpc v1.47.0
|
||||
google.golang.org/protobuf v1.28.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect
|
||||
golang.org/x/text v0.3.3 // indirect
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
|
||||
)
|
||||
128
circuitbreakerrpc/go.sum
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
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/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
|
||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
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/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
153
config.go
|
|
@ -1,33 +1,5 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
type yamlGroupConfig struct {
|
||||
MaxPendingHtlcs int `yaml:"maxPendingHtlcs"`
|
||||
HtlcMinInterval time.Duration `yaml:"htlcMinInterval"`
|
||||
HtlcBurstSize int `yaml:"htlcBurstSize"`
|
||||
Mode string `yaml:"mode"`
|
||||
}
|
||||
|
||||
type yamlGroup struct {
|
||||
yamlGroupConfig `yaml:",inline"`
|
||||
|
||||
Peers []string `yaml:"peers"`
|
||||
}
|
||||
|
||||
type yamlConfig struct {
|
||||
yamlGroupConfig `yaml:",inline"`
|
||||
|
||||
Groups []yamlGroup `yaml:"groups"`
|
||||
}
|
||||
|
||||
type Mode int
|
||||
|
||||
const (
|
||||
|
|
@ -39,134 +11,15 @@ const (
|
|||
func (m Mode) String() string {
|
||||
switch m {
|
||||
case ModeFail:
|
||||
return "fail"
|
||||
return "FAIL"
|
||||
|
||||
case ModeQueue:
|
||||
return "queue"
|
||||
return "QUEUE"
|
||||
|
||||
case ModeQueuePeerInitiated:
|
||||
return "queue_peer_initiated"
|
||||
return "QUEUE_PEER_INITIATED"
|
||||
|
||||
default:
|
||||
panic("unknown mode")
|
||||
}
|
||||
}
|
||||
|
||||
type groupConfig struct {
|
||||
MaxPendingHtlcs int
|
||||
|
||||
HtlcMinInterval time.Duration
|
||||
HtlcBurstSize int
|
||||
|
||||
Mode Mode
|
||||
}
|
||||
|
||||
type config struct {
|
||||
groupConfig
|
||||
|
||||
PerPeer map[route.Vertex]groupConfig
|
||||
}
|
||||
|
||||
// forPeer returns the config for a specific peer.
|
||||
func (c *config) forPeer(peer route.Vertex) *groupConfig {
|
||||
if cfg, ok := c.PerPeer[peer]; ok {
|
||||
return &cfg
|
||||
}
|
||||
|
||||
return &c.groupConfig
|
||||
}
|
||||
|
||||
type configLoader struct {
|
||||
path string
|
||||
}
|
||||
|
||||
func newConfigLoader(path string) *configLoader {
|
||||
loader := &configLoader{
|
||||
path: path,
|
||||
}
|
||||
|
||||
return loader
|
||||
}
|
||||
|
||||
func (c *configLoader) load() (*config, error) {
|
||||
if _, err := os.Stat(c.path); os.IsNotExist(err) {
|
||||
return nil, fmt.Errorf("no config file at %v", c.path)
|
||||
}
|
||||
|
||||
yamlFile, err := os.ReadFile(c.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var yamlCfg yamlConfig
|
||||
err = yaml.UnmarshalStrict(yamlFile, &yamlCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parseGroupConfig := func(cfg *yamlGroupConfig) (groupConfig, error) {
|
||||
burstSize := cfg.HtlcBurstSize
|
||||
if burstSize == 0 {
|
||||
burstSize = 1
|
||||
}
|
||||
|
||||
var mode Mode
|
||||
switch cfg.Mode {
|
||||
case "", "fail":
|
||||
mode = ModeFail
|
||||
|
||||
case "queue":
|
||||
mode = ModeQueue
|
||||
|
||||
case "queue_peer_initiated":
|
||||
mode = ModeQueuePeerInitiated
|
||||
|
||||
default:
|
||||
return groupConfig{}, fmt.Errorf("unknown mode %v", cfg.Mode)
|
||||
}
|
||||
|
||||
return groupConfig{
|
||||
MaxPendingHtlcs: cfg.MaxPendingHtlcs,
|
||||
HtlcMinInterval: cfg.HtlcMinInterval,
|
||||
HtlcBurstSize: burstSize,
|
||||
Mode: mode,
|
||||
}, nil
|
||||
}
|
||||
|
||||
defaultCfg, err := parseGroupConfig(&yamlCfg.yamlGroupConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config := config{
|
||||
groupConfig: defaultCfg,
|
||||
PerPeer: make(map[route.Vertex]groupConfig),
|
||||
}
|
||||
|
||||
for _, group := range yamlCfg.Groups {
|
||||
for _, peer := range group.Peers {
|
||||
peerPubkey, err := route.NewVertexFromStr(peer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, exists := config.PerPeer[peerPubkey]
|
||||
if exists {
|
||||
return nil, fmt.Errorf("peer %v in multiple groups",
|
||||
peerPubkey)
|
||||
}
|
||||
|
||||
peerCfg, err := parseGroupConfig(&group.yamlGroupConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config.PerPeer[peerPubkey] = peerCfg
|
||||
}
|
||||
}
|
||||
|
||||
log.Infow("Read config file",
|
||||
"file", c.path)
|
||||
|
||||
return &config, nil
|
||||
}
|
||||
|
|
|
|||
154
db.go
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
migrate "github.com/rubenv/sql-migrate"
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
var migrations = &migrate.MemoryMigrationSource{
|
||||
Migrations: []*migrate.Migration{
|
||||
{
|
||||
Id: "1",
|
||||
Up: []string{
|
||||
`
|
||||
CREATE TABLE IF NOT EXISTS limits (
|
||||
peer TEXT PRIMARY KEY NOT NULL,
|
||||
htlc_max_pending INTEGER NOT NULL,
|
||||
htlc_max_hourly_rate INTEGER NOT NULL,
|
||||
mode TEXT CHECK(mode IN ('FAIL', 'QUEUE', 'QUEUE_PEER_INITIATED')) NOT NULL DEFAULT 'FAIL'
|
||||
);
|
||||
|
||||
INSERT OR IGNORE INTO limits(peer, htlc_max_pending, htlc_max_hourly_rate)
|
||||
VALUES('000000000000000000000000000000000000000000000000000000000000000000', 5, 3600);
|
||||
`,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var defaultNodeKey = route.Vertex{}
|
||||
|
||||
type Db struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewDb(dbPath string) (*Db, error) {
|
||||
db, err := sql.Open("sqlite", dbPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, err := migrate.Exec(db, "sqlite3", migrations, migrate.Up)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("migration error: %w", err)
|
||||
}
|
||||
if n > 0 {
|
||||
log.Infow("Applied migrations", "count", n)
|
||||
}
|
||||
|
||||
return &Db{
|
||||
db: db,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type Limit struct {
|
||||
MaxHourlyRate int64
|
||||
MaxPending int64
|
||||
Mode Mode
|
||||
}
|
||||
|
||||
type Limits struct {
|
||||
Default Limit
|
||||
PerPeer map[route.Vertex]Limit
|
||||
}
|
||||
|
||||
func (d *Db) UpdateLimit(ctx context.Context, peer route.Vertex,
|
||||
limit Limit) error {
|
||||
|
||||
peerHex := hex.EncodeToString(peer[:])
|
||||
|
||||
const replace string = `REPLACE INTO limits(peer, htlc_max_pending, htlc_max_hourly_rate, mode) VALUES(?, ?, ?, ?);`
|
||||
|
||||
_, err := d.db.ExecContext(
|
||||
ctx, replace, peerHex,
|
||||
limit.MaxPending, limit.MaxHourlyRate,
|
||||
limit.Mode.String(),
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Db) ClearLimit(ctx context.Context, peer route.Vertex) error {
|
||||
if peer == defaultNodeKey {
|
||||
return errors.New("cannot clear default limit")
|
||||
}
|
||||
|
||||
const query string = `DELETE FROM limits WHERE peer = ?;`
|
||||
|
||||
_, err := d.db.ExecContext(
|
||||
ctx, query, hex.EncodeToString(peer[:]),
|
||||
)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *Db) GetLimits(ctx context.Context) (*Limits, error) {
|
||||
const query string = `
|
||||
SELECT peer, htlc_max_pending, htlc_max_hourly_rate, mode from limits;`
|
||||
|
||||
rows, err := d.db.QueryContext(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var limits = Limits{
|
||||
PerPeer: make(map[route.Vertex]Limit),
|
||||
}
|
||||
for rows.Next() {
|
||||
var (
|
||||
limit Limit
|
||||
peerHex string
|
||||
modeStr string
|
||||
)
|
||||
err := rows.Scan(
|
||||
&peerHex, &limit.MaxPending, &limit.MaxHourlyRate, &modeStr,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch modeStr {
|
||||
case "FAIL":
|
||||
limit.Mode = ModeFail
|
||||
|
||||
case "QUEUE":
|
||||
limit.Mode = ModeQueue
|
||||
|
||||
case "QUEUE_PEER_INITIATED":
|
||||
limit.Mode = ModeQueuePeerInitiated
|
||||
|
||||
default:
|
||||
return nil, errors.New("unknown mode")
|
||||
}
|
||||
|
||||
key, err := route.NewVertexFromStr(peerHex)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if key == defaultNodeKey {
|
||||
limits.Default = limit
|
||||
} else {
|
||||
limits.PerPeer[key] = limit
|
||||
}
|
||||
}
|
||||
|
||||
return &limits, nil
|
||||
}
|
||||
106
go.mod
|
|
@ -4,18 +4,24 @@ go 1.18
|
|||
|
||||
require (
|
||||
github.com/btcsuite/btcd/btcutil v1.1.3
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0
|
||||
github.com/lightningequipment/circuitbreaker/circuitbreakerrpc v0.0.0-00010101000000-000000000000
|
||||
github.com/lightningnetwork/lnd v0.15.4-beta
|
||||
github.com/paulbellamy/ratecounter v0.2.0
|
||||
github.com/rubenv/sql-migrate v1.2.0
|
||||
github.com/stretchr/testify v1.7.1
|
||||
github.com/urfave/cli v1.22.9
|
||||
go.uber.org/zap v1.17.0
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||
google.golang.org/grpc v1.38.0
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65
|
||||
google.golang.org/grpc v1.47.0
|
||||
gopkg.in/macaroon.v2 v2.1.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
modernc.org/sqlite v1.20.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.99.0 // indirect
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
||||
github.com/aead/siphash v1.0.1 // indirect
|
||||
github.com/andybalholm/brotli v1.0.3 // indirect
|
||||
|
|
@ -34,7 +40,8 @@ require (
|
|||
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd // indirect
|
||||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 // indirect
|
||||
github.com/btcsuite/winsvc v1.0.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||
|
|
@ -46,18 +53,21 @@ require (
|
|||
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||
github.com/dvyukov/go-fuzz v0.0.0-20210602112143-b1f3d6f4ef4e // indirect
|
||||
github.com/fergusstrange/embedded-postgres v1.10.0 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
|
||||
github.com/frankban/quicktest v1.11.3 // indirect
|
||||
github.com/go-errors/errors v1.0.1 // indirect
|
||||
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
|
||||
github.com/go-logr/logr v1.2.2 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/gofrs/uuid v4.2.0+incompatible // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.5.0 // indirect
|
||||
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
|
||||
github.com/jackc/pgconn v1.10.0 // indirect
|
||||
github.com/jackc/pgio v1.0.0 // indirect
|
||||
|
|
@ -69,11 +79,12 @@ require (
|
|||
github.com/jessevdk/go-flags v1.4.0 // indirect
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/jrick/logrotate v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.11 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/juju/clock v1.0.2 // indirect
|
||||
github.com/juju/errors v1.0.0 // indirect
|
||||
github.com/juju/loggo v1.0.0 // indirect
|
||||
github.com/juju/testing v1.0.2 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kkdai/bstream v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.13.6 // indirect
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
|
|
@ -90,22 +101,26 @@ require (
|
|||
github.com/lightningnetwork/lnd/tlv v1.0.3 // indirect
|
||||
github.com/lightningnetwork/lnd/tor v1.0.1 // indirect
|
||||
github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mattn/go-isatty v0.0.16 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
|
||||
github.com/mholt/archiver/v3 v3.5.0 // indirect
|
||||
github.com/miekg/dns v1.1.43 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/nwaples/rardecode v1.1.2 // indirect
|
||||
github.com/onsi/ginkgo v1.16.4 // indirect
|
||||
github.com/onsi/gomega v1.15.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.8 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_golang v1.11.0 // indirect
|
||||
github.com/prometheus/client_golang v1.11.1 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.26.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/prometheus/common v0.30.0 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
|
||||
github.com/rogpeppe/fastuuid v1.2.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/sirupsen/logrus v1.7.0 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/stretchr/objx v0.2.0 // indirect
|
||||
|
|
@ -115,35 +130,60 @@ require (
|
|||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/client/v2 v2.305.0 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/raft/v3 v3.5.0 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.6 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.6 // indirect
|
||||
go.etcd.io/etcd/client/v2 v2.305.6 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.6 // indirect
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.6 // indirect
|
||||
go.etcd.io/etcd/raft/v3 v3.5.6 // indirect
|
||||
go.etcd.io/etcd/server/v3 v3.5.0 // indirect
|
||||
go.opentelemetry.io/contrib v0.20.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk/metric v0.20.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v0.20.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.7.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0 // indirect
|
||||
go.opentelemetry.io/otel v1.3.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.3.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.3.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.11.0 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
golang.org/x/crypto v0.3.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||
golang.org/x/net v0.2.0 // indirect
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||
golang.org/x/sys v0.2.0 // indirect
|
||||
golang.org/x/term v0.2.0 // indirect
|
||||
golang.org/x/text v0.4.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced // indirect
|
||||
google.golang.org/protobuf v1.26.0 // indirect
|
||||
golang.org/x/tools v0.1.12 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/errgo.v1 v1.0.1 // indirect
|
||||
gopkg.in/macaroon-bakery.v2 v2.0.1 // indirect
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
lukechampine.com/uint128 v1.2.0 // indirect
|
||||
modernc.org/cc/v3 v3.40.0 // indirect
|
||||
modernc.org/ccgo/v3 v3.16.13 // indirect
|
||||
modernc.org/libc v1.21.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.4.0 // indirect
|
||||
modernc.org/opt v0.1.3 // indirect
|
||||
modernc.org/strutil v1.1.3 // indirect
|
||||
modernc.org/token v1.0.1 // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/lightningequipment/circuitbreaker/circuitbreakerrpc => ./circuitbreakerrpc
|
||||
|
||||
replace go.etcd.io/etcd/api/v3 => go.etcd.io/etcd/api/v3 v3.5.6
|
||||
|
||||
replace go.etcd.io/etcd/client/pkg/v3 => go.etcd.io/etcd/client/pkg/v3 v3.5.6
|
||||
|
||||
replace go.etcd.io/etcd/client/v3 => go.etcd.io/etcd/client/v3 v3.5.6
|
||||
|
||||
replace go.etcd.io/etcd/pkg/v3 => go.etcd.io/etcd/pkg/v3 v3.5.6
|
||||
|
||||
replace go.etcd.io/etcd/raft/v3 => go.etcd.io/etcd/raft/v3 v3.5.6
|
||||
|
||||
replace go.etcd.io/etcd/server/v3 => go.etcd.io/etcd/server/v3 v3.5.6
|
||||
|
|
|
|||
415
go.sum
|
|
@ -12,8 +12,21 @@ cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bP
|
|||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0 h1:Dg9iHVQfrhq82rUNu9ZxUDrJLaxFUe/HlCVaLyRruq8=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg=
|
||||
cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8=
|
||||
cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0=
|
||||
cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY=
|
||||
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
|
||||
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
|
||||
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
|
||||
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
|
||||
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
|
||||
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||
cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY=
|
||||
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
|
|
@ -36,8 +49,10 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
|||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc=
|
||||
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
|
||||
github.com/Masterminds/sprig/v3 v3.2.0/go.mod h1:tWhwTbUTndesPNeF0C900vKoq283u6zp4APT9vaF3SI=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
|
||||
|
|
@ -55,14 +70,13 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd
|
|||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/benbjohnson/clock v1.0.3 h1:vkLuvpK4fmtSCuo60+yC63p7y0BmQ8gm5ZXGuBCJyXg=
|
||||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/btcsuite/btcd v0.0.0-20190824003749-130ea5bddde3/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
|
||||
github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ=
|
||||
github.com/btcsuite/btcd v0.22.0-beta.0.20220111032746-97732e52810c/go.mod h1:tjmYdS6MLJ5/s0Fj4DbLgSbDHbEqLJrtnHecBFkdz5M=
|
||||
|
|
@ -120,19 +134,30 @@ github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792 h1:R8vQdOQdZ9Y3
|
|||
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
|
||||
github.com/btcsuite/winsvc v1.0.0 h1:J9B4L7e3oqhXOcm+2IuNApwzQec85lE+QaikUcCs+dk=
|
||||
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
|
||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
|
||||
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
|
||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E=
|
||||
|
|
@ -166,6 +191,7 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1
|
|||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs=
|
||||
github.com/decred/dcrd/lru v1.0.0 h1:Kbsb1SFDsIlaupWPwsPp+dkxiBY1frcS07PCPgotKz8=
|
||||
github.com/decred/dcrd/lru v1.0.0/go.mod h1:mxKOwFd7lFjN2GZYsiz/ecgqR6kkYAl+0pz0tEMk218=
|
||||
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dsnet/compress v0.0.1 h1:PlZu0n3Tuv04TzpfPbrnI0HW/YwodEXDS+oPKahKF0Q=
|
||||
|
|
@ -178,17 +204,20 @@ github.com/dvyukov/go-fuzz v0.0.0-20210602112143-b1f3d6f4ef4e/go.mod h1:11Gm+ccJ
|
|||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fergusstrange/embedded-postgres v1.10.0 h1:YnwF6xAQYmKLAXXrrRx4rHDLih47YJwVPvg8jeKfdNg=
|
||||
github.com/fergusstrange/embedded-postgres v1.10.0/go.mod h1:a008U8/Rws5FtIOTGYDYa7beVWsT3qVKyqExqYYjL+c=
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/frankban/quicktest v1.0.0/go.mod h1:R98jIehRai+d1/3Hv2//jOVCTJhW1VBavT6B6CuGq2k=
|
||||
github.com/frankban/quicktest v1.2.2 h1:xfmOhhoH5fGPgbEAlhLpJH9p0z/0Qizio9osmvn9IUY=
|
||||
github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20=
|
||||
github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
|
|
@ -200,14 +229,34 @@ github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm
|
|||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gorp/gorp/v3 v3.0.2 h1:ULqJXIekoqMx29FI5ekXXFoH1dT2Vc8UhnRzBg+Emz4=
|
||||
github.com/go-gorp/gorp/v3 v3.0.2/go.mod h1:BJ3q1ejpV8cVALtcXvXaXyTOlMmJhWDxTmncaR6rwBY=
|
||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU=
|
||||
github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs=
|
||||
github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0=
|
||||
github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY=
|
||||
github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY=
|
||||
github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE=
|
||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gofrs/uuid v4.2.0+incompatible h1:yyYWMnhkhrKwwr8gAOcOCYxOOscHgDS9yZgBrnJfGa0=
|
||||
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
|
|
@ -216,6 +265,9 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
|
|||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
|
||||
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/glog v0.0.0-20210429001901-424d2337a529 h1:2voWjNECnrZRbfwXxHB1/j8wa6xdKn85B5NzgVL/pTU=
|
||||
github.com/golang/glog v0.0.0-20210429001901-424d2337a529/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
|
|
@ -232,6 +284,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
|
|||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
|
|
@ -251,6 +305,7 @@ github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx
|
|||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
|
|
@ -265,13 +320,17 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
|
|
@ -279,10 +338,23 @@ github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hf
|
|||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
|
|
@ -317,7 +389,11 @@ github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0m
|
|||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||
|
|
@ -375,8 +451,9 @@ github.com/jrick/logrotate v1.0.0 h1:lQ1bL/n9mBNeIXoTUoYRlK4dHuNJVofX9oWqBtPnSzI
|
|||
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
|
||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
|
|
@ -392,6 +469,10 @@ github.com/juju/testing v1.0.2/go.mod h1:h3Vd2rzB57KrdsBEy6R7bmSKPzP76BnNavt7i8P
|
|||
github.com/juju/utils/v3 v3.0.0 h1:Gg3n63mGPbBuoXCo+EPJuMi44hGZfloI8nlCIebHu2Q=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
|
||||
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
|
|
@ -411,8 +492,11 @@ github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQ
|
|||
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/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kortschak/utter v1.0.1/go.mod h1:vSmSjbyrlKjjsL71193LmzBOKgwePk9DH6uFaWHIInc=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
|
|
@ -424,6 +508,7 @@ github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
|||
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/lib/pq v1.10.3 h1:v9QZf2Sn6AmjXtQeFpdoq/eaNtYP6IN+7lcrygsIAtg=
|
||||
github.com/lib/pq v1.10.3/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
|
|
@ -460,6 +545,13 @@ github.com/ltcsuite/ltcd v0.0.0-20190101042124-f37f8bf35796/go.mod h1:3p7ZTf9V1s
|
|||
github.com/ltcsuite/ltcutil v0.0.0-20181217130922-17f3b04680b6/go.mod h1:8Vg/LTOO0KYa/vlHWJ6XZAevPQThGH5sufO0Hrou/lA=
|
||||
github.com/lunixbochs/vtclean v0.0.0-20160125035106-4fbf7632a2c6/go.mod h1:pHhQNgMf3btfWnGBVipUOjRYhoOsdGqdm/+2c2E2WMI=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI=
|
||||
github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc=
|
||||
github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY=
|
||||
github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI=
|
||||
github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI=
|
||||
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
|
||||
github.com/mattn/go-colorable v0.0.6/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
|
|
@ -469,14 +561,24 @@ github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
|
|||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/mholt/archiver/v3 v3.5.0 h1:nE8gZIrw66cu4osS/U7UW7YDuGMHssxKutU8IfWxwWE=
|
||||
github.com/mholt/archiver/v3 v3.5.0/go.mod h1:qqTTPUK/HZPFgFQ/TJ3BzvTpF/dPtFVJXdQbCmeMxwc=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.43 h1:JKfpVSCB84vrAmHzyrsxB5NAr5kLoMXZArPSw7Qlgyg=
|
||||
github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/cli v1.1.4/go.mod h1:vTLESy5mRhKOs9KDp0/RATawxP1UqBmdrpVRMnpcvKQ=
|
||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
|
|
@ -484,33 +586,43 @@ github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS4
|
|||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||
github.com/nwaples/rardecode v1.1.2 h1:Cj0yZY6T1Zx1R7AhTbyGSALm44/Mmq+BAPc4B/p/d3M=
|
||||
github.com/nwaples/rardecode v1.1.2/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA=
|
||||
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.15.0 h1:WjP/FQ/sk43MRmnEcT+MlDw2TFvkrXlprrPST/IudjU=
|
||||
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/paulbellamy/ratecounter v0.2.0 h1:2L/RhJq+HA8gBQImDXtLPrDXK5qAj6ozWVK/zFXVJGs=
|
||||
github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pierrec/lz4/v4 v4.0.3/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pierrec/lz4/v4 v4.1.8 h1:ieHkV+i2BRzngO4Wd/3HGowuZStgq6QkPsD1eolNAO4=
|
||||
github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
|
|
@ -519,15 +631,19 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1 h1:oL4IBbcqwhhNWh31bjOX8C/OCy0zs9906d/VUru+bqg=
|
||||
github.com/poy/onpar v0.0.0-20190519213022-ee068f8ea4d1/go.mod h1:nSbFQvMj97ZyhFRSJYtut+msi4sOY6zJDGCdSc+/rZU=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
|
||||
github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_golang v1.11.1 h1:+4eQaD7vAZ6DsfsxB15hbE0odUjGI5ARs9yskGu1v4s=
|
||||
github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0=
|
||||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
|
||||
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
|
|
@ -537,24 +653,31 @@ github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7q
|
|||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/common v0.30.0 h1:JEkYlQnpzrzQFxi6gnukFPdQ+ac82oRhzMcIduJu/Ug=
|
||||
github.com/prometheus/common v0.30.0/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU=
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
|
||||
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
|
||||
github.com/rubenv/sql-migrate v1.2.0 h1:fOXMPLMd41sK7Tg75SXDec15k3zg5WNV6SjuDRiNfcU=
|
||||
github.com/rubenv/sql-migrate v1.2.0/go.mod h1:Z5uVnq7vrIrPmHbVFfR4YLHRZquxeHpckCnRq0P/K9Y=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
|
|
@ -569,8 +692,9 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
|||
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
|
|
@ -578,13 +702,18 @@ github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js=
|
|||
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
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 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
|
|
@ -618,60 +747,68 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
|
||||
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
|
||||
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/bbolt v1.3.5-0.20200615073812-232d8fc87f50/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0 h1:GsV3S+OfZEOCNXdtNkBSR7kgLobAa/SO6tCxRa0GAYw=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0 h1:2aQv6F436YnN7I4VbI8PPYrBhu+SmrTaADcf8Mi/6PU=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0 h1:ftQ0nOOHMcbMS3KIaDQ0g5Qcd6bhaBrQT6b89DfwLTs=
|
||||
go.etcd.io/etcd/api/v3 v3.5.6 h1:Cy2qx3npLcYqTKqGJzMypnMv2tiRyifZJ17BlWIWA7A=
|
||||
go.etcd.io/etcd/api/v3 v3.5.6/go.mod h1:KFtNaxGDw4Yx/BA4iPPwevUTAuqcsPxzyX8PHydchN8=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.6 h1:TXQWYceBKqLp4sa87rcPs11SXxUA/mHwH975v+BDvLU=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.6/go.mod h1:ggrwbk069qxpKPq8/FKkQ3Xq9y39kbFR4LnKszpRXeQ=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
go.etcd.io/etcd/client/v3 v3.5.0 h1:62Eh0XOro+rDwkrypAGDfgmNh5Joq+z+W9HZdlXMzek=
|
||||
go.etcd.io/etcd/client/v3 v3.5.0/go.mod h1:AIKXXVX/DQXtfTEqBryiLTUXwON+GuvO6Z7lLS/oTh0=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.0 h1:ntrg6vvKRW26JRmHTE0iNlDgYK6JX3hg/4cD62X0ixk=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.0/go.mod h1:UzJGatBQ1lXChBkQF0AuAtkRQMYnHubxAEYIrC3MSsE=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.0 h1:kw2TmO3yFTgE+F0mdKkG7xMxkit2duBDa2Hu6D/HMlw=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.0/go.mod h1:UFOHSIvO/nKwd4lhkwabrTD3cqW5yVyYYf/KlD00Szc=
|
||||
go.etcd.io/etcd/server/v3 v3.5.0 h1:jk8D/lwGEDlQU9kZXUFMSANkE22Sg5+mW27ip8xcF9E=
|
||||
go.etcd.io/etcd/server/v3 v3.5.0/go.mod h1:3Ah5ruV+M+7RZr0+Y/5mNLwC+eQlni+mQmOVdCRJoS4=
|
||||
go.etcd.io/etcd/client/v2 v2.305.6 h1:fIDR0p4KMjw01MJMfUIDWdQbjo06PD6CeYM5z4EHLi0=
|
||||
go.etcd.io/etcd/client/v2 v2.305.6/go.mod h1:BHha8XJGe8vCIBfWBpbBLVZ4QjOIlfoouvOwydu63E0=
|
||||
go.etcd.io/etcd/client/v3 v3.5.6 h1:coLs69PWCXE9G4FKquzNaSHrRyMCAXwF+IX1tAPVO8E=
|
||||
go.etcd.io/etcd/client/v3 v3.5.6/go.mod h1:f6GRinRMCsFVv9Ht42EyY7nfsVGwrNO0WEoS2pRKzQk=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.6 h1:k1GZrGrfMHy5/cg2bxNGsmLTFisatyhDYCFLRuaavWg=
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.6/go.mod h1:qATwUzDb6MLyGWq2nUj+jwXqZJcxkCuabh0P7Cuff3k=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.6 h1:tOmx6Ym6rn2GpZOrvTGJZciJHek6RnC3U/zNInzIN50=
|
||||
go.etcd.io/etcd/raft/v3 v3.5.6/go.mod h1:wL8kkRGx1Hp8FmZUuHfL3K2/OaGIDaXGr1N7i2G07J0=
|
||||
go.etcd.io/etcd/server/v3 v3.5.6 h1:RXuwaB8AMiV62TqcqIt4O4bG8NWjsxOkDJVT3MZI5Ds=
|
||||
go.etcd.io/etcd/server/v3 v3.5.6/go.mod h1:6/Gfe8XTGXQJgLYQ65oGKMfPivb2EASLUSMSWN9Sroo=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0=
|
||||
go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0 h1:sO4WKdPAudZGKPcpZT4MJn6JaDmpyLrMPDGGyA1SttE=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
|
||||
go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g=
|
||||
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
|
||||
go.opentelemetry.io/otel/exporters/otlp v0.20.0 h1:PTNgq9MRmQqqJY0REVbZFvwkYOA85vbdQU/nVfxDyqg=
|
||||
go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
|
||||
go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8=
|
||||
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
|
||||
go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw=
|
||||
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
|
||||
go.opentelemetry.io/otel/sdk v0.20.0 h1:JsxtGXd06J8jrnya7fdI/U/MR6yXA5DtbZy+qoHQlr8=
|
||||
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.20.0 h1:c5VRjxCXdQlx1HjzwGdQHzZaVI82b5EbBgOu2ljD92g=
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
|
||||
go.opentelemetry.io/otel/sdk/metric v0.20.0 h1:7ao1wpzHRVKf0OQ7GIxiQJA6X7DLX9o14gmVon7mMK8=
|
||||
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
|
||||
go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw=
|
||||
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0 h1:rwOQPCuKAKmwGKq2aVNnYIibI6wnV7EvzgfTCzcdGg8=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0 h1:Ky1MObd188aGbgb5OgNnwGuEEwI9MVIcc7rBW6zk5Ak=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w=
|
||||
go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU=
|
||||
go.opentelemetry.io/otel v1.3.0 h1:APxLf0eiBwLl+SOXiJJCVYzA1OOJNyAoV8C5RNRyy7Y=
|
||||
go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0 h1:R/OBkMoGgfy2fLhs2QhkCI1w4HLEQX92GCcJB6SSdNk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0 h1:giGm8w67Ja7amYNfYMdme7xSp2pIxThWopw8+QP51Yk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0 h1:VQbUHoJqytHHSJ1OZodPH9tvZZSVzUHjPHpkO85sT6k=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY=
|
||||
go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI=
|
||||
go.opentelemetry.io/otel/sdk v1.3.0 h1:3278edCoH89MEJ0Ky8WQXVmDQv3FX4ZJ3Pp+9fJreAI=
|
||||
go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs=
|
||||
go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk=
|
||||
go.opentelemetry.io/otel/trace v1.3.0 h1:doy8Hzb1RJ+I3yFhtDmwNc7tIyw1tNMOIsyPzp1NOGY=
|
||||
go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg=
|
||||
go.opentelemetry.io/proto/otlp v0.11.0 h1:cLDgIBTf4lLOlztkhzAEdQsJ4Lj+i5Wc9k6Nn0K1VyU=
|
||||
go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
|
||||
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
|
||||
|
|
@ -689,16 +826,19 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf
|
|||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
|
|
@ -724,7 +864,7 @@ golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHl
|
|||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
|
|
@ -734,7 +874,11 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
|
|||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
|
@ -774,10 +918,20 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R
|
|||
golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
|
|
@ -785,8 +939,20 @@ golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4Iltr
|
|||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1 h1:x622Z2o4hgCr/4CiKWc51jHVKaWdtVpBNmEI8wI9Qns=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210615190721-d04028783cf1/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
|
|
@ -797,8 +963,9 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
|
@ -844,24 +1011,45 @@ golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210426080607-c94f62235c83/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A=
|
||||
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
|
@ -877,8 +1065,9 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
|||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs=
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
|
@ -902,7 +1091,6 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
|
|||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
|
|
@ -931,16 +1119,27 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY
|
|||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
|
|
@ -958,13 +1157,29 @@ google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0M
|
|||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU=
|
||||
google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94=
|
||||
google.golang.org/api v0.44.0/go.mod h1:EBOGZqzyhtvMDoxwS97ctnh0zUmYY6CxqXsc1AvkYD8=
|
||||
google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo=
|
||||
google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4=
|
||||
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
|
||||
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
|
||||
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
|
||||
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
|
||||
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
|
||||
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190201180003-4b09977fb922/go.mod h1:L3J43x8/uS+qIUoksaLKe6OS3nUKxOKuIFz1sl2/jx4=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
|
|
@ -997,9 +1212,37 @@ google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7Fc
|
|||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced h1:c5geK1iMU3cDKtFrCVQIcjR3W+JOZMuhIyICMCTbtus=
|
||||
google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
google.golang.org/genproto v0.0.0-20210617175327-b9e0b3197ced/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||
google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k=
|
||||
google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48=
|
||||
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
|
||||
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
|
||||
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106 h1:ErU+UA6wxadoU8nWrsy5MZUVBs75K17zUCsUCIfrXCE=
|
||||
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
|
||||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
|
||||
google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
|
|
@ -1014,11 +1257,25 @@ google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKa
|
|||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
|
||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
|
||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
|
||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
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=
|
||||
|
|
@ -1030,20 +1287,24 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
|||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
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-20160105164936-4f90aeace3a2/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v1 v1.0.1 h1:oQFRXzZ7CkBGdm1XZm/EbQYaYNNEElNBOd09M6cqNso=
|
||||
gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/macaroon-bakery.v2 v2.0.1 h1:0N1TlEdfLP4HXNCg7MQUMp5XwvOoxk+oe9Owr2cpvsc=
|
||||
gopkg.in/macaroon-bakery.v2 v2.0.1/go.mod h1:B4/T17l+ZWGwxFSZQmlBwp25x+og7OkhETfr3S9MbIA=
|
||||
gopkg.in/macaroon.v2 v2.1.0 h1:HZcsjBCzq9t0eBPMKqTN/uSN6JOm78ZJ2INbqcBQOUI=
|
||||
|
|
@ -1074,6 +1335,30 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
|
||||
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||
modernc.org/cc/v3 v3.40.0 h1:P3g79IUS/93SYhtoeaHW+kRCIrYaxJ27MFPv+7kaTOw=
|
||||
modernc.org/cc/v3 v3.40.0/go.mod h1:/bTg4dnWkSXowUO6ssQKnOV0yMVxDYNIsIrzqTFDGH0=
|
||||
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
|
||||
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
|
||||
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
|
||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
||||
modernc.org/libc v1.21.5 h1:xBkU9fnHV+hvZuPSRszN0AXDG4M7nwPLwTWwkYcvLCI=
|
||||
modernc.org/libc v1.21.5/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI=
|
||||
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
|
||||
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||
modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk=
|
||||
modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
|
||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||
modernc.org/sqlite v1.20.0 h1:80zmD3BGkm8BZ5fUi/4lwJQHiO3GXgIUvZRXpoIfROY=
|
||||
modernc.org/sqlite v1.20.0/go.mod h1:EsYz8rfOvLCiYTy5ZFsOYzoCcRMu98YYkwAcCw5YIYw=
|
||||
modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
|
||||
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
|
||||
modernc.org/tcl v1.15.0 h1:oY+JeD11qVVSgVvodMJsu7Edf8tr5E/7tuhF5cNYz34=
|
||||
modernc.org/token v1.0.1 h1:A3qvTqOwexpfZZeyI0FeGPDlSWX5pjZu9hF4lU+EKWg=
|
||||
modernc.org/token v1.0.1/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||
modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
|||
203
lndclient.go
|
|
@ -6,45 +6,149 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lncfg"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
"github.com/lightningnetwork/lnd/macaroons"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/urfave/cli"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/status"
|
||||
"gopkg.in/macaroon.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
// maxMsgRecvSize is the largest message our client will receive. We
|
||||
// set this to 200MiB atm.
|
||||
maxMsgRecvSize = grpc.MaxCallRecvMsgSize(1 * 1024 * 1024 * 200)
|
||||
|
||||
ErrNodeNotFound = errors.New("node info not available")
|
||||
)
|
||||
|
||||
type lndclientGrpc struct {
|
||||
conn *grpc.ClientConn
|
||||
log *zap.SugaredLogger
|
||||
|
||||
main lnrpc.LightningClient
|
||||
router routerrpc.RouterClient
|
||||
}
|
||||
|
||||
func newLndClient(ctx *cli.Context) (*lndclientGrpc, error) {
|
||||
// First, we'll parse the args from the command.
|
||||
tlsCertPath, macPath, err := extractPathArgs(ctx)
|
||||
type htlcEventsClient interface {
|
||||
recv() (*resolvedEvent, error)
|
||||
}
|
||||
|
||||
type lndHtlcEventsClient struct {
|
||||
client routerrpc.Router_SubscribeHtlcEventsClient
|
||||
}
|
||||
|
||||
func (h *lndHtlcEventsClient) recvInternal() (*resolvedEvent, error) {
|
||||
event, err := h.client.Recv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if event.EventType != routerrpc.HtlcEvent_FORWARD {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var settled bool
|
||||
switch event.Event.(type) {
|
||||
case *routerrpc.HtlcEvent_SettleEvent:
|
||||
settled = true
|
||||
|
||||
case *routerrpc.HtlcEvent_ForwardFailEvent:
|
||||
case *routerrpc.HtlcEvent_LinkFailEvent:
|
||||
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return &resolvedEvent{
|
||||
settled: settled,
|
||||
circuitKey: circuitKey{
|
||||
channel: event.IncomingChannelId,
|
||||
htlc: event.IncomingHtlcId,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *lndHtlcEventsClient) recv() (*resolvedEvent, error) {
|
||||
for {
|
||||
event, err := h.recvInternal()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if event != nil {
|
||||
return event, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type htlcInterceptorClient interface {
|
||||
recv() (*interceptedEvent, error)
|
||||
send(*interceptResponse) error
|
||||
}
|
||||
|
||||
type lndHtlcInterceptorClient struct {
|
||||
client routerrpc.Router_HtlcInterceptorClient
|
||||
}
|
||||
|
||||
type interceptedEvent struct {
|
||||
circuitKey circuitKey
|
||||
}
|
||||
|
||||
func (h *lndHtlcInterceptorClient) recv() (*interceptedEvent, error) {
|
||||
event, err := h.client.Recv()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &interceptedEvent{
|
||||
circuitKey: circuitKey{
|
||||
channel: event.IncomingCircuitKey.ChanId,
|
||||
htlc: event.IncomingCircuitKey.HtlcId,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type interceptResponse struct {
|
||||
key circuitKey
|
||||
resume bool
|
||||
}
|
||||
|
||||
func (h *lndHtlcInterceptorClient) send(resp *interceptResponse) error {
|
||||
response := &routerrpc.ForwardHtlcInterceptResponse{
|
||||
IncomingCircuitKey: &routerrpc.CircuitKey{
|
||||
ChanId: resp.key.channel,
|
||||
HtlcId: resp.key.htlc,
|
||||
},
|
||||
}
|
||||
if resp.resume {
|
||||
response.Action = routerrpc.ResolveHoldForwardAction_RESUME
|
||||
} else {
|
||||
response.Action = routerrpc.ResolveHoldForwardAction_FAIL
|
||||
}
|
||||
|
||||
return h.client.Send(response)
|
||||
}
|
||||
|
||||
type LndConfig struct {
|
||||
TlsCertPath, MacPath, RpcServer string
|
||||
Log *zap.SugaredLogger
|
||||
}
|
||||
|
||||
func NewLndClient(cfg *LndConfig) (*lndclientGrpc, error) {
|
||||
// Load the specified TLS certificate and build transport credentials
|
||||
// with it.
|
||||
creds, err := credentials.NewClientTLSFromFile(tlsCertPath, "")
|
||||
creds, err := credentials.NewClientTLSFromFile(cfg.TlsCertPath, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Create a dial options array.
|
||||
opts := []grpc.DialOption{
|
||||
grpc.WithTransportCredentials(creds),
|
||||
}
|
||||
|
||||
// Load the specified macaroon file.
|
||||
macBytes, err := os.ReadFile(macPath)
|
||||
macBytes, err := os.ReadFile(cfg.MacPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to read macaroon path (check "+
|
||||
"the network setting!): %v", err)
|
||||
|
|
@ -60,21 +164,21 @@ func newLndClient(ctx *cli.Context) (*lndclientGrpc, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot create mac credential: %w", err)
|
||||
}
|
||||
opts = append(opts, grpc.WithPerRPCCredentials(cred))
|
||||
|
||||
// We need to use a custom dialer so we can also connect to unix sockets
|
||||
// and not just TCP addresses.
|
||||
genericDialer := lncfg.ClientAddressDialer(defaultRPCPort)
|
||||
opts = append(opts, grpc.WithContextDialer(genericDialer))
|
||||
opts = append(opts, grpc.WithDefaultCallOptions(maxMsgRecvSize))
|
||||
opts := []grpc.DialOption{
|
||||
grpc.WithTransportCredentials(creds),
|
||||
grpc.WithDefaultCallOptions(maxMsgRecvSize),
|
||||
grpc.WithPerRPCCredentials(cred),
|
||||
}
|
||||
|
||||
conn, err := grpc.Dial(ctx.GlobalString("rpcserver"), opts...)
|
||||
conn, err := grpc.Dial(cfg.RpcServer, opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"unable to connect to RPC server: %v", err)
|
||||
}
|
||||
|
||||
return &lndclientGrpc{
|
||||
log: cfg.Log,
|
||||
conn: conn,
|
||||
main: lnrpc.NewLightningClient(conn),
|
||||
router: routerrpc.NewRouterClient(conn),
|
||||
|
|
@ -102,7 +206,7 @@ func (l *lndclientGrpc) listChannels() (map[uint64]*channel, error) {
|
|||
ctx, cancel := context.WithTimeout(ctxb, rpcTimeout)
|
||||
defer cancel()
|
||||
|
||||
log.Debugw("Retrieving channels")
|
||||
l.log.Debugw("Retrieving channels")
|
||||
|
||||
resp, err := l.main.ListChannels(ctx, &lnrpc.ListChannelsRequest{})
|
||||
if err != nil {
|
||||
|
|
@ -125,20 +229,31 @@ func (l *lndclientGrpc) listChannels() (map[uint64]*channel, error) {
|
|||
return chans, nil
|
||||
}
|
||||
|
||||
func (l *lndclientGrpc) subscribeHtlcEvents(ctx context.Context,
|
||||
in *routerrpc.SubscribeHtlcEventsRequest) (
|
||||
routerrpc.Router_SubscribeHtlcEventsClient, error) {
|
||||
func (l *lndclientGrpc) subscribeHtlcEvents(ctx context.Context) (
|
||||
htlcEventsClient, error) {
|
||||
|
||||
return l.router.SubscribeHtlcEvents(ctx, in)
|
||||
req := &routerrpc.SubscribeHtlcEventsRequest{}
|
||||
|
||||
client, err := l.router.SubscribeHtlcEvents(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &lndHtlcEventsClient{client: client}, nil
|
||||
}
|
||||
|
||||
func (l *lndclientGrpc) htlcInterceptor(ctx context.Context) (
|
||||
routerrpc.Router_HtlcInterceptorClient, error) {
|
||||
htlcInterceptorClient, error) {
|
||||
|
||||
return l.router.HtlcInterceptor(ctx)
|
||||
client, err := l.router.HtlcInterceptor(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &lndHtlcInterceptorClient{client: client}, nil
|
||||
}
|
||||
|
||||
func (l *lndclientGrpc) close() {
|
||||
func (l *lndclientGrpc) Close() {
|
||||
l.conn.Close()
|
||||
}
|
||||
|
||||
|
|
@ -146,25 +261,28 @@ func (l *lndclientGrpc) getNodeAlias(key route.Vertex) (string, error) {
|
|||
ctx, cancel := context.WithTimeout(ctxb, rpcTimeout)
|
||||
defer cancel()
|
||||
|
||||
log.Debugw("Retrieving node info",
|
||||
l.log.Debugw("Retrieving node info",
|
||||
"key", key)
|
||||
|
||||
info, err := l.main.GetNodeInfo(ctx, &lnrpc.NodeInfoRequest{
|
||||
PubKey: key.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
switch {
|
||||
case status.Code(err) == codes.NotFound:
|
||||
return "", ErrNodeNotFound
|
||||
|
||||
if info.Node == nil {
|
||||
return "", errors.New("node info not available")
|
||||
case info.Node == nil:
|
||||
return "", ErrNodeNotFound
|
||||
|
||||
case err != nil:
|
||||
return "", err
|
||||
}
|
||||
|
||||
return info.Node.Alias, nil
|
||||
}
|
||||
|
||||
func (l *lndclientGrpc) getPendingIncomingHtlcs(ctx context.Context,
|
||||
peer *route.Vertex) (map[circuitKey]struct{}, error) {
|
||||
func (l *lndclientGrpc) getPendingIncomingHtlcs(ctx context.Context, peer *route.Vertex) (
|
||||
map[route.Vertex]map[circuitKey]struct{}, error) {
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, rpcTimeout)
|
||||
defer cancel()
|
||||
|
|
@ -179,8 +297,19 @@ func (l *lndclientGrpc) getPendingIncomingHtlcs(ctx context.Context,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
htlcs := make(map[circuitKey]struct{})
|
||||
allHtlcs := make(map[route.Vertex]map[circuitKey]struct{})
|
||||
for _, channel := range resp.Channels {
|
||||
peer, err := route.NewVertexFromStr(channel.RemotePubkey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
htlcs, ok := allHtlcs[peer]
|
||||
if !ok {
|
||||
htlcs = make(map[circuitKey]struct{})
|
||||
allHtlcs[peer] = htlcs
|
||||
}
|
||||
|
||||
for _, htlc := range channel.PendingHtlcs {
|
||||
if !htlc.Incoming {
|
||||
continue
|
||||
|
|
@ -195,5 +324,5 @@ func (l *lndclientGrpc) getPendingIncomingHtlcs(ctx context.Context,
|
|||
}
|
||||
}
|
||||
|
||||
return htlcs, nil
|
||||
return allHtlcs, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,16 +10,16 @@ import (
|
|||
var mockIdentity = route.Vertex{1, 2, 3}
|
||||
|
||||
type lndclientMock struct {
|
||||
htlcEvents chan *routerrpc.HtlcEvent
|
||||
htlcInterceptorRequests chan *routerrpc.ForwardHtlcInterceptRequest
|
||||
htlcInterceptorResponses chan *routerrpc.ForwardHtlcInterceptResponse
|
||||
htlcEvents chan *resolvedEvent
|
||||
htlcInterceptorRequests chan *interceptedEvent
|
||||
htlcInterceptorResponses chan *interceptResponse
|
||||
}
|
||||
|
||||
func newLndclientMock() *lndclientMock {
|
||||
return &lndclientMock{
|
||||
htlcEvents: make(chan *routerrpc.HtlcEvent),
|
||||
htlcInterceptorRequests: make(chan *routerrpc.ForwardHtlcInterceptRequest),
|
||||
htlcInterceptorResponses: make(chan *routerrpc.ForwardHtlcInterceptResponse),
|
||||
htlcEvents: make(chan *resolvedEvent),
|
||||
htlcInterceptorRequests: make(chan *interceptedEvent),
|
||||
htlcInterceptorResponses: make(chan *interceptResponse),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -34,9 +34,8 @@ func (l *lndclientMock) listChannels() (map[uint64]*channel, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (l *lndclientMock) subscribeHtlcEvents(ctx context.Context,
|
||||
in *routerrpc.SubscribeHtlcEventsRequest) (
|
||||
routerrpc.Router_SubscribeHtlcEventsClient, error) {
|
||||
func (l *lndclientMock) subscribeHtlcEvents(ctx context.Context) (
|
||||
htlcEventsClient, error) {
|
||||
|
||||
return &htlcEventsMock{
|
||||
ctx: ctx,
|
||||
|
|
@ -45,7 +44,7 @@ func (l *lndclientMock) subscribeHtlcEvents(ctx context.Context,
|
|||
}
|
||||
|
||||
func (l *lndclientMock) htlcInterceptor(ctx context.Context) (
|
||||
routerrpc.Router_HtlcInterceptorClient, error) {
|
||||
htlcInterceptorClient, error) {
|
||||
|
||||
return &htlcInterceptorMock{
|
||||
ctx: ctx,
|
||||
|
|
@ -58,10 +57,10 @@ func (l *lndclientMock) getNodeAlias(key route.Vertex) (string, error) {
|
|||
return "alias-" + key.String()[:6], nil
|
||||
}
|
||||
|
||||
func (l *lndclientMock) getPendingIncomingHtlcs(ctx context.Context,
|
||||
peer *route.Vertex) (map[circuitKey]struct{}, error) {
|
||||
func (l *lndclientMock) getPendingIncomingHtlcs(ctx context.Context, peer *route.Vertex) (
|
||||
map[route.Vertex]map[circuitKey]struct{}, error) {
|
||||
|
||||
htlcs := make(map[circuitKey]struct{})
|
||||
htlcs := make(map[route.Vertex]map[circuitKey]struct{})
|
||||
|
||||
return htlcs, nil
|
||||
}
|
||||
|
|
@ -70,10 +69,10 @@ type htlcEventsMock struct {
|
|||
ctx context.Context //nolint:containedctx
|
||||
routerrpc.Router_SubscribeHtlcEventsClient
|
||||
|
||||
htlcEvents chan *routerrpc.HtlcEvent
|
||||
htlcEvents chan *resolvedEvent
|
||||
}
|
||||
|
||||
func (h *htlcEventsMock) Recv() (*routerrpc.HtlcEvent, error) {
|
||||
func (h *htlcEventsMock) recv() (*resolvedEvent, error) {
|
||||
select {
|
||||
case event := <-h.htlcEvents:
|
||||
return event, nil
|
||||
|
|
@ -87,11 +86,11 @@ type htlcInterceptorMock struct {
|
|||
ctx context.Context //nolint:containedctx
|
||||
routerrpc.Router_HtlcInterceptorClient
|
||||
|
||||
htlcInterceptorRequests chan *routerrpc.ForwardHtlcInterceptRequest
|
||||
htlcInterceptorResponses chan *routerrpc.ForwardHtlcInterceptResponse
|
||||
htlcInterceptorRequests chan *interceptedEvent
|
||||
htlcInterceptorResponses chan *interceptResponse
|
||||
}
|
||||
|
||||
func (h *htlcInterceptorMock) Send(resp *routerrpc.ForwardHtlcInterceptResponse) error {
|
||||
func (h *htlcInterceptorMock) send(resp *interceptResponse) error {
|
||||
select {
|
||||
case h.htlcInterceptorResponses <- resp:
|
||||
return nil
|
||||
|
|
@ -101,7 +100,7 @@ func (h *htlcInterceptorMock) Send(resp *routerrpc.ForwardHtlcInterceptResponse)
|
|||
}
|
||||
}
|
||||
|
||||
func (h *htlcInterceptorMock) Recv() (*routerrpc.ForwardHtlcInterceptRequest, error) {
|
||||
func (h *htlcInterceptorMock) recv() (*interceptedEvent, error) {
|
||||
select {
|
||||
case event := <-h.htlcInterceptorRequests:
|
||||
return event, nil
|
||||
|
|
|
|||
53
main.go
|
|
@ -1,7 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/user"
|
||||
|
|
@ -11,7 +10,6 @@ import (
|
|||
"github.com/btcsuite/btcd/btcutil"
|
||||
"github.com/lightningnetwork/lnd/build"
|
||||
"github.com/urfave/cli"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
@ -19,20 +17,28 @@ const (
|
|||
defaultChainSubDir = "chain"
|
||||
defaultTLSCertFilename = "tls.cert"
|
||||
defaultMacaroonFilename = "admin.macaroon"
|
||||
defaultRPCPort = "10009"
|
||||
defaultRPCHostPort = "localhost:" + defaultRPCPort
|
||||
|
||||
chain = "bitcoin"
|
||||
confFn = "circuitbreaker.yaml"
|
||||
chain = "bitcoin"
|
||||
dbFn = "circuitbreaker.db"
|
||||
)
|
||||
|
||||
var (
|
||||
defaultLndDir = btcutil.AppDataDir("lnd", false)
|
||||
defaultTLSCertPath = filepath.Join(defaultLndDir, defaultTLSCertFilename)
|
||||
|
||||
// maxMsgRecvSize is the largest message our client will receive. We
|
||||
// set this to 200MiB atm.
|
||||
maxMsgRecvSize = grpc.MaxCallRecvMsgSize(1 * 1024 * 1024 * 200)
|
||||
defaultRPCPort = "10009"
|
||||
defaultRPCHostPort = "localhost:" + defaultRPCPort
|
||||
|
||||
httpListenFlag = cli.StringFlag{
|
||||
Name: "httplisten",
|
||||
Value: "127.0.0.1:9235",
|
||||
Usage: "http server listen address",
|
||||
}
|
||||
|
||||
stubFlag = cli.BoolFlag{
|
||||
Name: "stub",
|
||||
Usage: "set to enable stub mode (no lnd instance connected)",
|
||||
}
|
||||
)
|
||||
|
||||
// extractPathArgs parses the TLS certificate and macaroon paths from the
|
||||
|
|
@ -84,7 +90,7 @@ func main() {
|
|||
defaultAppDir := btcutil.AppDataDir("circuitbreaker", false)
|
||||
|
||||
app := cli.NewApp()
|
||||
app.Name = "circuitbreaker"
|
||||
app.Name = "circuitbreakerd"
|
||||
app.Version = build.Version() + " commit=" + build.Commit
|
||||
app.Flags = []cli.Flag{
|
||||
cli.StringFlag{
|
||||
|
|
@ -117,27 +123,16 @@ func main() {
|
|||
Value: defaultAppDir,
|
||||
Usage: "path to CircuitBreaker's base directory",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "listen",
|
||||
Value: "127.0.0.1:9234",
|
||||
Usage: "grpc server listen address",
|
||||
},
|
||||
httpListenFlag,
|
||||
stubFlag,
|
||||
}
|
||||
|
||||
app.Action = func(c *cli.Context) error {
|
||||
configPath := filepath.Join(c.String("configdir"), confFn)
|
||||
loader := newConfigLoader(configPath)
|
||||
|
||||
config, err := loader.load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client, err := newLndClient(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer client.close()
|
||||
|
||||
p := newProcess(client, config)
|
||||
|
||||
return p.run(context.Background())
|
||||
}
|
||||
app.Action = run
|
||||
|
||||
if err := app.Run(os.Args); err != nil {
|
||||
log.Errorw("Unexpected exit", "err", err)
|
||||
|
|
|
|||
|
|
@ -6,16 +6,63 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/paulbellamy/ratecounter"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
type eventCounter struct {
|
||||
fail *ratecounter.RateCounter
|
||||
success *ratecounter.RateCounter
|
||||
reject *ratecounter.RateCounter
|
||||
}
|
||||
|
||||
type eventType int
|
||||
|
||||
const (
|
||||
eventSuccess eventType = iota
|
||||
eventFail
|
||||
eventReject
|
||||
)
|
||||
|
||||
func newEventCounter(interval time.Duration) *eventCounter {
|
||||
return &eventCounter{
|
||||
fail: ratecounter.NewRateCounter(interval),
|
||||
success: ratecounter.NewRateCounter(interval),
|
||||
reject: ratecounter.NewRateCounter(interval),
|
||||
}
|
||||
}
|
||||
|
||||
func (e *eventCounter) Incr(event eventType) {
|
||||
switch event {
|
||||
case eventSuccess:
|
||||
e.success.Incr(1)
|
||||
|
||||
case eventFail:
|
||||
e.fail.Incr(1)
|
||||
|
||||
case eventReject:
|
||||
e.reject.Incr(1)
|
||||
|
||||
default:
|
||||
panic("unknown event type")
|
||||
}
|
||||
}
|
||||
|
||||
func (e *eventCounter) Rates() (int64, int64, int64) {
|
||||
return e.success.Rate(), e.fail.Rate(), e.reject.Rate()
|
||||
}
|
||||
|
||||
type peerController struct {
|
||||
cfg *groupConfig
|
||||
limiter *rate.Limiter
|
||||
logger *zap.SugaredLogger
|
||||
interceptChan chan peerInterceptEvent
|
||||
resolvedChan chan circuitKey
|
||||
cfg Limit
|
||||
limiter *rate.Limiter
|
||||
logger *zap.SugaredLogger
|
||||
interceptChan chan peerInterceptEvent
|
||||
resolvedChan chan resolvedEvent
|
||||
updateLimitChan chan Limit
|
||||
getStateChan chan chan *peerState
|
||||
|
||||
rateCounters []*eventCounter
|
||||
|
||||
htlcs map[circuitKey]struct{}
|
||||
|
||||
|
|
@ -30,70 +77,130 @@ type peerInterceptEvent struct {
|
|||
peerInitiated bool
|
||||
}
|
||||
|
||||
type peerState struct {
|
||||
counts []rateCounts
|
||||
queueLen int64
|
||||
pendingHtlcCount int64
|
||||
}
|
||||
|
||||
type rateCounts struct {
|
||||
success, fail, reject int64
|
||||
}
|
||||
|
||||
var rateCounterIntervals = []time.Duration{time.Hour, 24 * time.Hour}
|
||||
|
||||
type peerControllerCfg struct {
|
||||
logger *zap.SugaredLogger
|
||||
cfg *groupConfig
|
||||
htlcs map[circuitKey]struct{}
|
||||
lnd lndclient
|
||||
pubKey route.Vertex
|
||||
logger *zap.SugaredLogger
|
||||
limit Limit
|
||||
burstSize int
|
||||
htlcs map[circuitKey]struct{}
|
||||
lnd lndclient
|
||||
pubKey route.Vertex
|
||||
}
|
||||
|
||||
func newPeerController(cfg *peerControllerCfg) *peerController {
|
||||
logger := cfg.logger
|
||||
|
||||
var limiter *rate.Limiter
|
||||
logger := cfg.logger.With(
|
||||
"peer", cfg.pubKey.String(),
|
||||
)
|
||||
|
||||
// Skip if no interval set.
|
||||
limit := rate.Inf
|
||||
if cfg.cfg.HtlcMinInterval > 0 {
|
||||
limit = rate.Every(cfg.cfg.HtlcMinInterval)
|
||||
}
|
||||
limiter = rate.NewLimiter(limit, cfg.cfg.HtlcBurstSize)
|
||||
limiter := rate.NewLimiter(getRate(cfg.limit.MaxHourlyRate), cfg.burstSize)
|
||||
|
||||
logger.Infow("Peer controller initialized",
|
||||
"htlcMinInterval", cfg.cfg.HtlcMinInterval,
|
||||
"htlcBurstSize", cfg.cfg.HtlcBurstSize,
|
||||
"maxPendingHtlcs", cfg.cfg.MaxPendingHtlcs,
|
||||
"mode", cfg.cfg.Mode)
|
||||
"maxHourlyRate", cfg.limit.MaxHourlyRate,
|
||||
"maxPendingHtlcs", cfg.limit.MaxPending,
|
||||
"mode", cfg.limit.Mode)
|
||||
|
||||
// Log initial pending htlcs.
|
||||
for h := range cfg.htlcs {
|
||||
logger.Infow("Initial pending htlc", "channel", h.channel, "htlc", h.htlc)
|
||||
}
|
||||
|
||||
rateCounters := make([]*eventCounter, len(rateCounterIntervals))
|
||||
for idx, interval := range rateCounterIntervals {
|
||||
rateCounters[idx] = newEventCounter(interval)
|
||||
}
|
||||
|
||||
return &peerController{
|
||||
cfg: cfg.cfg,
|
||||
cfg: cfg.limit,
|
||||
limiter: limiter,
|
||||
logger: logger,
|
||||
interceptChan: make(chan peerInterceptEvent),
|
||||
resolvedChan: make(chan circuitKey),
|
||||
resolvedChan: make(chan resolvedEvent),
|
||||
updateLimitChan: make(chan Limit),
|
||||
getStateChan: make(chan chan *peerState),
|
||||
htlcs: cfg.htlcs,
|
||||
rateCounters: rateCounters,
|
||||
lnd: cfg.lnd,
|
||||
pubKey: cfg.pubKey,
|
||||
lastChannelSync: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
func (p *peerController) state(ctx context.Context) (*peerState, error) {
|
||||
respChan := make(chan *peerState)
|
||||
select {
|
||||
case p.getStateChan <- respChan:
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
select {
|
||||
case state := <-respChan:
|
||||
return state, nil
|
||||
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *peerController) rateInternal() []rateCounts {
|
||||
allRateCounts := make([]rateCounts, len(p.rateCounters))
|
||||
for idx, counter := range p.rateCounters {
|
||||
success, fail, reject := counter.Rates()
|
||||
allRateCounts[idx] = rateCounts{
|
||||
success: success,
|
||||
fail: fail,
|
||||
reject: reject,
|
||||
}
|
||||
}
|
||||
|
||||
return allRateCounts
|
||||
}
|
||||
|
||||
func (p *peerController) updateLimit(ctx context.Context, limit Limit) error {
|
||||
select {
|
||||
case p.updateLimitChan <- limit:
|
||||
return nil
|
||||
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *peerController) newHtlcAllowed() bool {
|
||||
return p.cfg.MaxPendingHtlcs == 0 ||
|
||||
len(p.htlcs) < p.cfg.MaxPendingHtlcs
|
||||
return p.cfg.MaxPending == 0 ||
|
||||
len(p.htlcs) < int(p.cfg.MaxPending)
|
||||
}
|
||||
|
||||
func (p *peerController) syncPendingHtlcs(ctx context.Context) (bool, error) {
|
||||
p.logger.Infow("Syncing pending htlcs")
|
||||
|
||||
htlcs, err := p.lnd.getPendingIncomingHtlcs(ctx, &p.pubKey)
|
||||
allHtlcs, err := p.lnd.getPendingIncomingHtlcs(ctx, &p.pubKey)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
htlcs := allHtlcs[p.pubKey]
|
||||
|
||||
p.lastChannelSync = time.Now()
|
||||
|
||||
deletes := false
|
||||
for key := range p.htlcs {
|
||||
_, ok := htlcs[key]
|
||||
if ok {
|
||||
continue
|
||||
if htlcs != nil {
|
||||
if _, ok := htlcs[key]; ok {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// Htlc is no longer pending on incoming side. Must have missed
|
||||
|
|
@ -169,32 +276,30 @@ func (p *peerController) run(ctx context.Context) error {
|
|||
continue
|
||||
}
|
||||
|
||||
// Determine whether the htlc can be forwarded immediately.
|
||||
forwardDirect := true
|
||||
switch {
|
||||
// If there is a queue, then don't jump the queue.
|
||||
case queue.Len() > 0:
|
||||
|
||||
// Check if new htlcs are allowed.
|
||||
case !newHtlcAllowed:
|
||||
forwardDirect = false
|
||||
logger.Infow("Pending htlc limit exceeded")
|
||||
|
||||
logger.Infow("Failed on pending htlc limit")
|
||||
|
||||
case !p.limiter.Allow():
|
||||
forwardDirect = false
|
||||
|
||||
logger.Infow("Failed on rate limit")
|
||||
}
|
||||
|
||||
// Forward directly if possible.
|
||||
if forwardDirect {
|
||||
// Check the rate limit and forward immediately if allowed.
|
||||
case p.limiter.Allow():
|
||||
if err := p.forward(event.interceptEvent); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
continue
|
||||
|
||||
default:
|
||||
logger.Infow("Rate limit exceeded")
|
||||
}
|
||||
|
||||
// Queue if in one of the queue modes.
|
||||
if p.cfg.Mode == ModeQueue ||
|
||||
(p.cfg.Mode == ModeQueuePeerInitiated && event.peerInitiated) {
|
||||
mode := p.cfg.Mode
|
||||
if mode == ModeQueue ||
|
||||
(mode == ModeQueuePeerInitiated && event.peerInitiated) {
|
||||
|
||||
queue.PushFront(event)
|
||||
|
||||
|
|
@ -208,6 +313,8 @@ func (p *peerController) run(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
p.incrCounter(eventReject)
|
||||
|
||||
// There are items in the queue, max pending htlcs has not yet been
|
||||
// reached, and the rate limit delay has passed. Take the oldest item
|
||||
// from the queue and forward it.
|
||||
|
|
@ -230,7 +337,9 @@ func (p *peerController) run(ctx context.Context) error {
|
|||
|
||||
// An htlc has been resolved in lnd. Remove it from the pending htlcs
|
||||
// map to free up the slot for another htlc.
|
||||
case key := <-p.resolvedChan:
|
||||
case resolvedEvent := <-p.resolvedChan:
|
||||
key := resolvedEvent.circuitKey
|
||||
|
||||
_, ok := p.htlcs[key]
|
||||
if !ok {
|
||||
// Do not log here, because the event is still coming even for
|
||||
|
|
@ -241,8 +350,36 @@ func (p *peerController) run(ctx context.Context) error {
|
|||
|
||||
delete(p.htlcs, key)
|
||||
|
||||
// Update rate counters.
|
||||
if resolvedEvent.settled {
|
||||
p.incrCounter(eventSuccess)
|
||||
} else {
|
||||
p.incrCounter(eventFail)
|
||||
}
|
||||
|
||||
logger := p.keyLogger(key)
|
||||
logger.Infow("Resolved htlc", "pending_htlcs", len(p.htlcs))
|
||||
logger.Infow("Resolved htlc", "settled", resolvedEvent.settled,
|
||||
"pending_htlcs", len(p.htlcs))
|
||||
|
||||
case limit := <-p.updateLimitChan:
|
||||
p.logger.Infow("Updating peer controller", "limit", limit)
|
||||
p.cfg = limit
|
||||
|
||||
p.limiter.SetLimit(getRate(limit.MaxHourlyRate))
|
||||
|
||||
case respChan := <-p.getStateChan:
|
||||
counts := p.rateInternal()
|
||||
|
||||
select {
|
||||
case respChan <- &peerState{
|
||||
counts: counts,
|
||||
queueLen: int64(queue.Len()),
|
||||
pendingHtlcCount: int64(len(p.htlcs)),
|
||||
}:
|
||||
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
|
|
@ -250,6 +387,20 @@ func (p *peerController) run(ctx context.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
func (p *peerController) incrCounter(event eventType) {
|
||||
for _, counter := range p.rateCounters {
|
||||
counter.Incr(event)
|
||||
}
|
||||
}
|
||||
|
||||
func getRate(maxHourlyRate int64) rate.Limit {
|
||||
if maxHourlyRate == 0 {
|
||||
return rate.Inf
|
||||
}
|
||||
|
||||
return rate.Limit(float64(maxHourlyRate) / 3600)
|
||||
}
|
||||
|
||||
func (p *peerController) forward(event interceptEvent) error {
|
||||
p.htlcs[event.circuitKey] = struct{}{}
|
||||
|
||||
|
|
@ -277,7 +428,7 @@ func (p *peerController) process(ctx context.Context,
|
|||
}
|
||||
|
||||
func (p *peerController) resolved(ctx context.Context,
|
||||
key circuitKey) error {
|
||||
key resolvedEvent) error {
|
||||
|
||||
select {
|
||||
case p.resolvedChan <- key:
|
||||
|
|
|
|||
300
process.go
|
|
@ -2,11 +2,12 @@ package main
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/sync/errgroup"
|
||||
)
|
||||
|
||||
|
|
@ -15,6 +16,8 @@ var (
|
|||
ctxb = context.Background()
|
||||
)
|
||||
|
||||
const burstSize = 10
|
||||
|
||||
type lndclient interface {
|
||||
getIdentity() (route.Vertex, error)
|
||||
|
||||
|
|
@ -22,15 +25,12 @@ type lndclient interface {
|
|||
|
||||
getNodeAlias(key route.Vertex) (string, error)
|
||||
|
||||
subscribeHtlcEvents(ctx context.Context,
|
||||
in *routerrpc.SubscribeHtlcEventsRequest) (
|
||||
routerrpc.Router_SubscribeHtlcEventsClient, error)
|
||||
subscribeHtlcEvents(ctx context.Context) (htlcEventsClient, error)
|
||||
|
||||
htlcInterceptor(ctx context.Context) (
|
||||
routerrpc.Router_HtlcInterceptorClient, error)
|
||||
htlcInterceptor(ctx context.Context) (htlcInterceptorClient, error)
|
||||
|
||||
getPendingIncomingHtlcs(ctx context.Context, peer *route.Vertex) (
|
||||
map[circuitKey]struct{}, error)
|
||||
map[route.Vertex]map[circuitKey]struct{}, error)
|
||||
}
|
||||
|
||||
type circuitKey struct {
|
||||
|
|
@ -40,16 +40,31 @@ type circuitKey struct {
|
|||
|
||||
type interceptEvent struct {
|
||||
circuitKey
|
||||
valueMsat int64
|
||||
resume func(bool) error
|
||||
resume func(bool) error
|
||||
}
|
||||
|
||||
type resolvedEvent struct {
|
||||
circuitKey
|
||||
settled bool
|
||||
}
|
||||
|
||||
type rateCounters struct {
|
||||
counters map[route.Vertex]*peerState
|
||||
}
|
||||
|
||||
type rateCountersRequest struct {
|
||||
counters chan *rateCounters
|
||||
}
|
||||
|
||||
type process struct {
|
||||
client lndclient
|
||||
cfg *config
|
||||
limits *Limits
|
||||
log *zap.SugaredLogger
|
||||
|
||||
interceptChan chan interceptEvent
|
||||
resolveChan chan circuitKey
|
||||
interceptChan chan interceptEvent
|
||||
resolveChan chan resolvedEvent
|
||||
updateLimitChan chan updateLimitEvent
|
||||
rateCountersRequestChan chan rateCountersRequest
|
||||
|
||||
identity route.Vertex
|
||||
chanMap map[uint64]*channel
|
||||
|
|
@ -57,39 +72,70 @@ type process struct {
|
|||
|
||||
peerCtrls map[route.Vertex]*peerController
|
||||
|
||||
burstSize int
|
||||
|
||||
// Testing hook
|
||||
resolvedCallback func()
|
||||
}
|
||||
|
||||
func newProcess(client lndclient, cfg *config) *process {
|
||||
func NewProcess(client lndclient, log *zap.SugaredLogger, limits *Limits) *process {
|
||||
return &process{
|
||||
interceptChan: make(chan interceptEvent),
|
||||
resolveChan: make(chan circuitKey),
|
||||
chanMap: make(map[uint64]*channel),
|
||||
aliasMap: make(map[route.Vertex]string),
|
||||
client: client,
|
||||
cfg: cfg,
|
||||
peerCtrls: make(map[route.Vertex]*peerController),
|
||||
log: log,
|
||||
client: client,
|
||||
interceptChan: make(chan interceptEvent),
|
||||
resolveChan: make(chan resolvedEvent),
|
||||
updateLimitChan: make(chan updateLimitEvent),
|
||||
rateCountersRequestChan: make(chan rateCountersRequest),
|
||||
chanMap: make(map[uint64]*channel),
|
||||
aliasMap: make(map[route.Vertex]string),
|
||||
peerCtrls: make(map[route.Vertex]*peerController),
|
||||
limits: limits,
|
||||
burstSize: burstSize,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *process) run(ctx context.Context) error {
|
||||
log.Info("CircuitBreaker started")
|
||||
type updateLimitEvent struct {
|
||||
limit *Limit
|
||||
peer *route.Vertex
|
||||
}
|
||||
|
||||
func (p *process) UpdateLimit(ctx context.Context, peer *route.Vertex,
|
||||
limit *Limit) error {
|
||||
|
||||
if peer == nil && limit == nil {
|
||||
return errors.New("cannot clear default limit")
|
||||
}
|
||||
|
||||
update := updateLimitEvent{
|
||||
limit: limit,
|
||||
peer: peer,
|
||||
}
|
||||
|
||||
select {
|
||||
case p.updateLimitChan <- update:
|
||||
return nil
|
||||
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *process) Run(ctx context.Context) error {
|
||||
p.log.Info("CircuitBreaker started")
|
||||
|
||||
var err error
|
||||
|
||||
p.identity, err = p.client.getIdentity()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Infow("Connected to lnd node",
|
||||
p.log.Infow("Connected to lnd node",
|
||||
"pubkey", p.identity.String())
|
||||
|
||||
group, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
stream, err := p.client.subscribeHtlcEvents(
|
||||
ctx, &routerrpc.SubscribeHtlcEventsRequest{},
|
||||
)
|
||||
stream, err := p.client.subscribeHtlcEvents(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -99,7 +145,7 @@ func (p *process) run(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
log.Info("Interceptor/notification handlers registered")
|
||||
p.log.Info("Interceptor/notification handlers registered")
|
||||
|
||||
group.Go(func() error {
|
||||
err := p.processHtlcEvents(ctx, stream)
|
||||
|
|
@ -143,21 +189,18 @@ func (p *process) getPeerController(ctx context.Context, peer route.Vertex,
|
|||
func (p *process) createPeerController(ctx context.Context, peer route.Vertex,
|
||||
startGo func(func() error), htlcs map[circuitKey]struct{}) *peerController {
|
||||
|
||||
peerCfg := p.cfg.forPeer(peer)
|
||||
|
||||
alias := p.getNodeAlias(peer)
|
||||
|
||||
logger := log.With(
|
||||
"peer_alias", alias,
|
||||
"peer", peer.String(),
|
||||
)
|
||||
peerCfg, ok := p.limits.PerPeer[peer]
|
||||
if !ok {
|
||||
peerCfg = p.limits.Default
|
||||
}
|
||||
|
||||
cfg := &peerControllerCfg{
|
||||
logger: logger,
|
||||
cfg: peerCfg,
|
||||
htlcs: htlcs,
|
||||
lnd: p.client,
|
||||
pubKey: peer,
|
||||
logger: p.log,
|
||||
limit: peerCfg,
|
||||
burstSize: p.burstSize,
|
||||
htlcs: htlcs,
|
||||
lnd: p.client,
|
||||
pubKey: peer,
|
||||
}
|
||||
ctrl := newPeerController(cfg)
|
||||
|
||||
|
|
@ -178,28 +221,11 @@ func (p *process) eventLoop(ctx context.Context) error {
|
|||
}()
|
||||
|
||||
// Retrieve all pending htlcs from lnd.
|
||||
allHtlcs, err := p.client.getPendingIncomingHtlcs(ctx, nil)
|
||||
htlcsPerPeer, err := p.client.getPendingIncomingHtlcs(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Arrange htlcs per peer.
|
||||
htlcsPerPeer := make(map[route.Vertex]map[circuitKey]struct{})
|
||||
for h := range allHtlcs {
|
||||
peer, err := p.getChanInfo(h.channel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
htlcs := htlcsPerPeer[peer.peer]
|
||||
if htlcs == nil {
|
||||
htlcs = make(map[circuitKey]struct{})
|
||||
htlcsPerPeer[peer.peer] = htlcs
|
||||
}
|
||||
|
||||
htlcs[h] = struct{}{}
|
||||
}
|
||||
|
||||
// Initialize peer controllers with currently pending htlcs.
|
||||
for peer, htlcs := range htlcsPerPeer {
|
||||
p.createPeerController(ctx, peer, group.Go, htlcs)
|
||||
|
|
@ -223,15 +249,15 @@ func (p *process) eventLoop(ctx context.Context) error {
|
|||
return err
|
||||
}
|
||||
|
||||
case resolvedKey := <-p.resolveChan:
|
||||
chanInfo, err := p.getChanInfo(resolvedKey.channel)
|
||||
case resolvedEvent := <-p.resolveChan:
|
||||
chanInfo, err := p.getChanInfo(resolvedEvent.channel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctrl := p.getPeerController(ctx, chanInfo.peer, group.Go)
|
||||
|
||||
if err := ctrl.resolved(ctx, resolvedKey); err != nil {
|
||||
if err := ctrl.resolved(ctx, resolvedEvent); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -239,40 +265,106 @@ func (p *process) eventLoop(ctx context.Context) error {
|
|||
p.resolvedCallback()
|
||||
}
|
||||
|
||||
case update := <-p.updateLimitChan:
|
||||
switch {
|
||||
// Update sets default limit.
|
||||
case update.peer == nil:
|
||||
p.limits.Default = *update.limit
|
||||
|
||||
// Update all controllers that have no specific limit.
|
||||
for node, ctrl := range p.peerCtrls {
|
||||
_, ok := p.limits.PerPeer[node]
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
|
||||
err := ctrl.updateLimit(ctx, *update.limit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Update sets specific limit.
|
||||
case update.limit != nil:
|
||||
p.limits.PerPeer[*update.peer] = *update.limit
|
||||
|
||||
// Update specific controller if it exists.
|
||||
ctrl, ok := p.peerCtrls[*update.peer]
|
||||
if ok {
|
||||
err := ctrl.updateLimit(ctx, *update.limit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Update clears limit.
|
||||
case update.limit == nil:
|
||||
delete(p.limits.PerPeer, *update.peer)
|
||||
|
||||
// Apply default limit to peer controller.
|
||||
ctrl, ok := p.peerCtrls[*update.peer]
|
||||
if ok {
|
||||
err := ctrl.updateLimit(ctx, p.limits.Default)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case req := <-p.rateCountersRequestChan:
|
||||
allCounts := make(map[route.Vertex]*peerState)
|
||||
for node, ctrl := range p.peerCtrls {
|
||||
state, err := ctrl.state(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
allCounts[node] = state
|
||||
}
|
||||
|
||||
req.counters <- &rateCounters{
|
||||
counters: allCounts,
|
||||
}
|
||||
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *process) getRateCounters(ctx context.Context) (
|
||||
map[route.Vertex]*peerState, error) {
|
||||
|
||||
replyChan := make(chan *rateCounters)
|
||||
|
||||
select {
|
||||
case p.rateCountersRequestChan <- rateCountersRequest{
|
||||
counters: replyChan,
|
||||
}:
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
|
||||
select {
|
||||
case reply := <-replyChan:
|
||||
return reply.counters, nil
|
||||
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *process) processHtlcEvents(ctx context.Context,
|
||||
stream routerrpc.Router_SubscribeHtlcEventsClient) error {
|
||||
stream htlcEventsClient) error {
|
||||
|
||||
for {
|
||||
event, err := stream.Recv()
|
||||
event, err := stream.recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if event.EventType != routerrpc.HtlcEvent_FORWARD {
|
||||
continue
|
||||
}
|
||||
|
||||
switch event.Event.(type) {
|
||||
case *routerrpc.HtlcEvent_SettleEvent:
|
||||
case *routerrpc.HtlcEvent_ForwardFailEvent:
|
||||
case *routerrpc.HtlcEvent_LinkFailEvent:
|
||||
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
select {
|
||||
case p.resolveChan <- circuitKey{
|
||||
channel: event.IncomingChannelId,
|
||||
htlc: event.IncomingHtlcId,
|
||||
}:
|
||||
|
||||
case p.resolveChan <- *event:
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
|
|
@ -280,39 +372,26 @@ func (p *process) processHtlcEvents(ctx context.Context,
|
|||
}
|
||||
|
||||
func (p *process) processInterceptor(ctx context.Context,
|
||||
interceptor routerrpc.Router_HtlcInterceptorClient) error {
|
||||
interceptor htlcInterceptorClient) error {
|
||||
|
||||
for {
|
||||
event, err := interceptor.Recv()
|
||||
event, err := interceptor.recv()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
key := circuitKey{
|
||||
channel: event.IncomingCircuitKey.ChanId,
|
||||
htlc: event.IncomingCircuitKey.HtlcId,
|
||||
}
|
||||
key := event.circuitKey
|
||||
|
||||
resume := func(resume bool) error {
|
||||
response := &routerrpc.ForwardHtlcInterceptResponse{
|
||||
IncomingCircuitKey: &routerrpc.CircuitKey{
|
||||
ChanId: key.channel,
|
||||
HtlcId: key.htlc,
|
||||
},
|
||||
}
|
||||
if resume {
|
||||
response.Action = routerrpc.ResolveHoldForwardAction_RESUME
|
||||
} else {
|
||||
response.Action = routerrpc.ResolveHoldForwardAction_FAIL
|
||||
}
|
||||
|
||||
return interceptor.Send(response)
|
||||
return interceptor.send(&interceptResponse{
|
||||
key: key,
|
||||
resume: resume,
|
||||
})
|
||||
}
|
||||
|
||||
select {
|
||||
case p.interceptChan <- interceptEvent{
|
||||
circuitKey: key,
|
||||
valueMsat: int64(event.OutgoingAmountMsat),
|
||||
resume: resume,
|
||||
}:
|
||||
|
||||
|
|
@ -322,25 +401,6 @@ func (p *process) processInterceptor(ctx context.Context,
|
|||
}
|
||||
}
|
||||
|
||||
func (p *process) getNodeAlias(key route.Vertex) string {
|
||||
alias, ok := p.aliasMap[key]
|
||||
if ok {
|
||||
return alias
|
||||
}
|
||||
|
||||
alias, err := p.client.getNodeAlias(key)
|
||||
if err != nil {
|
||||
log.Warnw("cannot get node alias",
|
||||
"err", err)
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
p.aliasMap[key] = alias
|
||||
|
||||
return alias
|
||||
}
|
||||
|
||||
func (p *process) getChanInfo(channel uint64) (*channel, error) {
|
||||
// Try to look up from the cache.
|
||||
ch, ok := p.chanMap[channel]
|
||||
|
|
|
|||
148
process_test.go
|
|
@ -5,8 +5,9 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func TestProcess(t *testing.T) {
|
||||
|
|
@ -32,17 +33,27 @@ const (
|
|||
)
|
||||
|
||||
func testProcess(t *testing.T, event resolveEvent) {
|
||||
cfg := &config{
|
||||
groupConfig: groupConfig{
|
||||
MaxPendingHtlcs: 2,
|
||||
},
|
||||
}
|
||||
|
||||
client := newLndclientMock()
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
p := newProcess(client, cfg)
|
||||
log, err := zap.NewDevelopment()
|
||||
require.NoError(t, err)
|
||||
|
||||
cfg := &Limits{
|
||||
PerPeer: map[route.Vertex]Limit{
|
||||
{2}: {
|
||||
MaxHourlyRate: 60,
|
||||
MaxPending: 1,
|
||||
},
|
||||
{3}: {
|
||||
MaxHourlyRate: 60,
|
||||
MaxPending: 1,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
p := NewProcess(client, log.Sugar(), cfg)
|
||||
|
||||
resolved := make(chan struct{})
|
||||
p.resolvedCallback = func() {
|
||||
|
|
@ -51,35 +62,33 @@ func testProcess(t *testing.T, event resolveEvent) {
|
|||
|
||||
exit := make(chan error)
|
||||
go func() {
|
||||
exit <- p.run(ctx)
|
||||
exit <- p.Run(ctx)
|
||||
}()
|
||||
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: 2,
|
||||
HtlcId: 5,
|
||||
key := circuitKey{
|
||||
channel: 2,
|
||||
htlc: 5,
|
||||
}
|
||||
client.htlcInterceptorRequests <- &routerrpc.ForwardHtlcInterceptRequest{
|
||||
IncomingCircuitKey: key,
|
||||
client.htlcInterceptorRequests <- &interceptedEvent{
|
||||
circuitKey: key,
|
||||
}
|
||||
|
||||
resp := <-client.htlcInterceptorResponses
|
||||
require.Equal(t, routerrpc.ResolveHoldForwardAction_RESUME, resp.Action)
|
||||
require.True(t, resp.resume)
|
||||
|
||||
htlcEvent := &routerrpc.HtlcEvent{
|
||||
EventType: routerrpc.HtlcEvent_FORWARD,
|
||||
IncomingChannelId: key.ChanId,
|
||||
IncomingHtlcId: key.HtlcId,
|
||||
htlcEvent := &resolvedEvent{
|
||||
circuitKey: key,
|
||||
}
|
||||
|
||||
switch event {
|
||||
case resolveEventForwardFail:
|
||||
htlcEvent.Event = &routerrpc.HtlcEvent_ForwardFailEvent{}
|
||||
htlcEvent.settled = false
|
||||
|
||||
case resolveEventLinkFail:
|
||||
htlcEvent.Event = &routerrpc.HtlcEvent_LinkFailEvent{}
|
||||
htlcEvent.settled = false
|
||||
|
||||
case resolveEventSettle:
|
||||
htlcEvent.Event = &routerrpc.HtlcEvent_SettleEvent{}
|
||||
htlcEvent.settled = true
|
||||
}
|
||||
|
||||
client.htlcEvents <- htlcEvent
|
||||
|
|
@ -102,11 +111,16 @@ func TestLimits(t *testing.T) {
|
|||
func testRateLimit(t *testing.T, mode Mode) {
|
||||
defer Timeout()()
|
||||
|
||||
cfg := &config{
|
||||
groupConfig: groupConfig{
|
||||
HtlcMinInterval: 2 * time.Second,
|
||||
HtlcBurstSize: 2,
|
||||
Mode: mode,
|
||||
cfg := &Limits{
|
||||
PerPeer: map[route.Vertex]Limit{
|
||||
{2}: {
|
||||
MaxHourlyRate: 1800,
|
||||
Mode: mode,
|
||||
},
|
||||
{3}: {
|
||||
MaxHourlyRate: 1800,
|
||||
Mode: mode,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -114,11 +128,15 @@ func testRateLimit(t *testing.T, mode Mode) {
|
|||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
p := newProcess(client, cfg)
|
||||
log, err := zap.NewDevelopment()
|
||||
require.NoError(t, err)
|
||||
|
||||
p := NewProcess(client, log.Sugar(), cfg)
|
||||
p.burstSize = 2
|
||||
|
||||
exit := make(chan error)
|
||||
go func() {
|
||||
exit <- p.run(ctx)
|
||||
exit <- p.Run(ctx)
|
||||
}()
|
||||
|
||||
var chanId uint64 = 2
|
||||
|
|
@ -128,27 +146,27 @@ func testRateLimit(t *testing.T, mode Mode) {
|
|||
chanId = 3
|
||||
}
|
||||
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: chanId,
|
||||
HtlcId: 5,
|
||||
key := circuitKey{
|
||||
channel: chanId,
|
||||
htlc: 5,
|
||||
}
|
||||
interceptReq := &routerrpc.ForwardHtlcInterceptRequest{
|
||||
IncomingCircuitKey: key,
|
||||
interceptReq := &interceptedEvent{
|
||||
circuitKey: key,
|
||||
}
|
||||
|
||||
// First htlc accepted.
|
||||
client.htlcInterceptorRequests <- interceptReq
|
||||
resp := <-client.htlcInterceptorResponses
|
||||
require.Equal(t, routerrpc.ResolveHoldForwardAction_RESUME, resp.Action)
|
||||
require.True(t, resp.resume)
|
||||
|
||||
// Second htlc right after is also accepted because of burst size 2.
|
||||
interceptReq.IncomingCircuitKey.HtlcId++
|
||||
interceptReq.circuitKey.htlc++
|
||||
client.htlcInterceptorRequests <- interceptReq
|
||||
resp = <-client.htlcInterceptorResponses
|
||||
require.Equal(t, routerrpc.ResolveHoldForwardAction_RESUME, resp.Action)
|
||||
require.True(t, resp.resume)
|
||||
|
||||
// Third htlc again right after should hit the rate limit.
|
||||
interceptReq.IncomingCircuitKey.HtlcId++
|
||||
interceptReq.circuitKey.htlc++
|
||||
client.htlcInterceptorRequests <- interceptReq
|
||||
|
||||
interceptStart := time.Now()
|
||||
|
|
@ -156,16 +174,14 @@ func testRateLimit(t *testing.T, mode Mode) {
|
|||
resp = <-client.htlcInterceptorResponses
|
||||
|
||||
if mode == ModeQueue {
|
||||
require.Equal(t, routerrpc.ResolveHoldForwardAction_RESUME, resp.Action)
|
||||
require.True(t, resp.resume)
|
||||
require.GreaterOrEqual(t, time.Since(interceptStart), time.Second)
|
||||
} else {
|
||||
require.Equal(t, routerrpc.ResolveHoldForwardAction_FAIL, resp.Action)
|
||||
require.False(t, resp.resume)
|
||||
|
||||
htlcEvent := &routerrpc.HtlcEvent{
|
||||
EventType: routerrpc.HtlcEvent_FORWARD,
|
||||
IncomingChannelId: key.ChanId,
|
||||
IncomingHtlcId: key.HtlcId,
|
||||
Event: &routerrpc.HtlcEvent_ForwardFailEvent{},
|
||||
htlcEvent := &resolvedEvent{
|
||||
circuitKey: key,
|
||||
settled: false,
|
||||
}
|
||||
|
||||
client.htlcEvents <- htlcEvent
|
||||
|
|
@ -182,12 +198,18 @@ func testRateLimit(t *testing.T, mode Mode) {
|
|||
func testMaxPending(t *testing.T, mode Mode) {
|
||||
defer Timeout()()
|
||||
|
||||
cfg := &config{
|
||||
groupConfig: groupConfig{
|
||||
HtlcMinInterval: time.Minute,
|
||||
HtlcBurstSize: 2,
|
||||
MaxPendingHtlcs: 1,
|
||||
Mode: mode,
|
||||
cfg := &Limits{
|
||||
PerPeer: map[route.Vertex]Limit{
|
||||
{2}: {
|
||||
MaxHourlyRate: 60,
|
||||
MaxPending: 1,
|
||||
Mode: mode,
|
||||
},
|
||||
{3}: {
|
||||
MaxHourlyRate: 60,
|
||||
MaxPending: 1,
|
||||
Mode: mode,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -195,11 +217,15 @@ func testMaxPending(t *testing.T, mode Mode) {
|
|||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
p := newProcess(client, cfg)
|
||||
log, err := zap.NewDevelopment()
|
||||
require.NoError(t, err)
|
||||
|
||||
p := NewProcess(client, log.Sugar(), cfg)
|
||||
p.burstSize = 2
|
||||
|
||||
exit := make(chan error)
|
||||
go func() {
|
||||
exit <- p.run(ctx)
|
||||
exit <- p.Run(ctx)
|
||||
}()
|
||||
|
||||
var chanId uint64 = 2
|
||||
|
|
@ -209,21 +235,21 @@ func testMaxPending(t *testing.T, mode Mode) {
|
|||
chanId = 3
|
||||
}
|
||||
|
||||
key := &routerrpc.CircuitKey{
|
||||
ChanId: chanId,
|
||||
HtlcId: 5,
|
||||
key := circuitKey{
|
||||
channel: chanId,
|
||||
htlc: 5,
|
||||
}
|
||||
interceptReq := &routerrpc.ForwardHtlcInterceptRequest{
|
||||
IncomingCircuitKey: key,
|
||||
interceptReq := &interceptedEvent{
|
||||
circuitKey: key,
|
||||
}
|
||||
|
||||
// First htlc accepted.
|
||||
client.htlcInterceptorRequests <- interceptReq
|
||||
resp := <-client.htlcInterceptorResponses
|
||||
require.Equal(t, routerrpc.ResolveHoldForwardAction_RESUME, resp.Action)
|
||||
require.True(t, resp.resume)
|
||||
|
||||
// Second htlc should be hitting the max pending htlcs limit.
|
||||
interceptReq.IncomingCircuitKey.HtlcId++
|
||||
interceptReq.circuitKey.htlc++
|
||||
client.htlcInterceptorRequests <- interceptReq
|
||||
|
||||
if mode == ModeQueue {
|
||||
|
|
@ -235,7 +261,7 @@ func testMaxPending(t *testing.T, mode Mode) {
|
|||
}
|
||||
} else {
|
||||
resp = <-client.htlcInterceptorResponses
|
||||
require.Equal(t, routerrpc.ResolveHoldForwardAction_FAIL, resp.Action)
|
||||
require.False(t, resp.resume)
|
||||
}
|
||||
|
||||
cancel()
|
||||
|
|
|
|||
179
run.go
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"embed"
|
||||
"io/fs"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/lightningequipment/circuitbreaker/circuitbreakerrpc"
|
||||
"github.com/urfave/cli"
|
||||
"golang.org/x/sync/errgroup"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
//go:embed webui-build
|
||||
var content embed.FS
|
||||
|
||||
func run(c *cli.Context) error {
|
||||
ctx := context.Background()
|
||||
|
||||
confDir := c.String("configdir")
|
||||
err := os.MkdirAll(confDir, os.ModePerm)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
dbPath := filepath.Join(confDir, dbFn)
|
||||
|
||||
log.Infow("Opening database", "path", dbPath)
|
||||
|
||||
// Open database.
|
||||
db, err := NewDb(dbPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stub := c.Bool(stubFlag.Name)
|
||||
var client lndclient
|
||||
if stub {
|
||||
stubClient := newStubClient()
|
||||
|
||||
client = stubClient
|
||||
} else {
|
||||
// First, we'll parse the args from the command.
|
||||
tlsCertPath, macPath, err := extractPathArgs(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
lndCfg := LndConfig{
|
||||
RpcServer: c.GlobalString("rpcserver"),
|
||||
TlsCertPath: tlsCertPath,
|
||||
MacPath: macPath,
|
||||
Log: log,
|
||||
}
|
||||
|
||||
lndClient, err := NewLndClient(&lndCfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer lndClient.Close()
|
||||
|
||||
client = lndClient
|
||||
}
|
||||
|
||||
limits, err := db.GetLimits(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p := NewProcess(client, log, limits)
|
||||
|
||||
grpcServer := grpc.NewServer(
|
||||
grpc.StreamInterceptor(grpc_middleware.ChainStreamServer()),
|
||||
grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer()),
|
||||
)
|
||||
|
||||
reflection.Register(grpcServer)
|
||||
|
||||
server := NewServer(log, p, client, db)
|
||||
|
||||
circuitbreakerrpc.RegisterServiceServer(
|
||||
grpcServer, server,
|
||||
)
|
||||
|
||||
listenAddress := c.String("listen")
|
||||
grpcInternalListener, err := net.Listen("tcp", listenAddress)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a client connection to the gRPC server we just started
|
||||
// This is where the gRPC-Gateway proxies the requests
|
||||
conn, err := grpc.DialContext(
|
||||
ctx,
|
||||
listenAddress,
|
||||
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create http server.
|
||||
gwmux := runtime.NewServeMux()
|
||||
|
||||
err = circuitbreakerrpc.RegisterServiceHandler(ctx, gwmux, conn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
serverRoot, err := fs.Sub(content, "webui-build")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
fs := http.FileServer(http.FS(serverRoot))
|
||||
mux := http.NewServeMux()
|
||||
mux.Handle("/api/", http.StripPrefix("/api", gwmux))
|
||||
mux.HandleFunc("/", fs.ServeHTTP)
|
||||
|
||||
httpListen := c.String(httpListenFlag.Name)
|
||||
gwServer := &http.Server{
|
||||
Addr: httpListen,
|
||||
Handler: mux,
|
||||
ReadHeaderTimeout: time.Second * 10,
|
||||
}
|
||||
|
||||
group, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
// Run circuitbreaker core.
|
||||
group.Go(func() error {
|
||||
return p.Run(ctx)
|
||||
})
|
||||
|
||||
// Run grpc server.
|
||||
group.Go(func() error {
|
||||
log.Infow("Grpc server starting", "listenAddress", listenAddress)
|
||||
err := grpcServer.Serve(grpcInternalListener)
|
||||
if err != nil && err != grpc.ErrServerStopped {
|
||||
log.Errorw("grpc server error", "err", err)
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
// Run http server.
|
||||
group.Go(func() error {
|
||||
log.Infow("HTTP server starting", "listenAddress", httpListen)
|
||||
|
||||
return gwServer.ListenAndServe()
|
||||
})
|
||||
|
||||
// Stop servers when context is cancelled.
|
||||
group.Go(func() error {
|
||||
<-ctx.Done()
|
||||
|
||||
// Stop http server.
|
||||
log.Infof("Stopping http server")
|
||||
err := gwServer.Shutdown(context.Background()) //nolint:contextcheck
|
||||
if err != nil {
|
||||
log.Errorw("Error shutting down http server", "err", err)
|
||||
}
|
||||
|
||||
// Stop grpc server.
|
||||
log.Infof("Stopping grpc server")
|
||||
grpcServer.Stop()
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return group.Wait()
|
||||
}
|
||||
BIN
screenshot.png
Normal file
|
After Width: | Height: | Size: 141 KiB |
290
server.go
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"github.com/lightningequipment/circuitbreaker/circuitbreakerrpc"
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type server struct {
|
||||
process *process
|
||||
lnd lndclient
|
||||
db *Db
|
||||
log *zap.SugaredLogger
|
||||
|
||||
aliases map[route.Vertex]string
|
||||
aliasesLock sync.Mutex
|
||||
|
||||
circuitbreakerrpc.UnimplementedServiceServer
|
||||
}
|
||||
|
||||
func NewServer(log *zap.SugaredLogger, process *process,
|
||||
lnd lndclient, db *Db) *server {
|
||||
|
||||
return &server{
|
||||
process: process,
|
||||
lnd: lnd,
|
||||
db: db,
|
||||
log: log,
|
||||
aliases: make(map[route.Vertex]string),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) getAlias(key route.Vertex) (string, error) {
|
||||
s.aliasesLock.Lock()
|
||||
defer s.aliasesLock.Unlock()
|
||||
|
||||
alias, ok := s.aliases[key]
|
||||
if ok {
|
||||
return alias, nil
|
||||
}
|
||||
|
||||
alias, err := s.lnd.getNodeAlias(key)
|
||||
switch {
|
||||
case err == ErrNodeNotFound:
|
||||
|
||||
case err != nil:
|
||||
return "", err
|
||||
}
|
||||
|
||||
s.aliases[key] = alias
|
||||
|
||||
return alias, nil
|
||||
}
|
||||
|
||||
func (s *server) GetInfo(ctx context.Context,
|
||||
req *circuitbreakerrpc.GetInfoRequest) (*circuitbreakerrpc.GetInfoResponse,
|
||||
error) {
|
||||
|
||||
key, err := s.lnd.getIdentity()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &circuitbreakerrpc.GetInfoResponse{
|
||||
ConnectedNode: hex.EncodeToString(key[:]),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func unmarshalLimit(rpcLimit *circuitbreakerrpc.Limit) (Limit, error) {
|
||||
limit := Limit{
|
||||
MaxHourlyRate: rpcLimit.MaxHourlyRate,
|
||||
MaxPending: rpcLimit.MaxPending,
|
||||
}
|
||||
|
||||
switch rpcLimit.Mode {
|
||||
case circuitbreakerrpc.Mode_MODE_FAIL:
|
||||
limit.Mode = ModeFail
|
||||
|
||||
case circuitbreakerrpc.Mode_MODE_QUEUE:
|
||||
limit.Mode = ModeQueue
|
||||
|
||||
case circuitbreakerrpc.Mode_MODE_QUEUE_PEER_INITIATED:
|
||||
limit.Mode = ModeQueuePeerInitiated
|
||||
|
||||
default:
|
||||
return Limit{}, errors.New("unknown mode")
|
||||
}
|
||||
|
||||
return limit, nil
|
||||
}
|
||||
|
||||
func (s *server) UpdateLimit(ctx context.Context,
|
||||
req *circuitbreakerrpc.UpdateLimitRequest) (
|
||||
*circuitbreakerrpc.UpdateLimitResponse, error) {
|
||||
|
||||
node, err := route.NewVertexFromStr(req.Node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if node == defaultNodeKey {
|
||||
return nil, errors.New("set default limit through UpdateDefaultLimit")
|
||||
}
|
||||
|
||||
if req.Limit == nil {
|
||||
return nil, errors.New("no limit specified")
|
||||
}
|
||||
|
||||
limit, err := unmarshalLimit(req.Limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.log.Infow("Updating limit", "node", node, "limit", limit)
|
||||
|
||||
err = s.db.UpdateLimit(ctx, node, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.process.UpdateLimit(ctx, &node, &limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &circuitbreakerrpc.UpdateLimitResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *server) ClearLimit(ctx context.Context,
|
||||
req *circuitbreakerrpc.ClearLimitRequest) (
|
||||
*circuitbreakerrpc.ClearLimitResponse, error) {
|
||||
|
||||
node, err := route.NewVertexFromStr(req.Node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.log.Infow("Clearing limit", "node", node)
|
||||
|
||||
err = s.db.ClearLimit(ctx, node)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.process.UpdateLimit(ctx, &node, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &circuitbreakerrpc.ClearLimitResponse{}, nil
|
||||
}
|
||||
|
||||
func (s *server) UpdateDefaultLimit(ctx context.Context,
|
||||
req *circuitbreakerrpc.UpdateDefaultLimitRequest) (
|
||||
*circuitbreakerrpc.UpdateDefaultLimitResponse, error) {
|
||||
|
||||
limit, err := unmarshalLimit(req.Limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.log.Infow("Updating default limit", "limit", limit)
|
||||
|
||||
err = s.db.UpdateLimit(ctx, defaultNodeKey, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = s.process.UpdateLimit(ctx, nil, &limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &circuitbreakerrpc.UpdateDefaultLimitResponse{}, nil
|
||||
}
|
||||
|
||||
func marshalLimit(limit Limit) (*circuitbreakerrpc.Limit, error) {
|
||||
rpcLimit := &circuitbreakerrpc.Limit{
|
||||
MaxHourlyRate: limit.MaxHourlyRate,
|
||||
MaxPending: limit.MaxPending,
|
||||
}
|
||||
|
||||
switch limit.Mode {
|
||||
case ModeFail:
|
||||
rpcLimit.Mode = circuitbreakerrpc.Mode_MODE_FAIL
|
||||
|
||||
case ModeQueue:
|
||||
rpcLimit.Mode = circuitbreakerrpc.Mode_MODE_QUEUE
|
||||
|
||||
case ModeQueuePeerInitiated:
|
||||
rpcLimit.Mode = circuitbreakerrpc.Mode_MODE_QUEUE_PEER_INITIATED
|
||||
|
||||
default:
|
||||
return nil, errors.New("unknown mode")
|
||||
}
|
||||
|
||||
return rpcLimit, nil
|
||||
}
|
||||
|
||||
func (s *server) ListLimits(ctx context.Context,
|
||||
req *circuitbreakerrpc.ListLimitsRequest) (
|
||||
*circuitbreakerrpc.ListLimitsResponse, error) {
|
||||
|
||||
limits, err := s.db.GetLimits(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
counters, err := s.process.getRateCounters(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
marshalCounter := func(count rateCounts) *circuitbreakerrpc.Counter {
|
||||
return &circuitbreakerrpc.Counter{
|
||||
Success: count.success,
|
||||
Fail: count.fail,
|
||||
Reject: count.reject,
|
||||
}
|
||||
}
|
||||
|
||||
var rpcLimits = []*circuitbreakerrpc.NodeLimit{}
|
||||
|
||||
createRpcState := func(peer route.Vertex, state *peerState) (
|
||||
*circuitbreakerrpc.NodeLimit, error) {
|
||||
|
||||
alias, err := s.getAlias(peer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &circuitbreakerrpc.NodeLimit{
|
||||
Node: hex.EncodeToString(peer[:]),
|
||||
Alias: alias,
|
||||
Counter_1H: marshalCounter(state.counts[0]),
|
||||
Counter_24H: marshalCounter(state.counts[1]),
|
||||
QueueLen: state.queueLen,
|
||||
PendingHtlcCount: state.pendingHtlcCount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
for peer, limit := range limits.PerPeer {
|
||||
counts, ok := counters[peer]
|
||||
if !ok {
|
||||
// Report all zeroes.
|
||||
counts = &peerState{
|
||||
counts: make([]rateCounts, len(rateCounterIntervals)),
|
||||
}
|
||||
}
|
||||
|
||||
rpcState, err := createRpcState(peer, counts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rpcLimit, err := marshalLimit(limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rpcState.Limit = rpcLimit
|
||||
|
||||
delete(counters, peer)
|
||||
|
||||
rpcLimits = append(rpcLimits, rpcState)
|
||||
}
|
||||
|
||||
for peer, counts := range counters {
|
||||
rpcLimit, err := createRpcState(peer, counts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rpcLimits = append(rpcLimits, rpcLimit)
|
||||
}
|
||||
|
||||
defaultLimit, err := marshalLimit(limits.Default)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &circuitbreakerrpc.ListLimitsResponse{
|
||||
DefaultLimit: defaultLimit,
|
||||
Limits: rpcLimits,
|
||||
}, nil
|
||||
}
|
||||
318
stub.go
Normal file
|
|
@ -0,0 +1,318 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"math/rand"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/lightningnetwork/lnd/routing/route"
|
||||
)
|
||||
|
||||
var stubNodes = []string{
|
||||
"WalletOfSatoshi.com",
|
||||
"deezy.io",
|
||||
"🕊️ born to be free 🕊️",
|
||||
"c-otto.de",
|
||||
"BCash_Is_Trash",
|
||||
"1sats.com 🤩 0 fee",
|
||||
"NordicRails",
|
||||
"Stone Of Jordan",
|
||||
"Mushi",
|
||||
}
|
||||
|
||||
type stubChannel struct {
|
||||
initiator bool
|
||||
}
|
||||
|
||||
type stubLndClient struct {
|
||||
peers map[route.Vertex]*stubPeer
|
||||
chanMap map[uint64]route.Vertex
|
||||
|
||||
pendingHtlcs map[route.Vertex]map[circuitKey]struct{}
|
||||
pendingHtlcsLock sync.Mutex
|
||||
|
||||
eventChan chan *resolvedEvent
|
||||
interceptRequestChan chan *interceptedEvent
|
||||
interceptResponseChan chan *interceptResponse
|
||||
}
|
||||
|
||||
type stubPeer struct {
|
||||
channels map[uint64]*stubChannel
|
||||
alias string
|
||||
}
|
||||
|
||||
func newStubClient() *stubLndClient {
|
||||
peers := make(map[route.Vertex]*stubPeer)
|
||||
chanMap := make(map[uint64]route.Vertex)
|
||||
pendingHtlcs := make(map[route.Vertex]map[circuitKey]struct{})
|
||||
|
||||
var chanId uint64 = 1
|
||||
for _, alias := range stubNodes {
|
||||
// Derive key.
|
||||
hash := sha256.Sum256([]byte(alias))
|
||||
keySlice := append([]byte{0}, hash[:]...)
|
||||
key, err := route.NewVertexFromBytes(keySlice)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Derive channels.
|
||||
channels := make(map[uint64]*stubChannel)
|
||||
channelCount := int(key[5]%5) + 1
|
||||
for i := 0; i < channelCount; i++ {
|
||||
initiator := key[6+i]%2 == 0
|
||||
channels[chanId] = &stubChannel{
|
||||
initiator: initiator,
|
||||
}
|
||||
|
||||
chanMap[chanId] = key
|
||||
|
||||
chanId++
|
||||
}
|
||||
|
||||
peers[key] = &stubPeer{
|
||||
alias: alias,
|
||||
channels: channels,
|
||||
}
|
||||
|
||||
pendingHtlcs[key] = make(map[circuitKey]struct{})
|
||||
|
||||
log.Infow("populated", "peer", alias, "key", key[:])
|
||||
}
|
||||
|
||||
client := &stubLndClient{
|
||||
peers: peers,
|
||||
chanMap: chanMap,
|
||||
|
||||
eventChan: make(chan *resolvedEvent),
|
||||
interceptRequestChan: make(chan *interceptedEvent),
|
||||
interceptResponseChan: make(chan *interceptResponse),
|
||||
|
||||
pendingHtlcs: pendingHtlcs,
|
||||
}
|
||||
|
||||
first := true
|
||||
for key, peer := range peers {
|
||||
// The first peer is in-active.
|
||||
if first {
|
||||
first = false
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
key, peer := key, peer
|
||||
|
||||
go client.generateHtlcs(key, peer)
|
||||
}
|
||||
|
||||
go client.run()
|
||||
|
||||
return client
|
||||
}
|
||||
|
||||
func (s *stubLndClient) run() {
|
||||
for resp := range s.interceptResponseChan {
|
||||
go s.resolveHtlc(resp)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stubLndClient) resolveHtlc(resp *interceptResponse) {
|
||||
if !resp.resume {
|
||||
s.eventChan <- &resolvedEvent{
|
||||
circuitKey: resp.key,
|
||||
settled: false,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Retrieve node key.
|
||||
key, ok := s.chanMap[resp.key.channel]
|
||||
if !ok {
|
||||
panic("peer not found")
|
||||
}
|
||||
|
||||
// Random delay according to profile.
|
||||
delayProfile := int(key[6] % 3)
|
||||
|
||||
time.Sleep(randomDelay(delayProfile))
|
||||
|
||||
// Random settlement according to profile.
|
||||
var settledPerc int32
|
||||
switch key[7] % 3 {
|
||||
case 0:
|
||||
settledPerc = 5
|
||||
|
||||
case 1:
|
||||
settledPerc = 50
|
||||
|
||||
case 2:
|
||||
settledPerc = 90
|
||||
}
|
||||
|
||||
settled := rand.Int31n(100) < settledPerc //nolint: gosec
|
||||
|
||||
s.eventChan <- &resolvedEvent{
|
||||
circuitKey: resp.key,
|
||||
settled: settled,
|
||||
}
|
||||
|
||||
s.pendingHtlcsLock.Lock()
|
||||
delete(s.pendingHtlcs[key], resp.key)
|
||||
s.pendingHtlcsLock.Unlock()
|
||||
}
|
||||
|
||||
func randomDelay(profile int) time.Duration {
|
||||
var delayMinMs, delayMaxMs int32
|
||||
switch profile {
|
||||
case 0:
|
||||
delayMinMs, delayMaxMs = 100, 1000
|
||||
|
||||
case 1:
|
||||
delayMinMs, delayMaxMs = 1000, 5000
|
||||
|
||||
case 2:
|
||||
delayMinMs, delayMaxMs = 5000, 30000
|
||||
}
|
||||
|
||||
return time.Duration(delayMinMs+rand.Int31n(delayMaxMs-delayMinMs)) * //nolint: gosec
|
||||
time.Millisecond
|
||||
}
|
||||
|
||||
func (s *stubLndClient) generateHtlcs(key route.Vertex, peer *stubPeer) {
|
||||
log.Infow("Starting stub", "peer", peer.alias)
|
||||
chanCount := len(peer.channels)
|
||||
chanIds := make([]uint64, 0)
|
||||
for chanId := range peer.channels {
|
||||
chanIds = append(chanIds, chanId)
|
||||
}
|
||||
|
||||
delayProfile := int(key[5] % 3)
|
||||
|
||||
var htlcId uint64
|
||||
for {
|
||||
chanId := chanIds[rand.Int31n(int32(chanCount))] //nolint: gosec
|
||||
|
||||
circuitKey := circuitKey{
|
||||
channel: chanId,
|
||||
htlc: htlcId,
|
||||
}
|
||||
|
||||
s.pendingHtlcsLock.Lock()
|
||||
s.pendingHtlcs[key][circuitKey] = struct{}{}
|
||||
s.pendingHtlcsLock.Unlock()
|
||||
|
||||
s.interceptRequestChan <- &interceptedEvent{
|
||||
circuitKey: circuitKey,
|
||||
}
|
||||
|
||||
htlcId++
|
||||
|
||||
time.Sleep(randomDelay(delayProfile))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stubLndClient) getIdentity() (route.Vertex, error) {
|
||||
return route.Vertex{1, 2, 3}, nil
|
||||
}
|
||||
|
||||
func (s *stubLndClient) listChannels() (map[uint64]*channel, error) {
|
||||
allChannels := make(map[uint64]*channel)
|
||||
for key, peer := range s.peers {
|
||||
for chanId, ch := range peer.channels {
|
||||
allChannels[chanId] = &channel{
|
||||
peer: key,
|
||||
initiator: ch.initiator,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allChannels, nil
|
||||
}
|
||||
|
||||
func (s *stubLndClient) getNodeAlias(key route.Vertex) (string, error) {
|
||||
peer, ok := s.peers[key]
|
||||
if !ok {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
return peer.alias, nil
|
||||
}
|
||||
|
||||
type stubHtlcEventsClient struct {
|
||||
parent *stubLndClient
|
||||
}
|
||||
|
||||
func newStubHtlcEventsClient(parent *stubLndClient) *stubHtlcEventsClient {
|
||||
return &stubHtlcEventsClient{
|
||||
parent: parent,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stubHtlcEventsClient) recv() (*resolvedEvent, error) {
|
||||
event, ok := <-s.parent.eventChan
|
||||
if !ok {
|
||||
return nil, errors.New("no more events")
|
||||
}
|
||||
|
||||
return event, nil
|
||||
}
|
||||
|
||||
func (s *stubLndClient) subscribeHtlcEvents(ctx context.Context) (htlcEventsClient, error) {
|
||||
return newStubHtlcEventsClient(s), nil
|
||||
}
|
||||
|
||||
type stubHtlcInterceptorClient struct {
|
||||
parent *stubLndClient
|
||||
}
|
||||
|
||||
func newStubHtlcInterceptorClient(parent *stubLndClient) *stubHtlcInterceptorClient {
|
||||
return &stubHtlcInterceptorClient{
|
||||
parent: parent,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *stubHtlcInterceptorClient) recv() (*interceptedEvent, error) {
|
||||
event, ok := <-s.parent.interceptRequestChan
|
||||
if !ok {
|
||||
return nil, errors.New("no more events")
|
||||
}
|
||||
|
||||
return event, nil
|
||||
}
|
||||
|
||||
func (s *stubHtlcInterceptorClient) send(resp *interceptResponse) error {
|
||||
s.parent.interceptResponseChan <- resp
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *stubLndClient) htlcInterceptor(ctx context.Context) (htlcInterceptorClient, error) {
|
||||
return newStubHtlcInterceptorClient(s), nil
|
||||
}
|
||||
|
||||
func (s *stubLndClient) getPendingIncomingHtlcs(ctx context.Context, peer *route.Vertex) (
|
||||
map[route.Vertex]map[circuitKey]struct{}, error) {
|
||||
|
||||
allHtlcs := make(map[route.Vertex]map[circuitKey]struct{})
|
||||
|
||||
s.pendingHtlcsLock.Lock()
|
||||
for peerKey, peerHtlcs := range s.pendingHtlcs {
|
||||
if peer != nil && peerKey != *peer {
|
||||
continue
|
||||
}
|
||||
|
||||
htlcs := make(map[circuitKey]struct{})
|
||||
for htlc := range peerHtlcs {
|
||||
htlcs[htlc] = struct{}{}
|
||||
}
|
||||
|
||||
allHtlcs[peerKey] = htlcs
|
||||
}
|
||||
s.pendingHtlcsLock.Unlock()
|
||||
|
||||
return allHtlcs, nil
|
||||
}
|
||||
21
webui-build/asset-manifest.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.1d740b7c.css",
|
||||
"main.js": "/static/js/main.97b4518e.js",
|
||||
"static/js/787.5fcbf511.chunk.js": "/static/js/787.5fcbf511.chunk.js",
|
||||
"static/media/primeicons.svg": "/static/media/primeicons.e1441b135b3ca9ad643c.svg",
|
||||
"static/media/primeicons.eot": "/static/media/primeicons.d44157bdfa026dc877af.eot",
|
||||
"static/media/primeicons.woff": "/static/media/primeicons.10d3152104f2208ac82a.woff",
|
||||
"static/media/primeicons.ttf": "/static/media/primeicons.ea5358601d0a3fd6670b.ttf",
|
||||
"static/media/primeicons.woff2": "/static/media/primeicons.78172950b335ccdb94e2.woff2",
|
||||
"static/media/logo.svg": "/static/media/logo.6ce24c58023cc2f8fd88fe9d219db6c6.svg",
|
||||
"index.html": "/index.html",
|
||||
"main.1d740b7c.css.map": "/static/css/main.1d740b7c.css.map",
|
||||
"main.97b4518e.js.map": "/static/js/main.97b4518e.js.map",
|
||||
"787.5fcbf511.chunk.js.map": "/static/js/787.5fcbf511.chunk.js.map"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/css/main.1d740b7c.css",
|
||||
"static/js/main.97b4518e.js"
|
||||
]
|
||||
}
|
||||
BIN
webui-build/favicon.ico
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
1
webui-build/index.html
Normal file
|
|
@ -0,0 +1 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.97b4518e.js"></script><link href="/static/css/main.1d740b7c.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
||||
BIN
webui-build/logo192.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
webui-build/logo512.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
25
webui-build/manifest.json
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
3
webui-build/robots.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
2
webui-build/static/css/main.1d740b7c.css
Normal file
1
webui-build/static/css/main.1d740b7c.css.map
Normal file
2
webui-build/static/js/787.5fcbf511.chunk.js
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
"use strict";(self.webpackChunkcircuitbreaker=self.webpackChunkcircuitbreaker||[]).push([[787],{787:function(e,t,n){n.r(t),n.d(t,{getCLS:function(){return y},getFCP:function(){return g},getFID:function(){return F},getLCP:function(){return P},getTTFB:function(){return D}});var i,r,a,o,u=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:"v2-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},c=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if("first-input"===e&&!("PerformanceEventTiming"in self))return;var n=new PerformanceObserver((function(e){return e.getEntries().map(t)}));return n.observe({type:e,buffered:!0}),n}}catch(e){}},f=function(e,t){var n=function n(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(e(i),t&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},s=function(e){addEventListener("pageshow",(function(t){t.persisted&&e(t)}),!0)},m=function(e,t,n){var i;return function(r){t.value>=0&&(r||n)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},v=-1,p=function(){return"hidden"===document.visibilityState?0:1/0},d=function(){f((function(e){var t=e.timeStamp;v=t}),!0)},l=function(){return v<0&&(v=p(),d(),s((function(){setTimeout((function(){v=p(),d()}),0)}))),{get firstHiddenTime(){return v}}},g=function(e,t){var n,i=l(),r=u("FCP"),a=function(e){"first-contentful-paint"===e.name&&(f&&f.disconnect(),e.startTime<i.firstHiddenTime&&(r.value=e.startTime,r.entries.push(e),n(!0)))},o=window.performance&&performance.getEntriesByName&&performance.getEntriesByName("first-contentful-paint")[0],f=o?null:c("paint",a);(o||f)&&(n=m(e,r,t),o&&a(o),s((function(i){r=u("FCP"),n=m(e,r,t),requestAnimationFrame((function(){requestAnimationFrame((function(){r.value=performance.now()-i.timeStamp,n(!0)}))}))})))},h=!1,T=-1,y=function(e,t){h||(g((function(e){T=e.value})),h=!0);var n,i=function(t){T>-1&&e(t)},r=u("CLS",0),a=0,o=[],v=function(e){if(!e.hadRecentInput){var t=o[0],i=o[o.length-1];a&&e.startTime-i.startTime<1e3&&e.startTime-t.startTime<5e3?(a+=e.value,o.push(e)):(a=e.value,o=[e]),a>r.value&&(r.value=a,r.entries=o,n())}},p=c("layout-shift",v);p&&(n=m(i,r,t),f((function(){p.takeRecords().map(v),n(!0)})),s((function(){a=0,T=-1,r=u("CLS",0),n=m(i,r,t)})))},E={passive:!0,capture:!0},w=new Date,L=function(e,t){i||(i=t,r=e,a=new Date,k(removeEventListener),S())},S=function(){if(r>=0&&r<a-w){var e={entryType:"first-input",name:i.type,target:i.target,cancelable:i.cancelable,startTime:i.timeStamp,processingStart:i.timeStamp+r};o.forEach((function(t){t(e)})),o=[]}},b=function(e){if(e.cancelable){var t=(e.timeStamp>1e12?new Date:performance.now())-e.timeStamp;"pointerdown"==e.type?function(e,t){var n=function(){L(e,t),r()},i=function(){r()},r=function(){removeEventListener("pointerup",n,E),removeEventListener("pointercancel",i,E)};addEventListener("pointerup",n,E),addEventListener("pointercancel",i,E)}(t,e):L(t,e)}},k=function(e){["mousedown","keydown","touchstart","pointerdown"].forEach((function(t){return e(t,b,E)}))},F=function(e,t){var n,a=l(),v=u("FID"),p=function(e){e.startTime<a.firstHiddenTime&&(v.value=e.processingStart-e.startTime,v.entries.push(e),n(!0))},d=c("first-input",p);n=m(e,v,t),d&&f((function(){d.takeRecords().map(p),d.disconnect()}),!0),d&&s((function(){var a;v=u("FID"),n=m(e,v,t),o=[],r=-1,i=null,k(addEventListener),a=p,o.push(a),S()}))},C={},P=function(e,t){var n,i=l(),r=u("LCP"),a=function(e){var t=e.startTime;t<i.firstHiddenTime&&(r.value=t,r.entries.push(e),n())},o=c("largest-contentful-paint",a);if(o){n=m(e,r,t);var v=function(){C[r.id]||(o.takeRecords().map(a),o.disconnect(),C[r.id]=!0,n(!0))};["keydown","click"].forEach((function(e){addEventListener(e,v,{once:!0,capture:!0})})),f(v,!0),s((function(i){r=u("LCP"),n=m(e,r,t),requestAnimationFrame((function(){requestAnimationFrame((function(){r.value=performance.now()-i.timeStamp,C[r.id]=!0,n(!0)}))}))}))}},D=function(e){var t,n=u("TTFB");t=function(){try{var t=performance.getEntriesByType("navigation")[0]||function(){var e=performance.timing,t={entryType:"navigation",startTime:0};for(var n in e)"navigationStart"!==n&&"toJSON"!==n&&(t[n]=Math.max(e[n]-e.navigationStart,0));return t}();if(n.value=n.delta=t.responseStart,n.value<0||n.value>performance.now())return;n.entries=[t],e(n)}catch(e){}},"complete"===document.readyState?setTimeout(t,0):addEventListener("load",(function(){return setTimeout(t,0)}))}}}]);
|
||||
//# sourceMappingURL=787.5fcbf511.chunk.js.map
|
||||
1
webui-build/static/js/787.5fcbf511.chunk.js.map
Normal file
3
webui-build/static/js/main.97b4518e.js
Normal file
43
webui-build/static/js/main.97b4518e.js.LICENSE.txt
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-dom.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-jsx-runtime.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* scheduler.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
//! moment.js
|
||||
1
webui-build/static/js/main.97b4518e.js.map
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
BIN
webui-build/static/media/primeicons.10d3152104f2208ac82a.woff
Normal file
BIN
webui-build/static/media/primeicons.78172950b335ccdb94e2.woff2
Normal file
BIN
webui-build/static/media/primeicons.d44157bdfa026dc877af.eot
Normal file
292
webui-build/static/media/primeicons.e1441b135b3ca9ad643c.svg
Normal file
|
After Width: | Height: | Size: 285 KiB |
BIN
webui-build/static/media/primeicons.ea5358601d0a3fd6670b.ttf
Normal file
20
webui/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
70
webui/README.md
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
# Getting Started with Create React App
|
||||
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm start`
|
||||
|
||||
Runs the app in the development mode.\
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
|
||||
|
||||
The page will reload when you make changes.\
|
||||
You may also see any lint errors in the console.
|
||||
|
||||
### `npm test`
|
||||
|
||||
Launches the test runner in the interactive watch mode.\
|
||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Builds the app for production to the `build` folder.\
|
||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.\
|
||||
Your app is ready to be deployed!
|
||||
|
||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||
|
||||
### `npm run eject`
|
||||
|
||||
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
|
||||
|
||||
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||
|
||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
|
||||
|
||||
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
|
||||
|
||||
## Learn More
|
||||
|
||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||
|
||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||
|
||||
### Code Splitting
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
|
||||
|
||||
### Analyzing the Bundle Size
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
|
||||
|
||||
### Making a Progressive Web App
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
|
||||
|
||||
### Advanced Configuration
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
|
||||
|
||||
### Deployment
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
|
||||
|
||||
### `npm run build` fails to minify
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
|
||||
17434
webui/package-lock.json
generated
Normal file
43
webui/package.json
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"name": "circuitbreaker",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"create-react-app": "^5.0.1",
|
||||
"moment": "^2.29.4",
|
||||
"primeicons": "^6.0.1",
|
||||
"primereact": "^8.7.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "BUILD_PATH='../webui-build' react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"proxy": "http://127.0.0.1:9235"
|
||||
}
|
||||
BIN
webui/public/favicon.ico
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
43
webui/public/index.html
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
BIN
webui/public/logo192.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
webui/public/logo512.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
25
webui/public/manifest.json
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
3
webui/public/robots.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
38
webui/src/App.css
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
.App {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.App-logo {
|
||||
height: 40vmin;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
.App-logo {
|
||||
animation: App-logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.App-header {
|
||||
background-color: #282c34;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: calc(10px + 2vmin);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.App-link {
|
||||
color: #61dafb;
|
||||
}
|
||||
|
||||
@keyframes App-logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
303
webui/src/App.js
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import logo from './logo.svg';
|
||||
import './App.css';
|
||||
import { DataTable } from 'primereact/datatable';
|
||||
import { Card } from 'primereact/card';
|
||||
import { Column } from 'primereact/column';
|
||||
import { ColumnGroup } from 'primereact/columngroup';
|
||||
import { InputNumber } from 'primereact/inputnumber';
|
||||
import { Row } from 'primereact/row';
|
||||
import { Tooltip } from 'primereact/tooltip';
|
||||
import { Dropdown } from 'primereact/dropdown';
|
||||
import { Button } from 'primereact/button';
|
||||
import { Panel } from 'primereact/panel';
|
||||
import { Divider } from 'primereact/divider';
|
||||
import { Messages } from 'primereact/messages';
|
||||
import { Message } from 'primereact/message';
|
||||
|
||||
import "primereact/resources/themes/lara-light-indigo/theme.css"; //theme
|
||||
import "primereact/resources/primereact.min.css"; //core css
|
||||
import "primeicons/primeicons.css"; //icons
|
||||
import moment, { HTML5_FMT } from 'moment';
|
||||
|
||||
function App() {
|
||||
const [data, setData] = useState([]);
|
||||
const [defaultLimits, setDefaultLimits] = useState([]);
|
||||
const [dynamicColumns, setDynamicColumns] = useState();
|
||||
const tooltipRef = useRef(null);
|
||||
const warningMsg = useRef(null);
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const response = await fetch("/api/limits");
|
||||
const json = await response.json();
|
||||
|
||||
console.log(json)
|
||||
|
||||
let warning = false
|
||||
|
||||
const tableData = json.limits.map((l) => {
|
||||
const tableRow = {
|
||||
alias: l.alias,
|
||||
node: l.node,
|
||||
pendingHtlcCount: l.pendingHtlcCount,
|
||||
counter1h_success: l.counter1h.success,
|
||||
counter1h_fail: l.counter1h.fail,
|
||||
counter1h_reject: l.counter1h.reject,
|
||||
counter24h_success: l.counter24h.success,
|
||||
counter24h_fail: l.counter24h.fail,
|
||||
counter24h_reject: l.counter24h.reject,
|
||||
|
||||
queueLen: l.queueLen,
|
||||
|
||||
mode: 'MODE_DEFAULT',
|
||||
maxPending: 0,
|
||||
maxHourlyRate: 0,
|
||||
};
|
||||
|
||||
if (l.limit !== null) {
|
||||
tableRow.mode = l.limit.mode
|
||||
tableRow.maxPending = l.limit.maxPending
|
||||
tableRow.maxHourlyRate = l.limit.maxHourlyRate
|
||||
|
||||
if (l.limit.mode == 'MODE_QUEUE' || l.limit.mode == 'MODE_QUEUE_PEER_INITIATED') {
|
||||
warning = true
|
||||
}
|
||||
}
|
||||
|
||||
if (l.alias == "") {
|
||||
tableRow.alias = l.node.slice(0, 8) + '...' + l.node.slice(58, 66)
|
||||
}
|
||||
|
||||
|
||||
return tableRow
|
||||
})
|
||||
|
||||
if (json.defaultLimit.mode == 'MODE_QUEUE' || json.defaultLimit.mode == 'MODE_QUEUE_PEER_INITIATED') {
|
||||
warning = true
|
||||
}
|
||||
|
||||
let msgs = []
|
||||
|
||||
if (warning) {
|
||||
msgs.push({ sticky: true, severity: 'warn', summary: 'Warning: if something goes wrong in queue mode, this may lead to channel force-closes in lnd 0.15 and below', closable: false })
|
||||
}
|
||||
|
||||
warningMsg.current.replace(msgs);
|
||||
|
||||
setData(tableData)
|
||||
setDefaultLimits([json.defaultLimit])
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
tooltipRef.current && tooltipRef.current.updateTargetEvents();
|
||||
}, [data]);
|
||||
|
||||
const bodyTemplate = (rowData) => {
|
||||
return <div className="custom-tooltip" data-pr-tooltip={rowData.node}>{rowData.alias}</div>
|
||||
}
|
||||
|
||||
|
||||
const textEditor = (options) => {
|
||||
return <InputNumber value={options.value} onValueChange={(e) => options.editorCallback(e.value)} size="8" useGrouping={false} />
|
||||
}
|
||||
|
||||
const onDefaultLimitEditComplete = (e) => {
|
||||
let { newData, index } = e;
|
||||
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
limit: {
|
||||
maxHourlyRate: newData.maxHourlyRate,
|
||||
maxPending: newData.maxPending,
|
||||
mode: newData.mode
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
fetch('/api/updatedefaultlimit', requestOptions)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log(data)
|
||||
|
||||
fetchData();
|
||||
});
|
||||
}
|
||||
|
||||
const onRowEditComplete = (e) => {
|
||||
let { newData, index } = e;
|
||||
|
||||
if (newData.mode == 'MODE_DEFAULT') {
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
};
|
||||
|
||||
fetch('/api/clearlimit/' + newData.node, requestOptions)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log(data)
|
||||
|
||||
fetchData();
|
||||
});
|
||||
} else {
|
||||
const requestOptions = {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
limit: {
|
||||
maxHourlyRate: newData.maxHourlyRate,
|
||||
maxPending: newData.maxPending,
|
||||
mode: newData.mode
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
fetch('/api/updatelimit/' + newData.node, requestOptions)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
console.log(data)
|
||||
|
||||
fetchData();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const modes = [
|
||||
{ label: 'Fail', value: 'MODE_FAIL' },
|
||||
{ label: 'Queue', value: 'MODE_QUEUE' },
|
||||
{ label: 'Queue peer initiated', value: 'MODE_QUEUE_PEER_INITIATED' }
|
||||
];
|
||||
|
||||
const modesWithUseDefault = [...modes, { label: 'Use default', value: 'MODE_DEFAULT' }]
|
||||
|
||||
const modeEditor = (options, addUseDefault) => {
|
||||
let thisModes = modes
|
||||
if (addUseDefault) {
|
||||
thisModes = modesWithUseDefault
|
||||
}
|
||||
return (
|
||||
<Dropdown value={options.value} options={thisModes} optionLabel="label" optionValue="value"
|
||||
onChange={(e) => options.editorCallback(e.value)} placeholder="Select a Mode" />
|
||||
);
|
||||
}
|
||||
|
||||
const modeBodyTemplate = (rowData) => {
|
||||
let mode = 'NA'
|
||||
switch (rowData.mode) {
|
||||
case 'MODE_FAIL':
|
||||
mode = 'Fail'
|
||||
break;
|
||||
|
||||
case 'MODE_QUEUE':
|
||||
mode = 'Queue'
|
||||
break;
|
||||
|
||||
case 'MODE_QUEUE_PEER_INITIATED':
|
||||
mode = 'Queue peer initiated'
|
||||
break;
|
||||
|
||||
case 'MODE_DEFAULT':
|
||||
mode = 'Use default'
|
||||
break;
|
||||
}
|
||||
|
||||
return mode
|
||||
}
|
||||
|
||||
const numberBodyTemplate = (mode, number) => {
|
||||
if (mode == 'MODE_DEFAULT') {
|
||||
return "Use default"
|
||||
}
|
||||
|
||||
if (number == 0) return "None"
|
||||
|
||||
return number
|
||||
}
|
||||
|
||||
const dashNumberBodyTemplate = (number) => {
|
||||
if (number == 0) return "-"
|
||||
|
||||
return number
|
||||
}
|
||||
|
||||
|
||||
|
||||
let headerGroup = (
|
||||
<ColumnGroup>
|
||||
<Row>
|
||||
<Column header="Peer" field="alias" rowSpan={2} sortable />
|
||||
|
||||
<Column header="Last 1 hr counters" colSpan={3} />
|
||||
<Column header="Last 24 hr counters" colSpan={3} />
|
||||
|
||||
<Column header="Current fwds" field="queueLen" colSpan={2} />
|
||||
|
||||
<Column header="Limits" colSpan={5} />
|
||||
</Row>
|
||||
<Row>
|
||||
<Column header="OK" headerTooltip="Number of settled htlcs in the past 1 hr" field="counter1h_success" sortable />
|
||||
<Column header="Fail" headerTooltip="Number of failed htlcs in the past 1 hr" field="counter1h_fail" sortable />
|
||||
<Column header="Rej" headerTooltip="Number of htlcs rejected by circuit breaker in the past 1 hr" field="counter1h_reject" sortable />
|
||||
<Column header="OK" headerTooltip="Number of settled htlcs in the past 24 hr" field="counter24h_success" sortable />
|
||||
<Column header="Fail" headerTooltip="Number of failed htlcs in the past 24 hr" field="counter24h_fail" sortable />
|
||||
<Column header="Rej" headerTooltip="Number of htlcs rejected by circuit breaker in the past 24 hr" field="counter24h_reject" sortable />
|
||||
|
||||
<Column header="Queue len" field="queueLen" sortable />
|
||||
<Column header="Pending" field="pendingHtlcCount" sortable />
|
||||
|
||||
<Column header="Max Hourly Rate" headerTooltip="Maximum number of htlcs forwarded per hour" field="maxHourlyRate" sortable />
|
||||
<Column header="Max Pending" headerTooltip="Maximum number of pending htlcs" field="maxPending" sortable />
|
||||
<Column header="Mode" field="mode" sortable />
|
||||
<Column />
|
||||
</Row>
|
||||
</ColumnGroup>);
|
||||
|
||||
return (
|
||||
<Card title="Circuit Breaker">
|
||||
<Tooltip ref={tooltipRef} target=".custom-tooltip"></Tooltip>
|
||||
|
||||
<h3>Default limit</h3>
|
||||
<DataTable value={defaultLimits} editMode="row" onRowEditComplete={onDefaultLimitEditComplete} size="small">
|
||||
<Column header="Max Hourly Rate" field="maxHourlyRate" body={(rowData => numberBodyTemplate(rowData.mode, rowData.maxHourlyRate))} editor={(options) => textEditor(options)}></Column>
|
||||
<Column header="Max Pending" field="maxPending" body={(rowData => numberBodyTemplate(rowData.mode, rowData.maxPending))} editor={(options) => textEditor(options)}></Column>
|
||||
<Column header="Mode" field="mode" body={modeBodyTemplate} editor={(options) => modeEditor(options, false)}></Column>
|
||||
<Column rowEditor></Column>
|
||||
</DataTable>
|
||||
|
||||
<h3 style={{ 'padding-top': '2rem' }}>Per node limits</h3>
|
||||
<DataTable value={data} responsiveLayout="scroll" sortField="node" sortOrder={1} headerColumnGroup={headerGroup} editMode="row" onRowEditComplete={onRowEditComplete} size="small">
|
||||
<Column field="node" body={bodyTemplate}></Column>
|
||||
<Column field="counter1h_success" body={(rowData) => dashNumberBodyTemplate(rowData.counter1h_success)}></Column>
|
||||
<Column field="counter1h_fail" body={(rowData) => dashNumberBodyTemplate(rowData.counter1h_fail)}></Column>
|
||||
<Column field="counter1h_reject" body={(rowData) => dashNumberBodyTemplate(rowData.counter1h_reject)}></Column>
|
||||
<Column field="counter24h_success" body={(rowData) => dashNumberBodyTemplate(rowData.counter24h_success)}></Column>
|
||||
<Column field="counter24h_fail" body={(rowData) => dashNumberBodyTemplate(rowData.counter24h_fail)}></Column>
|
||||
<Column field="counter24h_reject" body={(rowData) => dashNumberBodyTemplate(rowData.counter24h_reject)}></Column>
|
||||
|
||||
<Column field="queueLen" body={(rowData) => dashNumberBodyTemplate(rowData.queueLen)}></Column>
|
||||
<Column field="pendingHtlcCount" body={(rowData) => dashNumberBodyTemplate(rowData.pendingHtlcCount)}></Column>
|
||||
|
||||
<Column field="maxHourlyRate" body={(rowData => numberBodyTemplate(rowData.mode, rowData.maxHourlyRate))} editor={(options) => textEditor(options)}></Column>
|
||||
<Column field="maxPending" body={(rowData => numberBodyTemplate(rowData.mode, rowData.maxPending))} editor={(options) => textEditor(options)}></Column>
|
||||
<Column field="mode" body={modeBodyTemplate} editor={(options) => modeEditor(options, true)}></Column>
|
||||
<Column rowEditor></Column>
|
||||
</DataTable>
|
||||
|
||||
<Messages ref={warningMsg} />
|
||||
</Card>
|
||||
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
8
webui/src/App.test.js
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { render, screen } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<App />);
|
||||
const linkElement = screen.getByText(/learn react/i);
|
||||
expect(linkElement).toBeInTheDocument();
|
||||
});
|
||||
13
webui/src/index.css
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
body {
|
||||
margin: 10px;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
17
webui/src/index.js
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById('root'));
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>
|
||||
);
|
||||
|
||||
// If you want to start measuring performance in your app, pass a function
|
||||
// to log results (for example: reportWebVitals(console.log))
|
||||
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
||||
reportWebVitals();
|
||||
1
webui/src/logo.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 2.6 KiB |
13
webui/src/reportWebVitals.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
const reportWebVitals = onPerfEntry => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
5
webui/src/setupTests.js
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
||||
// allows you to do things like:
|
||||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom';
|
||||