laserproxy: init
Change-Id: I1900be6eea2d702548279176d796c58c34952dc8
diff --git a/hswaw/laserproxy/locker.go b/hswaw/laserproxy/locker.go
new file mode 100644
index 0000000..044e832
--- /dev/null
+++ b/hswaw/laserproxy/locker.go
@@ -0,0 +1,131 @@
+package main
+
+import (
+ "context"
+ "time"
+
+ "github.com/golang/glog"
+)
+
+type lockCtrl struct {
+ getCurrent *lockCtrlGetCurrent
+ take *lockCtrlTake
+ release *lockCtrlRelease
+ subscribe *lockCtrlSubscribe
+ bump *lockCtrlBump
+}
+
+type lockCtrlGetCurrent struct {
+ res chan *lockResCurrent
+}
+
+type lockCtrlTake struct {
+ note string
+ addr string
+ prev string
+ res chan bool
+}
+
+type lockCtrlRelease struct {
+ addr string
+ force bool
+ res chan struct{}
+}
+
+type lockCtrlSubscribe struct {
+ subscriber chan *lockUpdate
+}
+
+type lockCtrlBump struct {
+ addr string
+}
+
+type lockResCurrent struct {
+ note string
+ addr string
+ deadline time.Time
+}
+
+type lockUpdate struct {
+ note string
+ addr string
+}
+
+func (s *service) runLocker(ctx context.Context, ctrlC chan *lockCtrl) {
+ glog.Infof("Locker starting...")
+
+ var curNote string
+ var curAddr string
+ var curDeadline time.Time
+ var subscribers []chan *lockUpdate
+
+ notify := func() {
+ for _, sub := range subscribers {
+ go func() {
+ sub <- &lockUpdate{
+ note: curNote,
+ addr: curAddr,
+ }
+ }()
+ }
+ }
+
+ t := time.NewTicker(5 * time.Second)
+ defer t.Stop()
+
+ for {
+ select {
+ case <-ctx.Done():
+ err := ctx.Err()
+ glog.Errorf("Locker stoppped: %v", err)
+ return
+ case <-t.C:
+ if curAddr != "" && time.Now().After(curDeadline) {
+ glog.Infof("Expiring lock")
+ curAddr = ""
+ curNote = ""
+ notify()
+ }
+ case ctrl := <-ctrlC:
+ switch {
+ case ctrl.take != nil:
+ won := false
+ if curAddr == ctrl.take.prev {
+ won = true
+ curNote = ctrl.take.note
+ curAddr = ctrl.take.addr
+ curDeadline = time.Now().Add(15 * time.Minute)
+ notify()
+ glog.Infof("Lock taken by %q %q", curNote, curAddr)
+ }
+ go func() {
+ ctrl.take.res <- won
+ }()
+ case ctrl.release != nil:
+ if curAddr == ctrl.release.addr || ctrl.release.force {
+ curAddr = ""
+ curNote = ""
+ notify()
+ glog.Infof("Lock relased")
+ }
+ go func() {
+ ctrl.release.res <- struct{}{}
+ }()
+ case ctrl.getCurrent != nil:
+ go func() {
+ ctrl.getCurrent.res <- &lockResCurrent{
+ note: curNote,
+ addr: curAddr,
+ deadline: curDeadline,
+ }
+ }()
+ case ctrl.bump != nil:
+ if curAddr != "" {
+ curDeadline = time.Now().Add(15 * time.Minute)
+ }
+ case ctrl.subscribe != nil:
+ subscribers = append(subscribers, ctrl.subscribe.subscriber)
+ }
+ }
+ }
+}