@@ -5,46 +5,122 @@ import (
55 "time"
66)
77
8- // UpdatingResource is a structure to wrap an object x which is regularly and
9- // asynchronously computed / updated.
10- type UpdatingResource struct {
8+ // Config is the configuration for a Resource.
9+ type Config struct {
10+
11+ // Name of this resource.
12+ Name string
13+
14+ // Update is the function to update the wrapped object. Update must handle nil
15+ // values.
16+ Update func (x interface {}) (interface {}, error )
17+
18+ // Interval is the time to wait between between automatic updates. If 0 (or not
19+ // set), updates will never trigger automatically.
20+ Interval time.Duration
21+
22+ // Success is the function (if any) to call, if the object was successfully
23+ // updated. Success is called with the new value the name of the resource.
24+ Success func (x interface {}, name string )
25+
26+ // Success is the function (if any) to call, if the object was successfully
27+ // updated. Error is called with the the error that occurred the name of the
28+ // resource.
29+ Error func (e error , name string )
30+ }
31+
32+ // Resource regularly, asynchronously updates a wrapped object.
33+ type Resource struct {
34+
35+ // resource configuration
36+ * Config
37+
38+ // mutex for protecting object updates
1139 mu * sync.RWMutex
12- x * interface {}
40+
41+ // the wrapped object
42+ x * interface {}
43+
44+ // a channel for terminating the updates
1345 done chan bool
46+
47+ // channel to manually trigger an update
48+ tick chan bool
49+
1450}
1551
16- // NewUpdatingResource creates a new UpdatingResource. Thereby, f is the function
17- // that will be called every ttl to compute a new value for x (i.e. x=f(x)).
18- func NewUpdatingResource (x interface {}, f func (x interface {}) interface {}, ttl time.Duration ) * UpdatingResource {
52+ // NewResource creates a new Resource.
53+ func (c * Config ) NewResource () * Resource {
1954 var mu sync.RWMutex
55+
2056 done := make (chan bool )
21- go func (f func (x interface {}) interface {}) {
22- ticker := time .NewTicker (ttl )
57+ tick := make (chan bool )
58+
59+ var startValue interface {} = nil
60+ x := & startValue
61+
62+ var timeTicker <- chan time.Time
63+ if c .Interval > 0 {
64+ timeTicker = time .NewTicker (c .Interval ).C
65+ }
66+
67+ go func (f func (x interface {}) (interface {}, error )) {
68+
69+ // wrap f to be used for inputs on multiple channels
70+ var fWrapper = func () {
71+ y , err := f (* x )
72+ if err != nil && c .Error != nil {
73+ c .Error (err , c .Name )
74+ } else {
75+ if c .Success != nil {
76+ c .Success (y , c .Name )
77+ }
78+ mu .Lock ()
79+ * x = y
80+ mu .Unlock ()
81+ }
82+ }
83+
84+ // wait (forever) on channels
2385 for {
2486 select {
2587 case <- done :
2688 return
27- case <- ticker .C :
28- y := f (x )
29- mu .Lock ()
30- x = y
31- mu .Unlock ()
89+ case <- timeTicker :
90+ fWrapper ()
91+ case <- tick :
92+ fWrapper ()
3293 }
3394 }
34- }(f )
35- resource := UpdatingResource {x : & x , mu : & mu , done : done }
95+ }(c .Update )
96+
97+ // compute step 0
98+ tick <- true
99+
100+ resource := Resource {
101+ Config : c ,
102+ mu : & mu ,
103+ x : x ,
104+ done : done ,
105+ tick : tick ,
106+ }
36107 return & resource
37108}
38109
39110// Get returns the current value of the wrapped object. Get is thread-safe
40111// wrt. to the function updating the encapsulated object.
41- func (r * UpdatingResource ) Get () interface {} {
112+ func (r * Resource ) Get () interface {} {
42113 r .mu .RLock ()
43114 defer r .mu .RUnlock ()
44115 return * r .x
45116}
46117
47118// Done stops the updating of the wrapped object.
48- func (r * UpdatingResource ) Done () {
119+ func (r * Resource ) Done () {
49120 r .done <- true
50- }
121+ }
122+
123+ // Tick manually trigger an update.
124+ func (r * Resource ) Tick () {
125+ r .tick <- true
126+ }
0 commit comments