Release Argo Tunnel Client 2018.6.1
This commit is contained in:
parent
4ca5e622ca
commit
4268bc1a9c
|
@ -7,6 +7,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/cloudflare/cloudflared/metallog"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
"golang.org/x/net/http2/hpack"
|
"golang.org/x/net/http2/hpack"
|
||||||
|
@ -46,7 +47,7 @@ type MuxerConfig struct {
|
||||||
// The minimum number of heartbeats to send before terminating the connection.
|
// The minimum number of heartbeats to send before terminating the connection.
|
||||||
MaxHeartbeats uint64
|
MaxHeartbeats uint64
|
||||||
// Logger to use
|
// Logger to use
|
||||||
Logger *log.Logger
|
Logger *log.Entry
|
||||||
}
|
}
|
||||||
|
|
||||||
type Muxer struct {
|
type Muxer struct {
|
||||||
|
@ -95,7 +96,7 @@ func Handshake(
|
||||||
config.Timeout = defaultTimeout
|
config.Timeout = defaultTimeout
|
||||||
}
|
}
|
||||||
if config.Logger == nil {
|
if config.Logger == nil {
|
||||||
config.Logger = log.New()
|
config.Logger = metallog.New().WithFields(log.Fields{})
|
||||||
}
|
}
|
||||||
// Initialise connection state fields
|
// Initialise connection state fields
|
||||||
m := &Muxer{
|
m := &Muxer{
|
||||||
|
@ -259,10 +260,9 @@ func joinErrorsWithTimeout(errChan <-chan error, receiveCount int, timeout time.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Muxer) Serve(ctx context.Context) error {
|
func (m *Muxer) Serve(ctx context.Context) error {
|
||||||
logger := m.config.Logger.WithField("name", m.config.Name)
|
|
||||||
errGroup, _ := errgroup.WithContext(ctx)
|
errGroup, _ := errgroup.WithContext(ctx)
|
||||||
errGroup.Go(func() error {
|
errGroup.Go(func() error {
|
||||||
err := m.muxReader.run(logger)
|
err := m.muxReader.run(m.config.Logger)
|
||||||
m.explicitShutdown.Fuse(false)
|
m.explicitShutdown.Fuse(false)
|
||||||
m.r.Close()
|
m.r.Close()
|
||||||
m.abort()
|
m.abort()
|
||||||
|
@ -270,7 +270,7 @@ func (m *Muxer) Serve(ctx context.Context) error {
|
||||||
})
|
})
|
||||||
|
|
||||||
errGroup.Go(func() error {
|
errGroup.Go(func() error {
|
||||||
err := m.muxWriter.run(logger)
|
err := m.muxWriter.run(m.config.Logger)
|
||||||
m.explicitShutdown.Fuse(false)
|
m.explicitShutdown.Fuse(false)
|
||||||
m.w.Close()
|
m.w.Close()
|
||||||
m.abort()
|
m.abort()
|
||||||
|
@ -278,7 +278,7 @@ func (m *Muxer) Serve(ctx context.Context) error {
|
||||||
})
|
})
|
||||||
|
|
||||||
errGroup.Go(func() error {
|
errGroup.Go(func() error {
|
||||||
err := m.muxMetricsUpdater.run(logger)
|
err := m.muxMetricsUpdater.run(m.config.Logger)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package metallog
|
||||||
|
|
||||||
|
import (
|
||||||
|
tunnellog "github.com/cloudflare/cloudflared/log"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// New creates a logger formatted for JSON output
|
||||||
|
func New() *log.Logger {
|
||||||
|
logger := log.New()
|
||||||
|
logger.Formatter = &tunnellog.JSONFormatter{}
|
||||||
|
return logger
|
||||||
|
}
|
|
@ -23,13 +23,13 @@ import (
|
||||||
raven "github.com/getsentry/raven-go"
|
raven "github.com/getsentry/raven-go"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
_ "github.com/prometheus/client_golang/prometheus"
|
_ "github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
rpc "zombiezen.com/go/capnproto2/rpc"
|
rpc "zombiezen.com/go/capnproto2/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
dialTimeout = 15 * time.Second
|
dialTimeout = 15 * time.Second
|
||||||
|
lbProbeUserAgentPrefix = "Mozilla/5.0 (compatible; Cloudflare-Traffic-Manager/1.0; +https://www.cloudflare.com/traffic-manager/;"
|
||||||
TagHeaderNamePrefix = "Cf-Warp-Tag-"
|
TagHeaderNamePrefix = "Cf-Warp-Tag-"
|
||||||
DuplicateConnectionError = "EDUPCONN"
|
DuplicateConnectionError = "EDUPCONN"
|
||||||
)
|
)
|
||||||
|
@ -53,8 +53,8 @@ type TunnelConfig struct {
|
||||||
HTTPTransport http.RoundTripper
|
HTTPTransport http.RoundTripper
|
||||||
Metrics *TunnelMetrics
|
Metrics *TunnelMetrics
|
||||||
MetricsUpdateFreq time.Duration
|
MetricsUpdateFreq time.Duration
|
||||||
ProtocolLogger *logrus.Logger
|
ProtocolLogger *log.Logger
|
||||||
Logger *logrus.Logger
|
Logger *log.Logger
|
||||||
IsAutoupdated bool
|
IsAutoupdated bool
|
||||||
GracePeriod time.Duration
|
GracePeriod time.Duration
|
||||||
RunFromTerminal bool
|
RunFromTerminal bool
|
||||||
|
@ -196,9 +196,9 @@ func ServeTunnel(
|
||||||
tags["ha"] = connectionTag
|
tags["ha"] = connectionTag
|
||||||
|
|
||||||
// Returns error from parsing the origin URL or handshake errors
|
// Returns error from parsing the origin URL or handshake errors
|
||||||
handler, originLocalIP, err := NewTunnelHandler(ctx, logger, config, addr.String(), connectionID)
|
handler, originLocalIP, err := NewTunnelHandler(ctx, config, addr.String(), connectionID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
errLog := logger.WithError(err)
|
errLog := config.Logger.WithError(err)
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case dialError:
|
case dialError:
|
||||||
errLog.Error("Unable to dial edge")
|
errLog.Error("Unable to dial edge")
|
||||||
|
@ -214,7 +214,7 @@ func ServeTunnel(
|
||||||
errGroup, serveCtx := errgroup.WithContext(ctx)
|
errGroup, serveCtx := errgroup.WithContext(ctx)
|
||||||
|
|
||||||
errGroup.Go(func() error {
|
errGroup.Go(func() error {
|
||||||
err := RegisterTunnel(serveCtx, logger, handler.muxer, config, connectionID, originLocalIP)
|
err := RegisterTunnel(serveCtx, handler.muxer, config, connectionID, originLocalIP)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
connectedFuse.Fuse(true)
|
connectedFuse.Fuse(true)
|
||||||
backoff.SetGracePeriod()
|
backoff.SetGracePeriod()
|
||||||
|
@ -226,9 +226,9 @@ func ServeTunnel(
|
||||||
updateMetricsTickC := time.Tick(config.MetricsUpdateFreq)
|
updateMetricsTickC := time.Tick(config.MetricsUpdateFreq)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-serveCtx.Done():
|
case <-serveCtx.Done():
|
||||||
// UnregisterTunnel blocks until the RPC call returns
|
// UnregisterTunnel blocks until the RPC call returns
|
||||||
err := UnregisterTunnel(logger, handler.muxer, config.GracePeriod)
|
err := UnregisterTunnel(handler.muxer, config.GracePeriod, config.Logger)
|
||||||
handler.muxer.Shutdown()
|
handler.muxer.Shutdown()
|
||||||
return err
|
return err
|
||||||
case <-updateMetricsTickC:
|
case <-updateMetricsTickC:
|
||||||
|
@ -241,7 +241,7 @@ func ServeTunnel(
|
||||||
// All routines should stop when muxer finish serving. When muxer is shutdown
|
// All routines should stop when muxer finish serving. When muxer is shutdown
|
||||||
// gracefully, it doesn't return an error, so we need to return errMuxerShutdown
|
// gracefully, it doesn't return an error, so we need to return errMuxerShutdown
|
||||||
// here to notify other routines to stop
|
// here to notify other routines to stop
|
||||||
err := handler.muxer.Serve(serveCtx);
|
err := handler.muxer.Serve(serveCtx)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return muxerShutdownError{}
|
return muxerShutdownError{}
|
||||||
}
|
}
|
||||||
|
@ -285,8 +285,8 @@ func IsRPCStreamResponse(headers []h2mux.Header) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterTunnel(ctx context.Context, logger *logrus.Entry, muxer *h2mux.Muxer, config *TunnelConfig, connectionID uint8, originLocalIP string) error {
|
func RegisterTunnel(ctx context.Context, muxer *h2mux.Muxer, config *TunnelConfig, connectionID uint8, originLocalIP string) error {
|
||||||
logger.Debug("initiating RPC stream to register")
|
config.Logger.Debug("initiating RPC stream to register")
|
||||||
stream, err := muxer.OpenStream([]h2mux.Header{
|
stream, err := muxer.OpenStream([]h2mux.Header{
|
||||||
{Name: ":method", Value: "RPC"},
|
{Name: ":method", Value: "RPC"},
|
||||||
{Name: ":scheme", Value: "capnp"},
|
{Name: ":scheme", Value: "capnp"},
|
||||||
|
@ -301,8 +301,8 @@ func RegisterTunnel(ctx context.Context, logger *logrus.Entry, muxer *h2mux.Muxe
|
||||||
return clientRegisterTunnelError{cause: err}
|
return clientRegisterTunnelError{cause: err}
|
||||||
}
|
}
|
||||||
conn := rpc.NewConn(
|
conn := rpc.NewConn(
|
||||||
tunnelrpc.NewTransportLogger(logger.WithField("subsystem", "rpc-register"), rpc.StreamTransport(stream)),
|
tunnelrpc.NewTransportLogger(config.Logger.WithField("subsystem", "rpc-register"), rpc.StreamTransport(stream)),
|
||||||
tunnelrpc.ConnLog(logger.WithField("subsystem", "rpc-transport")),
|
tunnelrpc.ConnLog(config.Logger.WithField("subsystem", "rpc-transport")),
|
||||||
)
|
)
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
ts := tunnelpogs.TunnelServer_PogsClient{Client: conn.Bootstrap(ctx)}
|
ts := tunnelpogs.TunnelServer_PogsClient{Client: conn.Bootstrap(ctx)}
|
||||||
|
@ -317,13 +317,13 @@ func RegisterTunnel(ctx context.Context, logger *logrus.Entry, muxer *h2mux.Muxe
|
||||||
config.Hostname,
|
config.Hostname,
|
||||||
config.RegistrationOptions(connectionID, originLocalIP),
|
config.RegistrationOptions(connectionID, originLocalIP),
|
||||||
)
|
)
|
||||||
LogServerInfo(logger, serverInfoPromise.Result(), connectionID, config.Metrics)
|
LogServerInfo(serverInfoPromise.Result(), connectionID, config.Metrics, config.Logger)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// RegisterTunnel RPC failure
|
// RegisterTunnel RPC failure
|
||||||
return clientRegisterTunnelError{cause: err}
|
return clientRegisterTunnelError{cause: err}
|
||||||
}
|
}
|
||||||
for _, logLine := range registration.LogLines {
|
for _, logLine := range registration.LogLines {
|
||||||
logger.Info(logLine)
|
config.Logger.Info(logLine)
|
||||||
}
|
}
|
||||||
if registration.Err == DuplicateConnectionError {
|
if registration.Err == DuplicateConnectionError {
|
||||||
return dupConnRegisterTunnelError{}
|
return dupConnRegisterTunnelError{}
|
||||||
|
@ -334,10 +334,12 @@ func RegisterTunnel(ctx context.Context, logger *logrus.Entry, muxer *h2mux.Muxe
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config.Logger.Info("Tunnel ID: " + registration.TunnelID)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnregisterTunnel(logger *logrus.Entry, muxer *h2mux.Muxer, gracePeriod time.Duration) error {
|
func UnregisterTunnel(muxer *h2mux.Muxer, gracePeriod time.Duration, logger *log.Logger) error {
|
||||||
logger.Debug("initiating RPC stream to unregister")
|
logger.Debug("initiating RPC stream to unregister")
|
||||||
stream, err := muxer.OpenStream([]h2mux.Header{
|
stream, err := muxer.OpenStream([]h2mux.Header{
|
||||||
{Name: ":method", Value: "RPC"},
|
{Name: ":method", Value: "RPC"},
|
||||||
|
@ -363,10 +365,11 @@ func UnregisterTunnel(logger *logrus.Entry, muxer *h2mux.Muxer, gracePeriod time
|
||||||
return ts.UnregisterTunnel(ctx, gracePeriod.Nanoseconds())
|
return ts.UnregisterTunnel(ctx, gracePeriod.Nanoseconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
func LogServerInfo(logger *logrus.Entry,
|
func LogServerInfo(
|
||||||
promise tunnelrpc.ServerInfo_Promise,
|
promise tunnelrpc.ServerInfo_Promise,
|
||||||
connectionID uint8,
|
connectionID uint8,
|
||||||
metrics *TunnelMetrics,
|
metrics *TunnelMetrics,
|
||||||
|
logger *log.Logger,
|
||||||
) {
|
) {
|
||||||
serverInfoMessage, err := promise.Struct()
|
serverInfoMessage, err := promise.Struct()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -432,14 +435,13 @@ type TunnelHandler struct {
|
||||||
metrics *TunnelMetrics
|
metrics *TunnelMetrics
|
||||||
// connectionID is only used by metrics, and prometheus requires labels to be string
|
// connectionID is only used by metrics, and prometheus requires labels to be string
|
||||||
connectionID string
|
connectionID string
|
||||||
logger *logrus.Entry
|
logger *log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
var dialer = net.Dialer{DualStack: true}
|
var dialer = net.Dialer{DualStack: true}
|
||||||
|
|
||||||
// NewTunnelHandler returns a TunnelHandler, origin LAN IP and error
|
// NewTunnelHandler returns a TunnelHandler, origin LAN IP and error
|
||||||
func NewTunnelHandler(ctx context.Context,
|
func NewTunnelHandler(ctx context.Context,
|
||||||
logger *logrus.Entry,
|
|
||||||
config *TunnelConfig,
|
config *TunnelConfig,
|
||||||
addr string,
|
addr string,
|
||||||
connectionID uint8,
|
connectionID uint8,
|
||||||
|
@ -455,7 +457,7 @@ func NewTunnelHandler(ctx context.Context,
|
||||||
tags: config.Tags,
|
tags: config.Tags,
|
||||||
metrics: config.Metrics,
|
metrics: config.Metrics,
|
||||||
connectionID: uint8ToString(connectionID),
|
connectionID: uint8ToString(connectionID),
|
||||||
logger: logger,
|
logger: config.Logger,
|
||||||
}
|
}
|
||||||
if h.httpClient == nil {
|
if h.httpClient == nil {
|
||||||
h.httpClient = http.DefaultTransport
|
h.httpClient = http.DefaultTransport
|
||||||
|
@ -484,7 +486,7 @@ func NewTunnelHandler(ctx context.Context,
|
||||||
IsClient: true,
|
IsClient: true,
|
||||||
HeartbeatInterval: config.HeartbeatInterval,
|
HeartbeatInterval: config.HeartbeatInterval,
|
||||||
MaxHeartbeats: config.MaxHeartbeats,
|
MaxHeartbeats: config.MaxHeartbeats,
|
||||||
Logger: config.ProtocolLogger,
|
Logger: config.ProtocolLogger.WithFields(log.Fields{}),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return h, "", errors.New("TLS handshake error")
|
return h, "", errors.New("TLS handshake error")
|
||||||
|
@ -510,7 +512,8 @@ func (h *TunnelHandler) ServeStream(stream *h2mux.MuxedStream) error {
|
||||||
}
|
}
|
||||||
h.AppendTagHeaders(req)
|
h.AppendTagHeaders(req)
|
||||||
cfRay := FindCfRayHeader(req)
|
cfRay := FindCfRayHeader(req)
|
||||||
h.logRequest(req, cfRay)
|
lbProbe := isLBProbeRequest(req)
|
||||||
|
h.logRequest(req, cfRay, lbProbe)
|
||||||
if websocket.IsWebSocketUpgrade(req) {
|
if websocket.IsWebSocketUpgrade(req) {
|
||||||
conn, response, err := websocket.ClientConnect(req, h.tlsConfig)
|
conn, response, err := websocket.ClientConnect(req, h.tlsConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -522,7 +525,7 @@ func (h *TunnelHandler) ServeStream(stream *h2mux.MuxedStream) error {
|
||||||
// connection because cloudflared doesn't operate on the message themselves
|
// connection because cloudflared doesn't operate on the message themselves
|
||||||
websocket.Stream(conn.UnderlyingConn(), stream)
|
websocket.Stream(conn.UnderlyingConn(), stream)
|
||||||
h.metrics.incrementResponses(h.connectionID, "200")
|
h.metrics.incrementResponses(h.connectionID, "200")
|
||||||
h.logResponse(response, cfRay)
|
h.logResponse(response, cfRay, lbProbe)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
response, err := h.httpClient.RoundTrip(req)
|
response, err := h.httpClient.RoundTrip(req)
|
||||||
|
@ -533,7 +536,7 @@ func (h *TunnelHandler) ServeStream(stream *h2mux.MuxedStream) error {
|
||||||
stream.WriteHeaders(H1ResponseToH2Response(response))
|
stream.WriteHeaders(H1ResponseToH2Response(response))
|
||||||
io.Copy(stream, response.Body)
|
io.Copy(stream, response.Body)
|
||||||
h.metrics.incrementResponses(h.connectionID, "200")
|
h.metrics.incrementResponses(h.connectionID, "200")
|
||||||
h.logResponse(response, cfRay)
|
h.logResponse(response, cfRay, lbProbe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
h.metrics.decrementConcurrentRequests(h.connectionID)
|
h.metrics.decrementConcurrentRequests(h.connectionID)
|
||||||
|
@ -547,18 +550,22 @@ func (h *TunnelHandler) logError(stream *h2mux.MuxedStream, err error) {
|
||||||
h.metrics.incrementResponses(h.connectionID, "502")
|
h.metrics.incrementResponses(h.connectionID, "502")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *TunnelHandler) logRequest(req *http.Request, cfRay string) {
|
func (h *TunnelHandler) logRequest(req *http.Request, cfRay string, lbProbe bool) {
|
||||||
if cfRay != "" {
|
if cfRay != "" {
|
||||||
h.logger.WithField("CF-RAY", cfRay).Infof("%s %s %s", req.Method, req.URL, req.Proto)
|
h.logger.WithField("CF-RAY", cfRay).Infof("%s %s %s", req.Method, req.URL, req.Proto)
|
||||||
|
} else if lbProbe {
|
||||||
|
h.logger.Debugf("Load Balancer health check %s %s %s", req.Method, req.URL, req.Proto)
|
||||||
} else {
|
} else {
|
||||||
h.logger.Warnf("All requests should have a CF-RAY header. Please open a support ticket with Cloudflare. %s %s %s ", req.Method, req.URL, req.Proto)
|
h.logger.Warnf("All requests should have a CF-RAY header. Please open a support ticket with Cloudflare. %s %s %s ", req.Method, req.URL, req.Proto)
|
||||||
}
|
}
|
||||||
h.logger.Debugf("Request Headers %+v", req.Header)
|
h.logger.Debugf("Request Headers %+v", req.Header)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *TunnelHandler) logResponse(r *http.Response, cfRay string) {
|
func (h *TunnelHandler) logResponse(r *http.Response, cfRay string, lbProbe bool) {
|
||||||
if cfRay != "" {
|
if cfRay != "" {
|
||||||
h.logger.WithField("CF-RAY", cfRay).Infof("%s", r.Status)
|
h.logger.WithField("CF-RAY", cfRay).Infof("%s", r.Status)
|
||||||
|
} else if lbProbe {
|
||||||
|
h.logger.Debugf("Response to Load Balancer health check %s", r.Status)
|
||||||
} else {
|
} else {
|
||||||
h.logger.Infof("%s", r.Status)
|
h.logger.Infof("%s", r.Status)
|
||||||
}
|
}
|
||||||
|
@ -572,3 +579,7 @@ func (h *TunnelHandler) UpdateMetrics(connectionID string) {
|
||||||
func uint8ToString(input uint8) string {
|
func uint8ToString(input uint8) string {
|
||||||
return strconv.FormatUint(uint64(input), 10)
|
return strconv.FormatUint(uint64(input), 10)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isLBProbeRequest(req *http.Request) bool {
|
||||||
|
return strings.HasPrefix(req.UserAgent(), lbProbeUserAgentPrefix)
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package pogs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/cloudflare/cloudflared/tunnelrpc"
|
"github.com/cloudflare/cloudflared/tunnelrpc"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"zombiezen.com/go/capnproto2"
|
"zombiezen.com/go/capnproto2"
|
||||||
"zombiezen.com/go/capnproto2/pogs"
|
"zombiezen.com/go/capnproto2/pogs"
|
||||||
|
@ -30,6 +31,7 @@ type TunnelRegistration struct {
|
||||||
Url string
|
Url string
|
||||||
LogLines []string
|
LogLines []string
|
||||||
PermanentFailure bool
|
PermanentFailure bool
|
||||||
|
TunnelID string `capnp:"tunnelID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func MarshalTunnelRegistration(s tunnelrpc.TunnelRegistration, p *TunnelRegistration) error {
|
func MarshalTunnelRegistration(s tunnelrpc.TunnelRegistration, p *TunnelRegistration) error {
|
||||||
|
@ -124,6 +126,7 @@ func (i TunnelServer_PogsImpl) RegisterTunnel(p tunnelrpc.TunnelServer_registerT
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
log.Info(registration.TunnelID)
|
||||||
return MarshalTunnelRegistration(result, registration)
|
return MarshalTunnelRegistration(result, registration)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@ struct TunnelRegistration {
|
||||||
logLines @2 :List(Text);
|
logLines @2 :List(Text);
|
||||||
# In case of error, whether the client should attempt to reconnect.
|
# In case of error, whether the client should attempt to reconnect.
|
||||||
permanentFailure @3 :Bool;
|
permanentFailure @3 :Bool;
|
||||||
|
# Displayed to user
|
||||||
|
tunnelID @4 :Text;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RegistrationOptions {
|
struct RegistrationOptions {
|
||||||
|
|
|
@ -119,12 +119,12 @@ type TunnelRegistration struct{ capnp.Struct }
|
||||||
const TunnelRegistration_TypeID = 0xf41a0f001ad49e46
|
const TunnelRegistration_TypeID = 0xf41a0f001ad49e46
|
||||||
|
|
||||||
func NewTunnelRegistration(s *capnp.Segment) (TunnelRegistration, error) {
|
func NewTunnelRegistration(s *capnp.Segment) (TunnelRegistration, error) {
|
||||||
st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 3})
|
st, err := capnp.NewStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 4})
|
||||||
return TunnelRegistration{st}, err
|
return TunnelRegistration{st}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRootTunnelRegistration(s *capnp.Segment) (TunnelRegistration, error) {
|
func NewRootTunnelRegistration(s *capnp.Segment) (TunnelRegistration, error) {
|
||||||
st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 3})
|
st, err := capnp.NewRootStruct(s, capnp.ObjectSize{DataSize: 8, PointerCount: 4})
|
||||||
return TunnelRegistration{st}, err
|
return TunnelRegistration{st}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,12 +209,31 @@ func (s TunnelRegistration) SetPermanentFailure(v bool) {
|
||||||
s.Struct.SetBit(0, v)
|
s.Struct.SetBit(0, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s TunnelRegistration) TunnelID() (string, error) {
|
||||||
|
p, err := s.Struct.Ptr(3)
|
||||||
|
return p.Text(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s TunnelRegistration) HasTunnelID() bool {
|
||||||
|
p, err := s.Struct.Ptr(3)
|
||||||
|
return p.IsValid() || err != nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s TunnelRegistration) TunnelIDBytes() ([]byte, error) {
|
||||||
|
p, err := s.Struct.Ptr(3)
|
||||||
|
return p.TextBytes(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s TunnelRegistration) SetTunnelID(v string) error {
|
||||||
|
return s.Struct.SetText(3, v)
|
||||||
|
}
|
||||||
|
|
||||||
// TunnelRegistration_List is a list of TunnelRegistration.
|
// TunnelRegistration_List is a list of TunnelRegistration.
|
||||||
type TunnelRegistration_List struct{ capnp.List }
|
type TunnelRegistration_List struct{ capnp.List }
|
||||||
|
|
||||||
// NewTunnelRegistration creates a new list of TunnelRegistration.
|
// NewTunnelRegistration creates a new list of TunnelRegistration.
|
||||||
func NewTunnelRegistration_List(s *capnp.Segment, sz int32) (TunnelRegistration_List, error) {
|
func NewTunnelRegistration_List(s *capnp.Segment, sz int32) (TunnelRegistration_List, error) {
|
||||||
l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 8, PointerCount: 3}, sz)
|
l, err := capnp.NewCompositeList(s, capnp.ObjectSize{DataSize: 8, PointerCount: 4}, sz)
|
||||||
return TunnelRegistration_List{l}, err
|
return TunnelRegistration_List{l}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1226,88 +1245,89 @@ func (p TunnelServer_unregisterTunnel_Results_Promise) Struct() (TunnelServer_un
|
||||||
return TunnelServer_unregisterTunnel_Results{s}, err
|
return TunnelServer_unregisterTunnel_Results{s}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const schema_db8274f9144abc7e = "x\xda\x9cU_l\x14U\x17\xff\x9d{w;\xdb\xa4" +
|
const schema_db8274f9144abc7e = "x\xda\x9cU_\x88Te\x14?\xbf\xef\x9b\x99;\x0b" +
|
||||||
"e;\x99m\x02\x1bH\x13\xd2\x86B\xbe\xf2\xc1\xc7\x87" +
|
"\xbb\xce^\xee,\xe8\xa0\x0c\xc8.\xae\xd2\x9af\x96n" +
|
||||||
"B\xfd\xd3?\x02\xba\xb5\x94\xbdl1\x08}`\xd8\xbd" +
|
"\x7f\xf6O\xab5\xdb\xba\xce\xe7\xaca\xeaC\xd7\x99\xcf" +
|
||||||
"l\xa7\xce\xcelffQH\x04%\x18#\x89\x04E" +
|
"\xf1n3\xf7\x0e\xf7\xde1\x95\xd4\x12\xa5\x12\x92\xca|" +
|
||||||
"^0\x9a@\xe2\x8b\x0fj\xe2\x83\x89\xc1\x04_\xe4\x81" +
|
"1\x0c\x15\x82\x8a\xa8\xa0 \x08\x03{\xc9\x07\x1f|\xa9" +
|
||||||
"\x07^\xd4h$1J\x88\x91h\x88\x8d\x9ahb\xc6" +
|
"(\x12\xa2\xc4\x87\xa4\x90\x96z(\x88\x1b\xdf\x9d\xbd3" +
|
||||||
"\xdc\xd9\xce\xecR\x14\xd0\xb7\x99\xdf=\xf7\x9c\xdf9\xf7" +
|
"\xe3Zj\xbd\xdd\xfb\xfb\xcew\xce\xef\x9c\xef\x9c\xdfY" +
|
||||||
"\x9c\xdfY\xf7+\x1be\xeb\xd3_\xa7\x01\xb1%\xdd\x11" +
|
"\x91\xe0\xc3le\xfc\xfb8\x91\x18\x8b'\x82\x07\xab\x97" +
|
||||||
">X\xbbr\xfe\xbe3\x97\x8fC\xcf\xb3\xf0\xc8\x85\x89" +
|
"\xce\xdew\xe2\xe2a\xd23,8pn<\xfd\x87\x7f" +
|
||||||
"\xdco\xc1\xb1\xaf\x00\xda\xf0\x19;L\xc6\xf7L\x03\x8c" +
|
"\xe8;\"\xac\xfa\x8a\xed\x83\xf1\x13\xd3\x88\x8c\xabl#" +
|
||||||
"\xebl\x07(\xbc\xf2\x9f\x0b\x1f\x9ez\xff\xc5\xd7!V" +
|
"!\xb8t\xd7\xb9O_\xf9\xe8\x857H,\x01\x88b" +
|
||||||
"\x11\x01)\x0d\xd8\xf0\x07\xfb\x9d@\x86\xceG@\xe1k" +
|
"\x1a\xd1\xaa\xbf\xd8\x9f \x18:\x1f\"\x04\xaf\x7f\xf3\xd9" +
|
||||||
"_|4U{\xe5\xecy\xe8\xab\xe2\xf3\xcd\x9c1\xa4" +
|
"d\xf5\xd5\x93gI_\x12\x9d\xaf\xe5\x8cQ,\xe8\xc9" +
|
||||||
"\xc2\xde\x02]\xbd\xb8>\xf5A\xf3$\xcd\xd5\xd1\x10\xbf" +
|
"\xe1\xf2\xf9\x95\xb1O\x1a'q\xae\x8e\x06\xf85uu" +
|
||||||
"\xa1\xae\x8e\xf1wA\xe1\x8a\x1f\xc7\xbb\x9d\x9b\xc7.B" +
|
"\x84\x7f@\x08\x16\xfd2\xdae_?t\x9e\xf4\x0cZ" +
|
||||||
"\xcfS\x8bE\xd3\xf0\x1b>A\xc6/\xea\xd3\xf8)2" +
|
",\x1a\x86?\xf0q\x18\xbf\xabO\xe3\xd7\xd0x|\xdb" +
|
||||||
"\x9e\xd8{\xfa\xd5\xf4\xf5\xd3\x97 \xf2\xd4n\xdd\xa1\xac" +
|
"\xf1\xd7\xe2W\x8f_ \x91A\xbbuBY\xbf\x1cs" +
|
||||||
"_Nyd\x9c\x8b\x82\xbf\x91\xba\x9f\x81\xc2\xfc{\x0f" +
|
"a\x9c\x09\x83\x9f\x8a\xdd\xcf\x08A\xe6\xc3\x07\xde\x1f-" +
|
||||||
"\xbc3^\xf9\xf2\xf2\"\xdfQf\x9d\xda\xbc\xd1\xab\xa9" +
|
"}{q\x8e\xef0\xb3\x0em\xc6\xe8\xd1\xd4\x97\xae=" +
|
||||||
"/]{\x1a\x14\xb2\xeb\xe6\xb2\xe7>\x7f\xf8j[\x0a" +
|
"C\x08\xd8Us\xc1s_?|\xb9-\x85\xaa\xf6#" +
|
||||||
"5\xed[B*\x9czb\xef\\\xe7\xb3\xd7\xae-\xa4" +
|
"(\x16L>\xb1m\xbac\xff\x95+\xb3)@\x1d\x99" +
|
||||||
"@\xea\xc8\xd4\xa2\x14\x1a\x9a\xca~\xe3\xbe19\xb3i" +
|
"Z\x98B]S\xd9\xaf~jDn_\xb3\xe5\x1a\xe9" +
|
||||||
"\xf7\x0d\xe8y~K!\xcfh\xc3d\xbc\x15\x059\xa7" +
|
"\x19~C!Oh\x830\xde\x0a\x83\x9c\xd1.\x18K" +
|
||||||
"]2Vg4 <yd\xcb\x8e\xcd+?\x9eo" +
|
"\x93\x1aQp\xec\xc0\xd8\xc6\xb5\x8b?\x9fiw\xa7'" +
|
||||||
"w\xa7g\xe6\x95\xbb\x81\x8crw`\xd3\x0f\x8f\x0e\x9c" +
|
"g\x94\xbb\xbe\xa4r\xb7s\xcd\xcf\x8f\xf6\x1d\xfbbf" +
|
||||||
"\xfcd~\x11\xeb\xc8pkf\x0d\x19\xbb\x94\x1fC(" +
|
"\x0e\xeb\xd0p]r\x19\x8c\xcd\xca\x8f!\x94\xf1\xf5\xf5" +
|
||||||
"\xe3\x9b\xdb\xde\xfc4\x9f\xcd\xff\xbc\xa8\x1eQ\xf5\x1a\x99" +
|
"o~\x99Ie~\x9bS\x8f\x90~=9\x0d\xe3%" +
|
||||||
"92^\x8al_\xc8|\x87\xa10h8\x8e\xb4\xbd" +
|
"e\xbb\xeaH2\x0b\x1a\x08\xfc\xbam\xcb\x8a[\x8b\x15" +
|
||||||
"z\xaa\xfc\xdf\xf8\xb3\xbc\xb6l\xd6\x9d\xfa\xf0\xd6g," +
|
"\xef\x8e>\x8b\xcb\x8bf\xcd\xae\x0d\xae\xdbcy\xbee" +
|
||||||
"?\xb0\x9c\xeat\x84\x8f\x14]\xdb*\x1f*\x12\x89." +
|
"\x97\xa7B|(\xefT\xac\xe2\xde< :\xc1\x88\xf4" +
|
||||||
"b\x80\xbeb\x18 \xd2{\xf7\x00\xc4t}\x1c\x18\xb1" +
|
"E\x83D\x80\xde\xb3\x95\x08L\xd7G\x89\x86\xac\xb2\xed" +
|
||||||
"\xaa\x8e\xeb\xc9\xb0b\xf9e\xd7q$x98\xba\xdf" +
|
"\xb82(Y^\xd1\xb1mI\xbc\xe8\x1f\xdcaVL" +
|
||||||
"\xb4M\xa7,\x93@\x1d\xb7\x07j\x06(I\xef\xa0\xf4" +
|
"\xbb(\x9b\x81\x127\x07j\x04(Hw\xb7t\x97\xd7" +
|
||||||
"\xd66\x1cOV-?\x90^\x13\xee\x1f)\x9a\x9eY" +
|
"mW\x96-\xcf\x97n\x03\xee\x1d\xca\x9b\xaeY\xf5D" +
|
||||||
"\xf3E\x8a\xa7\x80\x14\x01z\xf7Y@\xf4p\x12\xcb\x19" +
|
"\x8c\xc7\x88b \xd2\xbbN\x12\x89n\x0e\xb1\x90!(" +
|
||||||
"\x85U\xcf,\xcb\xa2\xf4\xc8r+S\xa6\xe3\x96\xb8," +
|
"\xbbfQ\xe6\xa5\x0b\xcb)M\x9a\xb6S\xe0\xb2\x888" +
|
||||||
"S\x1a\x8c\xd2\xa0$\xe8\x92\x7f\x1at\xa7\xf4\x1bv\xe0" +
|
"1\xc4\x09\xcd\xa0\xf3\xfek\xd0M\xd2\xabW|\x8f\x9a" +
|
||||||
"#\xb9u\xe7\xfb\x8bn\x17\xcdlD\xb9+\xa1\xbcu" +
|
"\xb7n}\x7f\xce\xed\xbc\x99\x0a)w6)\xaf\xdb\xaa" +
|
||||||
"\x8f\x1a0N\xa2\xc8H'\xca\xa9\x91\xd1\xb7O\x00b" +
|
"&\x8cC\xe4\x19t \xadfF\xdf0N$&8" +
|
||||||
"\x92\x93\xd8\xcdHg,\x17\x95u\xd78 \x8a\x9c\xc4" +
|
"\xc4\x16\x06\x9d\xb1tX\xd6\xcd\xa3D\"\xcf!\xb63" +
|
||||||
"\x0c\xa3\xd0\xf5\xac\xaa\xe5<\"\xc1\xbd\x80\xba\xc1\xa8\x1b" +
|
"\x04\x8ek\x95-\xfb\x11I\xdc\xf5\xd1E\x0c]\x84`" +
|
||||||
"\x14\xce\xba~\xe0\x985\x09\x80\xba\xc0\xa8\x0bt\xd4\xad" +
|
"\x97\xe3\xf9\xb6Y\x95D\x84Nb\xe8$\x1ctj\xbe" +
|
||||||
"\x07\x96\xeb\xf8\xd4\xd3\x1a\x07\x10\xf5\xb4\x95\xe0/\x1ex" +
|
"\xe5\xd8\x1e\xba[\xf3@@w[\x09\xfe\xe1\x81G\xea" +
|
||||||
"\xac\x11\xccJ'\xb0\xca\xa6\xba\x0cDo\xdb\xa2\xbc\x12" +
|
"\xfe.i\xfbV\xd1T\x97\x89\xc2\xb7mQ^L$" +
|
||||||
"\x10\xa3\x9c\xc4d\x1b\xe5\xc2\xff\xda\xf2\x88)o\xdf\xdf" +
|
"\x869\xc4D\x1b\xe5\xdc=myD\x947\xech\xe5" +
|
||||||
"\xcaC{J\x1e\x8aY\xf5\xc9\x9ai\xd9\xf1_\x9c\xcc" +
|
"\xa1=-\xf7F\xac\xb2\xb2jZ\x95\xe8/Jf\x84" +
|
||||||
"\x18\xb4\xc7[6w\xe2\xb73\xaa\xaa\x17\xb1\xdbQ\xef" +
|
"\xb4\xc7[6\xb7\xe2\xb7)\xac\xaa\x1b\xb2\xdbX\xcb\x86" +
|
||||||
"\x8b2T\x1c\x07c\x8eF'M\x00\xa5\x0cq*\xe5" +
|
"\x19*\x8e\xfd\x11G\xa3\x03\xe3D\x85$8\x0ai\xb4" +
|
||||||
"\xa8E\xd3\xd0i\x1c(u)|)\xb5\x98\x1a\xbd\x94" +
|
"h\x1a:F\x89\x0a\x9d\x0a\x9f\x8f\x16S\xa3\x07\x19\xa2" +
|
||||||
"\x07J=\x0a_N\x8c\x88\xe7\x88\x03\xc62z\x1b(" +
|
"B\xb7\xc2\x17\x82\x01<\x0dNd,\xc0\xbbD\x85\x85" +
|
||||||
"-W\xf0\xa02O\xf1\x1c\xa5\x00c r\xdf\xaf\xf0" +
|
"\x0a\xeeW\xe61\x9eF\x8c\xc8\xe8\x0b\xdd\xf7*|\x85" +
|
||||||
"u\x0aO\xa7r\x94\x06\x8c!Z\x03\x94\x06\x15\xbeE" +
|
"\xc2\xe3\xb14\xe2D\xc6\x00\x96\x11\x15\xfa\x15>\xa6\xf0" +
|
||||||
"\xe1\x1d,G\x1d\x801Fs@iT\xe1\x93\x0a\xd7" +
|
"\x04K#Ad\x8c`\x9a\xa80\xac\xf0\x09\x85k\xf1" +
|
||||||
"\xd295\xa1F\x81<\xa0\xf4\x98\xc2\xa7\x15\x9eY\x9a" +
|
"\xb4\x1aQ#\x07\x97\xa8\xf0\x98\xc2\xa7\x14\x9e\x9c\x9fF" +
|
||||||
"\xa3\x8c\x1a\xd7\x08/*|F\xe1\x9d\xcbr\xd4\x09\x18" +
|
"R\xcdk\x88\xe7\x15\xbe]\xe1\x1d\x0b\xd2\xe8 2\x9e" +
|
||||||
"O\xd21\xa0\xb4[\xe1\x15b\x14\x96mK:A\xa1" +
|
"\xc4!\xa2\xc2\x16\x85\x97\xc0\x10\x14+\x96\xb4\xfd\\\xa9" +
|
||||||
"\xd2\xfe\xe2\x07\xa5\xe7[\xae\x13\xffs\xd7OJ*\x17" +
|
"\xfd\xc5wK\xd7\xb3\x1c;\xfa\xe7\x8e\xd7,\xa9\x9c\x1d" +
|
||||||
"\x06\x97\x9a\xedXt\xb3jr)\xdbRw\x10eA" +
|
"\\4\xda1\xef\xa4\xd4\xe4\"\xd5\x92w\x02R\x84\xa0" +
|
||||||
"a\xddu\xed\xa9[;)\x1b\x98U\x9f\x96\x80\x8a\x9c" +
|
"\xe68\x95\xc9\x1b;)\xe5\x9be\x0f\xf3\x08y\x0et" +
|
||||||
"\xa8\xa7\xa5\x96 \x05\x86\xd1\\\x97\x03\x0bY\xd7)T" +
|
"\xb7\xe4\x92\xa0\xc0 \x9c\xeb\xa2oQ\xca\xb1s%$" +
|
||||||
"\xa8\x03\x8c:\x92\xa7\x9dt\xd1W6\xedB=ab" +
|
"\x88!\xd1|\xda\x09\x87\xb2E\xb3\x92\xab5\x99X\xde" +
|
||||||
"\xf9c\x8d\xc0m\xd4\xd1W1\x03Y!\x02#\x02\x85" +
|
"H\xddw\xea5\xca\x96L_\x96\x00b\x00!p\xeb" +
|
||||||
"^\xc3\xd9\xe6\xb9\xb5i\x92^\xcdrL\x1b\xc9I\xdc" +
|
"\xf6z\xd7\xa9NA\xbaU\xcb6+\xd4<\x89z\x80" +
|
||||||
"\x03lq;\xf4\xd5\x87\xa7\xcd\xaaz\xfeL\xd2\xa2\xab" +
|
"\xcdm\x87lmp\xca,\xab\xe7O6[t\xe92" +
|
||||||
"\xd7\x00\xa2\x9f\x93X\xd7\xd6\xa2C\xaaE\x079\x89\xff" +
|
"\"\xd1\xcb!V\xb4\xb5\xe8\x80j\xd1~\x0eq/C" +
|
||||||
"3\xca\xaa9I\xda\xf1\xa0i7\xe4m\x8dw7A" +
|
"J\xcdI\xb3\x1dw\x9b\x95\xba\xbc\xa9\xf1n'He" +
|
||||||
"\xaa\xca\xa0\xf9Up\x0e\xb8\xfdE\xd3\xd3\xcc\x9a\xff/" +
|
"\xe97\xber\xf6N\xa77o\xba\x9aY\xf5\xfe\xe7\xed" +
|
||||||
"o\xef\x94~V\xe9J\xbb\x98\x0d\x03\"\xc3I\xe4\x18" +
|
"M\xd2K)]i\x17\xb3A\"\x91\xe4\x10i\x86!" +
|
||||||
"\x8dx\x91\xecPOK\xef\x17M1\xff\xbbp#\xcd" +
|
"7\x94\x1dt\xb7\x04\x7f\xce\x14\xf3\x7f\x0b7\xd4\x88\xd2" +
|
||||||
"(\xcd\x11N\x03\xc9\x92\xa5x\xb7\xe8\xe20\x98^\xd0" +
|
"\x18\xe18Qs\xcb\"Z.\xba\xd8GL\xcfih" +
|
||||||
"\xa8\xb5\xd7(^c\xfaC\x1e\x98\xbeQ#\x96\xecu" +
|
"-6D{L\x7f\xc8%\xa6\xaf\xd6\xc0\x9a\x8b\x1d\xd1" +
|
||||||
"\x8a\xf7\xb7\xbe\xfa\x04\x98>\xa0\x85\xb1\xc8a\xa4\x19r" +
|
"\x02\xd7\x97\x1e%\xa6\xf7iA$r4\xd4\x089\x8c" +
|
||||||
"\x94\xc28;\xf4E\xf9\x8dR\x18+)\xc5b\x08\x8c" +
|
" \xca\x8e\xb2a~\xc3\x08\"%E$\x86D\xc3\xc8" +
|
||||||
"R\x91\xee\xbd\xdc\xb7\x09q\x9f\x7f/\x15\x8b\x97\xde\xdd" +
|
"\xe3\xce\xcb}\x93\x10g\xbd;\xa9X\xb4\xf5n_\xaf" +
|
||||||
"\xeb\xd5\x8c\x93U|U\xb5\xda\xfc\xce\x01\xa2\x8b\x93X" +
|
"F\x9c\x94\xe2\xab\xaa\xd5\xe6w\x9aHtr\x88\xf9\x0c" +
|
||||||
"\xca(\xb4\xdd\x05U\xccN\xb5\xb5\xd0\x9d\xd4\xaaI8" +
|
"A\xc5\x99U\xc5\xd4d[\x0b\xddJ\xad\x1a\x84#\xcd" +
|
||||||
"\xd6\xac\xac\xba\xac\xfc\xf7$\xfeM%\xa83\x9c\xc4l" +
|
"J\xa9\xcb\xca\x7f\xba\xe9\x7f\xbf\x12\xd4=\x1c\xe2p[" +
|
||||||
"[\xb7J\x05\xee\xe3$\xec6A\xb5\xd4b\x98\xe5$" +
|
"\xb7>\xaf\xc0g9\xc4\x8bm\x82zD-\x86\xc3\x1c" +
|
||||||
"\x8e'\x1a\xa5?\x7f\x02\x10\xc79\x89S\x8c4\xe9y" +
|
"\xe2tS\xa3\xf4SG\x89\xc4i\x0e\xf1^K\xa0\xf4" +
|
||||||
"1%\xad\xe1\xb5$\xd6v\xab\x93\x96#}5\xd0\x0b" +
|
"w\x94\xe1\xdb\x1c\xe2c\x06M\xban\xc4S\xab\xbb-" +
|
||||||
"3\xac\x8e\xd4\xe4\xd6\xa5W3\x1d\xe9P\xb0\xcd\xb4\xec" +
|
"\xdd\xad8\xe5\x09\xcb\x96\x9e\x9a\xf2\xd9\xc1VGj\x9c" +
|
||||||
"\x86'\x91\x0c\xdd\x9f\x01\x00\x00\xff\xffR3\x9d#"
|
"k\xd2\xad\x9a\xb6\xb4\xe1\xaf7\xadJ\xdd\x954w\x12" +
|
||||||
|
"scm\xe2\xf0w\x00\x00\x00\xff\xffk\x8c\xa4["
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
schemas.Register(schema_db8274f9144abc7e,
|
schemas.Register(schema_db8274f9144abc7e,
|
||||||
|
|
Loading…
Reference in New Issue