summaryrefslogtreecommitdiff
path: root/bittorrent/src/Network/BitTorrent/Internal/Cache.hs
diff options
context:
space:
mode:
Diffstat (limited to 'bittorrent/src/Network/BitTorrent/Internal/Cache.hs')
-rw-r--r--bittorrent/src/Network/BitTorrent/Internal/Cache.hs169
1 files changed, 169 insertions, 0 deletions
diff --git a/bittorrent/src/Network/BitTorrent/Internal/Cache.hs b/bittorrent/src/Network/BitTorrent/Internal/Cache.hs
new file mode 100644
index 00000000..8c74467a
--- /dev/null
+++ b/bittorrent/src/Network/BitTorrent/Internal/Cache.hs
@@ -0,0 +1,169 @@
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--
10module 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 , unsafeTryTakeData
31 , takeData
32 ) where
33
34import Control.Applicative
35import Data.Monoid
36import Data.Default
37import Data.Time
38import Data.Time.Clock.POSIX
39import System.IO.Unsafe
40
41
42data Cached a = Cached
43 { -- | Time of resource creation.
44 lastUpdated :: !POSIXTime
45
46 -- | Minimum invalidation timeout.
47 , minUpdateInterval :: !NominalDiffTime
48
49 -- | Resource lifetime.
50 , updateInterval :: !NominalDiffTime
51
52 -- | Resource data.
53 , cachedData :: a
54 } deriving (Show, Eq)
55
56-- INVARIANT: minUpdateInterval <= updateInterval
57
58instance Default (Cached a) where
59 def = mempty
60
61instance Functor Cached where
62 fmap f (Cached t i m a) = Cached t i m (f a)
63
64posixEpoch :: NominalDiffTime
65posixEpoch = 1000000000000000000000000000000000000000000000000000000
66
67instance Applicative Cached where
68 pure = Cached 0 posixEpoch posixEpoch
69 f <*> c = Cached
70 { lastUpdated = undefined
71 , minUpdateInterval = undefined
72 , updateInterval = undefined
73 , cachedData = cachedData f (cachedData c)
74 }
75
76instance Alternative Cached where
77 empty = mempty
78 (<|>) = error "cached alternative instance: not implemented"
79
80instance Monad Cached where
81 return = pure
82 Cached {..} >>= f = Cached
83 { lastUpdated = undefined
84 , updateInterval = undefined
85 , minUpdateInterval = undefined
86 , cachedData = undefined
87 }
88
89instance Monoid (Cached a) where
90 mempty = Cached
91 { lastUpdated = 0
92 , minUpdateInterval = 0
93 , updateInterval = 0
94 , cachedData = error "cached mempty: impossible happen"
95 }
96
97 mappend a b
98 | expirationTime a > expirationTime b = a
99 | otherwise = b
100
101normalize :: NominalDiffTime -> NominalDiffTime
102 -> (NominalDiffTime, NominalDiffTime)
103normalize a b
104 | a < b = (a, b)
105 | otherwise = (b, a)
106{-# INLINE normalize #-}
107
108newCached :: NominalDiffTime -> NominalDiffTime -> a -> IO (Cached a)
109newCached minInterval interval x = do
110 t <- getPOSIXTime
111 let (mui, ui) = normalize minInterval interval
112 return Cached
113 { lastUpdated = t
114 , minUpdateInterval = mui
115 , updateInterval = ui
116 , cachedData = x
117 }
118
119newCached_ :: NominalDiffTime -> a -> IO (Cached a)
120newCached_ interval x = newCached interval interval x
121{-# INLINE newCached_ #-}
122
123expirationTime :: Cached a -> POSIXTime
124expirationTime Cached {..} = undefined
125
126isAlive :: Cached a -> IO Bool
127isAlive Cached {..} = do
128 currentTime <- getPOSIXTime
129 return $ lastUpdated + updateInterval > currentTime
130
131isExpired :: Cached a -> IO Bool
132isExpired Cached {..} = undefined
133
134isStalled :: Cached a -> IO Bool
135isStalled Cached {..} = undefined
136
137canUpdate :: Cached a -> IO (Maybe NominalDiffTime)
138canUpdate = undefined --isStaled
139
140shouldUpdate :: Cached a -> IO (Maybe NominalDiffTime)
141shouldUpdate = undefined -- isExpired
142
143tryTakeData :: Cached a -> IO (Maybe a)
144tryTakeData c = do
145 alive <- isAlive c
146 return $ if alive then Just (cachedData c) else Nothing
147
148unsafeTryTakeData :: Cached a -> Maybe a
149unsafeTryTakeData = unsafePerformIO . tryTakeData
150
151invalidateData :: Cached a -> IO a -> IO (Cached a)
152invalidateData Cached {..} action = do
153 t <- getPOSIXTime
154 x <- action
155 return Cached
156 { lastUpdated = t
157 , updateInterval = updateInterval
158 , minUpdateInterval = minUpdateInterval
159 , cachedData = x
160 }
161
162takeData :: Cached a -> IO a -> IO a
163takeData c action = do
164 mdata <- tryTakeData c
165 case mdata of
166 Just a -> return a
167 Nothing -> do
168 c' <- invalidateData c action
169 takeData c' action