From 1b62f4c0070432d2dfe610cfa4ac86b09469637f Mon Sep 17 00:00:00 2001 From: Hans Moog <3293976+hmoog@users.noreply.github.com> Date: Thu, 12 Oct 2023 20:53:47 +0200 Subject: [PATCH] Feat: reactive.Clock --- ds/go.mod | 20 +++++++------- ds/go.sum | 45 +++++++++++++++++-------------- ds/reactive/clock.go | 20 ++++++++++++++ ds/reactive/clock_impl.go | 57 +++++++++++++++++++++++++++++++++++++++ ds/reactive/clock_test.go | 22 +++++++++++++++ 5 files changed, 135 insertions(+), 29 deletions(-) create mode 100644 ds/reactive/clock.go create mode 100644 ds/reactive/clock_impl.go create mode 100644 ds/reactive/clock_test.go diff --git a/ds/go.mod b/ds/go.mod index d91e9c9b9..cd81d572d 100644 --- a/ds/go.mod +++ b/ds/go.mod @@ -4,23 +4,25 @@ go 1.21 require ( github.com/emirpasic/gods v1.18.1 - github.com/iotaledger/hive.go/constraints v0.0.0-20230829145721-3041a551a2dd - github.com/iotaledger/hive.go/ierrors v0.0.0-20230829145721-3041a551a2dd - github.com/iotaledger/hive.go/lo v0.0.0-20230829145721-3041a551a2dd - github.com/iotaledger/hive.go/runtime v0.0.0-20230829145721-3041a551a2dd - github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20230829145721-3041a551a2dd - github.com/iotaledger/hive.go/stringify v0.0.0-20230829145721-3041a551a2dd + github.com/iotaledger/hive.go/constraints v0.0.0-20230829145823-fdcc6f1afb61 + github.com/iotaledger/hive.go/ierrors v0.0.0-20230829145823-fdcc6f1afb61 + github.com/iotaledger/hive.go/lo v0.0.0-20230829145823-fdcc6f1afb61 + github.com/iotaledger/hive.go/runtime v0.0.0-20231011215344-76ae390fe3c1 + github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20230829145823-fdcc6f1afb61 + github.com/iotaledger/hive.go/stringify v0.0.0-20230829145823-fdcc6f1afb61 github.com/mr-tron/base58 v1.2.0 github.com/stretchr/testify v1.8.4 - golang.org/x/crypto v0.12.0 + golang.org/x/crypto v0.13.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect - github.com/ethereum/go-ethereum v1.12.2 // indirect + github.com/ethereum/go-ethereum v1.13.1 // indirect github.com/iancoleman/orderedmap v0.3.0 // indirect github.com/kr/text v0.2.0 // indirect + github.com/petermattis/goid v0.0.0-20230808133559-b036b712a89b // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/sys v0.11.0 // indirect + github.com/sasha-s/go-deadlock v0.3.1 // indirect + golang.org/x/sys v0.12.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/ds/go.sum b/ds/go.sum index ce0b21cda..25c616541 100644 --- a/ds/go.sum +++ b/ds/go.sum @@ -7,40 +7,45 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 h1:HbphB4TFFXpv7MNrT52FGrrgVXF1 github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0/go.mod h1:DZGJHZMqrU4JJqFAWUS2UO1+lbSKsdiOoYi9Zzey7Fc= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= -github.com/ethereum/go-ethereum v1.12.2 h1:eGHJ4ij7oyVqUQn48LBz3B7pvQ8sV0wGJiIE6gDq/6Y= -github.com/ethereum/go-ethereum v1.12.2/go.mod h1:1cRAEV+rp/xX0zraSCBnu9Py3HQ+geRMj3HdR+k0wfI= +github.com/ethereum/go-ethereum v1.13.1 h1:UF2FaUKPIy5jeZk3X06ait3y2Q4wI+vJ1l7+UARp+60= +github.com/ethereum/go-ethereum v1.13.1/go.mod h1:xHQKzwkHSl0gnSjZK1mWa06XEdm9685AHqhRknOzqGQ= github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o= github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= -github.com/iotaledger/hive.go/constraints v0.0.0-20230829145721-3041a551a2dd h1:5q2FsSgXYJUWC+ETaODD+fgljP07D9fnXg4J+JO4aKk= -github.com/iotaledger/hive.go/constraints v0.0.0-20230829145721-3041a551a2dd/go.mod h1:dOBOM2s4se3HcWefPe8sQLUalGXJ8yVXw58oK8jke3s= -github.com/iotaledger/hive.go/ierrors v0.0.0-20230829145721-3041a551a2dd h1:rkTrQwU39o6ZT5RsrTzGKGqQ+PTjCbRIPZHJY+9csAk= -github.com/iotaledger/hive.go/ierrors v0.0.0-20230829145721-3041a551a2dd/go.mod h1:HcE8B5lP96enc/OALTb2/rIIi+yOLouRoHOKRclKmC8= -github.com/iotaledger/hive.go/lo v0.0.0-20230829145721-3041a551a2dd h1:O9ka/40xr6k+jjEYuwK6Y/AxB/6phoP4YesYkIhesx8= -github.com/iotaledger/hive.go/lo v0.0.0-20230829145721-3041a551a2dd/go.mod h1:/LERu5vqcessCqr40Wxmbx4x0bbymsK7GuL+TK/ckKo= -github.com/iotaledger/hive.go/runtime v0.0.0-20230829145721-3041a551a2dd h1:o6pe43Z9LSOW7vHLL+FHidWgPlTNf7dPUZonZt0dUEg= -github.com/iotaledger/hive.go/runtime v0.0.0-20230829145721-3041a551a2dd/go.mod h1:j03oAE0YQbsRlCs6MJkKLEyk0y7zxQfIUCmr5N1/sNQ= -github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20230829145721-3041a551a2dd h1:LODitqdRE4Bw++Lc/ANEA3l6/sK05WT3eWvZ4Q1rK4E= -github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20230829145721-3041a551a2dd/go.mod h1:IJgaaxbgKCsNat18jlJJEAxCY2oVYR3F30B+M4vJ89I= -github.com/iotaledger/hive.go/stringify v0.0.0-20230829145721-3041a551a2dd h1:JSO5iQPpUsmTXxXQYr4FKxIBN2hoq01qLAZgNQcv4sc= -github.com/iotaledger/hive.go/stringify v0.0.0-20230829145721-3041a551a2dd/go.mod h1:FTo/UWzNYgnQ082GI9QVM9HFDERqf9rw9RivNpqrnTs= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/iotaledger/hive.go/constraints v0.0.0-20230829145823-fdcc6f1afb61 h1:JxCyAh6yj/AoDszB2v2fuDCKaW9tLmuPKzZTClWRqK8= +github.com/iotaledger/hive.go/constraints v0.0.0-20230829145823-fdcc6f1afb61/go.mod h1:dOBOM2s4se3HcWefPe8sQLUalGXJ8yVXw58oK8jke3s= +github.com/iotaledger/hive.go/ierrors v0.0.0-20230829145823-fdcc6f1afb61 h1:TmZ0kYdD+5pS3KLUTRLtt+VqfIWe1dBAmb2kLGLRBZc= +github.com/iotaledger/hive.go/ierrors v0.0.0-20230829145823-fdcc6f1afb61/go.mod h1:HcE8B5lP96enc/OALTb2/rIIi+yOLouRoHOKRclKmC8= +github.com/iotaledger/hive.go/lo v0.0.0-20230829145823-fdcc6f1afb61 h1:eraNeQ5KKQpVJkKs4Ij/3eeVJfyJQ/PzZUAhnAkT2MI= +github.com/iotaledger/hive.go/lo v0.0.0-20230829145823-fdcc6f1afb61/go.mod h1:/LERu5vqcessCqr40Wxmbx4x0bbymsK7GuL+TK/ckKo= +github.com/iotaledger/hive.go/runtime v0.0.0-20231011215344-76ae390fe3c1 h1:iMqD38z9GJwU9uYUshszsLNC2H87TR1TDc4d3tQk21Y= +github.com/iotaledger/hive.go/runtime v0.0.0-20231011215344-76ae390fe3c1/go.mod h1:dJeQBt3UjsoRSm2yKiw80vDDgPBtIkun7N16ETmVhl4= +github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20230829145823-fdcc6f1afb61 h1:dOMCg/KYm/f/ZWJfNCMgJRGJJZ3SY4NZiho1FuQOnDI= +github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20230829145823-fdcc6f1afb61/go.mod h1:IJgaaxbgKCsNat18jlJJEAxCY2oVYR3F30B+M4vJ89I= +github.com/iotaledger/hive.go/stringify v0.0.0-20230829145823-fdcc6f1afb61 h1:cnps08Hd+bV9DccRlSGo/5wMyxeBsLEIWDJyguDY7Js= +github.com/iotaledger/hive.go/stringify v0.0.0-20230829145823-fdcc6f1afb61/go.mod h1:FTo/UWzNYgnQ082GI9QVM9HFDERqf9rw9RivNpqrnTs= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= +github.com/petermattis/goid v0.0.0-20230808133559-b036b712a89b h1:vab8deKC4QoIfm9fJM59iuNz1ELGsuLoYYpiF+pHiG8= +github.com/petermattis/goid v0.0.0-20230808133559-b036b712a89b/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= +github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0= +github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= -golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= -golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/ds/reactive/clock.go b/ds/reactive/clock.go new file mode 100644 index 000000000..cf92e452d --- /dev/null +++ b/ds/reactive/clock.go @@ -0,0 +1,20 @@ +package reactive + +import "time" + +// Clock is a reactive variable that automatically updates its value to the current time with the given granularity. +type Clock interface { + // Variable is the variable that holds the current time. + Variable[time.Time] + + // OnTick registers a callback that gets called when the clock ticks. + OnTick(handler func(now time.Time)) (unsubscribe func()) + + // Shutdown shuts down the Clock. + Shutdown() +} + +// NewClock creates a new Clock. +func NewClock(granularity time.Duration) Clock { + return newClock(granularity) +} diff --git a/ds/reactive/clock_impl.go b/ds/reactive/clock_impl.go new file mode 100644 index 000000000..0a0c32637 --- /dev/null +++ b/ds/reactive/clock_impl.go @@ -0,0 +1,57 @@ +package reactive + +import ( + "time" +) + +// clock is the default implementation of the Clock interface. +type clock struct { + // variable embeds variable that holds the current time. + *variable[time.Time] + + // shutdown is used to signal the clock to shut down. + shutdown chan bool +} + +// newClock creates a new clock instance. +func newClock(granularity time.Duration) *clock { + c := &clock{ + variable: newVariable[time.Time](), + shutdown: make(chan bool, 1), + } + + // set the initial value. + c.variable.Set(time.Now()) + + go func() { + // align the ticker to the given granularity. + time.Sleep(time.Duration(int64(granularity) - (time.Now().UnixNano() % int64(granularity)))) + ticker := time.NewTicker(granularity) + + // first tick after the initial value. + c.variable.Set(time.Now().Truncate(granularity)) + + for { + select { + case <-c.shutdown: + return + case t := <-ticker.C: + c.variable.Set(t.Truncate(granularity)) + } + } + }() + + return c +} + +// OnTick registers a callback that gets called when the clock ticks. +func (c *clock) OnTick(handler func(now time.Time)) (unsubscribe func()) { + return c.OnUpdate(func(_, now time.Time) { + handler(now) + }) +} + +// Shutdown shuts down the Clock. +func (c *clock) Shutdown() { + close(c.shutdown) +} diff --git a/ds/reactive/clock_test.go b/ds/reactive/clock_test.go new file mode 100644 index 000000000..45187f3c0 --- /dev/null +++ b/ds/reactive/clock_test.go @@ -0,0 +1,22 @@ +package reactive + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" +) + +func TestClock(t *testing.T) { + tickCount := 0 + + clock := NewClock(100 * time.Millisecond) + clock.OnTick(func(now time.Time) { + tickCount++ + require.Less(t, time.Now().Sub(now), 100*time.Millisecond) + }) + + time.Sleep(time.Second) + + require.Greater(t, tickCount, 10) +}