control_router.go 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package app
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "sync"
  6. "context"
  7. "github.com/weaveworks/scope/common/xfer"
  8. )
  9. // ControlRouter is a thing that can route control requests and responses
  10. // between the UI and a probe.
  11. type ControlRouter interface {
  12. Handle(ctx context.Context, probeID string, req xfer.Request) (xfer.Response, error)
  13. Register(ctx context.Context, probeID string, handler xfer.ControlHandlerFunc) (int64, error)
  14. Deregister(ctx context.Context, probeID string, id int64) error
  15. }
  16. // NewLocalControlRouter creates a new ControlRouter that does everything
  17. // locally, in memory.
  18. func NewLocalControlRouter() ControlRouter {
  19. return &localControlRouter{
  20. probes: map[string]probe{},
  21. }
  22. }
  23. type localControlRouter struct {
  24. sync.Mutex
  25. probes map[string]probe
  26. }
  27. type probe struct {
  28. id int64
  29. handler xfer.ControlHandlerFunc
  30. }
  31. func (l *localControlRouter) Handle(_ context.Context, probeID string, req xfer.Request) (xfer.Response, error) {
  32. l.Lock()
  33. probe, ok := l.probes[probeID]
  34. l.Unlock()
  35. if !ok {
  36. return xfer.Response{}, fmt.Errorf("probe %s is not connected right now", probeID)
  37. }
  38. return probe.handler(req), nil
  39. }
  40. func (l *localControlRouter) Register(_ context.Context, probeID string, handler xfer.ControlHandlerFunc) (int64, error) {
  41. l.Lock()
  42. defer l.Unlock()
  43. id := rand.Int63()
  44. l.probes[probeID] = probe{
  45. id: id,
  46. handler: handler,
  47. }
  48. return id, nil
  49. }
  50. func (l *localControlRouter) Deregister(_ context.Context, probeID string, id int64) error {
  51. l.Lock()
  52. defer l.Unlock()
  53. // NB probe might have reconnected in the mean time, need to ensure we do not
  54. // delete new connection! Also, it might have connected then deleted itself!
  55. if l.probes[probeID].id == id {
  56. delete(l.probes, probeID)
  57. }
  58. return nil
  59. }