-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLog.hs
127 lines (112 loc) · 3.54 KB
/
Log.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
{-# LANGUAGE OverloadedStrings, DoAndIfThenElse #-}
module Log
( getLogLazyS
, initLog
, putLog
) where
import Control.Concurrent.STM
import Control.Monad.Reader
import Data.ByteString as B
import Data.ByteString.Lazy as BL
import Data.Map.Strict as MS
import Data.Maybe
import Data.List as L
import Data.Sequence as Seq
import Data.String.Class as S
import Data.Text (Text)
import qualified Data.Text as T
import Data.Time
import Network.Xmpp.Internal hiding (priority, status)
import TByteVector as TBV
import Types
lookupLog :: Jid -> Hate (Maybe Log)
lookupLog jid = do
s <- ask
l <- liftIO $ readTVarIO $ logs s
return $ MS.lookup jid l
-- tabs are banned in JIDs as control characters, so they can be used as JID separators:
-- https://tools.ietf.org/html/rfc6122#appendix-A.5
-- https://tools.ietf.org/html/rfc3454#appendix-C.2.1
-- NUL is banned in XML, so it can be used as a message separator
showLog :: [LogEntry] -> Text
showLog = T.unlines . L.map (\(t, mn, m) -> T.concat
[S.toText (show t)
, "\t"
, fromMaybe "" mn
, "\t"
, m
, "\0"])
fillLogS :: Log -> IO ()
fillLogS (Log tentries tunshown shown) = do
(newLogEntry, unshown) <- atomically $ do
entries <- readTVar tentries
unshown <- readTVar tunshown
maybe retry (\ent -> return (ent, unshown)) $ Seq.lookup unshown entries
TBV.append shown $ showLog [newLogEntry]
atomically $ writeTVar tunshown (unshown + 1)
readLogLazyS :: Log -> Word -> Word -> IO BL.ByteString
readLogLazyS log offset len = do
cached <- atomically $ TBV.read (shownLog log) offset len
if B.null cached
then do
fillLogS log
readLogLazyS log offset len
else return $ BL.fromStrict cached
-- |Read the specific portion of the log, waiting for yet unavailable data
getLogLazyS :: Jid -> Word -> Word -> Hate BL.ByteString
getLogLazyS jid offset len = do
log <- lookupLog jid
liftIO $ maybe (return BL.empty) (\l -> readLogLazyS l offset len) log
newLog :: IO Log
newLog = do
le <- newTVarIO Seq.empty
idx <- newTVarIO 0
sl <- newTByteVector
return $ Log le idx sl
-- |Create a jid-attached log if it doesn't exist yet
initLog :: Jid -> Hate ()
initLog j = do
s <- ask
newlog <- liftIO newLog
liftIO $ atomically $ do
ls <- readTVar $ logs s
when (isNothing $ MS.lookup j ls) $ do
writeTVar (logEntries newlog) $ Seq.empty
writeTVar (logs s) $ MS.insert j newlog ls
putLog :: Jid -> Msg -> Maybe Nickname -> UTCTime -> Hate ()
putLog j m mn t = do
s <- ask
--liftIO $ print (j, m, t)
--liftIO $ TIO.putStr $ putTkabberLog $ TkabberLog t j "" m 0
initLog j
liftIO $ atomically $ do
ls <- readTVar $ logs s
case MS.lookup j ls of
-- logs are never destroyed so fromJust always succeeds
Just (Log entries _ _) -> do
modifyTVar entries $ \seq -> seq |> (t, mn, m)
data TkabberLog = TkabberLog {
timestamp :: UTCTime,
jid :: Jid,
nick :: Text,
body :: Msg,
me :: Int
}
--getTkabberLog :: Text -> TkabberLog
--putTkabberLog :: TkabberLog -> Text
--putTkabberLog (TkabberLog ts jid nick body me) = T.concat [
-- "timestamp ",
-- T.pack $ formatTime defaultTimeLocale "%Y%m%dT%H%M%S" ts,
-- " jid ",
-- escape $ jidToText jid,
-- " nick ",
-- escape nick,
-- " body ",
-- escape body,
-- " me ",
-- T.pack $ show me,
-- "\n"]
-- where
-- --escape t = if T.length t == 0 then "{}" else esc ' ' "\\\\ " $ esc '}' "\\}" $ esc '\n' "\\n" $ esc '\\' "\\\\" t
-- escape t = if T.length t == 0 then "{}" else L.foldl (\it c -> esc c (T.pack $ '\\':'\\':c:[]) it) (esc '\n' "\\\\n" $ esc '\\' "\\\\\\\\" t) ("{}\" $[]" :: String)
-- esc c e t = T.concat $ L.intersperse e $ T.split (== c) t