Skip to content

Commit

Permalink
Add decoder endpoint
Browse files Browse the repository at this point in the history
Allow to decode the kafka message body by calling an endpoint
  • Loading branch information
fkarakas committed Sep 17, 2021
1 parent 0cfc180 commit 25f61c8
Show file tree
Hide file tree
Showing 20 changed files with 529 additions and 75 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ URL Parameters:
| STATIC_FILES_DIR | ../client/build | location of the UI static files for the HTML & js files |
| DATA_ROOT_DIR | ./.db | Default location of internal database files |
| API_SERVER_ONLY | false | when true, only the rest api is exposed without serving the static files and default route is / (instead of /api) |
| KAFKA_MESSAGE_BODY_DECODER | | set an endpoint for decoding kafka message payload. Post with payload {id:xxx target-topic:yyy ...} |

## Development

Expand Down
7 changes: 6 additions & 1 deletion server/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,13 @@ func APIServerOnly() bool {
return getBool("API_SERVER_ONLY", false)
}

// URL for the http decoder can start with http:// or not
func KafkaMessageBodyDecoder() string {
return getString("KAFKA_MESSAGE_BODY_DECODER", "")
u := strings.ToLower(getString("KAFKA_MESSAGE_BODY_DECODER", ""))
if strings.HasPrefix(u, "http://") || strings.HasPrefix(u, "https://") {
return u
}
return "http://" + u
}

func DataRootDir() string {
Expand Down
7 changes: 7 additions & 0 deletions server/decoder/decoder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package decoder

import "github.com/etf1/kafka-message-scheduler/schedule"

type Decoder interface {
Decode(s schedule.Schedule) (schedule.Schedule, error)
}
101 changes: 101 additions & 0 deletions server/decoder/httpdecoder/http.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package httpdecoder

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"time"

"github.com/etf1/kafka-message-scheduler-admin/server/store/rest"
"github.com/etf1/kafka-message-scheduler/schedule"
"github.com/etf1/kafka-message-scheduler/schedule/kafka"
log "github.com/sirupsen/logrus"
)

var (
ErrUnknownScheduleType = fmt.Errorf("unknown schedule type")
)

type Decoder struct {
URL string
}

// Post sends an http post request with the payload and return the response
func (h Decoder) Post(payload interface{}) ([]byte, error) {
jsonStr, err := json.Marshal(payload)
if err != nil {
return nil, err
}

req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, h.URL, bytes.NewBuffer(jsonStr))
if err != nil {
return nil, err
}

req.Header.Set("Content-Type", "application/json; charset=UTF-8")

client := &http.Client{
Timeout: 1 * time.Second,
}

resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()

log.Println("response status code:", resp.StatusCode)
log.Println("response headers:", resp.Header)

body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}

if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("request failed: %v %s", resp.StatusCode, string(body))
}

return body, nil
}

// Decode returns a copy of the input schedule, its field 'value' replaced by the response from the http request
func (h Decoder) Decode(s schedule.Schedule) (schedule.Schedule, error) {
switch sch := s.(type) {
case *kafka.Schedule:
if len(sch.Message.Value) == 0 {
return s, nil
}

data, err := h.Post(sch)
if err != nil {
return s, err
}

if len(data) != 0 {
sch.Message.Value = data
}

return sch, nil
case rest.Schedule:
if len(sch.MessageValue) == 0 {
return s, nil
}

data, err := h.Post(sch)
if err != nil {
return s, err
}

if len(data) != 0 {
sch.MessageValue = data
}

return sch, nil
default:
return s, fmt.Errorf("%w: %T", ErrUnknownScheduleType, s)
}
}
119 changes: 119 additions & 0 deletions server/decoder/httpdecoder/http_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// INTEGRATION TESTS
package httpdecoder_test

import (
"fmt"
"net/http"
"reflect"
"testing"

confluent "github.com/confluentinc/confluent-kafka-go/kafka"
"github.com/etf1/kafka-message-scheduler-admin/server/decoder/httpdecoder"
"github.com/etf1/kafka-message-scheduler-admin/server/helper"
"github.com/etf1/kafka-message-scheduler/schedule/kafka"
)

// Rule #1: when received http response code != 200, the kafka message body should be unchanged
func TestHTTPDecoder_not200(t *testing.T) {
helper.VerifyIfSkipIntegrationTests(t)
tests := []struct {
code int
}{
{http.StatusNotFound},
{http.StatusBadRequest},
{http.StatusInternalServerError},
}

for i, tt := range tests {
t.Run(fmt.Sprintf("http_#%v", i), func(t *testing.T) {
func() {
server := helper.MockServer(tt.code, "response")
defer server.Close()

dec := httpdecoder.Decoder{
URL: server.URL,
}

topic := "topic"
sch := kafka.Schedule{
Message: &confluent.Message{
TopicPartition: confluent.TopicPartition{
Topic: &topic,
},
Key: []byte("video-1"),
Value: []byte("content"),
},
}

// create a copy of the schedule
sch2 := helper.CopyKafkaSchedule(sch)

sch3, err := dec.Decode(&sch)
if err == nil {
t.Error("expected error")
}

sch4, ok := sch3.(*kafka.Schedule)
if !ok {
t.Errorf("unexpected type: %v", sch3)
}

if reflect.DeepEqual(*sch4, sch2) == false {
t.Errorf("should be equal")
}
}()
})
}
}

// Rule #2: when received http response code == 200 and not empty response,
// the kafka message value should be changed
func TestHTTPDecoder_200(t *testing.T) {
helper.VerifyIfSkipIntegrationTests(t)

tests := []struct {
response string
expectedMessageValue string
}{
// message content updated with new content
{"response", "response"},
// message content should not be changed when empty response
{"", "content"},
}

for i, tt := range tests {
t.Run(fmt.Sprintf("case #%v", i+1), func(t *testing.T) {
server := helper.MockServer(200, tt.response)
defer server.Close()

dec := httpdecoder.Decoder{
URL: server.URL,
}

topic := "topic"
sch := kafka.Schedule{
Message: &confluent.Message{
TopicPartition: confluent.TopicPartition{
Topic: &topic,
},
Key: []byte("video-1"),
Value: []byte("content"),
},
}

sch2, err := dec.Decode(&sch)
if err != nil {
t.Error("unexpected error")
}

sch3, ok := sch2.(*kafka.Schedule)
if !ok {
t.Errorf("unexpected type: %T", sch2)
}

if string(sch3.Message.Value) != tt.expectedMessageValue {
t.Fatalf("message content not correct: %q", string(sch.Message.Value))
}
})
}
}
2 changes: 1 addition & 1 deletion server/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ services:
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'false'
KAFKA_AUTO_CREATE_TOPICS_ENABLE: 'false'
6 changes: 5 additions & 1 deletion server/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@ go 1.15

require (
github.com/blevesearch/bleve/v2 v2.0.3
github.com/blevesearch/bleve_index_api v1.0.0
github.com/confluentinc/confluent-kafka-go v1.5.2
github.com/drhodes/golorem v0.0.0-20160418191928-ecccc744c2d9
github.com/etf1/kafka-message-scheduler v0.0.4-0.20210615142246-56c1d6186d8f
github.com/gemnasium/logrus-graylog-hook v2.0.7+incompatible
github.com/google/go-cmp v0.5.5 // indirect
github.com/gorilla/mux v1.8.0
github.com/influxdata/influxdb v1.8.5 // indirect
github.com/kr/pretty v0.2.0 // indirect
github.com/prometheus/client_golang v1.8.0
github.com/rs/cors v1.7.0
github.com/sergi/go-diff v1.0.0
github.com/sirupsen/logrus v1.8.1
github.com/stretchr/testify v1.6.1 // indirect
github.com/tevjef/go-runtime-metrics v0.0.0-20170326170900-527a54029307
go.etcd.io/bbolt v1.3.5
golang.org/x/sys v0.0.0-20210304124612-50617c2ba197 // indirect
google.golang.org/protobuf v1.25.0 // indirect
)

//replace github.com/etf1/kafka-message-scheduler => /Users/fkarakas/go/src/github.com/etf1/kafka-message-scheduler
22 changes: 17 additions & 5 deletions server/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:x
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
Expand All @@ -188,8 +189,10 @@ github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
Expand Down Expand Up @@ -273,8 +276,9 @@ github.com/kljensen/snowball v0.6.0/go.mod h1:27N7E8fVU5H68RlUmnWwZCfxgt4POBJfEN
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.3/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/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
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=
Expand Down Expand Up @@ -395,6 +399,7 @@ github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
Expand Down Expand Up @@ -426,8 +431,9 @@ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.2.0/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/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tevjef/go-runtime-metrics v0.0.0-20170326170900-527a54029307 h1:gfHmITmROhuSzCe1+/zYncE940TURIlOGCQCwfuP6jM=
github.com/tevjef/go-runtime-metrics v0.0.0-20170326170900-527a54029307/go.mod h1:DUsG+nVLc17b0zOGba8MjqDv/ZKYJHD83hIX042cuKw=
Expand Down Expand Up @@ -638,6 +644,7 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
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.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
Expand All @@ -648,13 +655,17 @@ google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
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=
Expand All @@ -672,8 +683,9 @@ gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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=
Expand Down
Loading

0 comments on commit 25f61c8

Please sign in to comment.