diff --git a/.goreleaser.yml b/.goreleaser.yml
index 899ac85..a32bb10 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -1,21 +1,48 @@
+env:
+ - GO111MODULE=on
+ - CGO_ENABLED=1
before:
hooks:
- make clean
- - go mod download
- - go generate ./...
+ - make embed
builds:
- - main: ./cmd/hetty
+ - id: hetty-darwin-amd64
+ main: ./cmd/hetty
+ goarch:
+ - amd64
+ goos:
+ - darwin
env:
- - CGO_ENABLED=0
+ - CC=o64-clang
+ - CXX=o64-clang++
+ flags:
+ - -mod=readonly
+ ldflags:
+ - id: hetty-linux-amd64
+ main: ./cmd/hetty
+ goarch:
+ - amd64
goos:
- linux
+ flags:
+ - -mod=readonly
+ ldflags:
+ - id: hetty-windows-amd64
+ main: ./cmd/hetty
+ goarch:
+ - amd64
+ goos:
- windows
- - darwin
- hooks:
- pre: make embed
+ env:
+ - CC=x86_64-w64-mingw32-gcc
+ - CXX=x86_64-w64-mingw32-g++
+ flags:
+ - -mod=readonly
+ ldflags:
+ - -buildmode=exe
archives:
- replacements:
- darwin: Darwin
+ darwin: macOS
linux: Linux
windows: Windows
386: i386
diff --git a/Dockerfile b/Dockerfile
index fb5b435..83a7729 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,9 +1,10 @@
ARG GO_VERSION=1.15
-ARG CGO_ENABLED=0
+ARG CGO_ENABLED=1
ARG NODE_VERSION=14.11
FROM golang:${GO_VERSION}-alpine AS go-builder
WORKDIR /app
+RUN apk add --no-cache build-base
COPY go.mod go.sum ./
RUN go mod download
COPY cmd ./cmd
diff --git a/Makefile b/Makefile
index 7455569..21e0c44 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,6 @@
+PACKAGE_NAME := github.com/dstotijn/hetty
+GOLANG_CROSS_VERSION ?= v1.15.2
+
setup:
go mod download
go generate ./...
@@ -9,12 +12,34 @@ embed:
.PHONY: embed
build: embed
- go build ./cmd/hetty
+ env CGO_ENABLED=1 go build ./cmd/hetty
.PHONY: build
clean:
rm -rf cmd/hetty/rice-box.go
.PHONY: clean
+release-dry-run:
+ @docker run \
+ --rm \
+ -v `pwd`:/go/src/$(PACKAGE_NAME) \
+ -v `pwd`/admin/dist:/go/src/$(PACKAGE_NAME)/admin/dist \
+ -w /go/src/$(PACKAGE_NAME) \
+ troian/golang-cross:${GOLANG_CROSS_VERSION} \
+ --rm-dist --skip-validate --skip-publish
+.PHONY: release-dry-run
+
release:
- goreleaser -p 1
\ No newline at end of file
+ @if [ ! -f ".release-env" ]; then \
+ echo "\033[91mFile \`.release-env\` is missing.\033[0m";\
+ exit 1;\
+ fi
+ @docker run \
+ --rm \
+ -v `pwd`:/go/src/$(PACKAGE_NAME) \
+ -v `pwd`/admin/dist:/go/src/$(PACKAGE_NAME)/admin/dist \
+ -w /go/src/$(PACKAGE_NAME) \
+ --env-file .release-env \
+ troian/golang-cross:${GOLANG_CROSS_VERSION} \
+ release --rm-dist
+.PHONY: release
\ No newline at end of file
diff --git a/README.md b/README.md
index 2a40a98..600ff2e 100644
--- a/README.md
+++ b/README.md
@@ -59,7 +59,7 @@ on Docker Hub.
$ docker run \
-v $HOME/.hetty/hetty_key.pem:/root/.hetty/hetty_key.pem \
-v $HOME/.hetty/hetty_cert.pem:/root/.hetty/hetty_cert.pem \
--v $HOME/.hetty/hetty.bolt:/root/.hetty/hetty.bolt \
+-v $HOME/.hetty/hetty.db:/root/.hetty/hetty.db \
-p 127.0.0.1:8080:8080 \
dstotijn/hetty
```
@@ -81,7 +81,7 @@ Usage of ./hetty:
-cert string
CA certificate filepath. Creates a new CA certificate is file doesn't exist (default "~/.hetty/hetty_cert.pem")
-db string
- Database file path (default "~/.hetty/hetty.bolt")
+ Database file path (default "~/.hetty/hetty.db")
-key string
CA private key filepath. Creates a new CA private key if file doesn't exist (default "~/.hetty/hetty_key.pem")
```
@@ -103,11 +103,6 @@ write-up on its mission and roadmap. A short summary/braindump:
it as a CLI tool.
- Pluggable architecture for the MITM proxy and future modules, making it
possible for hook into the core engine.
-- I’ve chosen [Cayley](https://cayley.io/) as the graph database (backed by
- BoltDB storage on disk) for now (not sure if it will work in the long run).
- The benefit is that Cayley (also written in Go)
- is embedded as a library. Because of this, the complete application is self contained
- in a single running binary.
- Talk to the community, and focus on the features that the majority.
Less features means less code to maintain.
diff --git a/admin/src/components/Layout.tsx b/admin/src/components/Layout.tsx
index f2c4975..69fe1b6 100644
--- a/admin/src/components/Layout.tsx
+++ b/admin/src/components/Layout.tsx
@@ -154,7 +154,7 @@ export function Layout({ title, page, children }: Props): JSX.Element {
-
+
Hetty://
{title}
diff --git a/admin/src/components/reqlog/LogDetail.tsx b/admin/src/components/reqlog/LogDetail.tsx
index 8c787fe..03d06dc 100644
--- a/admin/src/components/reqlog/LogDetail.tsx
+++ b/admin/src/components/reqlog/LogDetail.tsx
@@ -32,7 +32,7 @@ const HTTP_REQUEST_LOG = gql`
`;
interface Props {
- requestId: string;
+ requestId: number;
}
function LogDetail({ requestId: id }: Props): JSX.Element {
diff --git a/admin/src/components/reqlog/LogsOverview.tsx b/admin/src/components/reqlog/LogsOverview.tsx
index e7907dd..16a0992 100644
--- a/admin/src/components/reqlog/LogsOverview.tsx
+++ b/admin/src/components/reqlog/LogsOverview.tsx
@@ -25,14 +25,14 @@ const HTTP_REQUEST_LOGS = gql`
function LogsOverview(): JSX.Element {
const router = useRouter();
- const detailReqLogId = router.query.id as string;
- console.log(detailReqLogId);
+ const detailReqLogId =
+ router.query.id && parseInt(router.query.id as string, 10);
const { loading, error, data } = useQuery(HTTP_REQUEST_LOGS, {
pollInterval: 1000,
});
- const handleLogClick = (reqId: string) => {
+ const handleLogClick = (reqId: number) => {
router.push("/proxy/logs?id=" + reqId, undefined, {
shallow: false,
});
diff --git a/admin/src/components/reqlog/RequestList.tsx b/admin/src/components/reqlog/RequestList.tsx
index 6076b95..50c6181 100644
--- a/admin/src/components/reqlog/RequestList.tsx
+++ b/admin/src/components/reqlog/RequestList.tsx
@@ -31,8 +31,8 @@ const useStyles = makeStyles((theme: Theme) =>
interface Props {
logs: Array;
- selectedReqLogId?: string;
- onLogClick(requestId: string): void;
+ selectedReqLogId?: number;
+ onLogClick(requestId: number): void;
theme: Theme;
}
@@ -63,8 +63,8 @@ function RequestList({
interface RequestListTableProps {
logs?: any;
- selectedReqLogId?: string;
- onLogClick(requestId: string): void;
+ selectedReqLogId?: number;
+ onLogClick(requestId: number): void;
theme: Theme;
}
diff --git a/cmd/hetty/main.go b/cmd/hetty/main.go
index ba70048..c4a476b 100644
--- a/cmd/hetty/main.go
+++ b/cmd/hetty/main.go
@@ -11,7 +11,7 @@ import (
rice "github.com/GeertJohan/go.rice"
"github.com/dstotijn/hetty/pkg/api"
- "github.com/dstotijn/hetty/pkg/db/cayley"
+ "github.com/dstotijn/hetty/pkg/db/sqlite"
"github.com/dstotijn/hetty/pkg/proxy"
"github.com/dstotijn/hetty/pkg/reqlog"
"github.com/dstotijn/hetty/pkg/scope"
@@ -33,7 +33,7 @@ var (
func main() {
flag.StringVar(&caCertFile, "cert", "~/.hetty/hetty_cert.pem", "CA certificate filepath. Creates a new CA certificate is file doesn't exist")
flag.StringVar(&caKeyFile, "key", "~/.hetty/hetty_key.pem", "CA private key filepath. Creates a new CA private key if file doesn't exist")
- flag.StringVar(&dbFile, "db", "~/.hetty/hetty.bolt", "Database file path")
+ flag.StringVar(&dbFile, "db", "~/.hetty/hetty.db", "Database file path")
flag.StringVar(&addr, "addr", ":8080", "TCP address to listen on, in the form \"host:port\"")
flag.StringVar(&adminPath, "adminPath", "", "File path to admin build")
flag.Parse()
@@ -59,7 +59,7 @@ func main() {
log.Fatalf("[FATAL] Could not create/load CA key pair: %v", err)
}
- db, err := cayley.NewDatabase(dbFile)
+ db, err := sqlite.New(dbFile)
if err != nil {
log.Fatalf("[FATAL] Could not initialize database: %v", err)
}
diff --git a/go.mod b/go.mod
index 313597c..b33a920 100644
--- a/go.mod
+++ b/go.mod
@@ -5,12 +5,11 @@ go 1.15
require (
github.com/99designs/gqlgen v0.11.3
github.com/GeertJohan/go.rice v1.0.0
- github.com/cayleygraph/cayley v0.7.7
- github.com/cayleygraph/quad v1.1.0
- github.com/google/uuid v1.1.2
github.com/gorilla/mux v1.7.4
- github.com/hidal-go/hidalgo v0.0.0-20190814174001-42e03f3b5eaa
+ github.com/gorilla/websocket v1.4.0 // indirect
+ github.com/hashicorp/golang-lru v0.5.1 // indirect
+ github.com/mattn/go-sqlite3 v1.14.4
github.com/mitchellh/go-homedir v1.1.0
+ github.com/mitchellh/mapstructure v1.1.2 // indirect
github.com/vektah/gqlparser/v2 v2.0.1
- golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346 // indirect
)
diff --git a/go.sum b/go.sum
index 0ab7b9d..eb58cb3 100644
--- a/go.sum
+++ b/go.sum
@@ -1,320 +1,85 @@
-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=
-cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw=
github.com/99designs/gqlgen v0.11.3 h1:oFSxl1DFS9X///uHV3y6CEfpcXWrDUxVblR4Xib2bs4=
github.com/99designs/gqlgen v0.11.3/go.mod h1:RgX5GRRdDWNkh4pBrdzNpNPFVsdoUFY2+adM6nb1N+4=
-github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
-github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg=
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ=
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
-github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
-github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
-github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/agnivade/levenshtein v1.0.1 h1:3oJU7J3FGFmyhn8KHjmVaZCN5hxTr7GxgRue+sxIXdQ=
github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM=
github.com/agnivade/levenshtein v1.0.3 h1:M5ZnqLOoZR8ygVq0FfkXsNOKzMCk0xRiow0R5+5VkQ0=
github.com/agnivade/levenshtein v1.0.3/go.mod h1:4SFRZbbXWLF4MU1T9Qg0pGgH3Pjs+t6ie5efyrwRJXs=
github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw=
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
-github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
-github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
-github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
-github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/badgerodon/peg v0.0.0-20130729175151-9e5f7f4d07ca/go.mod h1:TWe0N2hv5qvpLHT+K16gYcGBllld4h65dQ/5CNuirmk=
-github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
-github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
-github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
-github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
-github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
-github.com/cayleygraph/cayley v0.7.7 h1:z+7xkAbg6bKiXJOtOkEG3zCm2K084sr/aGwFV7xcQNs=
-github.com/cayleygraph/cayley v0.7.7/go.mod h1:VUd+PInYf94/VY41ePeFtFyP99BAs953kFT4N+6F7Ko=
-github.com/cayleygraph/quad v1.1.0 h1:w1nXAmn+nz07+qlw89dke9LwWkYpeX+OcvfTvGQRBpM=
-github.com/cayleygraph/quad v1.1.0/go.mod h1:maWODEekEhrO0mdc9h5n/oP7cH1h/OTgqQ2qWbuI9M4=
-github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
-github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
-github.com/containerd/continuity v0.0.0-20190426062206-aaeac12a7ffc/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y=
-github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
-github.com/coreos/bbolt v1.3.3/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
-github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
-github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
-github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
-github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
-github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
-github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
-github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/cznic/mathutil v0.0.0-20170313102836-1447ad269d64 h1:oad14P7M0/ZAPSMH1nl1vC8zdKVkA3kfHLO59z1l8Eg=
-github.com/cznic/mathutil v0.0.0-20170313102836-1447ad269d64/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
-github.com/d4l3k/messagediff v1.2.1 h1:ZcAIMYsUg0EAp9X+tt8/enBE/Q8Yd5kzPynLyKptt9U=
-github.com/d4l3k/messagediff v1.2.1/go.mod h1:Oozbb1TVXFac9FtSIxHBMnBCq2qeH/2KkEQxENCrlLo=
github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY=
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dennwc/base v1.0.0 h1:xlBzvBNRvkQ1LFI/jom7rr0vZsvYDKtvMM6lIpjFb3M=
-github.com/dennwc/base v1.0.0/go.mod h1:zaTDIiAcg2oKW9XhjIaRc1kJVteCFXSSW6jwmCedUaI=
-github.com/dennwc/graphql v0.0.0-20180603144102-12cfed44bc5d/go.mod h1:lg9KQn0BgRCSCGNpcGvJp/0Ljf1Yxk8TZq9HSYc43fk=
-github.com/dgraph-io/badger v1.5.4/go.mod h1:VZxzAIRPHRVNRKRo6AXrX9BJegn6il06VMTZVJYCIjQ=
-github.com/dgraph-io/badger v1.5.5/go.mod h1:QgCntgIUPsjnp7cMLhUybJHb7iIoQWAHT6tF8ngCjWk=
-github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
-github.com/dgryski/go-farm v0.0.0-20190416075124-e1214b5e05dc/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
-github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
-github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c h1:TUuUh0Xgj97tLMNtWtNvI9mIV6isjEb9lBMNv+77IGM=
github.com/dgryski/trifles v0.0.0-20190318185328-a8d75aae118c/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA=
-github.com/dlclark/regexp2 v1.1.4 h1:1udHhhGkIMplSrLeMJpPN7BHz1Iq2wVBUcb+3fxzhQM=
-github.com/dlclark/regexp2 v1.1.4/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
-github.com/docker/docker v0.7.3-0.20180412203414-a422774e593b/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
-github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
-github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
-github.com/dop251/goja v0.0.0-20190105122144-6d5bf35058fa h1:cA2OMt2CQ2yq2WhQw16mHv6ej9YY07H4pzfR/z/y+1Q=
-github.com/dop251/goja v0.0.0-20190105122144-6d5bf35058fa/go.mod h1:Mw6PkjjMXWbTj+nnj4s3QPXq1jaT0s5pC0iFD4+BOAA=
-github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
-github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
-github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/flimzy/diff v0.1.5/go.mod h1:lFJtC7SPsK0EroDmGTSrdtWKAxOk3rO+q+e04LL05Hs=
-github.com/flimzy/diff v0.1.6/go.mod h1:lFJtC7SPsK0EroDmGTSrdtWKAxOk3rO+q+e04LL05Hs=
-github.com/flimzy/kivik v1.8.1/go.mod h1:S2aPycbG0eDFll4wgXt9uacSNkXISPufutnc9sv+mdA=
-github.com/flimzy/testy v0.1.16/go.mod h1:3szguN8NXqgq9bt9Gu8TQVj698PJWmyx/VY1frwwKrM=
-github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
-github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
-github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
-github.com/fsouza/go-dockerclient v1.2.2/go.mod h1:KpcjM623fQYE9MZiTGzKhjfxXAV9wbyX2C1cyRHfhl0=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi v3.3.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
-github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
-github.com/go-kivik/couchdb v1.8.1/go.mod h1:5XJRkAMpBlEVA4q0ktIZjUPYBjoBmRoiWvwUBzP3BOQ=
-github.com/go-kivik/kivik v1.8.1/go.mod h1:nIuJ8z4ikBrVUSk3Ua8NoDqYKULPNjuddjqRvlSUyyQ=
-github.com/go-kivik/kiviktest v1.1.2/go.mod h1:JdhVyzixoYhoIDUt6hRf1yAfYyaDa5/u9SDOindDkfQ=
-github.com/go-kivik/pouchdb v1.3.5/go.mod h1:U+siUrqLCVxeMU3QjQTYIC3/F/e6EUKm+o5buJb7vpw=
-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-sourcemap/sourcemap v2.1.2+incompatible h1:0b/xya7BKGhXuqFESKM4oIiRo9WOt2ebz7KxfreD6ug=
-github.com/go-sourcemap/sourcemap v2.1.2+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg=
-github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
-github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
-github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI=
-github.com/gobuffalo/envy v1.7.1 h1:OQl5ys5MBea7OGCdvPbBJWRgnhC/fGona6QKfvFeau8=
-github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
-github.com/gobuffalo/logger v1.0.1 h1:ZEgyRGgAm4ZAhAO45YXMs5Fp+bzGLESFewzAVBMKuTg=
-github.com/gobuffalo/logger v1.0.1/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs=
-github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4=
-github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q=
-github.com/gobuffalo/packr/v2 v2.7.1 h1:n3CIW5T17T8v4GGK5sWXLVWJhCz7b5aNLSxW6gYim4o=
-github.com/gobuffalo/packr/v2 v2.7.1/go.mod h1:qYEvAazPaVxy7Y7KR0W8qYEE+RymX74kETFqjFoFlOc=
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
-github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
-github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE=
-github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/mock v1.2.0/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.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
-github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
-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/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
-github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
-github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
-github.com/gopherjs/gopherjs v0.0.0-20190411002643-bd77b112433e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gopherjs/gopherjs v0.0.0-20190430165422-3e4dfb77656c/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
-github.com/gopherjs/jsbuiltin v0.0.0-20180426082241-50091555e127/go.mod h1:7X1acUyFRf+oVFTU6SWw9mnb57Vxn+Nbh8iPbKg95hs=
github.com/gorilla/context v0.0.0-20160226214623-1ea25387ff6f/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
-github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.1/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
-github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc=
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.2.0 h1:VJtLvh6VQym50czpZzx07z/kw9EgAxI3x1ZB8taTMQQ=
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
-github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
-github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
-github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
-github.com/hidal-go/hidalgo v0.0.0-20190814174001-42e03f3b5eaa h1:hBE4LGxApbZiV/3YoEPv7uYlUMWOogG1hwtkpiU87zQ=
-github.com/hidal-go/hidalgo v0.0.0-20190814174001-42e03f3b5eaa/go.mod h1:bPkrxDlroXxigw8BMWTEPTv4W5/rQwNgg2BECXsgyX0=
-github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
-github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
-github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
-github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
-github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ=
-github.com/jackc/pgx v3.3.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
-github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
-github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
-github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
-github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
-github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-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/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
-github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
-github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
-github.com/linkeddata/gojsonld v0.0.0-20170418210642-4f5db6791326 h1:YP3lfXXYiQV5MKeUqVnxRP5uuMQTLPx+PGYm1UBoU98=
-github.com/linkeddata/gojsonld v0.0.0-20170418210642-4f5db6791326/go.mod h1:nfqkuSNlsk1bvti/oa7TThx4KmRMBmSxf3okHI9wp3E=
github.com/logrusorgru/aurora v0.0.0-20200102142835-e9ef32dff381/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4=
-github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
-github.com/mailru/easyjson v0.0.0-20180730094502-03f2033d19d5/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007 h1:reVOUXwnhsYv/8UqjvhrMOu5CNT9UapHFLbQ2JcXsmg=
github.com/matryer/moq v0.0.0-20200106131100-75d0ddfc0007/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
-github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
-github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
-github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/mattn/go-sqlite3 v1.14.4 h1:4rQjbDxdu9fSgI/r3KN72G3c2goxknAqHHgPWWs8UlI=
+github.com/mattn/go-sqlite3 v1.14.4/go.mod h1:WVKg1VTActs4Qso6iwGbiFih2UIHo0ENGwNd0Lj+XmI=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047 h1:zCoDWFD5nrJJVjbXiDZcVhOBSzKn3o9LgRLLMRNuru8=
github.com/mitchellh/mapstructure v0.0.0-20180203102830-a4e142e9c047/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
-github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg=
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
-github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
-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.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
-github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
-github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
-github.com/opencontainers/runc v0.1.1/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
-github.com/opencontainers/selinux v1.0.0/go.mod h1:+BLncwf63G4dgOzykXAxcmnFlUaOlkDdmw/CqsW6pjs=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
-github.com/ory/dockertest v3.3.4+incompatible/go.mod h1:1vX4m9wsvi00u5bseYwXaSnhNrne+V0E6LAcBILJdPs=
-github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
-github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
-github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
-github.com/peterh/liner v0.0.0-20170317030525-88609521dc4b/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
-github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
-github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
-github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
-github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
-github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
-github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
-github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
-github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM=
-github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
-github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
-github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY=
-github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
-github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
-github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
-github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
-github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.4.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
-github.com/rogpeppe/go-internal v1.5.0 h1:Usqs0/lDK/NqTkvrmKSwA/3XkZAs7ZAW/eLeQ2MVBTw=
-github.com/rogpeppe/go-internal v1.5.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
-github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
-github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
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/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
-github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/shurcooL/httpfs v0.0.0-20171119174359-809beceb2371/go.mod h1:ZY1cvUeJuFPAdZ/B6v7RHavJWZn2YPVFQ1OSXhCGOkg=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/shurcooL/vfsgen v0.0.0-20180121065927-ffb13db8def0/go.mod h1:TrYk7fJVaAttu97ZZKrO9UbRa8izdowaMIZcxYMbVaw=
-github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
-github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
-github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
-github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
-github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
-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.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
-github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
-github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
-github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
-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.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
-github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
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/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
-github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
-github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
-github.com/tylertreat/BoomFilters v0.0.0-20181028192813-611b3dbe80e8 h1:7X4KYG3guI2mPQGxm/ZNNsiu4BjKnef0KG0TblMC+Z8=
-github.com/tylertreat/BoomFilters v0.0.0-20181028192813-611b3dbe80e8/go.mod h1:OYRfF6eb5wY9VRFkXJH8FFBi3plw2v+giaIu7P054pM=
-github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
-github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k=
github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
@@ -325,152 +90,34 @@ github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e h1:+w0Zm/9gaWp
github.com/vektah/dataloaden v0.2.1-0.20190515034641-a19b9a6e7c9e/go.mod h1:/HUdMve7rvxZma+2ZELQeNh88+003LL7Pf/CZ089j8U=
github.com/vektah/gqlparser/v2 v2.0.1 h1:xgl5abVnsd4hkN9rk65OJID9bfcLSMuTaTcZj777q1o=
github.com/vektah/gqlparser/v2 v2.0.1/go.mod h1:SyUiHgLATUR8BiYURfTirrTcGpcE+4XkV2se04Px1Ms=
-github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhemzwFU4jHLhdvlE6uDZjXFejJXr49I=
-github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
-github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
-github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
-github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
-go.mongodb.org/mongo-driver v1.0.4/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
-go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
-go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
-go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
-go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
-golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20191002192127-34f69633bfdc/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
-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-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
-golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20181220203305-927f97764cc3/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-20190125091013-d26f9f9a57f3/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-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
-golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU=
-golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200822124328-c89045814202 h1:VvcQYSHwXgi7W+TpUR6A9g6Up98WAHf3f/ulnJ62IyA=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/oauth2 v0.0.0-20190402181905-9f3314589c9a/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-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY=
-golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 h1:qwRHBd0NqMbJxfbotnDhm2ByMI1Shq4Y6oRJo21SGJA=
-golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/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-20190222072716-a9d3bda3a223/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-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190614160838-b47fdc937951/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191009170203-06d7bd2c5f4f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
-golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
-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/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=
-golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/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-20190125232054-d66bd3c5d5a6/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-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd h1:oMEQDWVXVNpceQoVd1JN3CQ7LYJJzs5qWqZIUcxXHHw=
golang.org/x/tools v0.0.0-20190515012406-7d7faa4812bd/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
-golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
-golang.org/x/tools v0.0.0-20191004055002-72853e10c5a3/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20191010075000-0337d82405ff/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-20200114235610-7ae403b6b589 h1:rjUrONFu4kLchcZTfp3/96bR8bW8dIa8uz3cR5n0cgM=
golang.org/x/tools v0.0.0-20200114235610-7ae403b6b589/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346 h1:hzJjkvxUIF3bSt+v8N5tBQNx/605vszZJ+3XsIamzZo=
-golang.org/x/tools v0.0.0-20200925191224-5d1fdd8fa346/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
-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-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.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
-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/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
-google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
-google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
-gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-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/olivere/elastic.v5 v5.0.80/go.mod h1:uhHoB4o3bvX5sorxBU29rPcmBQdV2Qfg0FBrx5D6pV0=
-gopkg.in/olivere/elastic.v5 v5.0.81/go.mod h1:uhHoB4o3bvX5sorxBU29rPcmBQdV2Qfg0FBrx5D6pV0=
-gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
-gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
-gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
-honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
sourcegraph.com/sourcegraph/appdash v0.0.0-20180110180208-2cc67fd64755/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=
sourcegraph.com/sourcegraph/appdash-data v0.0.0-20151005221446-73f23eafcf67/go.mod h1:L5q+DGLGOQFpo1snNEkLOJT2d1YTW66rWNzatr3He1k=
diff --git a/gqlgen.yml b/gqlgen.yml
index a711959..9324f28 100644
--- a/gqlgen.yml
+++ b/gqlgen.yml
@@ -42,13 +42,10 @@ omit_slice_element_pointers: true
# The first line in each type will be used as defaults for resolver arguments and
# modelgen, the others will be allowed when binding to fields. Configure them to
# your liking
-# models:
-# ID:
-# model:
-# - github.com/99designs/gqlgen/graphql.ID
-# - github.com/99designs/gqlgen/graphql.Int
-# - github.com/99designs/gqlgen/graphql.Int64
-# - github.com/99designs/gqlgen/graphql.Int32
+models:
+ ID:
+ model:
+ - github.com/99designs/gqlgen/graphql.Int64
# Int:
# model:
# - github.com/99designs/gqlgen/graphql.Int
diff --git a/pkg/api/generated.go b/pkg/api/generated.go
index 1ef5e1e..f5b72b4 100644
--- a/pkg/api/generated.go
+++ b/pkg/api/generated.go
@@ -68,13 +68,13 @@ type ComplexityRoot struct {
}
Query struct {
- HTTPRequestLog func(childComplexity int, id string) int
+ HTTPRequestLog func(childComplexity int, id int64) int
HTTPRequestLogs func(childComplexity int) int
}
}
type QueryResolver interface {
- HTTPRequestLog(ctx context.Context, id string) (*HTTPRequestLog, error)
+ HTTPRequestLog(ctx context.Context, id int64) (*HTTPRequestLog, error)
HTTPRequestLogs(ctx context.Context) ([]HTTPRequestLog, error)
}
@@ -215,7 +215,7 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return 0, false
}
- return e.complexity.Query.HTTPRequestLog(childComplexity, args["id"].(string)), true
+ return e.complexity.Query.HTTPRequestLog(childComplexity, args["id"].(int64)), true
case "Query.httpRequestLogs":
if e.complexity.Query.HTTPRequestLogs == nil {
@@ -342,9 +342,9 @@ func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs
func (ec *executionContext) field_Query_httpRequestLog_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) {
var err error
args := map[string]interface{}{}
- var arg0 string
+ var arg0 int64
if tmp, ok := rawArgs["id"]; ok {
- arg0, err = ec.unmarshalNID2string(ctx, tmp)
+ arg0, err = ec.unmarshalNID2int64(ctx, tmp)
if err != nil {
return nil, err
}
@@ -486,9 +486,9 @@ func (ec *executionContext) _HttpRequestLog_id(ctx context.Context, field graphq
}
return graphql.Null
}
- res := resTmp.(string)
+ res := resTmp.(int64)
fc.Result = res
- return ec.marshalNID2string(ctx, field.Selections, res)
+ return ec.marshalNID2int64(ctx, field.Selections, res)
}
func (ec *executionContext) _HttpRequestLog_url(ctx context.Context, field graphql.CollectedField, obj *HTTPRequestLog) (ret graphql.Marshaler) {
@@ -752,9 +752,9 @@ func (ec *executionContext) _HttpResponseLog_requestId(ctx context.Context, fiel
}
return graphql.Null
}
- res := resTmp.(string)
+ res := resTmp.(int64)
fc.Result = res
- return ec.marshalNID2string(ctx, field.Selections, res)
+ return ec.marshalNID2int64(ctx, field.Selections, res)
}
func (ec *executionContext) _HttpResponseLog_proto(ctx context.Context, field graphql.CollectedField, obj *HTTPResponseLog) (ret graphql.Marshaler) {
@@ -948,7 +948,7 @@ func (ec *executionContext) _Query_httpRequestLog(ctx context.Context, field gra
fc.Args = args
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
- return ec.resolvers.Query().HTTPRequestLog(rctx, args["id"].(string))
+ return ec.resolvers.Query().HTTPRequestLog(rctx, args["id"].(int64))
})
if err != nil {
ec.Error(ctx, err)
@@ -2670,12 +2670,12 @@ func (ec *executionContext) marshalNHttpRequestLog2ᚕgithubᚗcomᚋdstotijnᚋ
return ret
}
-func (ec *executionContext) unmarshalNID2string(ctx context.Context, v interface{}) (string, error) {
- return graphql.UnmarshalID(v)
+func (ec *executionContext) unmarshalNID2int64(ctx context.Context, v interface{}) (int64, error) {
+ return graphql.UnmarshalInt64(v)
}
-func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler {
- res := graphql.MarshalID(v)
+func (ec *executionContext) marshalNID2int64(ctx context.Context, sel ast.SelectionSet, v int64) graphql.Marshaler {
+ res := graphql.MarshalInt64(v)
if res == graphql.Null {
if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) {
ec.Errorf(ctx, "must not be null")
diff --git a/pkg/api/models_gen.go b/pkg/api/models_gen.go
index abaf0ba..e10959e 100644
--- a/pkg/api/models_gen.go
+++ b/pkg/api/models_gen.go
@@ -15,7 +15,7 @@ type HTTPHeader struct {
}
type HTTPRequestLog struct {
- ID string `json:"id"`
+ ID int64 `json:"id"`
URL string `json:"url"`
Method HTTPMethod `json:"method"`
Proto string `json:"proto"`
@@ -26,7 +26,7 @@ type HTTPRequestLog struct {
}
type HTTPResponseLog struct {
- RequestID string `json:"requestId"`
+ RequestID int64 `json:"requestId"`
Proto string `json:"proto"`
Status string `json:"status"`
StatusCode int `json:"statusCode"`
diff --git a/pkg/api/resolvers.go b/pkg/api/resolvers.go
index 5d66841..aa3855e 100644
--- a/pkg/api/resolvers.go
+++ b/pkg/api/resolvers.go
@@ -6,8 +6,6 @@ import (
"context"
"fmt"
- "github.com/google/uuid"
-
"github.com/dstotijn/hetty/pkg/reqlog"
)
@@ -38,12 +36,8 @@ func (r *queryResolver) HTTPRequestLogs(ctx context.Context) ([]HTTPRequestLog,
return logs, nil
}
-func (r *queryResolver) HTTPRequestLog(ctx context.Context, id string) (*HTTPRequestLog, error) {
- reqLogID, err := uuid.Parse(id)
- if err != nil {
- return nil, fmt.Errorf("invalid id: %v", err)
- }
- log, err := r.RequestLogService.FindRequestLogByID(ctx, reqLogID)
+func (r *queryResolver) HTTPRequestLog(ctx context.Context, id int64) (*HTTPRequestLog, error) {
+ log, err := r.RequestLogService.FindRequestLogByID(ctx, id)
if err == reqlog.ErrRequestNotFound {
return nil, nil
}
@@ -65,7 +59,7 @@ func parseRequestLog(req reqlog.Request) (HTTPRequestLog, error) {
}
log := HTTPRequestLog{
- ID: req.ID.String(),
+ ID: req.ID,
URL: req.Request.URL.String(),
Proto: req.Request.Proto,
Method: method,
@@ -91,7 +85,7 @@ func parseRequestLog(req reqlog.Request) (HTTPRequestLog, error) {
if req.Response != nil {
log.Response = &HTTPResponseLog{
- RequestID: req.ID.String(),
+ RequestID: req.ID,
Proto: req.Response.Response.Proto,
Status: req.Response.Response.Status,
StatusCode: req.Response.Response.StatusCode,
diff --git a/pkg/db/cayley/bolt.go b/pkg/db/cayley/bolt.go
deleted file mode 100644
index ff94b47..0000000
--- a/pkg/db/cayley/bolt.go
+++ /dev/null
@@ -1,64 +0,0 @@
-package cayley
-
-import (
- "os"
- "path/filepath"
-
- "github.com/cayleygraph/cayley/clog"
- "github.com/cayleygraph/cayley/graph"
- hkv "github.com/hidal-go/hidalgo/kv"
- "github.com/hidal-go/hidalgo/kv/bolt"
-)
-
-const Type = bolt.Name
-
-func boltFilePath(path, filename string) string {
- return filepath.Join(path, filename)
-}
-
-func boltCreate(path string, opt graph.Options) (hkv.KV, error) {
- filename, err := opt.StringKey("filename", "indexes.bolt")
- if err != nil {
- return nil, err
- }
-
- err = os.MkdirAll(path, 0700)
- if err != nil {
- return nil, err
- }
-
- db, err := bolt.Open(boltFilePath(path, filename), nil)
- if err != nil {
- clog.Errorf("Error: couldn't create Bolt database: %v", err)
- return nil, err
- }
-
- return db, nil
-}
-
-func boltOpen(path string, opt graph.Options) (hkv.KV, error) {
- filename, err := opt.StringKey("filename", "indexes.bolt")
- if err != nil {
- return nil, err
- }
-
- db, err := bolt.Open(boltFilePath(path, filename), nil)
- if err != nil {
- clog.Errorf("Error, couldn't open! %v", err)
- return nil, err
- }
-
- bdb := db.DB()
- bdb.NoSync, err = opt.BoolKey("nosync", false)
- if err != nil {
- db.Close()
- return nil, err
- }
-
- bdb.NoGrowSync = bdb.NoSync
- if bdb.NoSync {
- clog.Infof("Running in nosync mode")
- }
-
- return db, nil
-}
diff --git a/pkg/db/cayley/cayley.go b/pkg/db/cayley/cayley.go
deleted file mode 100644
index 6814269..0000000
--- a/pkg/db/cayley/cayley.go
+++ /dev/null
@@ -1,325 +0,0 @@
-package cayley
-
-import (
- "context"
- "fmt"
- "log"
- "net/http"
- "net/url"
- "path"
- "strings"
- "sync"
- "time"
-
- "github.com/cayleygraph/cayley"
- "github.com/cayleygraph/cayley/graph"
- "github.com/cayleygraph/cayley/graph/kv"
- cpath "github.com/cayleygraph/cayley/graph/path"
- "github.com/cayleygraph/cayley/schema"
- "github.com/cayleygraph/quad"
- "github.com/cayleygraph/quad/voc"
- "github.com/cayleygraph/quad/voc/rdf"
- "github.com/google/uuid"
-
- "github.com/dstotijn/hetty/pkg/reqlog"
- "github.com/dstotijn/hetty/pkg/scope"
-)
-
-type HTTPRequest struct {
- rdfType struct{} `quad:"@type > hy:HTTPRequest"`
- ID quad.IRI `quad:"@id"`
- Proto string `quad:"hy:proto"`
- URL string `quad:"hy:url"`
- Method string `quad:"hy:method"`
- Body string `quad:"hy:body,optional"`
- Headers []HTTPHeader `quad:"hy:header"`
- Timestamp time.Time `quad:"hy:timestamp"`
- Response *HTTPResponse `quad:"hy:request < *,optional"`
-}
-
-type HTTPResponse struct {
- rdfType struct{} `quad:"@type > hy:HTTPResponse"`
- RequestID quad.IRI `quad:"hy:request"`
- Proto string `quad:"hy:proto"`
- Status string `quad:"hy:status"`
- StatusCode int `quad:"hy:status_code"`
- Headers []HTTPHeader `quad:"hy:header"`
- Body string `quad:"hy:body,optional"`
- Timestamp time.Time `quad:"hy:timestamp"`
-}
-
-type HTTPHeader struct {
- rdfType struct{} `quad:"@type > hy:HTTPHeader"`
- Key string `quad:"hy:key"`
- Value string `quad:"hy:value,optional"`
-}
-
-type Database struct {
- store *cayley.Handle
- schema *schema.Config
- mu sync.Mutex
-}
-
-func init() {
- voc.RegisterPrefix("hy:", "https://hetty.xyz/")
- schema.RegisterType(quad.IRI("hy:HTTPRequest"), HTTPRequest{})
- schema.RegisterType(quad.IRI("hy:HTTPResponse"), HTTPResponse{})
- schema.RegisterType(quad.IRI("hy:HTTPHeader"), HTTPHeader{})
-
- kv.Register(Type, kv.Registration{
- NewFunc: boltOpen,
- InitFunc: boltCreate,
- IsPersistent: true,
- })
-}
-
-func NewDatabase(filename string) (*Database, error) {
- dir, file := path.Split(filename)
- if dir == "" {
- dir = "."
- }
- opts := graph.Options{
- "filename": file,
- }
-
- schemaCfg := schema.NewConfig()
- schemaCfg.GenerateID = func(_ interface{}) quad.Value {
- return quad.BNode(uuid.New().String())
- }
-
- // Initialize the database.
- err := graph.InitQuadStore("bolt", dir, opts)
- if err != nil && err != graph.ErrDatabaseExists {
- return nil, fmt.Errorf("cayley: could not initialize database: %v", err)
- }
-
- // Open the database.
- store, err := cayley.NewGraph("bolt", dir, opts)
- if err != nil {
- return nil, fmt.Errorf("cayley: could not open database: %v", err)
- }
-
- return &Database{
- store: store,
- schema: schemaCfg,
- }, nil
-}
-
-func (db *Database) Close() error {
- return db.store.Close()
-}
-
-func (db *Database) FindRequestLogs(ctx context.Context, opts reqlog.FindRequestsOptions, scope *scope.Scope) ([]reqlog.Request, error) {
- db.mu.Lock()
- defer db.mu.Unlock()
-
- var reqLogs []reqlog.Request
- var reqs []HTTPRequest
-
- reqPath := cayley.StartPath(db.store, quad.IRI("hy:HTTPRequest")).In(quad.IRI(rdf.Type))
- if opts.OmitOutOfScope {
- var filterPath *cpath.Path
- for _, rule := range scope.Rules() {
- if rule.URL != nil {
- if filterPath == nil {
- filterPath = reqPath.Out(quad.IRI("hy:url")).Regex(rule.URL).In(quad.IRI("hy:url"))
- } else {
- filterPath = filterPath.Or(reqPath.Out(quad.IRI("hy:url")).Regex(rule.URL).In(quad.IRI("hy:url")))
- }
- }
- }
- if filterPath != nil {
- reqPath = filterPath
- }
- }
-
- err := reqPath.Iterate(ctx).EachValue(db.store, func(v quad.Value) {
- var req HTTPRequest
- if err := db.schema.LoadToDepth(ctx, db.store, &req, 0, v); err != nil {
- log.Printf("[ERROR] Could not load sub-graph for http requests: %v", err)
- return
- }
- reqs = append(reqs, req)
- })
- if err != nil {
- return nil, fmt.Errorf("cayley: could not iterate over http requests: %v", err)
- }
-
- for _, req := range reqs {
- reqLog, err := parseRequestQuads(req, nil)
- if err != nil {
- return nil, fmt.Errorf("cayley: could not parse request quads (id: %v): %v", req.ID, err)
- }
- reqLogs = append(reqLogs, reqLog)
- }
-
- // By default, all retrieved requests are ordered chronologically, oldest first.
- // Reverse the order, so newest logs are first.
- for i := len(reqLogs)/2 - 1; i >= 0; i-- {
- opp := len(reqLogs) - 1 - i
- reqLogs[i], reqLogs[opp] = reqLogs[opp], reqLogs[i]
- }
-
- return reqLogs, nil
-}
-
-func (db *Database) FindRequestLogByID(ctx context.Context, id uuid.UUID) (reqlog.Request, error) {
- db.mu.Lock()
- defer db.mu.Unlock()
-
- var req HTTPRequest
- err := db.schema.LoadTo(ctx, db.store, &req, iriFromUUID(id))
- if schema.IsNotFound(err) {
- return reqlog.Request{}, reqlog.ErrRequestNotFound
- }
- if err != nil {
- return reqlog.Request{}, fmt.Errorf("cayley: could not load value: %v", err)
- }
-
- reqLog, err := parseRequestQuads(req, nil)
- if err != nil {
- return reqlog.Request{}, fmt.Errorf("cayley: could not parse request log (id: %v): %v", req.ID, err)
- }
-
- return reqLog, nil
-}
-
-func (db *Database) AddRequestLog(ctx context.Context, reqLog reqlog.Request) error {
- db.mu.Lock()
- defer db.mu.Unlock()
-
- httpReq := HTTPRequest{
- ID: iriFromUUID(reqLog.ID),
- Proto: reqLog.Request.Proto,
- Method: reqLog.Request.Method,
- URL: reqLog.Request.URL.String(),
- Headers: httpHeadersSliceFromMap(reqLog.Request.Header),
- Body: string(reqLog.Body),
- Timestamp: reqLog.Timestamp,
- }
-
- tx := cayley.NewTransaction()
- qw := graph.NewTxWriter(tx, graph.Add)
-
- _, err := db.schema.WriteAsQuads(qw, httpReq)
- if err != nil {
- return fmt.Errorf("cayley: could not write quads: %v", err)
- }
-
- if err := db.store.ApplyTransaction(tx); err != nil {
- return fmt.Errorf("cayley: could not apply transaction: %v", err)
- }
-
- return nil
-}
-
-func (db *Database) AddResponseLog(ctx context.Context, resLog reqlog.Response) error {
- db.mu.Lock()
- defer db.mu.Unlock()
-
- httpRes := HTTPResponse{
- RequestID: iriFromUUID(resLog.RequestID),
- Proto: resLog.Response.Proto,
- Status: resLog.Response.Status,
- StatusCode: resLog.Response.StatusCode,
- Headers: httpHeadersSliceFromMap(resLog.Response.Header),
- Body: string(resLog.Body),
- Timestamp: resLog.Timestamp,
- }
-
- tx := cayley.NewTransaction()
- qw := graph.NewTxWriter(tx, graph.Add)
-
- _, err := db.schema.WriteAsQuads(qw, httpRes)
- if err != nil {
- return fmt.Errorf("cayley: could not write response quads: %v", err)
- }
-
- if err := db.store.ApplyTransaction(tx); err != nil {
- return fmt.Errorf("cayley: could not apply transaction: %v", err)
- }
-
- return nil
-}
-
-func iriFromUUID(id uuid.UUID) quad.IRI {
- return quad.IRI("hy:" + id.String()).Full().Short()
-}
-
-func uuidFromIRI(iri quad.IRI) (uuid.UUID, error) {
- iriString := iri.Short().String()
- stripped := strings.TrimRight(strings.TrimLeft(iriString, "")
- id, err := uuid.Parse(stripped)
- if err != nil {
- return uuid.Nil, err
- }
-
- return id, nil
-}
-
-func httpHeadersSliceFromMap(hm http.Header) []HTTPHeader {
- if hm == nil {
- return nil
- }
- var hs []HTTPHeader
- for key, values := range hm {
- for _, value := range values {
- hs = append(hs, HTTPHeader{Key: key, Value: value})
- }
- }
- return hs
-}
-
-func httpHeadersMapFromSlice(hs []HTTPHeader) http.Header {
- if hs == nil {
- return nil
- }
- hm := make(http.Header)
- for _, header := range hs {
- hm.Add(header.Key, header.Value)
- }
- return hm
-}
-
-func parseRequestQuads(req HTTPRequest, _ *HTTPResponse) (reqlog.Request, error) {
- reqID, err := uuidFromIRI(req.ID)
- if err != nil {
- return reqlog.Request{}, fmt.Errorf("cannot parse request id: %v", err)
- }
-
- u, err := url.Parse(req.URL)
- if err != nil {
- return reqlog.Request{}, fmt.Errorf("cannot parse request url: %v", err)
- }
-
- reqLog := reqlog.Request{
- ID: reqID,
- Request: http.Request{
- Method: req.Method,
- URL: u,
- Proto: req.Proto,
- Header: httpHeadersMapFromSlice(req.Headers),
- },
- Timestamp: req.Timestamp,
- }
- if req.Body != "" {
- reqLog.Body = []byte(reqLog.Body)
- }
-
- if req.Response != nil {
- reqLog.Response = &reqlog.Response{
- RequestID: reqID,
- Response: http.Response{
- Proto: req.Response.Proto,
- Status: req.Response.Status,
- StatusCode: req.Response.StatusCode,
- Header: httpHeadersMapFromSlice(req.Response.Headers),
- },
- }
- if req.Response.Body != "" {
- reqLog.Response.Body = []byte(req.Response.Body)
- }
- }
-
- return reqLog, nil
-}
diff --git a/pkg/db/sqlite/dto.go b/pkg/db/sqlite/dto.go
new file mode 100644
index 0000000..8518df4
--- /dev/null
+++ b/pkg/db/sqlite/dto.go
@@ -0,0 +1,11 @@
+package sqlite
+
+import "time"
+
+type httpResponse struct {
+ ID *int64
+ Proto *string
+ StatusCode *int
+ Body *[]byte
+ Timestamp *time.Time
+}
diff --git a/pkg/db/sqlite/sqlite.go b/pkg/db/sqlite/sqlite.go
new file mode 100644
index 0000000..9468b64
--- /dev/null
+++ b/pkg/db/sqlite/sqlite.go
@@ -0,0 +1,493 @@
+package sqlite
+
+import (
+ "context"
+ "database/sql"
+ "fmt"
+ "net/http"
+ "net/url"
+ "os"
+ "path/filepath"
+ "strconv"
+ "time"
+
+ "github.com/dstotijn/hetty/pkg/reqlog"
+ "github.com/dstotijn/hetty/pkg/scope"
+
+ // Register sqlite3 for use via database/sql.
+ _ "github.com/mattn/go-sqlite3"
+)
+
+// Client implements reqlog.Repository.
+type Client struct {
+ db *sql.DB
+}
+
+// New returns a new Client.
+func New(filename string) (*Client, error) {
+ // Create directory for DB if it doesn't exist yet.
+ if dbDir, _ := filepath.Split(filename); dbDir != "" {
+ if _, err := os.Stat(dbDir); os.IsNotExist(err) {
+ os.Mkdir(dbDir, 0755)
+ }
+ }
+
+ opts := make(url.Values)
+ opts.Set("_foreign_keys", "1")
+
+ dsn := fmt.Sprintf("file:%v?%v", filename, opts.Encode())
+ db, err := sql.Open("sqlite3", dsn)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := db.Ping(); err != nil {
+ return nil, fmt.Errorf("sqlite: could not ping database: %v", err)
+ }
+
+ c := &Client{db: db}
+
+ if err := c.prepareSchema(); err != nil {
+ return nil, fmt.Errorf("sqlite: could not prepare schema: %v", err)
+ }
+
+ return &Client{db: db}, nil
+}
+
+func (c Client) prepareSchema() error {
+ _, err := c.db.Exec(`CREATE TABLE IF NOT EXISTS http_requests (
+ id INTEGER PRIMARY KEY,
+ proto TEXT,
+ url TEXT,
+ method TEXT,
+ body BLOB,
+ timestamp DATETIME
+ )`)
+ if err != nil {
+ return fmt.Errorf("could not create http_requests table: %v", err)
+ }
+
+ _, err = c.db.Exec(`CREATE TABLE IF NOT EXISTS http_responses (
+ id INTEGER PRIMARY KEY,
+ req_id INTEGER REFERENCES http_requests(id) ON DELETE CASCADE,
+ proto TEXT,
+ status_code INTEGER,
+ status_reason TEXT,
+ body BLOB,
+ timestamp DATETIME
+ )`)
+ if err != nil {
+ return fmt.Errorf("could not create http_responses table: %v", err)
+ }
+
+ _, err = c.db.Exec(`CREATE TABLE IF NOT EXISTS http_headers (
+ id INTEGER PRIMARY KEY,
+ req_id INTEGER REFERENCES http_requests(id) ON DELETE CASCADE,
+ res_id INTEGER REFERENCES http_responses(id) ON DELETE CASCADE,
+ key TEXT,
+ value TEXT
+ )`)
+ if err != nil {
+ return fmt.Errorf("could not create http_headers table: %v", err)
+ }
+
+ return nil
+}
+
+// Close uses the underlying database.
+func (c *Client) Close() error {
+ return c.db.Close()
+}
+
+func (c *Client) FindRequestLogs(
+ ctx context.Context,
+ opts reqlog.FindRequestsOptions,
+ scope *scope.Scope,
+) (reqLogs []reqlog.Request, err error) {
+ // TODO: Pass GraphQL field collections upstream, so we can query only
+ // requested fields.
+ // TODO: Use opts and scope to filter.
+ reqQuery := `SELECT
+ req.id,
+ req.proto,
+ req.url,
+ req.method,
+ req.body,
+ req.timestamp,
+ res.id,
+ res.proto,
+ res.status_code,
+ res.status_reason,
+ res.body,
+ res.timestamp
+ FROM http_requests req
+ LEFT JOIN http_responses res ON req.id = res.req_id
+ ORDER BY req.id DESC`
+
+ rows, err := c.db.QueryContext(ctx, reqQuery)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not execute query: %v", err)
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var reqLog reqlog.Request
+ var resDTO httpResponse
+ var statusReason *string
+ var rawURL string
+
+ err := rows.Scan(
+ &reqLog.ID,
+ &reqLog.Request.Proto,
+ &rawURL,
+ &reqLog.Request.Method,
+ &reqLog.Body,
+ &reqLog.Timestamp,
+ &resDTO.ID,
+ &resDTO.Proto,
+ &resDTO.StatusCode,
+ &statusReason,
+ &resDTO.Body,
+ &resDTO.Timestamp,
+ )
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not scan row: %v", err)
+ }
+
+ u, err := url.Parse(rawURL)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not parse URL: %v", err)
+ }
+ reqLog.Request.URL = u
+
+ if resDTO.ID != nil {
+ status := strconv.Itoa(*resDTO.StatusCode) + " " + *statusReason
+ reqLog.Response = &reqlog.Response{
+ ID: *resDTO.ID,
+ RequestID: reqLog.ID,
+ Response: http.Response{
+ Status: status,
+ StatusCode: *resDTO.StatusCode,
+ Proto: *resDTO.Proto,
+ },
+ Body: *resDTO.Body,
+ Timestamp: *resDTO.Timestamp,
+ }
+ }
+
+ reqLogs = append(reqLogs, reqLog)
+ }
+ if err := rows.Err(); err != nil {
+ return nil, fmt.Errorf("sqlite: could not iterate over rows: %v", err)
+ }
+ rows.Close()
+
+ reqHeadersStmt, err := c.db.PrepareContext(ctx, `SELECT key, value FROM http_headers WHERE req_id = ?`)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not prepare statement: %v", err)
+ }
+ defer reqHeadersStmt.Close()
+ resHeadersStmt, err := c.db.PrepareContext(ctx, `SELECT key, value FROM http_headers WHERE res_id = ?`)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not prepare statement: %v", err)
+ }
+ defer resHeadersStmt.Close()
+
+ for _, reqLog := range reqLogs {
+ headers, err := findHeaders(ctx, reqHeadersStmt, reqLog.ID)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not query request headers: %v", err)
+ }
+ reqLog.Request.Header = headers
+
+ if reqLog.Response != nil {
+ headers, err := findHeaders(ctx, resHeadersStmt, reqLog.Response.ID)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not query response headers: %v", err)
+ }
+ reqLog.Response.Response.Header = headers
+ }
+ }
+
+ return reqLogs, nil
+}
+
+func (c *Client) FindRequestLogByID(ctx context.Context, id int64) (reqlog.Request, error) {
+ // TODO: Pass GraphQL field collections upstream, so we can query only
+ // requested fields.
+ reqQuery := `SELECT
+ req.id,
+ req.proto,
+ req.url,
+ req.method,
+ req.body,
+ req.timestamp,
+ res.id,
+ res.proto,
+ res.status_code,
+ res.status_reason,
+ res.body,
+ res.timestamp
+ FROM http_requests req
+ LEFT JOIN http_responses res ON req.id = res.req_id
+ WHERE req_id = ?
+ ORDER BY req.id DESC`
+
+ var reqLog reqlog.Request
+ var resDTO httpResponse
+ var statusReason *string
+ var rawURL string
+
+ err := c.db.QueryRowContext(ctx, reqQuery, id).Scan(
+ &reqLog.ID,
+ &reqLog.Request.Proto,
+ &rawURL,
+ &reqLog.Request.Method,
+ &reqLog.Body,
+ &reqLog.Timestamp,
+ &resDTO.ID,
+ &resDTO.Proto,
+ &resDTO.StatusCode,
+ &statusReason,
+ &resDTO.Body,
+ &resDTO.Timestamp,
+ )
+ if err == sql.ErrNoRows {
+ return reqlog.Request{}, reqlog.ErrRequestNotFound
+ }
+ if err != nil {
+ return reqlog.Request{}, fmt.Errorf("sqlite: could not scan row: %v", err)
+ }
+
+ u, err := url.Parse(rawURL)
+ if err != nil {
+ return reqlog.Request{}, fmt.Errorf("sqlite: could not parse URL: %v", err)
+ }
+ reqLog.Request.URL = u
+
+ if resDTO.ID != nil {
+ status := strconv.Itoa(*resDTO.StatusCode) + " " + *statusReason
+ reqLog.Response = &reqlog.Response{
+ ID: *resDTO.ID,
+ RequestID: reqLog.ID,
+ Response: http.Response{
+ Status: status,
+ StatusCode: *resDTO.StatusCode,
+ Proto: *resDTO.Proto,
+ },
+ Body: *resDTO.Body,
+ Timestamp: *resDTO.Timestamp,
+ }
+ }
+
+ reqHeadersStmt, err := c.db.PrepareContext(ctx, `SELECT key, value FROM http_headers WHERE req_id = ?`)
+ if err != nil {
+ return reqlog.Request{}, fmt.Errorf("sqlite: could not prepare statement: %v", err)
+ }
+ defer reqHeadersStmt.Close()
+ resHeadersStmt, err := c.db.PrepareContext(ctx, `SELECT key, value FROM http_headers WHERE res_id = ?`)
+ if err != nil {
+ return reqlog.Request{}, fmt.Errorf("sqlite: could not prepare statement: %v", err)
+ }
+ defer resHeadersStmt.Close()
+
+ headers, err := findHeaders(ctx, reqHeadersStmt, reqLog.ID)
+ if err != nil {
+ return reqlog.Request{}, fmt.Errorf("sqlite: could not query request headers: %v", err)
+ }
+ reqLog.Request.Header = headers
+
+ if reqLog.Response != nil {
+ headers, err := findHeaders(ctx, resHeadersStmt, reqLog.Response.ID)
+ if err != nil {
+ return reqlog.Request{}, fmt.Errorf("sqlite: could not query response headers: %v", err)
+ }
+ reqLog.Response.Response.Header = headers
+ }
+
+ return reqLog, nil
+}
+
+func (c *Client) AddRequestLog(
+ ctx context.Context,
+ req http.Request,
+ body []byte,
+ timestamp time.Time,
+) (*reqlog.Request, error) {
+
+ reqLog := &reqlog.Request{
+ Request: req,
+ Body: body,
+ Timestamp: timestamp,
+ }
+
+ tx, err := c.db.BeginTx(ctx, nil)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not start transaction: %v", err)
+ }
+ defer tx.Rollback()
+
+ reqStmt, err := tx.PrepareContext(ctx, `INSERT INTO http_requests (
+ proto,
+ url,
+ method,
+ body,
+ timestamp
+ ) VALUES (?, ?, ?, ?, ?)`)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not prepare statement: %v", err)
+ }
+ defer reqStmt.Close()
+
+ result, err := reqStmt.ExecContext(ctx,
+ reqLog.Request.Proto,
+ reqLog.Request.URL.String(),
+ reqLog.Request.Method,
+ reqLog.Body,
+ reqLog.Timestamp,
+ )
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not execute statement: %v", err)
+ }
+
+ reqID, err := result.LastInsertId()
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not get last insert ID: %v", err)
+ }
+ reqLog.ID = reqID
+
+ headerStmt, err := tx.PrepareContext(ctx, `INSERT INTO http_headers (
+ req_id,
+ key,
+ value
+ ) VALUES (?, ?, ?)`)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not prepare statement: %v", err)
+ }
+ defer headerStmt.Close()
+
+ err = insertHeaders(ctx, headerStmt, reqID, reqLog.Request.Header)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not insert http headers: %v", err)
+ }
+
+ if err := tx.Commit(); err != nil {
+ return nil, fmt.Errorf("sqlite: could not commit transaction: %v", err)
+ }
+
+ return reqLog, nil
+}
+
+func (c *Client) AddResponseLog(
+ ctx context.Context,
+ reqID int64,
+ res http.Response,
+ body []byte,
+ timestamp time.Time,
+) (*reqlog.Response, error) {
+ resLog := &reqlog.Response{
+ RequestID: reqID,
+ Response: res,
+ Body: body,
+ Timestamp: timestamp,
+ }
+ tx, err := c.db.BeginTx(ctx, nil)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not start transaction: %v", err)
+ }
+ defer tx.Rollback()
+
+ resStmt, err := tx.PrepareContext(ctx, `INSERT INTO http_responses (
+ req_id,
+ proto,
+ status_code,
+ status_reason,
+ body,
+ timestamp
+ ) VALUES (?, ?, ?, ?, ?, ?)`)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not prepare statement: %v", err)
+ }
+ defer resStmt.Close()
+
+ var statusReason string
+ if len(resLog.Response.Status) > 4 {
+ statusReason = resLog.Response.Status[4:]
+ }
+
+ result, err := resStmt.ExecContext(ctx,
+ resLog.RequestID,
+ resLog.Response.Proto,
+ resLog.Response.StatusCode,
+ statusReason,
+ resLog.Body,
+ resLog.Timestamp,
+ )
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not execute statement: %v", err)
+ }
+
+ resID, err := result.LastInsertId()
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not get last insert ID: %v", err)
+ }
+ resLog.ID = resID
+
+ headerStmt, err := tx.PrepareContext(ctx, `INSERT INTO http_headers (
+ res_id,
+ key,
+ value
+ ) VALUES (?, ?, ?)`)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not prepare statement: %v", err)
+ }
+ defer headerStmt.Close()
+
+ err = insertHeaders(ctx, headerStmt, resID, resLog.Response.Header)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not insert http headers: %v", err)
+ }
+
+ if err := tx.Commit(); err != nil {
+ return nil, fmt.Errorf("sqlite: could not commit transaction: %v", err)
+ }
+
+ return resLog, nil
+}
+
+func insertHeaders(ctx context.Context, stmt *sql.Stmt, id int64, headers http.Header) error {
+ for key, values := range headers {
+ for _, value := range values {
+ if _, err := stmt.ExecContext(ctx, id, key, value); err != nil {
+ return fmt.Errorf("could not execute statement: %v", err)
+ }
+ }
+ }
+ return nil
+}
+
+func findHeaders(ctx context.Context, stmt *sql.Stmt, id int64) (http.Header, error) {
+ headers := make(http.Header)
+ rows, err := stmt.QueryContext(ctx, id)
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not execute query: %v", err)
+ }
+ defer rows.Close()
+
+ for rows.Next() {
+ var key, value string
+ err := rows.Scan(
+ &key,
+ &value,
+ )
+ if err != nil {
+ return nil, fmt.Errorf("sqlite: could not scan row: %v", err)
+ }
+ headers.Add(key, value)
+ }
+ if err := rows.Err(); err != nil {
+ return nil, fmt.Errorf("sqlite: could not iterate over rows: %v", err)
+ }
+
+ return headers, nil
+}
diff --git a/pkg/proxy/proxy.go b/pkg/proxy/proxy.go
index 2e51fae..8cec97a 100644
--- a/pkg/proxy/proxy.go
+++ b/pkg/proxy/proxy.go
@@ -12,8 +12,6 @@ import (
"net/http/httputil"
"github.com/dstotijn/hetty/pkg/scope"
-
- "github.com/google/uuid"
)
type contextKey int
@@ -56,11 +54,6 @@ func NewProxy(ca *x509.Certificate, key crypto.PrivateKey) (*Proxy, error) {
}
func (p *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
- // Add a unique request ID, to be used for correlating responses to requests.
- reqID := uuid.New()
- ctx := context.WithValue(r.Context(), ReqIDKey, reqID)
- r = r.WithContext(ctx)
-
if r.Method == http.MethodConnect {
p.handleConnect(w, r)
return
diff --git a/pkg/reqlog/repo.go b/pkg/reqlog/repo.go
index 6185523..36264f1 100644
--- a/pkg/reqlog/repo.go
+++ b/pkg/reqlog/repo.go
@@ -2,14 +2,15 @@ package reqlog
import (
"context"
+ "net/http"
+ "time"
"github.com/dstotijn/hetty/pkg/scope"
- "github.com/google/uuid"
)
type Repository interface {
FindRequestLogs(ctx context.Context, opts FindRequestsOptions, scope *scope.Scope) ([]Request, error)
- FindRequestLogByID(ctx context.Context, id uuid.UUID) (Request, error)
- AddRequestLog(ctx context.Context, reqLog Request) error
- AddResponseLog(ctx context.Context, resLog Response) error
+ FindRequestLogByID(ctx context.Context, id int64) (Request, error)
+ AddRequestLog(ctx context.Context, req http.Request, body []byte, timestamp time.Time) (*Request, error)
+ AddResponseLog(ctx context.Context, reqID int64, res http.Response, body []byte, timestamp time.Time) (*Response, error)
}
diff --git a/pkg/reqlog/reqlog.go b/pkg/reqlog/reqlog.go
index c024272..6240c51 100644
--- a/pkg/reqlog/reqlog.go
+++ b/pkg/reqlog/reqlog.go
@@ -13,8 +13,6 @@ import (
"github.com/dstotijn/hetty/pkg/proxy"
"github.com/dstotijn/hetty/pkg/scope"
-
- "github.com/google/uuid"
)
type contextKey int
@@ -24,7 +22,7 @@ const LogBypassedKey contextKey = 0
var ErrRequestNotFound = errors.New("reqlog: request not found")
type Request struct {
- ID uuid.UUID
+ ID int64
Request http.Request
Body []byte
Timestamp time.Time
@@ -32,7 +30,8 @@ type Request struct {
}
type Response struct {
- RequestID uuid.UUID
+ ID int64
+ RequestID int64
Response http.Response
Body []byte
Timestamp time.Time
@@ -72,46 +71,44 @@ func (svc *Service) FindRequests(ctx context.Context, opts FindRequestsOptions)
return svc.repo.FindRequestLogs(ctx, opts, scope)
}
-func (svc *Service) FindRequestLogByID(ctx context.Context, id uuid.UUID) (Request, error) {
+func (svc *Service) FindRequestLogByID(ctx context.Context, id int64) (Request, error) {
return svc.repo.FindRequestLogByID(ctx, id)
}
-func (svc *Service) addRequest(ctx context.Context, reqID uuid.UUID, req http.Request, body []byte) error {
- reqLog := Request{
- ID: reqID,
- Request: req,
- Body: body,
- Timestamp: time.Now(),
- }
-
- return svc.repo.AddRequestLog(ctx, reqLog)
+func (svc *Service) addRequest(
+ ctx context.Context,
+ req http.Request,
+ body []byte,
+ timestamp time.Time,
+) (*Request, error) {
+ return svc.repo.AddRequestLog(ctx, req, body, timestamp)
}
-func (svc *Service) addResponse(ctx context.Context, reqID uuid.UUID, res http.Response, body []byte) error {
+func (svc *Service) addResponse(
+ ctx context.Context,
+ reqID int64,
+ res http.Response,
+ body []byte,
+ timestamp time.Time,
+) (*Response, error) {
if res.Header.Get("Content-Encoding") == "gzip" {
gzipReader, err := gzip.NewReader(bytes.NewBuffer(body))
if err != nil {
- return fmt.Errorf("reqlog: could not create gzip reader: %v", err)
+ return nil, fmt.Errorf("reqlog: could not create gzip reader: %v", err)
}
defer gzipReader.Close()
body, err = ioutil.ReadAll(gzipReader)
if err != nil {
- return fmt.Errorf("reqlog: could not read gzipped response body: %v", err)
+ return nil, fmt.Errorf("reqlog: could not read gzipped response body: %v", err)
}
}
- resLog := Response{
- RequestID: reqID,
- Response: res,
- Body: body,
- Timestamp: time.Now(),
- }
-
- return svc.repo.AddResponseLog(ctx, resLog)
+ return svc.repo.AddResponseLog(ctx, reqID, res, body, timestamp)
}
func (svc *Service) RequestModifier(next proxy.RequestModifyFunc) proxy.RequestModifyFunc {
return func(req *http.Request) {
+ now := time.Now()
next(req)
clone := req.Clone(req.Context())
@@ -131,26 +128,23 @@ func (svc *Service) RequestModifier(next proxy.RequestModifyFunc) proxy.RequestM
// doens't match any rules of the scope.
if svc.BypassOutOfScopeRequests && !svc.scope.Match(clone, body) {
ctx := context.WithValue(req.Context(), LogBypassedKey, true)
- req = req.WithContext(ctx)
+ *req = *req.WithContext(ctx)
return
}
- reqID, _ := req.Context().Value(proxy.ReqIDKey).(uuid.UUID)
- if reqID == uuid.Nil {
- log.Println("[ERROR] Request is missing a related request ID")
+ reqLog, err := svc.addRequest(req.Context(), *clone, body, now)
+ if err != nil {
+ log.Printf("[ERROR] Could not store request log: %v", err)
return
}
-
- go func() {
- if err := svc.addRequest(context.Background(), reqID, *clone, body); err != nil {
- log.Printf("[ERROR] Could not store request log: %v", err)
- }
- }()
+ ctx := context.WithValue(req.Context(), proxy.ReqIDKey, reqLog.ID)
+ *req = *req.WithContext(ctx)
}
}
func (svc *Service) ResponseModifier(next proxy.ResponseModifyFunc) proxy.ResponseModifyFunc {
return func(res *http.Response) error {
+ now := time.Now()
if err := next(res); err != nil {
return err
}
@@ -159,8 +153,8 @@ func (svc *Service) ResponseModifier(next proxy.ResponseModifyFunc) proxy.Respon
return nil
}
- reqID, _ := res.Request.Context().Value(proxy.ReqIDKey).(uuid.UUID)
- if reqID == uuid.Nil {
+ reqID, _ := res.Request.Context().Value(proxy.ReqIDKey).(int64)
+ if reqID == 0 {
return errors.New("reqlog: request is missing ID")
}
@@ -174,7 +168,7 @@ func (svc *Service) ResponseModifier(next proxy.ResponseModifyFunc) proxy.Respon
res.Body = ioutil.NopCloser(bytes.NewBuffer(body))
go func() {
- if err := svc.addResponse(res.Request.Context(), reqID, clone, body); err != nil {
+ if _, err := svc.addResponse(context.Background(), reqID, clone, body, now); err != nil {
log.Printf("[ERROR] Could not store response log: %v", err)
}
}()