@@ -2,20 +2,18 @@ package plugin
22
33import (
44 "context"
5- "crypto/tls"
65 "encoding/json"
76 "fmt"
8- "net/http"
97 "sort"
108 "strconv"
119 "strings"
12- "sync"
1310 "time"
1411
1512 "github.com/NeedleInAJayStack/haystack"
1613 "github.com/NeedleInAJayStack/haystack/client"
1714 "github.com/NeedleInAJayStack/haystack/io"
1815 "github.com/grafana/grafana-plugin-sdk-go/backend"
16+ "github.com/grafana/grafana-plugin-sdk-go/backend/httpclient"
1917 "github.com/grafana/grafana-plugin-sdk-go/backend/instancemgmt"
2018 "github.com/grafana/grafana-plugin-sdk-go/backend/log"
2119 "github.com/grafana/grafana-plugin-sdk-go/data"
@@ -38,24 +36,29 @@ func NewDatasource(ctx context.Context, settings backend.DataSourceInstanceSetti
3836
3937 // settings contains normal inputs in the .JSONData field in JSON byte form
4038 var options Options
41- jsonErr := json .Unmarshal (settings .JSONData , & options )
42- if jsonErr != nil {
43- return nil , jsonErr
39+ err := json .Unmarshal (settings .JSONData , & options )
40+ if err != nil {
41+ return nil , fmt . Errorf ( "datasource options: %w" , err )
4442 }
4543 url := options .Url
4644 username := options .Username
4745
4846 // settings contains secure inputs in .DecryptedSecureJSONData in a string:string map
4947 password := settings .DecryptedSecureJSONData ["password" ]
5048
51- client := client .NewClientFromHTTP (url , username , password , & http.Client {
52- Transport : & http.Transport {
53- TLSClientConfig : & tls.Config {InsecureSkipVerify : options .SkipTlsVerify },
54- },
55- })
56- openErr := client .Open ()
57- if openErr != nil {
58- return nil , openErr
49+ httpClientOptions , err := settings .HTTPClientOptions (ctx )
50+ if err != nil {
51+ return nil , fmt .Errorf ("http client options: %w" , err )
52+ }
53+ httpClientOptions .TLS = & httpclient.TLSOptions {InsecureSkipVerify : options .SkipTlsVerify }
54+ httpClient , err := httpclient .New (httpClientOptions )
55+ if err != nil {
56+ return nil , fmt .Errorf ("new http client: %w" , err )
57+ }
58+ client := client .NewClientFromHTTP (url , username , password , httpClient )
59+ err = client .Open ()
60+ if err != nil {
61+ return nil , fmt .Errorf ("haystack client opening: %w" , err )
5962 }
6063 datasource := Datasource {client : client }
6164 return & datasource , nil
@@ -117,10 +120,10 @@ func (datasource *Datasource) query(ctx context.Context, pCtx backend.PluginCont
117120 // Unmarshal the JSON into our queryModel.
118121 var model QueryModel
119122
120- jsonErr := json .Unmarshal (query .JSON , & model )
121- if jsonErr != nil {
122- log .DefaultLogger .Error (jsonErr .Error ())
123- return backend .ErrDataResponse (backend .StatusBadRequest , fmt .Sprintf ("json unmarshal failure: %v" , jsonErr .Error ()))
123+ err := json .Unmarshal (query .JSON , & model )
124+ if err != nil {
125+ log .DefaultLogger .Error (err .Error ())
126+ return backend .ErrDataResponse (backend .StatusBadRequest , fmt .Sprintf ("json unmarshal failure: %v" , err .Error ()))
124127 }
125128
126129 variables := map [string ]string {
@@ -201,37 +204,24 @@ func (datasource *Datasource) query(ctx context.Context, pCtx backend.PluginCont
201204 return backend .ErrDataResponse (backend .StatusBadRequest , errMsg )
202205 }
203206
204- // Function to read a single point and send it to a channel.
205- readPoint := func (point haystack.Row , hisReadChannel chan haystack.Grid , wg * sync.WaitGroup ) {
206- hisRead , err := datasource .hisRead (point , query .TimeRange )
207- if err != nil {
208- log .DefaultLogger .Error (err .Error ())
209- }
210- hisReadChannel <- hisRead // hisRead is empty under error condition
211- wg .Done ()
212- }
213-
214- // Start a goroutine to collect all the grids into a slice.
215- hisReadChannel := make (chan haystack.Grid )
216- combinedChannel := make (chan []haystack.Grid )
217- go func () {
218- grids := []haystack.Grid {}
219- for grid := range hisReadChannel {
220- grids = append (grids , grid )
221- }
222- combinedChannel <- grids
223- }()
224-
225207 // Read all the points in parallel using goroutines.
226- var wg sync.WaitGroup
227- wg .Add (len (points ))
208+ hisReadChannel := make (chan haystack.Grid )
228209 for _ , point := range points {
229- go readPoint (point , hisReadChannel , & wg )
210+ go func () {
211+ hisRead , err := datasource .hisRead (point , query .TimeRange )
212+ if err != nil {
213+ log .DefaultLogger .Error (err .Error ())
214+ }
215+ hisReadChannel <- hisRead // hisRead is empty under error condition
216+ }()
217+ }
218+
219+ grids := []haystack.Grid {}
220+ for _ = range len (points ) {
221+ grid := <- hisReadChannel
222+ grids = append (grids , grid )
230223 }
231- wg .Wait ()
232- close (hisReadChannel )
233224
234- grids := <- combinedChannel
235225 response := responseFromGrids (grids )
236226 // Make the display name on the "val" fields the names of the points.
237227 for _ , frame := range response .Frames {
@@ -260,11 +250,7 @@ func (datasource *Datasource) query(ctx context.Context, pCtx backend.PluginCont
260250func responseFromGrids (grids []haystack.Grid ) backend.DataResponse {
261251 frames := data.Frames {}
262252 for _ , grid := range grids {
263- frame , frameErr := dataFrameFromGrid (grid )
264- if frameErr != nil {
265- log .DefaultLogger .Error (frameErr .Error ())
266- return backend .ErrDataResponse (backend .StatusBadRequest , fmt .Sprintf ("Frame conversion failure: %v" , frameErr .Error ()))
267- }
253+ frame := dataFrameFromGrid (grid )
268254 frames = append (frames , frame )
269255 }
270256
@@ -333,13 +319,13 @@ func (datasource *Datasource) hisRead(point haystack.Row, timeRange backend.Time
333319
334320 // Must convert input date range to the point's timezone.
335321 // See https://github.com/skyfoundry/haystack-java/blob/30380dbbe4b5d9be8eb3f400195b0cdcdcc67b95/src/main/java/org/projecthaystack/server/HServer.java#L328
336- start , startErr := haystack .NewDateTimeFromGo (timeRange .From ).ToTz (tz .String ())
337- if startErr != nil {
338- return haystack .EmptyGrid (), startErr
322+ start , err := haystack .NewDateTimeFromGo (timeRange .From ).ToTz (tz .String ())
323+ if err != nil {
324+ return haystack .EmptyGrid (), fmt . Errorf ( "start time: %w" , err )
339325 }
340- end , endErr := haystack .NewDateTimeFromGo (timeRange .To ).ToTz (tz .String ())
341- if endErr != nil {
342- return haystack .EmptyGrid (), endErr
326+ end , err := haystack .NewDateTimeFromGo (timeRange .To ).ToTz (tz .String ())
327+ if err != nil {
328+ return haystack .EmptyGrid (), fmt . Errorf ( "end time: %w" , err )
343329 }
344330
345331 return datasource .withRetry (
@@ -415,7 +401,7 @@ func (datasource *Datasource) withRetry(
415401}
416402
417403// dataFrameFromGrid converts a haystack grid to a Grafana data frame
418- func dataFrameFromGrid (grid haystack.Grid ) ( * data.Frame , error ) {
404+ func dataFrameFromGrid (grid haystack.Grid ) * data.Frame {
419405 fields := []* data.Field {}
420406
421407 for _ , col := range grid .Cols () {
@@ -527,7 +513,7 @@ func dataFrameFromGrid(grid haystack.Grid) (*data.Frame, error) {
527513 frame := data .NewFrame ("response" , fields ... )
528514 frameName := disFromMeta (grid .Meta (), "" )
529515 frame .Name = frameName
530- return frame , nil
516+ return frame
531517}
532518
533519// disFromMeta returns the display name using metadata. It falls back to the provided string if no other name can be found
0 commit comments