| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | package testdatasource | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"math/rand" | 
					
						
							| 
									
										
										
										
											2021-12-18 03:42:37 +08:00
										 |  |  | 	"regexp" | 
					
						
							| 
									
										
										
										
											2021-06-23 05:19:29 +08:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/backend" | 
					
						
							|  |  |  | 	"github.com/grafana/grafana-plugin-sdk-go/data" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-18 03:42:37 +08:00
										 |  |  | var random20HzStreamRegex = regexp.MustCompile(`random-20Hz-stream(-\d+)?`) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | func (s *Service) SubscribeStream(_ context.Context, req *backend.SubscribeStreamRequest) (*backend.SubscribeStreamResponse, error) { | 
					
						
							|  |  |  | 	s.logger.Debug("Allowing access to stream", "path", req.Path, "user", req.PluginContext.User) | 
					
						
							|  |  |  | 	initialData, err := backend.NewInitialFrame(s.frame, data.IncludeSchemaOnly) | 
					
						
							| 
									
										
										
										
											2021-04-03 00:41:45 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-23 05:19:29 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// For flight simulations, send the more complex schema
 | 
					
						
							|  |  |  | 	if strings.HasPrefix(req.Path, "flight") { | 
					
						
							|  |  |  | 		ff := newFlightConfig().initFields() | 
					
						
							|  |  |  | 		initialData, err = backend.NewInitialFrame(ff.frame, data.IncludeSchemaOnly) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 01:54:05 +08:00
										 |  |  | 	if strings.Contains(req.Path, "-labeled") { | 
					
						
							|  |  |  | 		initialData, err = backend.NewInitialFrame(s.labelFrame, data.IncludeSchemaOnly) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-21 05:42:05 +08:00
										 |  |  | 	if s.features.IsLivePipelineEnabled() { | 
					
						
							| 
									
										
										
										
											2021-09-17 21:40:32 +08:00
										 |  |  | 		// While developing Live pipeline avoid sending initial data.
 | 
					
						
							|  |  |  | 		initialData = nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-03 00:41:45 +08:00
										 |  |  | 	return &backend.SubscribeStreamResponse{ | 
					
						
							| 
									
										
										
										
											2021-05-26 01:29:02 +08:00
										 |  |  | 		Status:      backend.SubscribeStreamStatusOK, | 
					
						
							|  |  |  | 		InitialData: initialData, | 
					
						
							| 
									
										
										
										
											2021-04-03 00:41:45 +08:00
										 |  |  | 	}, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | func (s *Service) PublishStream(_ context.Context, req *backend.PublishStreamRequest) (*backend.PublishStreamResponse, error) { | 
					
						
							|  |  |  | 	s.logger.Debug("Attempt to publish into stream", "path", req.Path, "user", req.PluginContext.User) | 
					
						
							| 
									
										
										
										
											2021-04-03 00:41:45 +08:00
										 |  |  | 	return &backend.PublishStreamResponse{ | 
					
						
							|  |  |  | 		Status: backend.PublishStreamStatusPermissionDenied, | 
					
						
							|  |  |  | 	}, nil | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | func (s *Service) RunStream(ctx context.Context, request *backend.RunStreamRequest, sender *backend.StreamSender) error { | 
					
						
							|  |  |  | 	s.logger.Debug("New stream call", "path", request.Path) | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	var conf testStreamConfig | 
					
						
							| 
									
										
										
										
											2021-12-18 03:42:37 +08:00
										 |  |  | 	switch { | 
					
						
							|  |  |  | 	case request.Path == "random-2s-stream": | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 		conf = testStreamConfig{ | 
					
						
							| 
									
										
										
										
											2021-04-02 13:32:56 +08:00
										 |  |  | 			Interval: 2 * time.Second, | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-12-18 03:42:37 +08:00
										 |  |  | 	case request.Path == "random-flakey-stream": | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 		conf = testStreamConfig{ | 
					
						
							| 
									
										
										
										
											2021-04-02 13:32:56 +08:00
										 |  |  | 			Interval: 100 * time.Millisecond, | 
					
						
							|  |  |  | 			Drop:     0.75, // keep 25%
 | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-12-18 03:42:37 +08:00
										 |  |  | 	case request.Path == "random-labeled-stream": | 
					
						
							| 
									
										
										
										
											2021-11-20 01:54:05 +08:00
										 |  |  | 		conf = testStreamConfig{ | 
					
						
							|  |  |  | 			Interval: 200 * time.Millisecond, | 
					
						
							|  |  |  | 			Drop:     0.2, // keep 80%
 | 
					
						
							|  |  |  | 			Labeled:  true, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-12-18 03:42:37 +08:00
										 |  |  | 	case request.Path == "flight-5hz-stream": | 
					
						
							| 
									
										
										
										
											2021-06-23 05:19:29 +08:00
										 |  |  | 		conf = testStreamConfig{ | 
					
						
							|  |  |  | 			Interval: 200 * time.Millisecond, | 
					
						
							|  |  |  | 			Flight:   newFlightConfig(), | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-12-18 03:42:37 +08:00
										 |  |  | 	case random20HzStreamRegex.MatchString(request.Path): | 
					
						
							|  |  |  | 		conf = testStreamConfig{ | 
					
						
							|  |  |  | 			Interval: 50 * time.Millisecond, | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		return fmt.Errorf("testdata plugin does not support path: %s", request.Path) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | 	return s.runTestStream(ctx, request.Path, conf, sender) | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type testStreamConfig struct { | 
					
						
							|  |  |  | 	Interval time.Duration | 
					
						
							|  |  |  | 	Drop     float64 | 
					
						
							| 
									
										
										
										
											2021-06-23 05:19:29 +08:00
										 |  |  | 	Flight   *flightConfig | 
					
						
							| 
									
										
										
										
											2021-11-20 01:54:05 +08:00
										 |  |  | 	Labeled  bool | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | func (s *Service) runTestStream(ctx context.Context, path string, conf testStreamConfig, sender *backend.StreamSender) error { | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	spread := 50.0 | 
					
						
							|  |  |  | 	walker := rand.Float64() * 100 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ticker := time.NewTicker(conf.Interval) | 
					
						
							|  |  |  | 	defer ticker.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-23 05:19:29 +08:00
										 |  |  | 	var flight *flightFields | 
					
						
							|  |  |  | 	if conf.Flight != nil { | 
					
						
							|  |  |  | 		flight = conf.Flight.initFields() | 
					
						
							|  |  |  | 		flight.append(conf.Flight.getNextPoint(time.Now())) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 01:54:05 +08:00
										 |  |  | 	labelFrame := data.NewFrame("labeled", | 
					
						
							|  |  |  | 		data.NewField("labels", nil, make([]string, 2)), | 
					
						
							|  |  |  | 		data.NewField("Time", nil, make([]time.Time, 2)), | 
					
						
							|  |  |  | 		data.NewField("Value", nil, make([]float64, 2)), | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-ctx.Done(): | 
					
						
							| 
									
										
										
										
											2021-11-01 17:53:33 +08:00
										 |  |  | 			s.logger.Debug("Stop streaming data for path", "path", path) | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 			return ctx.Err() | 
					
						
							|  |  |  | 		case t := <-ticker.C: | 
					
						
							|  |  |  | 			if rand.Float64() < conf.Drop { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-06-23 05:19:29 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-10 00:19:29 +08:00
										 |  |  | 			mode := data.IncludeDataOnly | 
					
						
							| 
									
										
										
										
											2022-01-21 05:42:05 +08:00
										 |  |  | 			if s.features.IsLivePipelineEnabled() { | 
					
						
							| 
									
										
										
										
											2021-09-10 00:19:29 +08:00
										 |  |  | 				mode = data.IncludeAll | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-23 05:19:29 +08:00
										 |  |  | 			if flight != nil { | 
					
						
							|  |  |  | 				flight.set(0, conf.Flight.getNextPoint(t)) | 
					
						
							| 
									
										
										
										
											2021-09-10 00:19:29 +08:00
										 |  |  | 				if err := sender.SendFrame(flight.frame, mode); err != nil { | 
					
						
							| 
									
										
										
										
											2021-06-23 05:19:29 +08:00
										 |  |  | 					return err | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				delta := rand.Float64() - 0.5 | 
					
						
							|  |  |  | 				walker += delta | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-20 01:54:05 +08:00
										 |  |  | 				if conf.Labeled { | 
					
						
							|  |  |  | 					secA := t.Second() / 3 | 
					
						
							|  |  |  | 					secB := t.Second() / 7 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					labelFrame.Fields[0].Set(0, fmt.Sprintf("s=A,s=p%d,x=X", secA)) | 
					
						
							|  |  |  | 					labelFrame.Fields[1].Set(0, t) | 
					
						
							|  |  |  | 					labelFrame.Fields[2].Set(0, walker) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					labelFrame.Fields[0].Set(1, fmt.Sprintf("s=B,s=p%d,x=X", secB)) | 
					
						
							|  |  |  | 					labelFrame.Fields[1].Set(1, t) | 
					
						
							|  |  |  | 					labelFrame.Fields[2].Set(1, walker+10) | 
					
						
							|  |  |  | 					if err := sender.SendFrame(labelFrame, mode); err != nil { | 
					
						
							|  |  |  | 						return err | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					s.frame.Fields[0].Set(0, t) | 
					
						
							|  |  |  | 					s.frame.Fields[1].Set(0, walker)                                // Value
 | 
					
						
							|  |  |  | 					s.frame.Fields[2].Set(0, walker-((rand.Float64()*spread)+0.01)) // Min
 | 
					
						
							|  |  |  | 					s.frame.Fields[3].Set(0, walker+((rand.Float64()*spread)+0.01)) // Max
 | 
					
						
							|  |  |  | 					if err := sender.SendFrame(s.frame, mode); err != nil { | 
					
						
							|  |  |  | 						return err | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2021-06-23 05:19:29 +08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2021-03-24 01:24:08 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |