diff --git a/.github/workflows/golang-test-linux.yml b/.github/workflows/golang-test-linux.yml index 049e05c7c..9f20682a4 100644 --- a/.github/workflows/golang-test-linux.yml +++ b/.github/workflows/golang-test-linux.yml @@ -35,8 +35,11 @@ jobs: - name: Checkout code uses: actions/checkout@v2 + - name: Install dependencies + run: sudo apt update && sudo apt install -y -q libgtk-3-dev libappindicator3-dev libayatana-appindicator3-dev + - name: Install modules run: go mod tidy - name: Test - run: go test -exec sudo -timeout 5m -p 1 ./... \ No newline at end of file + run: go test -exec sudo -timeout 5m -p 1 ./... diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 054f571f4..e0bc9fbc5 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -6,6 +6,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + + - name: Install dependencies + run: sudo apt update && sudo apt install -y -q libgtk-3-dev libappindicator3-dev libayatana-appindicator3-dev + - name: golangci-lint uses: golangci/golangci-lint-action@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f11071774..d21c97c0a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -49,6 +49,8 @@ jobs: with: username: ${{ secrets.DOCKER_USER }} password: ${{ secrets.DOCKER_TOKEN }} + - name: Install dependencies + run: sudo apt update && sudo apt install -y -q libgtk-3-dev libappindicator3-dev libayatana-appindicator3-dev - name: Run GoReleaser uses: goreleaser/goreleaser-action@v2 @@ -71,3 +73,39 @@ jobs: ref: v0.0.2 token: ${{ secrets.SIGN_GITHUB_TOKEN }} inputs: '{ "tag": "${{ github.ref }}" }' + + release_ui: + runs-on: macos-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 # It is required for GoReleaser to work properly + - + name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.17 + - + name: Cache Go modules + uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - + name: Install modules + run: go mod tidy + - + name: Run GoReleaser + uses: goreleaser/goreleaser-action@v2 + with: + version: v1.6.3 + args: release --config .goreleaser_ui_darwin.yaml --rm-dist + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }} + UPLOAD_DEBIAN_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }} + UPLOAD_YUM_SECRET: ${{ secrets.PKG_UPLOAD_SECRET }} diff --git a/.goreleaser.yaml b/.goreleaser.yaml index d214d8e86..ab9f6d8ed 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -4,7 +4,6 @@ builds: dir: client binary: wiretrustee env: [CGO_ENABLED=0] - goos: - linux - darwin @@ -55,14 +54,50 @@ builds: ldflags: - -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser mod_timestamp: '{{ .CommitTimestamp }}' + + - id: wiretrustee-ui + dir: client/ui + binary: wiretrustee-ui + env: [CGO_ENABLED=1] + goos: + - windows + - linux + goarch: + - amd64 + ldflags: + - -s -w -X github.com/wiretrustee/wiretrustee/client/ui/system.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser + mod_timestamp: '{{ .CommitTimestamp }}' + archives: - builds: - wiretrustee + nfpms: + + - maintainer: Wiretrustee + description: Wiretrustee client UI. + homepage: https://wiretrustee.com/ + id: wiretrustee-ui-deb + package_name: wiretrustee-ui + builds: + - wiretrustee-ui + formats: + - deb + - rpm + contents: + - src: client/ui/wiretrustee.desktop + dst: /usr/share/applications/wiretrustee.desktop + - src: client/ui/wiretrustee.png + dst: /usr/share/icons/hicolor/256x256/wiretrustee.png + dependencies: + - libayatana-appindicator3-1 + - libgtk-3-dev + - libappindicator3-dev + - maintainer: Wiretrustee description: Wiretrustee client. homepage: https://wiretrustee.com/ - id: deb + id: wiretrustee-deb bindir: /usr/bin builds: - wiretrustee @@ -76,7 +111,7 @@ nfpms: - maintainer: Wiretrustee description: Wiretrustee client. homepage: https://wiretrustee.com/ - id: rpm + id: wiretrustee-rpm bindir: /usr/bin builds: - wiretrustee diff --git a/.goreleaser_ui_darwin.yaml b/.goreleaser_ui_darwin.yaml new file mode 100644 index 000000000..27de3a2df --- /dev/null +++ b/.goreleaser_ui_darwin.yaml @@ -0,0 +1,38 @@ +project_name: wiretrustee-ui +builds: + - id: wiretrustee-ui-darwin + dir: client/ui + binary: wiretrustee-ui + env: [CGO_ENABLED=1] + + goos: + - darwin + goarch: + - amd64 + - arm64 + gomips: + - hardfloat + - softfloat + ldflags: + - -s -w -X github.com/wiretrustee/wiretrustee/client/ui/system.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.CommitDate}} -X main.builtBy=goreleaser + mod_timestamp: '{{ .CommitTimestamp }}' + tags: + - load_wgnt_from_rsrc + +archives: + - builds: + - wiretrustee-ui-darwin + +brews: + - + tap: + owner: wiretrustee + name: homebrew-client-ui + token: "{{ .Env.HOMEBREW_TAP_GITHUB_TOKEN }}" + commit_author: + name: Wiretrustee + email: wiretrustee@wiretrustee.com + description: Wiretrustee project. + download_strategy: CurlDownloadStrategy + homepage: https://wiretrustee.com/ + license: "BSD3" diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..7d7828384 --- /dev/null +++ b/Makefile @@ -0,0 +1,42 @@ +PACKAGE_NAME := github.com/wiretrustee/wiretrustee/ +GOLANG_CROSS_VERSION ?= v1.17.6 + +SYSROOT_DIR ?= sysroots +SYSROOT_ARCHIVE ?= sysroots.tar.bz2 + +.PHONY: sysroot-pack +sysroot-pack: + @tar cf - $(SYSROOT_DIR) -P | pv -s $[$(du -sk $(SYSROOT_DIR) | awk '{print $1}') * 1024] | pbzip2 > $(SYSROOT_ARCHIVE) + +.PHONY: sysroot-unpack +sysroot-unpack: + @pv $(SYSROOT_ARCHIVE) | pbzip2 -cd | tar -xf - + +.PHONY: release-dry-run +release-dry-run: + @docker run \ + --rm \ + --privileged \ + -e CGO_ENABLED=1 \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v `pwd`:/go/src/$(PACKAGE_NAME) \ + -w /go/src/$(PACKAGE_NAME) \ + goreleaser/goreleaser-cross:${GOLANG_CROSS_VERSION} \ + --rm-dist --skip-validate --skip-publish + +.PHONY: release +release: + @if [ ! -f ".release-env" ]; then \ + echo "\033[91m.release-env is required for release\033[0m";\ + exit 1;\ + fi + docker run \ + --rm \ + --privileged \ + -e CGO_ENABLED=1 \ + --env-file .release-env \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -v `pwd`:/go/src/$(PACKAGE_NAME) \ + -w /go/src/$(PACKAGE_NAME) \ + goreleaser/goreleaser-cross:${GOLANG_CROSS_VERSION} \ + release --rm-dist diff --git a/README.md b/README.md index 3951811a8..2e46b2b11 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Hosted version: ```shell brew install wiretrustee/client/wiretrustee ``` -**Installation from binary** +**Installation from binary** 1. Checkout Wiretrustee [releases](https://github.com/wiretrustee/wiretrustee/releases/latest) 2. Download the latest release (**Switch VERSION to the latest**): ```shell @@ -138,15 +138,15 @@ Hosted version: sudo mv wiretrusee /usr/bin/wiretrustee chmod +x /usr/bin/wiretrustee ``` -After that you may need to add /usr/bin in your PATH environment variable: + After that you may need to add /usr/bin in your PATH environment variable: ````shell export PATH=$PATH:/usr/bin ```` 4. Install and run the service -```shell + ```shell sudo wiretrustee service install - sudo wiretrustee service start -``` + sudo wiretrustee service start + ``` #### Windows 1. Checkout Wiretrustee [releases](https://github.com/wiretrustee/wiretrustee/releases/latest) diff --git a/client/ui/client_ui.go b/client/ui/client_ui.go new file mode 100644 index 000000000..d72663d16 --- /dev/null +++ b/client/ui/client_ui.go @@ -0,0 +1,216 @@ +package main + +import ( + "context" + "flag" + "fmt" + "runtime" + "strings" + "time" + + _ "embed" + + "github.com/getlantern/systray" + log "github.com/sirupsen/logrus" + "github.com/skratchdot/open-golang/open" + "github.com/wiretrustee/wiretrustee/client/internal" + "github.com/wiretrustee/wiretrustee/client/proto" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +func main() { + var daemonAddr string + + defaultDaemonAddr := "unix:///var/run/wiretrustee.sock" + if runtime.GOOS == "windows" { + defaultDaemonAddr = "tcp://127.0.0.1:41731" + } + + flag.StringVar( + &daemonAddr, "daemon-addr", + defaultDaemonAddr, + "Daemon service address to serve CLI requests [unix|tcp]://[path|host:port]") + + flag.Parse() + + client := newServiceClient(daemonAddr) + systray.Run(client.onTrayReady, client.onTrayExit) +} + +//go:embed connected.ico +var iconConnected []byte + +//go:embed disconnected.ico +var iconDisconnected []byte + +type serviceClient struct { + ctx context.Context + addr string + conn proto.DaemonServiceClient + mStatus *systray.MenuItem + mUp *systray.MenuItem + mDown *systray.MenuItem +} + +func newServiceClient(addr string) *serviceClient { + s := &serviceClient{ + ctx: context.Background(), + addr: addr, + } + return s +} + +func (s *serviceClient) up() error { + conn, err := s.client() + if err != nil { + log.Errorf("get client: %v", err) + return err + } + + status, err := conn.Status(s.ctx, &proto.StatusRequest{}) + if err != nil { + log.Errorf("get service status: %v", err) + return err + } + + if status.Status != string(internal.StatusIdle) { + log.Warnf("already connected") + return nil + } + + if _, err := s.conn.Up(s.ctx, &proto.UpRequest{}); err != nil { + log.Errorf("up service: %v", err) + return err + } + + return nil +} + +func (s *serviceClient) down() error { + conn, err := s.client() + if err != nil { + log.Errorf("get client: %v", err) + return err + } + + status, err := conn.Status(s.ctx, &proto.StatusRequest{}) + if err != nil { + log.Errorf("get service status: %v", err) + return err + } + + if status.Status != string(internal.StatusConnected) { + log.Warnf("already down") + return nil + } + + if _, err := s.conn.Down(s.ctx, &proto.DownRequest{}); err != nil { + log.Errorf("down service: %v", err) + return err + } + + return nil +} + +func (s *serviceClient) updateStatus() { + conn, err := s.client() + if err != nil { + log.Errorf("get client: %v", err) + return + } + + status, err := conn.Status(s.ctx, &proto.StatusRequest{}) + if err != nil { + log.Errorf("get service status: %v", err) + return + } + + if status.Status == string(internal.StatusConnected) { + systray.SetTemplateIcon(iconConnected, iconConnected) + s.mStatus.SetTitle("Connected") + s.mUp.Disable() + s.mDown.Enable() + } else { + systray.SetTemplateIcon(iconDisconnected, iconDisconnected) + s.mStatus.SetTitle("Disconnected") + s.mDown.Disable() + s.mUp.Enable() + } +} + +func (s *serviceClient) onTrayReady() { + systray.SetTemplateIcon(iconDisconnected, iconDisconnected) + go func() { + s.mStatus = systray.AddMenuItem("Disconnected", "Disconnected") + s.mStatus.Disable() + + systray.AddSeparator() + + s.mUp = systray.AddMenuItem("Up", "Up") + + s.mDown = systray.AddMenuItem("Down", "Down") + s.mDown.Disable() + + mURL := systray.AddMenuItem("Open UI", "wiretrustee website") + + systray.AddSeparator() + + mQuit := systray.AddMenuItem("Quit", "Quit the whole app") + + s.updateStatus() + + ticker := time.NewTicker(time.Second * 3) + defer ticker.Stop() + + var err error + for { + select { + case <-mURL.ClickedCh: + err = open.Run("https://app.wiretrustee.com") + case <-s.mUp.ClickedCh: + s.mUp.Disable() + if err = s.up(); err != nil { + s.mUp.Enable() + } + case <-s.mDown.ClickedCh: + s.mDown.Disable() + if err = s.down(); err != nil { + s.mDown.Enable() + } + case <-mQuit.ClickedCh: + systray.Quit() + return + case <-ticker.C: + s.updateStatus() + } + if err != nil { + log.Errorf("process connection: %v", err) + } + } + }() +} + +func (s *serviceClient) onTrayExit() {} + +func (s *serviceClient) client() (proto.DaemonServiceClient, error) { + if s.conn != nil { + return s.conn, nil + } + + ctx, cancel := context.WithTimeout(context.Background(), time.Second*3) + defer cancel() + + conn, err := grpc.DialContext( + ctx, + strings.TrimPrefix(s.addr, "tcp://"), + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithBlock(), + ) + if err != nil { + return nil, fmt.Errorf("dial service: %w", err) + } + + s.conn = proto.NewDaemonServiceClient(conn) + return s.conn, nil +} diff --git a/client/ui/config/config.go b/client/ui/config/config.go new file mode 100644 index 000000000..fc3361b61 --- /dev/null +++ b/client/ui/config/config.go @@ -0,0 +1,46 @@ +package config + +import ( + "os" + "runtime" +) + +// ClientConfig basic settings for the UI application. +type ClientConfig struct { + configPath string + logFile string + daemonAddr string +} + +// Config object with default settings. +// +// We are creating this package to extract utility functions from the cmd package +// reading and parsing the configurations for the client should be done here +func Config() *ClientConfig { + defaultConfigPath := "/etc/wiretrustee/config.json" + defaultLogFile := "/var/log/wiretrustee/client.log" + if runtime.GOOS == "windows" { + defaultConfigPath = os.Getenv("PROGRAMDATA") + "\\Wiretrustee\\" + "config.json" + defaultLogFile = os.Getenv("PROGRAMDATA") + "\\Wiretrustee\\" + "client.log" + } + + defaultDaemonAddr := "unix:///var/run/wiretrustee.sock" + if runtime.GOOS == "windows" { + defaultDaemonAddr = "tcp://127.0.0.1:41731" + } + return &ClientConfig{ + configPath: defaultConfigPath, + logFile: defaultLogFile, + daemonAddr: defaultDaemonAddr, + } +} + +// DaemonAddr of the gRPC API. +func (c *ClientConfig) DaemonAddr() string { + return c.daemonAddr +} + +// LogFile path. +func (c *ClientConfig) LogFile() string { + return c.logFile +} diff --git a/client/ui/connected.ico b/client/ui/connected.ico new file mode 100644 index 000000000..7ec2fb4f6 Binary files /dev/null and b/client/ui/connected.ico differ diff --git a/client/ui/disconnected.ico b/client/ui/disconnected.ico new file mode 100644 index 000000000..6f02f9ff5 Binary files /dev/null and b/client/ui/disconnected.ico differ diff --git a/client/ui/wiretrustee.desktop b/client/ui/wiretrustee.desktop new file mode 100644 index 000000000..0f39a9a3c --- /dev/null +++ b/client/ui/wiretrustee.desktop @@ -0,0 +1,9 @@ +#!/usr/bin/env xdg-open +[Desktop Entry] +Version=1.0 +Terminal=false +Type=Application +Name=Wiretrustee UI +Exec=/usr/bin/wiretrustee-ui +Icon=/usr/share/icons/hicolor/256x256/wiretrustee.png +Comment=Wiretrustee client UI. diff --git a/client/ui/wiretrustee.png b/client/ui/wiretrustee.png new file mode 100644 index 000000000..296be93b0 Binary files /dev/null and b/client/ui/wiretrustee.png differ diff --git a/go.mod b/go.mod index 85f13eff4..4d3210f78 100644 --- a/go.mod +++ b/go.mod @@ -28,8 +28,10 @@ require ( ) require ( + github.com/getlantern/systray v1.2.1 github.com/magiconair/properties v1.8.5 github.com/rs/xid v1.3.0 + github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 github.com/stretchr/testify v1.7.0 ) @@ -37,6 +39,13 @@ require ( github.com/BurntSushi/toml v0.4.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 // indirect + github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 // indirect + github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 // indirect + github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 // indirect + github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 // indirect + github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f // indirect + github.com/go-stack/stack v1.8.0 // indirect github.com/google/go-cmp v0.5.6 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/josharian/native v0.0.0-20200817173448-b6b71def0850 // indirect @@ -44,6 +53,7 @@ require ( github.com/mdlayher/netlink v1.4.2 // indirect github.com/mdlayher/socket v0.0.0-20211102153432-57e3fa563ecb // indirect github.com/nxadm/tail v1.4.8 // indirect + github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c // indirect github.com/pion/dtls/v2 v2.1.2 // indirect github.com/pion/logging v0.2.2 // indirect github.com/pion/mdns v0.0.5 // indirect diff --git a/go.sum b/go.sum index 37181556e..5a007a7f8 100644 --- a/go.sum +++ b/go.sum @@ -116,6 +116,20 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/getlantern/context v0.0.0-20190109183933-c447772a6520 h1:NRUJuo3v3WGC/g5YiyF790gut6oQr5f3FBI88Wv0dx4= +github.com/getlantern/context v0.0.0-20190109183933-c447772a6520/go.mod h1:L+mq6/vvYHKjCX2oez0CgEAJmbq1fbb/oNJIWQkBybY= +github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7 h1:6uJ+sZ/e03gkbqZ0kUG6mfKoqDb4XMAzMIwlajq19So= +github.com/getlantern/errors v0.0.0-20190325191628-abdb3e3e36f7/go.mod h1:l+xpFBrCtDLpK9qNjxs+cHU6+BAdlBaxHqikB6Lku3A= +github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7 h1:guBYzEaLz0Vfc/jv0czrr2z7qyzTOGC9hiQ0VC+hKjk= +github.com/getlantern/golog v0.0.0-20190830074920-4ef2e798c2d7/go.mod h1:zx/1xUUeYPy3Pcmet8OSXLbF47l+3y6hIPpyLWoR9oc= +github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7 h1:micT5vkcr9tOVk1FiH8SWKID8ultN44Z+yzd2y/Vyb0= +github.com/getlantern/hex v0.0.0-20190417191902-c6586a6fe0b7/go.mod h1:dD3CgOrwlzca8ed61CsZouQS5h5jIzkK9ZWrTcf0s+o= +github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55 h1:XYzSdCbkzOC0FDNrgJqGRo8PCMFOBFL9py72DRs7bmc= +github.com/getlantern/hidden v0.0.0-20190325191715-f02dbb02be55/go.mod h1:6mmzY2kW1TOOrVy+r41Za2MxXM+hhqTtY3oBKd2AgFA= +github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f h1:wrYrQttPS8FHIRSlsrcuKazukx/xqO/PpLZzZXsF+EA= +github.com/getlantern/ops v0.0.0-20190325191751-d70cb0d6f85f/go.mod h1:D5ao98qkA6pxftxoqzibIBBrLSUli+kYnJqrgBf9cIA= +github.com/getlantern/systray v1.2.1 h1:udsC2k98v2hN359VTFShuQW6GGprRprw6kD6539JikI= +github.com/getlantern/systray v1.2.1/go.mod h1:AecygODWIsBquJCJFop8MEQcJbWFfw/1yWbVabNgpCM= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do= @@ -128,6 +142,7 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM= github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY= +github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= 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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -353,6 +368,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0 h1:9Luw4uT5HTjHTN8+aNcSThgH1vdXnmdJ8xIfZ4wyTRE= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c h1:rp5dCmg/yLR3mgFuSOe4oEnDDmGLROTvMragMUXpTQw= +github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -406,6 +423,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.3.3/go.mod h1:5KUK8ByomD5Ti5Artl0RtHeI5pTF7MIDuXL3yY520V4= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=