summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--krpc.cabal7
-rw-r--r--src/Data/BEncode/Pretty.hs75
-rw-r--r--src/Network/KRPC/Manager.hs15
3 files changed, 93 insertions, 4 deletions
diff --git a/krpc.cabal b/krpc.cabal
index 66c08ccb..452f1132 100644
--- a/krpc.cabal
+++ b/krpc.cabal
@@ -38,6 +38,9 @@ flag builder
38 description: Use older bytestring package and bytestring-builder. 38 description: Use older bytestring package and bytestring-builder.
39 default: False 39 default: False
40 40
41flag aeson
42 description: Use aeson for pretty-printing bencoded data.
43 default: True
41 44
42library 45library
43 default-language: Haskell2010 46 default-language: Haskell2010
@@ -48,6 +51,7 @@ library
48 Network.KRPC.Message 51 Network.KRPC.Message
49 Network.KRPC.Method 52 Network.KRPC.Method
50 Network.KRPC.Manager 53 Network.KRPC.Manager
54 Data.BEncode.Pretty
51 build-depends: base == 4.* 55 build-depends: base == 4.*
52 , text >= 0.11 56 , text >= 0.11
53 , data-default-class 57 , data-default-class
@@ -60,6 +64,9 @@ library
60 , network >= 2.3 64 , network >= 2.3
61 , cereal 65 , cereal
62 , containers 66 , containers
67 if flag(aeson)
68 build-depends: aeson, aeson-pretty, unordered-containers, vector
69 ghc-options: -DBENCODE_AESON
63 if flag(builder) 70 if flag(builder)
64 build-depends: bytestring >= 0.9, bytestring-builder 71 build-depends: bytestring >= 0.9, bytestring-builder
65 else 72 else
diff --git a/src/Data/BEncode/Pretty.hs b/src/Data/BEncode/Pretty.hs
new file mode 100644
index 00000000..7b0d46a0
--- /dev/null
+++ b/src/Data/BEncode/Pretty.hs
@@ -0,0 +1,75 @@
1{-# LANGUAGE CPP #-}
2module Data.BEncode.Pretty where -- (showBEncode) where
3
4import Data.BEncode.Types
5import qualified Data.ByteString as BS
6import qualified Data.ByteString.Lazy as BL
7import qualified Data.ByteString.Lazy.Char8 as BL8
8import Data.Text (Text)
9import qualified Data.Text as T
10#ifdef BENCODE_AESON
11import Data.BEncode.BDict hiding (map)
12import Data.Aeson.Types hiding (parse)
13import Data.Aeson.Encode.Pretty
14import qualified Data.HashMap.Strict as HashMap
15import qualified Data.Vector as Vector
16import Data.Foldable as Foldable
17import Data.Text.Encoding
18import Text.Printf
19#endif
20
21#ifdef BENCODE_AESON
22
23unhex :: Text -> BS.ByteString
24unhex t = BS.pack $ map unhex1 [0 .. BS.length nibs `div` 2]
25 where
26 nibs = encodeUtf8 t
27 unhex1 i = unnib (BS.index nibs (i * 2)) * 0x10
28 + unnib (BS.index nibs (i * 2 + 1))
29 unnib a | a <= 0x39 = a - 0x30
30 | otherwise = a - (0x41 - 10)
31
32hex :: BS.ByteString -> Text
33hex bs = T.concat $ map (T.pack . printf "%02X") $ BS.unpack bs
34
35quote_chr :: Char
36quote_chr = ' '
37
38quote :: Text -> Text
39quote t = quote_chr `T.cons` t `T.snoc` quote_chr
40
41
42instance ToJSON BValue where
43 toJSON (BInteger x) = Number $ fromIntegral x
44 toJSON (BString s) = String $ either (const $ hex s) quote $ decodeUtf8' s
45 toJSON (BList xs) = Array $ Vector.fromList $ map toJSON xs
46 toJSON (BDict d) = toJSON d
47
48instance ToJSON a => ToJSON (BDictMap a) where
49 toJSON d = Object $ HashMap.fromList $ map convert $ toAscList d
50 where
51 convert (k,v) = (decodeUtf8 k,toJSON v)
52
53instance FromJSON BValue where
54 parseJSON (Number x) = pure $ BInteger (truncate x)
55 parseJSON (Bool x) = pure $ BInteger $ if x then 1 else 0
56 parseJSON (String s)
57 | T.head s==quote_chr = pure $ BString $ encodeUtf8 (T.takeWhile (/=quote_chr) $ T.drop 1 s)
58 | otherwise = pure $ BString $ unhex s
59 parseJSON (Array v) = BList <$> traverse parseJSON (Foldable.toList v)
60 parseJSON (Object d) = BDict <$> parseJSON (Object d)
61 parseJSON (Null) = pure $ BDict Nil
62
63instance FromJSON v => FromJSON (BDictMap v) where
64 parseJSON (Object d) = fromAscList <$> traverse convert (HashMap.toList d)
65 where
66 convert (k,v) = (,) (encodeUtf8 k) <$> parseJSON v
67 parseJSON _ = fail "Not a BDict"
68#endif
69
70showBEncode :: BValue -> BL.ByteString
71#ifdef BENCODE_AESON
72showBEncode b = encodePretty $ toJSON b
73#else
74showBEncode b = BL8.pack (show b)
75#endif
diff --git a/src/Network/KRPC/Manager.hs b/src/Network/KRPC/Manager.hs
index 9477d23c..c90c92f9 100644
--- a/src/Network/KRPC/Manager.hs
+++ b/src/Network/KRPC/Manager.hs
@@ -52,6 +52,7 @@ import Control.Monad.Reader
52import Control.Monad.Trans.Control 52import Control.Monad.Trans.Control
53import Data.BEncode as BE 53import Data.BEncode as BE
54import Data.BEncode.Internal as BE 54import Data.BEncode.Internal as BE
55import Data.BEncode.Pretty (showBEncode)
55import Data.ByteString as BS 56import Data.ByteString as BS
56import Data.ByteString.Char8 as BC 57import Data.ByteString.Char8 as BC
57import Data.ByteString.Lazy as BL 58import Data.ByteString.Lazy as BL
@@ -428,11 +429,17 @@ dispatchHandler q @ KQuery {..} addr = do
428-- peer B fork too many threads 429-- peer B fork too many threads
429-- ... space leak 430-- ... space leak
430-- 431--
431handleQuery :: MonadKRPC h m => KQuery -> SockAddr -> m () 432handleQuery :: MonadKRPC h m => BValue -> KQuery -> SockAddr -> m ()
432handleQuery q addr = void $ fork $ do 433handleQuery raw q addr = void $ fork $ do
433 Manager {..} <- getManager 434 Manager {..} <- getManager
434 res <- dispatchHandler q addr 435 res <- dispatchHandler q addr
435 sendMessage sock addr $ either toBEncode toBEncode res 436 let resbe = either toBEncode toBEncode res
437 $(logOther "q") $ T.unlines
438 [ either (const "<unicode-fail>") id $ T.decodeUtf8' (BL.toStrict $ showBEncode raw)
439 , "==>"
440 , either (const "<unicode-fail>") id $ T.decodeUtf8' (BL.toStrict $ showBEncode resbe)
441 ]
442 sendMessage sock addr resbe
436 443
437handleResponse :: MonadKRPC h m => BValue -> KResult -> SockAddr -> m () 444handleResponse :: MonadKRPC h m => BValue -> KResult -> SockAddr -> m ()
438handleResponse raw result addr = do 445handleResponse raw result addr = do
@@ -445,7 +452,7 @@ handleResponse raw result addr = do
445 Just ares -> putMVar ares (raw,result) 452 Just ares -> putMVar ares (raw,result)
446 453
447handleMessage :: MonadKRPC h m => BValue -> KMessage -> SockAddr -> m () 454handleMessage :: MonadKRPC h m => BValue -> KMessage -> SockAddr -> m ()
448handleMessage _ (Q q) = handleQuery q 455handleMessage raw (Q q) = handleQuery raw q
449handleMessage raw (R r) = handleResponse raw (Right r) 456handleMessage raw (R r) = handleResponse raw (Right r)
450handleMessage raw (E e) = handleResponse raw (Left e) 457handleMessage raw (E e) = handleResponse raw (Left e)
451 458