summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Codec/LineReady.hs23
-rw-r--r--Codec/SafeBlob.hs22
-rw-r--r--KikiD/GetLine.hs18
-rw-r--r--KikiD/Message.hs35
-rw-r--r--KikiD/PortServer.hs43
-rw-r--r--kiki.cabal3
-rw-r--r--kikid.hs15
7 files changed, 66 insertions, 93 deletions
diff --git a/Codec/LineReady.hs b/Codec/LineReady.hs
new file mode 100644
index 0000000..ca2cde3
--- /dev/null
+++ b/Codec/LineReady.hs
@@ -0,0 +1,23 @@
1module Codec.LineReady where
2
3import qualified Data.ByteString.Char8 as B
4import Data.Monoid
5import Data.List (foldl')
6import Data.Maybe
7
8toLineReady :: B.ByteString -> B.ByteString
9toLineReady blob =
10 let as = zip [0..] (B.unpack blob)
11 bs = filter ((=='\n') . snd) as
12 is = map fst bs
13 in B.pack (show is) <> foldl' (replaceCharStrIndex '#') blob is <> B.singleton '\n'
14
15replaceCharStrIndex :: Char -> B.ByteString -> Int -> B.ByteString
16replaceCharStrIndex c str i = a <> B.singleton c <> B.drop 1 b
17 where (a,b) = B.splitAt i str
18
19fromLineReady :: B.ByteString -> B.ByteString
20fromLineReady str = foldl' (replaceCharStrIndex '\n') (B.drop 1 str') is
21 where is = map fst . mapMaybe B.readInt $
22 B.groupBy (\c d -> (c/=',')&&(d/=',')) ls
23 (ls,str') = B.break (==']') (B.tail str)
diff --git a/Codec/SafeBlob.hs b/Codec/SafeBlob.hs
deleted file mode 100644
index a6db80e..0000000
--- a/Codec/SafeBlob.hs
+++ /dev/null
@@ -1,22 +0,0 @@
1{-# LANGUAGE ViewPatterns #-}
2module Codec.SafeBlob where
3
4import qualified Data.ByteString.Char8 as B
5import Data.Monoid
6import Data.List (foldl')
7import Data.Maybe
8
9toSafe :: B.ByteString -> B.ByteString
10toSafe blob = let as = zip [0..] (B.unpack blob)
11 bs = filter ((=='\n') . snd) as
12 is = map fst bs
13 in B.pack (show is) <> foldl' (replaceCharStrIndex '#') blob is
14
15replaceCharStrIndex :: Char -> B.ByteString -> Int -> B.ByteString
16replaceCharStrIndex c str i = a <> B.singleton c <> b
17 where (a,B.uncons -> Just (_,b)) = B.splitAt i str
18
19fromSafe str = foldl' (replaceCharStrIndex '\n') (B.drop 1 str') is
20 where is = map fst . mapMaybe B.readInt $
21 B.groupBy (\c d -> (c/=',')&&(d/=',')) ls
22 (ls,str') = B.break (==']') (B.tail str)
diff --git a/KikiD/GetLine.hs b/KikiD/GetLine.hs
deleted file mode 100644
index 8af5dc6..0000000
--- a/KikiD/GetLine.hs
+++ /dev/null
@@ -1,18 +0,0 @@
1module KikiD.GetLine where
2
3import Control.Monad
4import Data.Serialize
5import qualified Data.ByteString as BS
6import qualified Data.ByteString.Lazy as L
7import Data.Monoid
8import Data.Binary.Builder
9
10getLine :: Get BS.ByteString
11getLine = getWords empty
12 where
13 getWords b = do
14 w <- getWord8
15 let x = singleton w
16 if (w == 10 || w == 0)
17 then return $ BS.concat . L.toChunks . toLazyByteString $ b <> x
18 else getWords (b <> x)
diff --git a/KikiD/Message.hs b/KikiD/Message.hs
index 5b642f3..cd3ee71 100644
--- a/KikiD/Message.hs
+++ b/KikiD/Message.hs
@@ -1,22 +1,37 @@
1{-# LANGUAGE DoAndIfThenElse #-}
1module KikiD.Message where 2module KikiD.Message where
2 3
3import Data.Serialize 4import Data.Serialize as Cereal
4import qualified KikiD.GetLine
5import qualified Data.ByteString.Char8 as B 5import qualified Data.ByteString.Char8 as B
6import Data.Monoid 6import Data.Monoid
7import Text.Read 7import Text.Read
8import Data.Char (ord) 8import Data.Char (ord,chr)
9import Control.Monad 9import Control.Monad
10import Data.Bytes.Serial as R
11import Data.Bytes.Put as Put
12import Data.Bytes.Get as Get
13import Codec.LineReady
14import Control.Monad.Loops
10 15
11data KikiDMessage = TODO deriving (Show,Read) 16data KikiDMessage = TODO deriving (Show,Read)
12 17
13instance Serialize KikiDMessage where 18instance Serialize KikiDMessage where
14 put m = mapM_ (putWord8 . fromIntegral . ord) "TODO" 19 put m = mapM_ (Cereal.putWord8 . fromIntegral . ord) "TO\nO"
15 -- putByteString . B.pack $ show m ++ "\n" 20 -- putByteString . B.pack $ show m ++ "\n"
16 get = do 21 get = do
17 t <- getWord8 22 t <- Cereal.getWord8
18 o <- getWord8 23 o <- Cereal.getWord8
19 d <- getWord8 24 d <- Cereal.getWord8
20 o <- getWord8 25 o <- Cereal.getWord8
21 return TODO 26 let s = map (chr . fromIntegral) [t,o,d,o]
22 27 if "TO\nO" == s
28 then return TODO
29 else fail ("Could not decode message: " ++ show s)
30
31instance Serial KikiDMessage where
32 serialize m = Put.putByteString . toLineReady . Cereal.encode $ m
33 deserialize = do
34 xs <- unfoldWhileM (/= '\n') (fmap (chr . fromIntegral) Get.getWord8)
35 case (Cereal.decode . fromLineReady $ B.pack xs) of
36 Left str -> fail str
37 Right x -> return x
diff --git a/KikiD/PortServer.hs b/KikiD/PortServer.hs
index 31101a7..b42e340 100644
--- a/KikiD/PortServer.hs
+++ b/KikiD/PortServer.hs
@@ -22,28 +22,13 @@ import Control.Monad.Loops
22import KikiD.Multiplex (pipeTransHookMicroseconds) 22import KikiD.Multiplex (pipeTransHookMicroseconds)
23import Control.Exception 23import Control.Exception
24import Control.Concurrent.Async 24import Control.Concurrent.Async
25import Data.Serialize 25import Data.Bytes.Serial as R
26import Data.Bytes.Put as Put
26 27
27import Control.Arrow (second) 28import Control.Arrow (second)
28--import qualified Merv.GetLine as MG
29 29
30{-instance Serialize IRC.Message where
31 put = putByteString . IRC.encode
32 get = do
33 x <- MG.getLine
34 case IRC.decode x of
35 Just x -> return x
36 Nothing -> fail ("IRC PARSE ERROR:'" <> B.unpack x <> "'")
37 30
38 31createTCPPortListener :: Serial a => PortNumber -> B.ByteString -> Int -> Int -> Int
39createIRCPortListener :: PortNumber -> B.ByteString -> Int -> Int -> Int
40 -> TBMQueue (ThreadId,TBMQueue IRC.Message) -> TBMQueue IRC.Message -> IO ()
41createIRCPortListener port name delay qsize maxconns postNewTChans outq =
42 createTCPPortListener port name delay qsize maxconns postNewTChans outq ircReact
43
44-}
45
46createTCPPortListener :: Serialize a => PortNumber -> B.ByteString -> Int -> Int -> Int
47 -> TBMQueue (ThreadId,TBMQueue a) -> TBMQueue a 32 -> TBMQueue (ThreadId,TBMQueue a) -> TBMQueue a
48 -> (Handle -> TBMQueue a -> IO ()) -> IO () 33 -> (Handle -> TBMQueue a -> IO ()) -> IO ()
49createTCPPortListener port name delay qsize maxconns postNewTChans outq react = 34createTCPPortListener port name delay qsize maxconns postNewTChans outq react =
@@ -65,7 +50,7 @@ createTCPPortListener port name delay qsize maxconns postNewTChans outq react =
65 sockAcceptLoop sock name delay qsize postNewTChans outq react 50 sockAcceptLoop sock name delay qsize postNewTChans outq react
66 ) 51 )
67 52
68sockAcceptLoop :: Serialize a => Socket -> B.ByteString -> Int -> Int -> TBMQueue (ThreadId,TBMQueue a) -> TBMQueue a 53sockAcceptLoop :: Serial a => Socket -> B.ByteString -> Int -> Int -> TBMQueue (ThreadId,TBMQueue a) -> TBMQueue a
69 -> (Handle -> TBMQueue a -> IO ()) -> IO () 54 -> (Handle -> TBMQueue a -> IO ()) -> IO ()
70sockAcceptLoop listenSock name delay qsize postNewTChans outq react = 55sockAcceptLoop listenSock name delay qsize postNewTChans outq react =
71 whileM_ (atomically $ fmap not (isClosedTBMQueue postNewTChans)) $ do 56 whileM_ (atomically $ fmap not (isClosedTBMQueue postNewTChans)) $ do
@@ -98,7 +83,7 @@ sockAcceptLoop listenSock name delay qsize postNewTChans outq react =
98 waitBoth async1 async2 83 waitBoth async1 async2
99 ) 84 )
100 85
101runConn :: Serialize a => Handle -> B.ByteString -> TBMQueue a -> TBMQueue a -> Int 86runConn :: Serial a => Handle -> B.ByteString -> TBMQueue a -> TBMQueue a -> Int
102 -> (Handle -> TBMQueue a -> IO ()) -> IO () 87 -> (Handle -> TBMQueue a -> IO ()) -> IO ()
103runConn hdl name q outq delay react = do 88runConn hdl name q outq delay react = do
104 --send sock (encode (Message Nothing "NOTICE" ["*", ("Hi " <> name <> "!\n")])) 89 --send sock (encode (Message Nothing "NOTICE" ["*", ("Hi " <> name <> "!\n")]))
@@ -115,7 +100,7 @@ runConn hdl name q outq delay react = do
115 whileM_ pending $ do 100 whileM_ pending $ do
116 m <- atomically (readTBMQueue q) 101 m <- atomically (readTBMQueue q)
117 case m of 102 case m of
118 Just m -> B.hPutStrLn hdl (encode m) 103 Just m -> B.hPutStrLn hdl (runPutS $ R.serialize m)
119 -- Nothing means the Queue is closed and empty, so dont loop 104 -- Nothing means the Queue is closed and empty, so dont loop
120 Nothing -> return () 105 Nothing -> return ()
121 threadDelay delay 106 threadDelay delay
@@ -127,19 +112,3 @@ runConn hdl name q outq delay react = do
127 (whileM_ (atomically . fmap not $ isClosedTBMQueue outq) $ react hdl outq ) 112 (whileM_ (atomically . fmap not $ isClosedTBMQueue outq) $ react hdl outq )
128 113
129 114
130{-
131ircReact hdl outq = do
132 line <- B.hGetLine hdl
133 -- debugging
134 dir <- getAppUserDataDirectory "merv"
135 tid <- myThreadId
136 let bQuit = (B.isPrefixOf "/quit") line
137 appendFile (dir </> "xdebug")
138 (printf "%s:%s\n(bQuit=%s) %s\n" (show tid) (show line) (show bQuit) (show $ IRC.parseMessage line))
139 -- end debugging
140 case IRC.decode line of
141 Just (IRC.msg_command -> "QUIT") -> atomically $ closeTBMQueue outq
142 Just m -> atomically $ writeTBMQueue outq m
143 Nothing | "/q" `B.isPrefixOf` line -> atomically $ closeTBMQueue outq
144 _ -> return undefined
145-}
diff --git a/kiki.cabal b/kiki.cabal
index 2632e6d..450a3ab 100644
--- a/kiki.cabal
+++ b/kiki.cabal
@@ -45,7 +45,8 @@ Executable kikid
45 monad-loops -any, 45 monad-loops -any,
46 HTTP -any, 46 HTTP -any,
47 stm >= 2.3, 47 stm >= 2.3,
48 cereal -any 48 cereal -any,
49 bytes -any
49 50
50library 51library
51 exposed-modules: KeyRing 52 exposed-modules: KeyRing
diff --git a/kikid.hs b/kikid.hs
index 31426a3..04e06d3 100644
--- a/kikid.hs
+++ b/kikid.hs
@@ -16,8 +16,11 @@ import Control.Monad.Loops
16import Control.Exception 16import Control.Exception
17import Data.Monoid 17import Data.Monoid
18import qualified Data.ByteString.Char8 as B 18import qualified Data.ByteString.Char8 as B
19import Data.Serialize 19--import Data.Serialize
20import qualified Data.Map as M 20import qualified Data.Map as M
21import qualified Data.Bytes.Serial as Bytes
22import qualified Data.Bytes.Get as Bytes
23--import qualified Data.Bytes.Put as Bytes
21 24
22-- TODO: Set this in config file 25-- TODO: Set this in config file
23port = 9800 26port = 9800
@@ -64,7 +67,7 @@ kikidMain _ = do
64 atomically $ closeTBMQueue newchans 67 atomically $ closeTBMQueue newchans
65 atomically $ closeTBMQueue incomming 68 atomically $ closeTBMQueue incomming
66 69
67data ClientState = CState {cs_queue :: TBMQueue KikiDMessage} 70data ClientState = CState {csQueue :: TBMQueue KikiDMessage}
68type ClientID = ThreadId 71type ClientID = ThreadId
69threadIdToClient = id 72threadIdToClient = id
70 73
@@ -96,12 +99,14 @@ purgeClosedConnections quit currentClients = whileM_ (fmap not quit) $ do
96handleMessage hdl outq = do 99handleMessage hdl outq = do
97 line <- B.hGetLine hdl 100 line <- B.hGetLine hdl
98 tid <- myThreadId 101 tid <- myThreadId
99 case (decode line :: Either String KikiDMessage) of 102 case (Bytes.runGetS Bytes.deserialize (B.snoc line '\n') :: Either String KikiDMessage) of
100 Right _ -> 103 Right msg -> do
101 syslog Notice ("Message decoded on thread=" <> show tid) 104 syslog Notice ("Message decoded on thread=" <> show tid)
105 syslog Notice ("Message: " <> show msg)
102 Left str -> do 106 Left str -> do
107 syslog Notice ("ERROR: " <> show line)
103 syslog Notice ("ERROR: Unable to decode message on thread=" <> show tid) 108 syslog Notice ("ERROR: Unable to decode message on thread=" <> show tid)
104 syslog Notice str 109 syslog Notice ("ERROR: " ++ str)
105 110
106consumeMessage currentClients msg = void $ syslog Notice ("Recieved Message: " ++ show msg) 111consumeMessage currentClients msg = void $ syslog Notice ("Recieved Message: " ++ show msg)
107-- TODO: Do more here... 112-- TODO: Do more here...