Skip to content

Commit 39bb0e4

Browse files
committedFeb 7, 2020
initial backend plugin
1 parent c072c9c commit 39bb0e4

10 files changed

+415
-1
lines changed
 

‎.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ build/Release
2929
# Dependency directories
3030
node_modules
3131
jspm_packages
32+
vendor
3233

3334
# Optional npm cache directory
3435
.npm
@@ -49,3 +50,5 @@ dist/
4950

5051
# lockfile
5152
package-lock.json
53+
54+
tmp/

‎Makefile

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
all: install build test lint
2+
3+
# Install dependencies
4+
install:
5+
# Frontend
6+
yarn install --pure-lockfile
7+
# Backend
8+
go mod vendor
9+
GO111MODULE=off go get -u golang.org/x/lint/golint
10+
11+
build: build-frontend build-backend
12+
build-frontend:
13+
yarn dev
14+
build-backend:
15+
env GOOS=linux go build -mod=vendor -o ./dist/strava-plugin_linux_amd64 ./pkg
16+
build-debug:
17+
env GOOS=linux go build -mod=vendor -gcflags=all="-N -l" -o ./dist/strava-plugin_linux_amd64 ./pkg
18+
19+
dist: dist-frontend dist-backend
20+
dist-frontend:
21+
yarn build
22+
dist-backend: dist-backend-linux dist-backend-darwin dist-backend-windows
23+
dist-backend-windows: extension = .exe
24+
dist-backend-%:
25+
$(eval filename = strava-plugin_$*_amd64$(extension))
26+
env GOOS=$* GOARCH=amd64 go build -ldflags="-s -w" -mod=vendor -o ./dist/$(filename) ./pkg
27+
28+
start-frontend:
29+
yarn start
30+
31+
.PHONY: test
32+
test: test-frontend test-backend
33+
test-frontend:
34+
yarn test
35+
test-backend:
36+
go test -v -mod=vendor ./pkg/...
37+
test-ci:
38+
yarn ci-test
39+
mkdir -p tmp/coverage/golang/
40+
go test -race -coverprofile=tmp/coverage/golang/coverage.txt -covermode=atomic -mod=vendor ./pkg/...
41+
42+
.PHONY: clean
43+
clean:
44+
-rm -r ./dist/
45+
46+
.PHONY: lint
47+
lint:
48+
yarn lint
49+
golint -min_confidence=1.1 -set_exit_status pkg/...

‎debug-backend.sh

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#!/bin/bash
2+
if [ "$1" == "-h" ]; then
3+
echo "Usage: ${BASH_SOURCE[0]} [plugin process name] [port]"
4+
exit
5+
fi
6+
7+
PORT="${2:-3222}"
8+
PLUGIN_NAME="${1:-strava-plugin}"
9+
10+
if [ "$OSTYPE" == "linux-gnu" ]; then
11+
ptrace_scope=`cat /proc/sys/kernel/yama/ptrace_scope`
12+
if [ "$ptrace_scope" != 0 ]; then
13+
echo "WARNING: ptrace_scope set to value other than 0, this might prevent debugger from connecting, try writing \"0\" to /proc/sys/kernel/yama/ptrace_scope.
14+
Read more at https://www.kernel.org/doc/Documentation/security/Yama.txt"
15+
read -p "Set ptrace_scope to 0? y/N (default N)" set_ptrace_input
16+
if [ "$set_ptrace_input" == "y" ] || [ "$set_ptrace_input" == "Y" ]; then
17+
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
18+
fi
19+
fi
20+
fi
21+
22+
PLUGIN_PID=`pgrep ${PLUGIN_NAME}`
23+
dlv attach ${PLUGIN_PID} --headless --listen=:${PORT} --api-version 2 --log
24+
pkill dlv

‎go.mod

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module github.com/grafana/strava-datasource
2+
3+
go 1.13
4+
5+
require (
6+
github.com/bitly/go-simplejson v0.5.0
7+
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
8+
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4
9+
github.com/hashicorp/go-hclog v0.12.0
10+
github.com/hashicorp/go-plugin v1.0.1
11+
github.com/kr/pretty v0.2.0 // indirect
12+
github.com/patrickmn/go-cache v2.1.0+incompatible
13+
)

‎go.sum

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y=
2+
github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA=
3+
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4=
4+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
6+
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
7+
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
8+
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
9+
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
10+
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
11+
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4 h1:SPdxCL9BChFTlyi0Khv64vdCW4TMna8+sxL7+Chx+Ag=
12+
github.com/grafana/grafana-plugin-model v0.0.0-20190930120109-1fc953a61fb4/go.mod h1:nc0XxBzjeGcrMltCDw269LoWF9S8ibhgxolCdA1R8To=
13+
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
14+
github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM=
15+
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
16+
github.com/hashicorp/go-plugin v1.0.1 h1:4OtAfUGbnKC6yS48p0CtMX2oFYtzFZVv6rok3cRWgnE=
17+
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
18+
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
19+
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
20+
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
21+
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
22+
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
23+
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
24+
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
25+
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
26+
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
27+
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
28+
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
29+
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77 h1:7GoSOOW2jpsfkntVKaS2rAr1TJqfcxotyaUcuxoZSzg=
30+
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
31+
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
32+
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
33+
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
34+
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
35+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
36+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
37+
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
38+
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
39+
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
40+
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d h1:g9qWBGx4puODJTMVyoPrpoxPFgVGd+z1DZwjfRu4d0I=
41+
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
42+
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
43+
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
44+
golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
45+
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
46+
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
47+
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
48+
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
49+
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
50+
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
51+
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
52+
google.golang.org/grpc v1.14.0 h1:ArxJuB1NWfPY6r9Gp9gqwplT0Ge7nqv9msgu03lHLmo=
53+
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
54+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
55+
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

‎pkg/cache.go

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package main
2+
3+
import (
4+
"crypto/sha1"
5+
"encoding/hex"
6+
"encoding/json"
7+
"time"
8+
9+
"github.com/grafana/grafana-plugin-model/go/datasource"
10+
cache "github.com/patrickmn/go-cache"
11+
)
12+
13+
// Cache is a abstraction over go-cache.
14+
type Cache struct {
15+
cache *cache.Cache
16+
}
17+
18+
// NewCache creates a go-cache with expiration(ttl) time and cleanupInterval.
19+
func NewCache(ttl time.Duration, cleanupInterval time.Duration) *Cache {
20+
return &Cache{
21+
cache.New(ttl, cleanupInterval),
22+
}
23+
}
24+
25+
// Set the value of the key "request" to "rersponse" with default expiration time.
26+
func (c *Cache) Set(request string, response interface{}) {
27+
c.cache.SetDefault(request, response)
28+
}
29+
30+
// Get the value associated with request from the cache
31+
func (c *Cache) Get(request string) (interface{}, bool) {
32+
return c.cache.Get(request)
33+
}
34+
35+
// HashString converts the given text string to hash string
36+
func HashString(text string) string {
37+
hash := sha1.New()
38+
hash.Write([]byte(text))
39+
return hex.EncodeToString(hash.Sum(nil))
40+
}
41+
42+
// HashDatasourceInfo converts the given datasource info to hash string
43+
func HashDatasourceInfo(dsInfo *datasource.DatasourceInfo) string {
44+
digester := sha1.New()
45+
if err := json.NewEncoder(digester).Encode(dsInfo); err != nil {
46+
panic(err) // This shouldn't be possible but just in case DatasourceInfo changes
47+
}
48+
return hex.EncodeToString(digester.Sum(nil))
49+
}

‎pkg/datasource.go

+181
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"crypto/tls"
6+
"encoding/json"
7+
"errors"
8+
"fmt"
9+
"net"
10+
"net/http"
11+
"net/url"
12+
"time"
13+
14+
simplejson "github.com/bitly/go-simplejson"
15+
"github.com/grafana/grafana-plugin-model/go/datasource"
16+
hclog "github.com/hashicorp/go-hclog"
17+
plugin "github.com/hashicorp/go-plugin"
18+
)
19+
20+
// StravaPlugin implements the Grafana backend interface and forwards queries to the StravaDatasource
21+
type StravaPlugin struct {
22+
plugin.NetRPCUnsupportedPlugin
23+
logger hclog.Logger
24+
datasourceCache *Cache
25+
}
26+
27+
// ZabbixDatasource stores state about a specific datasource and provides methods to make
28+
// requests to the Zabbix API
29+
type StravaDatasource struct {
30+
url *url.URL
31+
authToken string
32+
dsInfo *datasource.DatasourceInfo
33+
queryCache *Cache
34+
logger hclog.Logger
35+
httpClient *http.Client
36+
}
37+
38+
// newZabbixDatasource returns an initialized ZabbixDatasource
39+
func newStravaDatasource(dsInfo *datasource.DatasourceInfo) (*StravaDatasource, error) {
40+
zabbixURLStr := dsInfo.GetUrl()
41+
zabbixURL, err := url.Parse(zabbixURLStr)
42+
if err != nil {
43+
return nil, err
44+
}
45+
46+
return &StravaDatasource{
47+
url: zabbixURL,
48+
dsInfo: dsInfo,
49+
queryCache: NewCache(10*time.Minute, 10*time.Minute),
50+
httpClient: &http.Client{
51+
Transport: &http.Transport{
52+
TLSClientConfig: &tls.Config{
53+
Renegotiation: tls.RenegotiateFreelyAsClient,
54+
},
55+
Proxy: http.ProxyFromEnvironment,
56+
Dial: (&net.Dialer{
57+
Timeout: 30 * time.Second,
58+
KeepAlive: 30 * time.Second,
59+
}).Dial,
60+
TLSHandshakeTimeout: 10 * time.Second,
61+
ExpectContinueTimeout: 1 * time.Second,
62+
MaxIdleConns: 100,
63+
IdleConnTimeout: 90 * time.Second,
64+
},
65+
Timeout: time.Duration(time.Second * 30),
66+
},
67+
}, nil
68+
}
69+
70+
func (p *StravaPlugin) NewStravaDatasource(dsInfo *datasource.DatasourceInfo) (*StravaDatasource, error) {
71+
ds, err := newStravaDatasource(dsInfo)
72+
if err != nil {
73+
return nil, err
74+
}
75+
76+
ds.logger = p.logger
77+
return ds, nil
78+
}
79+
80+
// Query receives requests from the Grafana backend. Requests are filtered by query type and sent to the
81+
// applicable StravaDatasource.
82+
func (p *StravaPlugin) Query(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (resp *datasource.DatasourceResponse, err error) {
83+
StravaDS, err := p.GetDatasource(tsdbReq)
84+
if err != nil {
85+
return nil, err
86+
}
87+
88+
queryType, err := GetQueryType(tsdbReq)
89+
if err != nil {
90+
return nil, err
91+
}
92+
93+
switch queryType {
94+
case "StravaAPI":
95+
resp, err = StravaDS.StravaAPIQuery(ctx, tsdbReq)
96+
default:
97+
err = errors.New("Query not implemented")
98+
return BuildErrorResponse(err), nil
99+
}
100+
101+
return
102+
}
103+
104+
func (ds *StravaDatasource) StravaAPIQuery(ctx context.Context, tsdbReq *datasource.DatasourceRequest) (*datasource.DatasourceResponse, error) {
105+
response := &datasource.DatasourceResponse{
106+
Results: []*datasource.QueryResult{
107+
&datasource.QueryResult{
108+
RefId: "stravaAPI",
109+
MetaJson: "",
110+
},
111+
},
112+
}
113+
return response, nil
114+
}
115+
116+
// GetDatasource Returns cached datasource or creates new one
117+
func (p *StravaPlugin) GetDatasource(tsdbReq *datasource.DatasourceRequest) (*StravaDatasource, error) {
118+
dsInfoHash := HashDatasourceInfo(tsdbReq.GetDatasource())
119+
120+
if cachedData, ok := p.datasourceCache.Get(dsInfoHash); ok {
121+
if cachedDS, ok := cachedData.(*StravaDatasource); ok {
122+
return cachedDS, nil
123+
}
124+
}
125+
126+
dsInfo := tsdbReq.GetDatasource()
127+
if p.logger.IsDebug() {
128+
p.logger.Debug(fmt.Sprintf("Datasource cache miss (Org %d Id %d '%s' %s)", dsInfo.GetOrgId(), dsInfo.GetId(), dsInfo.GetName(), dsInfoHash))
129+
}
130+
131+
ds, err := p.NewStravaDatasource(dsInfo)
132+
if err != nil {
133+
return nil, err
134+
}
135+
136+
p.datasourceCache.Set(dsInfoHash, ds)
137+
return ds, nil
138+
}
139+
140+
// GetQueryType determines the query type from a query or list of queries
141+
func GetQueryType(tsdbReq *datasource.DatasourceRequest) (string, error) {
142+
queryType := "query"
143+
if len(tsdbReq.Queries) > 0 {
144+
firstQuery := tsdbReq.Queries[0]
145+
queryJSON, err := simplejson.NewJson([]byte(firstQuery.ModelJson))
146+
if err != nil {
147+
return "", err
148+
}
149+
queryType = queryJSON.Get("queryType").MustString("query")
150+
}
151+
return queryType, nil
152+
}
153+
154+
// BuildResponse transforms a Strava API response to a DatasourceResponse
155+
func BuildResponse(responseData interface{}) (*datasource.DatasourceResponse, error) {
156+
jsonBytes, err := json.Marshal(responseData)
157+
if err != nil {
158+
return nil, err
159+
}
160+
161+
return &datasource.DatasourceResponse{
162+
Results: []*datasource.QueryResult{
163+
&datasource.QueryResult{
164+
RefId: "StravaAPI",
165+
MetaJson: string(jsonBytes),
166+
},
167+
},
168+
}, nil
169+
}
170+
171+
// BuildErrorResponse creates a QueryResult that forwards an error to the front-end
172+
func BuildErrorResponse(err error) *datasource.DatasourceResponse {
173+
return &datasource.DatasourceResponse{
174+
Results: []*datasource.QueryResult{
175+
&datasource.QueryResult{
176+
RefId: "StravaAPI",
177+
Error: err.Error(),
178+
},
179+
},
180+
}
181+
}

‎pkg/plugin.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package main
2+
3+
import (
4+
"time"
5+
6+
"github.com/grafana/grafana-plugin-model/go/datasource"
7+
hclog "github.com/hashicorp/go-hclog"
8+
plugin "github.com/hashicorp/go-plugin"
9+
)
10+
11+
var pluginLogger = hclog.New(&hclog.LoggerOptions{
12+
Name: "strava-datasource",
13+
Level: hclog.LevelFromString("DEBUG"),
14+
})
15+
16+
func main() {
17+
pluginLogger.Debug("Running Strava backend datasource")
18+
19+
plugin.Serve(&plugin.ServeConfig{
20+
21+
HandshakeConfig: plugin.HandshakeConfig{
22+
ProtocolVersion: 1,
23+
MagicCookieKey: "grafana_plugin_type",
24+
MagicCookieValue: "datasource",
25+
},
26+
Plugins: map[string]plugin.Plugin{
27+
"strava-backend-datasource": &datasource.DatasourcePluginImpl{Plugin: &StravaPlugin{
28+
datasourceCache: NewCache(10*time.Minute, 10*time.Minute),
29+
logger: pluginLogger,
30+
}},
31+
},
32+
33+
// A non-nil value here enables gRPC serving for this plugin...
34+
GRPCServer: plugin.DefaultGRPCServer,
35+
})
36+
}

‎src/plugin.json

+4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66
"metrics": true,
77
"annotations": false,
88

9+
"backend": true,
10+
"alerting": false,
11+
"executable": "./strava-plugin",
12+
913
"routes": [
1014
{
1115
"path": "strava",

‎webpack/webpack.dev.conf.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
const baseWebpackConfig = require('./webpack.base.conf');
22

33
var conf = baseWebpackConfig;
4-
conf.watch = true;
4+
conf.watch = false;
55
conf.mode = 'development';
66
conf.devtool = 'source-map';
77

0 commit comments

Comments
 (0)
Please sign in to comment.