diff options
author | Sam Truzjan <pxqr.sta@gmail.com> | 2014-03-18 03:32:42 +0400 |
---|---|---|
committer | Sam Truzjan <pxqr.sta@gmail.com> | 2014-03-18 03:32:42 +0400 |
commit | 30a1c20cf431c2ce1b36d9432a78c913a429cefe (patch) | |
tree | 44f860588bb6eb31871f8e37b892b58635e6f63d /src/Network/BitTorrent/Internal/Cache.hs | |
parent | 70a172a43d5b34853289bbf57c3e5a168431a954 (diff) |
Move Cache module to Internal subsystem
Diffstat (limited to 'src/Network/BitTorrent/Internal/Cache.hs')
-rw-r--r-- | src/Network/BitTorrent/Internal/Cache.hs | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/Network/BitTorrent/Internal/Cache.hs b/src/Network/BitTorrent/Internal/Cache.hs new file mode 100644 index 00000000..1eb2f192 --- /dev/null +++ b/src/Network/BitTorrent/Internal/Cache.hs | |||
@@ -0,0 +1,164 @@ | |||
1 | -- | | ||
2 | -- Copyright : (c) Sam Truzjan 2014 | ||
3 | -- License : BSD | ||
4 | -- Maintainer : pxqr.sta@gmail.com | ||
5 | -- Stability : experimental | ||
6 | -- Portability : portable | ||
7 | -- | ||
8 | -- Cached data for tracker responses. | ||
9 | -- | ||
10 | module Network.BitTorrent.Internal.Cache | ||
11 | ( -- * Cache | ||
12 | Cached | ||
13 | , lastUpdated | ||
14 | , updateInterval | ||
15 | , minUpdateInterval | ||
16 | |||
17 | -- * Construction | ||
18 | , newCached | ||
19 | , newCached_ | ||
20 | |||
21 | -- * Query | ||
22 | , isAlive | ||
23 | , isStalled | ||
24 | , isExpired | ||
25 | , canUpdate | ||
26 | , shouldUpdate | ||
27 | |||
28 | -- * Cached data | ||
29 | , tryTakeData | ||
30 | , takeData | ||
31 | ) where | ||
32 | |||
33 | import Control.Applicative | ||
34 | import Data.Monoid | ||
35 | import Data.Default | ||
36 | import Data.Time | ||
37 | import Data.Time.Clock.POSIX | ||
38 | |||
39 | |||
40 | data Cached a = Cached | ||
41 | { -- | Time of resource creation. | ||
42 | lastUpdated :: !POSIXTime | ||
43 | |||
44 | -- | Minimum invalidation timeout. | ||
45 | , minUpdateInterval :: !NominalDiffTime | ||
46 | |||
47 | -- | Resource lifetime. | ||
48 | , updateInterval :: !NominalDiffTime | ||
49 | |||
50 | -- | Resource data. | ||
51 | , cachedData :: a | ||
52 | } deriving (Show, Eq) | ||
53 | |||
54 | -- INVARIANT: minUpdateInterval <= updateInterval | ||
55 | |||
56 | instance Default (Cached a) where | ||
57 | def = mempty | ||
58 | |||
59 | instance Functor Cached where | ||
60 | fmap f (Cached t i m a) = Cached t i m (f a) | ||
61 | |||
62 | posixEpoch :: NominalDiffTime | ||
63 | posixEpoch = 1000000000000000000000000000000000000000000000000000000 | ||
64 | |||
65 | instance Applicative Cached where | ||
66 | pure = Cached 0 posixEpoch posixEpoch | ||
67 | f <*> c = Cached | ||
68 | { lastUpdated = undefined | ||
69 | , minUpdateInterval = undefined | ||
70 | , updateInterval = undefined | ||
71 | , cachedData = cachedData f (cachedData c) | ||
72 | } | ||
73 | |||
74 | instance Alternative Cached where | ||
75 | empty = mempty | ||
76 | (<|>) = error "cached alternative instance: not implemented" | ||
77 | |||
78 | instance Monad Cached where | ||
79 | return = pure | ||
80 | Cached {..} >>= f = Cached | ||
81 | { lastUpdated = undefined | ||
82 | , updateInterval = undefined | ||
83 | , minUpdateInterval = undefined | ||
84 | , cachedData = undefined | ||
85 | } | ||
86 | |||
87 | instance Monoid (Cached a) where | ||
88 | mempty = Cached | ||
89 | { lastUpdated = 0 | ||
90 | , minUpdateInterval = 0 | ||
91 | , updateInterval = 0 | ||
92 | , cachedData = error "cached mempty: impossible happen" | ||
93 | } | ||
94 | |||
95 | mappend a b | ||
96 | | expirationTime a > expirationTime b = a | ||
97 | | otherwise = b | ||
98 | |||
99 | normalize :: NominalDiffTime -> NominalDiffTime | ||
100 | -> (NominalDiffTime, NominalDiffTime) | ||
101 | normalize a b | ||
102 | | a < b = (a, b) | ||
103 | | otherwise = (b, a) | ||
104 | {-# INLINE normalize #-} | ||
105 | |||
106 | newCached :: NominalDiffTime -> NominalDiffTime -> a -> IO (Cached a) | ||
107 | newCached minInterval interval x = do | ||
108 | t <- getPOSIXTime | ||
109 | let (mui, ui) = normalize minInterval interval | ||
110 | return Cached | ||
111 | { lastUpdated = t | ||
112 | , minUpdateInterval = mui | ||
113 | , updateInterval = ui | ||
114 | , cachedData = x | ||
115 | } | ||
116 | |||
117 | newCached_ :: NominalDiffTime -> a -> IO (Cached a) | ||
118 | newCached_ interval x = newCached interval interval x | ||
119 | {-# INLINE newCached_ #-} | ||
120 | |||
121 | expirationTime :: Cached a -> POSIXTime | ||
122 | expirationTime Cached {..} = undefined | ||
123 | |||
124 | isAlive :: Cached a -> IO Bool | ||
125 | isAlive Cached {..} = do | ||
126 | currentTime <- getPOSIXTime | ||
127 | return $ lastUpdated + updateInterval > currentTime | ||
128 | |||
129 | isExpired :: Cached a -> IO Bool | ||
130 | isExpired Cached {..} = undefined | ||
131 | |||
132 | isStalled :: Cached a -> IO Bool | ||
133 | isStalled Cached {..} = undefined | ||
134 | |||
135 | canUpdate :: Cached a -> IO (Maybe NominalDiffTime) | ||
136 | canUpdate = undefined --isStaled | ||
137 | |||
138 | shouldUpdate :: Cached a -> IO (Maybe NominalDiffTime) | ||
139 | shouldUpdate = undefined -- isExpired | ||
140 | |||
141 | tryTakeData :: Cached a -> IO (Maybe a) | ||
142 | tryTakeData c = do | ||
143 | alive <- isAlive c | ||
144 | return $ if alive then Just (cachedData c) else Nothing | ||
145 | |||
146 | invalidateData :: Cached a -> IO a -> IO (Cached a) | ||
147 | invalidateData Cached {..} action = do | ||
148 | t <- getPOSIXTime | ||
149 | x <- action | ||
150 | return Cached | ||
151 | { lastUpdated = t | ||
152 | , updateInterval = updateInterval | ||
153 | , minUpdateInterval = minUpdateInterval | ||
154 | , cachedData = x | ||
155 | } | ||
156 | |||
157 | takeData :: Cached a -> IO a -> IO a | ||
158 | takeData c action = do | ||
159 | mdata <- tryTakeData c | ||
160 | case mdata of | ||
161 | Just a -> return a | ||
162 | Nothing -> do | ||
163 | c' <- invalidateData c action | ||
164 | takeData c' action | ||