blob: 8080e9ba5c6556301598fa65e4cbb81e4bd9248a [file] [log] [blame]
Serge Bazanskide0330a2020-07-30 20:48:48 +02001package main
2
3import (
4 "context"
5 "time"
6
7 "github.com/golang/glog"
8)
9
10type lockCtrl struct {
11 getCurrent *lockCtrlGetCurrent
12 take *lockCtrlTake
13 release *lockCtrlRelease
14 subscribe *lockCtrlSubscribe
15 bump *lockCtrlBump
16}
17
18type lockCtrlGetCurrent struct {
19 res chan *lockResCurrent
20}
21
22type lockCtrlTake struct {
23 note string
24 addr string
25 prev string
26 res chan bool
27}
28
29type lockCtrlRelease struct {
30 addr string
31 force bool
32 res chan struct{}
33}
34
35type lockCtrlSubscribe struct {
36 subscriber chan *lockUpdate
37}
38
39type lockCtrlBump struct {
40 addr string
41}
42
43type lockResCurrent struct {
44 note string
45 addr string
46 deadline time.Time
47}
48
49type lockUpdate struct {
50 note string
51 addr string
52}
53
radex81da4e52020-08-27 23:56:29 +020054func (s *service) runLocker(ctx context.Context, ctrlC chan *lockCtrl, ownershipDuration time.Duration) {
Serge Bazanskide0330a2020-07-30 20:48:48 +020055 glog.Infof("Locker starting...")
56
57 var curNote string
58 var curAddr string
59 var curDeadline time.Time
60 var subscribers []chan *lockUpdate
61
62 notify := func() {
63 for _, sub := range subscribers {
64 go func() {
65 sub <- &lockUpdate{
66 note: curNote,
67 addr: curAddr,
68 }
69 }()
70 }
71 }
72
73 t := time.NewTicker(5 * time.Second)
74 defer t.Stop()
75
76 for {
77 select {
78 case <-ctx.Done():
79 err := ctx.Err()
80 glog.Errorf("Locker stoppped: %v", err)
81 return
82 case <-t.C:
83 if curAddr != "" && time.Now().After(curDeadline) {
84 glog.Infof("Expiring lock")
85 curAddr = ""
86 curNote = ""
87 notify()
88 }
89 case ctrl := <-ctrlC:
90 switch {
91 case ctrl.take != nil:
92 won := false
93 if curAddr == ctrl.take.prev {
94 won = true
95 curNote = ctrl.take.note
96 curAddr = ctrl.take.addr
radex81da4e52020-08-27 23:56:29 +020097 curDeadline = time.Now().Add(ownershipDuration)
Serge Bazanskide0330a2020-07-30 20:48:48 +020098 notify()
99 glog.Infof("Lock taken by %q %q", curNote, curAddr)
100 }
101 go func() {
102 ctrl.take.res <- won
103 }()
104 case ctrl.release != nil:
105 if curAddr == ctrl.release.addr || ctrl.release.force {
106 curAddr = ""
107 curNote = ""
108 notify()
109 glog.Infof("Lock relased")
110 }
111 go func() {
112 ctrl.release.res <- struct{}{}
113 }()
114 case ctrl.getCurrent != nil:
115 go func() {
116 ctrl.getCurrent.res <- &lockResCurrent{
117 note: curNote,
118 addr: curAddr,
119 deadline: curDeadline,
120 }
121 }()
122 case ctrl.bump != nil:
123 if curAddr != "" {
radex81da4e52020-08-27 23:56:29 +0200124 curDeadline = time.Now().Add(ownershipDuration)
Serge Bazanskide0330a2020-07-30 20:48:48 +0200125 }
126 case ctrl.subscribe != nil:
127 subscribers = append(subscribers, ctrl.subscribe.subscriber)
128 }
129 }
130 }
131}