From 7f138126abf5b11a091f033f7ffd940669dc37df Mon Sep 17 00:00:00 2001 From: Neil Alexander Date: Wed, 25 Nov 2020 15:55:11 +0000 Subject: [PATCH] Update Pinecone demo --- build/gobind-pinecone/build.sh | 5 + build/gobind-pinecone/monolith.go | 279 ++++++++++++++++++ .../platform_ios.go | 0 .../platform_other.go | 0 build/{gobind => gobind-yggdrasil}/build.sh | 2 +- .../{gobind => gobind-yggdrasil}/monolith.go | 0 build/gobind-yggdrasil/platform_ios.go | 25 ++ build/gobind-yggdrasil/platform_other.go | 12 + cmd/dendrite-demo-pinecone/conn/client.go | 4 +- cmd/dendrite-demo-pinecone/main.go | 4 +- cmd/dendrite-demo-pinecone/signing/fetcher.go | 69 ----- go.mod | 2 + go.sum | 14 + 13 files changed, 342 insertions(+), 74 deletions(-) create mode 100644 build/gobind-pinecone/build.sh create mode 100644 build/gobind-pinecone/monolith.go rename build/{gobind => gobind-pinecone}/platform_ios.go (100%) rename build/{gobind => gobind-pinecone}/platform_other.go (100%) rename build/{gobind => gobind-yggdrasil}/build.sh (71%) rename build/{gobind => gobind-yggdrasil}/monolith.go (100%) create mode 100644 build/gobind-yggdrasil/platform_ios.go create mode 100644 build/gobind-yggdrasil/platform_other.go delete mode 100644 cmd/dendrite-demo-pinecone/signing/fetcher.go diff --git a/build/gobind-pinecone/build.sh b/build/gobind-pinecone/build.sh new file mode 100644 index 000000000..2dfa0178d --- /dev/null +++ b/build/gobind-pinecone/build.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +gomobile bind -v \ + -target ios \ + github.com/matrix-org/dendrite/build/gobind-pinecone \ No newline at end of file diff --git a/build/gobind-pinecone/monolith.go b/build/gobind-pinecone/monolith.go new file mode 100644 index 000000000..00622fe96 --- /dev/null +++ b/build/gobind-pinecone/monolith.go @@ -0,0 +1,279 @@ +package gobind + +import ( + "context" + "crypto/ed25519" + "crypto/tls" + "encoding/hex" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net" + "net/http" + "os" + "time" + + "github.com/gorilla/mux" + "github.com/hjson/hjson-go" + "github.com/matrix-org/dendrite/appservice" + "github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/conn" + "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing" + "github.com/matrix-org/dendrite/eduserver" + "github.com/matrix-org/dendrite/eduserver/cache" + "github.com/matrix-org/dendrite/federationsender" + "github.com/matrix-org/dendrite/federationsender/api" + "github.com/matrix-org/dendrite/internal/config" + "github.com/matrix-org/dendrite/internal/httputil" + "github.com/matrix-org/dendrite/internal/setup" + "github.com/matrix-org/dendrite/keyserver" + "github.com/matrix-org/dendrite/roomserver" + "github.com/matrix-org/dendrite/userapi" + "github.com/matrix-org/gomatrixserverlib" + "github.com/sirupsen/logrus" + + pineconeMulticast "github.com/matrix-org/pinecone/multicast" + pineconeSwitch "github.com/matrix-org/pinecone/packetswitch" + pineconeRouter "github.com/matrix-org/pinecone/router" + pineconeSessions "github.com/matrix-org/pinecone/sessions" + yggdrasilConfig "github.com/yggdrasil-network/yggdrasil-go/src/config" +) + +type DendriteMonolith struct { + logger logrus.Logger + config *yggdrasilConfig.NodeConfig + PineconeSwitch *pineconeSwitch.Switch + PineconeRouter *pineconeRouter.Router + PineconeMulticast *pineconeMulticast.Multicast + PineconeQUIC *pineconeSessions.QUIC + StorageDirectory string + listener net.Listener + httpServer *http.Server +} + +func (m *DendriteMonolith) BaseURL() string { + return fmt.Sprintf("http://%s", m.listener.Addr().String()) +} + +func (m *DendriteMonolith) PeerCount() int { + return m.PineconeSwitch.PeerCount() +} + +func (m *DendriteMonolith) SessionCount() int { + return len(m.PineconeQUIC.Sessions()) +} + +func (m *DendriteMonolith) SetMulticastEnabled(enabled bool) { + // TODO +} + +func (m *DendriteMonolith) SetStaticPeer(uri string) error { + parent, err := net.Dial("tcp", uri) + if err != nil { + logrus.WithError(err).Errorf("Failed to connect to Pinecone static peer") + return err + } + + if _, err := m.PineconeSwitch.Connect(parent); err != nil { + logrus.WithError(err).Errorf("Failed to connect Pinecone static peer to switch") + return err + } + + return nil +} + +func (m *DendriteMonolith) DisconnectNonMulticastPeers() { + // TODO +} + +func (m *DendriteMonolith) DisconnectMulticastPeers() { + // TODO +} + +func (m *DendriteMonolith) Start() { + m.config = yggdrasilConfig.GenerateConfig() + // If we already have an Yggdrasil config file from the Ygg + // demo then we'll just reuse the ed25519 keys from that. + var sk ed25519.PrivateKey + var pk ed25519.PublicKey + yggfile := fmt.Sprintf("%s/dendrite-yggdrasil.conf", m.StorageDirectory) + if _, err := os.Stat(yggfile); !os.IsNotExist(err) { + yggconf, e := ioutil.ReadFile(yggfile) + if e != nil { + panic(err) + } + mapconf := map[string]interface{}{} + if err = hjson.Unmarshal([]byte(yggconf), &mapconf); err != nil { + panic(err) + } + if mapconf["SigningPrivateKey"] != nil && mapconf["SigningPublicKey"] != nil { + if sk, err = hex.DecodeString(mapconf["SigningPrivateKey"].(string)); err != nil { + panic(err) + } + if pk, err = hex.DecodeString(mapconf["SigningPublicKey"].(string)); err != nil { + panic(err) + } + } else { + panic("should have private and public signing keys") + } + } else { + if pk, sk, err = ed25519.GenerateKey(nil); err != nil { + panic(err) + } + m.config.SigningPrivateKey = hex.EncodeToString(sk) + m.config.SigningPublicKey = hex.EncodeToString(pk) + yggconf, err := json.Marshal(m.config) + if err != nil { + panic(err) + } + if err := ioutil.WriteFile(yggfile, yggconf, 0644); err != nil { + panic(err) + } + } + + var err error + m.listener, err = net.Listen("tcp", "localhost:65432") + if err != nil { + panic(err) + } + + m.logger = logrus.Logger{ + Out: BindLogger{}, + } + m.logger.SetOutput(BindLogger{}) + logrus.SetOutput(BindLogger{}) + + logger := log.New(os.Stdout, "", 0) + + rL, rR := net.Pipe() + m.PineconeSwitch = pineconeSwitch.NewSwitch(logger, sk, pk, false) + m.PineconeRouter = pineconeRouter.NewRouter(logger, sk, pk, rL, "router", nil) + if _, err := m.PineconeSwitch.Connect(rR); err != nil { + panic(err) + } + + m.PineconeQUIC = pineconeSessions.NewQUIC(logger, m.PineconeRouter) + m.PineconeMulticast = pineconeMulticast.NewMulticast(logger, m.PineconeSwitch) + + cfg := &config.Dendrite{} + cfg.Defaults() + cfg.Global.ServerName = gomatrixserverlib.ServerName(m.config.SigningPublicKey) + cfg.Global.PrivateKey = sk + cfg.Global.KeyID = gomatrixserverlib.KeyID(signing.KeyID) + cfg.Global.Kafka.UseNaffka = true + cfg.Global.Kafka.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-naffka.db", m.StorageDirectory)) + cfg.UserAPI.AccountDatabase.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-account.db", m.StorageDirectory)) + cfg.UserAPI.DeviceDatabase.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-device.db", m.StorageDirectory)) + cfg.MediaAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-mediaapi.db", m.StorageDirectory)) + cfg.SyncAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-syncapi.db", m.StorageDirectory)) + cfg.RoomServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-roomserver.db", m.StorageDirectory)) + cfg.SigningKeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-signingkeyserver.db", m.StorageDirectory)) + cfg.KeyServer.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-keyserver.db", m.StorageDirectory)) + cfg.FederationSender.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-federationsender.db", m.StorageDirectory)) + cfg.AppServiceAPI.Database.ConnectionString = config.DataSource(fmt.Sprintf("file:%s/dendrite-p2p-appservice.db", m.StorageDirectory)) + cfg.MediaAPI.BasePath = config.Path(fmt.Sprintf("%s/tmp", m.StorageDirectory)) + cfg.MediaAPI.AbsBasePath = config.Path(fmt.Sprintf("%s/tmp", m.StorageDirectory)) + if err := cfg.Derive(); err != nil { + panic(err) + } + + base := setup.NewBaseDendrite(cfg, "Monolith", false) + defer base.Close() // nolint: errcheck + + accountDB := base.CreateAccountsDB() + federation := conn.CreateFederationClient(base, m.PineconeQUIC) + + serverKeyAPI := &signing.YggdrasilKeys{} + keyRing := serverKeyAPI.KeyRing() + keyAPI := keyserver.NewInternalAPI(&base.Cfg.KeyServer, federation) + userAPI := userapi.NewInternalAPI(accountDB, &cfg.UserAPI, cfg.Derived.ApplicationServices, keyAPI) + keyAPI.SetUserAPI(userAPI) + + rsAPI := roomserver.NewInternalAPI( + base, keyRing, + ) + + eduInputAPI := eduserver.NewInternalAPI( + base, cache.New(), userAPI, + ) + + asAPI := appservice.NewInternalAPI(base, userAPI, rsAPI) + fsAPI := federationsender.NewInternalAPI( + base, federation, rsAPI, keyRing, + ) + + // The underlying roomserver implementation needs to be able to call the fedsender. + // This is different to rsAPI which can be the http client which doesn't need this dependency + rsAPI.SetFederationSenderAPI(fsAPI) + + monolith := setup.Monolith{ + Config: base.Cfg, + AccountDB: accountDB, + Client: conn.CreateClient(base, m.PineconeQUIC), + FedClient: federation, + KeyRing: keyRing, + + AppserviceAPI: asAPI, + EDUInternalAPI: eduInputAPI, + FederationSenderAPI: fsAPI, + RoomserverAPI: rsAPI, + UserAPI: userAPI, + KeyAPI: keyAPI, + ExtPublicRoomsProvider: nil, + } + monolith.AddAllPublicRoutes( + base.PublicClientAPIMux, + base.PublicFederationAPIMux, + base.PublicKeyAPIMux, + base.PublicMediaAPIMux, + ) + + httpRouter := mux.NewRouter().SkipClean(true).UseEncodedPath() + httpRouter.PathPrefix(httputil.InternalPathPrefix).Handler(base.InternalAPIMux) + httpRouter.PathPrefix(httputil.PublicClientPathPrefix).Handler(base.PublicClientAPIMux) + httpRouter.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) + + pMux := mux.NewRouter().SkipClean(true).UseEncodedPath() + pMux.PathPrefix(httputil.PublicFederationPathPrefix).Handler(base.PublicFederationAPIMux) + pMux.PathPrefix(httputil.PublicMediaPathPrefix).Handler(base.PublicMediaAPIMux) + + m.PineconeQUIC.Mux().Handle(httputil.PublicFederationPathPrefix, pMux) + m.PineconeQUIC.Mux().Handle(httputil.PublicMediaPathPrefix, pMux) + + // Build both ends of a HTTP multiplex. + m.httpServer = &http.Server{ + Addr: ":0", + TLSNextProto: map[string]func(*http.Server, *tls.Conn, http.Handler){}, + ReadTimeout: 10 * time.Second, + WriteTimeout: 10 * time.Second, + IdleTimeout: 30 * time.Second, + BaseContext: func(_ net.Listener) context.Context { + return context.Background() + }, + Handler: pMux, + } + + go func() { + m.logger.Info("Listening on ", cfg.Global.ServerName) + m.logger.Fatal(m.httpServer.Serve(m.PineconeQUIC)) + }() + go func() { + logrus.Info("Listening on ", m.listener.Addr()) + logrus.Fatal(http.Serve(m.listener, httpRouter)) + }() + go func() { + logrus.Info("Sending wake-up message to known nodes") + req := &api.PerformBroadcastEDURequest{} + res := &api.PerformBroadcastEDUResponse{} + if err := fsAPI.PerformBroadcastEDU(context.TODO(), req, res); err != nil { + logrus.WithError(err).Error("Failed to send wake-up message to known nodes") + } + }() +} + +func (m *DendriteMonolith) Suspend() { + m.logger.Info("Suspending monolith") + if err := m.httpServer.Close(); err != nil { + m.logger.Warn("Error stopping HTTP server:", err) + } +} diff --git a/build/gobind/platform_ios.go b/build/gobind-pinecone/platform_ios.go similarity index 100% rename from build/gobind/platform_ios.go rename to build/gobind-pinecone/platform_ios.go diff --git a/build/gobind/platform_other.go b/build/gobind-pinecone/platform_other.go similarity index 100% rename from build/gobind/platform_other.go rename to build/gobind-pinecone/platform_other.go diff --git a/build/gobind/build.sh b/build/gobind-yggdrasil/build.sh similarity index 71% rename from build/gobind/build.sh rename to build/gobind-yggdrasil/build.sh index aa2cdfc5a..334cc03a2 100644 --- a/build/gobind/build.sh +++ b/build/gobind-yggdrasil/build.sh @@ -3,4 +3,4 @@ gomobile bind -v \ -ldflags "-X github.com/yggdrasil-network/yggdrasil-go/src/version.buildName=dendrite" \ -target ios \ - github.com/matrix-org/dendrite/build/gobind \ No newline at end of file + github.com/matrix-org/dendrite/build/gobind-yggdrasil \ No newline at end of file diff --git a/build/gobind/monolith.go b/build/gobind-yggdrasil/monolith.go similarity index 100% rename from build/gobind/monolith.go rename to build/gobind-yggdrasil/monolith.go diff --git a/build/gobind-yggdrasil/platform_ios.go b/build/gobind-yggdrasil/platform_ios.go new file mode 100644 index 000000000..01f8a6a04 --- /dev/null +++ b/build/gobind-yggdrasil/platform_ios.go @@ -0,0 +1,25 @@ +// +build ios + +package gobind + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework Foundation +#import +void Log(const char *text) { + NSString *nss = [NSString stringWithUTF8String:text]; + NSLog(@"%@", nss); +} +*/ +import "C" +import "unsafe" + +type BindLogger struct { +} + +func (nsl BindLogger) Write(p []byte) (n int, err error) { + p = append(p, 0) + cstr := (*C.char)(unsafe.Pointer(&p[0])) + C.Log(cstr) + return len(p), nil +} diff --git a/build/gobind-yggdrasil/platform_other.go b/build/gobind-yggdrasil/platform_other.go new file mode 100644 index 000000000..fdfb13bc0 --- /dev/null +++ b/build/gobind-yggdrasil/platform_other.go @@ -0,0 +1,12 @@ +// +build !ios + +package gobind + +import "log" + +type BindLogger struct{} + +func (nsl BindLogger) Write(p []byte) (n int, err error) { + log.Println(string(p)) + return len(p), nil +} diff --git a/cmd/dendrite-demo-pinecone/conn/client.go b/cmd/dendrite-demo-pinecone/conn/client.go index b4bcb5fa5..959099b5f 100644 --- a/cmd/dendrite-demo-pinecone/conn/client.go +++ b/cmd/dendrite-demo-pinecone/conn/client.go @@ -26,7 +26,7 @@ func CreateClient( tr.RegisterProtocol( "matrix", &RoundTripper{ inner: &http.Transport{ - MaxIdleConnsPerHost: 1, + MaxIdleConnsPerHost: -1, DisableKeepAlives: true, TLSHandshakeTimeout: 10 * time.Second, ResponseHeaderTimeout: 10 * time.Second, @@ -48,7 +48,7 @@ func CreateFederationClient( tr.RegisterProtocol( "matrix", &RoundTripper{ inner: &http.Transport{ - MaxIdleConnsPerHost: 1, + MaxIdleConnsPerHost: -1, DisableKeepAlives: true, TLSHandshakeTimeout: 10 * time.Second, ResponseHeaderTimeout: 10 * time.Second, diff --git a/cmd/dendrite-demo-pinecone/main.go b/cmd/dendrite-demo-pinecone/main.go index 3016064e3..e919c4c7b 100644 --- a/cmd/dendrite-demo-pinecone/main.go +++ b/cmd/dendrite-demo-pinecone/main.go @@ -32,7 +32,7 @@ import ( "github.com/matrix-org/dendrite/appservice" "github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/conn" "github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/embed" - "github.com/matrix-org/dendrite/cmd/dendrite-demo-pinecone/signing" + "github.com/matrix-org/dendrite/cmd/dendrite-demo-yggdrasil/signing" "github.com/matrix-org/dendrite/eduserver" "github.com/matrix-org/dendrite/eduserver/cache" "github.com/matrix-org/dendrite/federationsender" @@ -138,7 +138,7 @@ func main() { accountDB := base.CreateAccountsDB() federation := conn.CreateFederationClient(base, pQUIC) - serverKeyAPI := &signing.PineconeKeys{} + serverKeyAPI := &signing.YggdrasilKeys{} keyRing := serverKeyAPI.KeyRing() keyAPI := keyserver.NewInternalAPI(&base.Cfg.KeyServer, federation) diff --git a/cmd/dendrite-demo-pinecone/signing/fetcher.go b/cmd/dendrite-demo-pinecone/signing/fetcher.go deleted file mode 100644 index 7cc97470f..000000000 --- a/cmd/dendrite-demo-pinecone/signing/fetcher.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2020 The Matrix.org Foundation C.I.C. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package signing - -import ( - "context" - "encoding/hex" - "fmt" - "time" - - "github.com/matrix-org/gomatrixserverlib" -) - -const KeyID = "ed25519:dendrite-demo-pinecone" - -type PineconeKeys struct { -} - -func (f *PineconeKeys) KeyRing() *gomatrixserverlib.KeyRing { - return &gomatrixserverlib.KeyRing{ - KeyDatabase: f, - } -} - -func (f *PineconeKeys) FetchKeys( - ctx context.Context, - requests map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.Timestamp, -) (map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult, error) { - res := make(map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult) - for req := range requests { - if req.KeyID != KeyID { - return nil, fmt.Errorf("FetchKeys: cannot fetch key with ID %s, should be %s", req.KeyID, KeyID) - } - - hexkey, err := hex.DecodeString(string(req.ServerName)) - if err != nil { - return nil, fmt.Errorf("FetchKeys: can't decode server name %q: %w", req.ServerName, err) - } - - res[req] = gomatrixserverlib.PublicKeyLookupResult{ - VerifyKey: gomatrixserverlib.VerifyKey{ - Key: hexkey, - }, - ExpiredTS: gomatrixserverlib.PublicKeyNotExpired, - ValidUntilTS: gomatrixserverlib.AsTimestamp(time.Now().Add(24 * time.Hour * 365)), - } - } - return res, nil -} - -func (f *PineconeKeys) FetcherName() string { - return "PineconeKeys" -} - -func (f *PineconeKeys) StoreKeys(ctx context.Context, results map[gomatrixserverlib.PublicKeyLookupRequest]gomatrixserverlib.PublicKeyLookupResult) error { - return nil -} diff --git a/go.mod b/go.mod index 094388c38..69ae89a2d 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/gologme/log v1.2.0 github.com/gorilla/mux v1.8.0 github.com/hashicorp/golang-lru v0.5.4 + github.com/hjson/hjson-go v3.0.2-0.20200316202735-d5d0e8b0617d+incompatible github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect github.com/lib/pq v1.8.0 github.com/libp2p/go-libp2p v0.11.0 @@ -44,6 +45,7 @@ require ( github.com/yggdrasil-network/yggdrasil-go v0.3.15-0.20201006093556-760d9a7fd5ee go.uber.org/atomic v1.7.0 golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9 + golang.org/x/mobile v0.0.0-20200801112145-973feb4309de // indirect golang.org/x/net v0.0.0-20201110031124-69a78807bb2b gopkg.in/h2non/bimg.v1 v1.1.4 gopkg.in/yaml.v2 v2.3.0 diff --git a/go.sum b/go.sum index d2f968db9..281b71ebf 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,7 @@ github.com/Arceliar/phony v0.0.0-20191006174943-d0c68492aca0 h1:p3puK8Sl2xK+2Fnn github.com/Arceliar/phony v0.0.0-20191006174943-d0c68492aca0/go.mod h1:6Lkn+/zJilRMsKmbmG1RPoamiArC6HS73xbwRyp3UyI= 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/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Kubuxu/go-os-helper v0.0.1/go.mod h1:N8B+I7vPCT80IcP58r50u4+gEEcsZETFUpAzWW2ep1Y= @@ -212,6 +213,7 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hjson/hjson-go v3.0.2-0.20200316202735-d5d0e8b0617d+incompatible h1:v6BPcb9q9U6JDVsuizxBr/piVB/2Y1Q5GWoBybvZVWI= github.com/hjson/hjson-go v3.0.2-0.20200316202735-d5d0e8b0617d+incompatible/go.mod h1:qsetwF8NlsTsOTwZTApNlTCerV+b2GjYRRcIk4JMFio= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -937,14 +939,22 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9 h1:phUcVbl53swtrUN8kQEXFhUxPlIlWyBfKmidCu7P95o= golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 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/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20200801112145-973feb4309de h1:OVJ6QQUBAesB8CZijKDSsXX7xYVtUhrkY0gwMfbi4p4= +golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/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= @@ -1056,13 +1066,17 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd h1:/e+gpKk9r3dJobndpTytxS2gOy6m5uvpg+ISQoEcusQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= 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-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425 h1:VvQyQJN0tSuecqgcIxMWnnfG5kSmgy9KZR9sW3W5QeA= golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69 h1:yBHHx+XZqXJBm6Exke3N7V9gnlsyXxoCPEb1yVenjfk= +golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= 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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=