module Main where
-import System.IO
+import Prelude hiding (lookup, readFile)
+import System.Environment
+import System.IO hiding (readFile)
+import System.IO.Error
+import Control.Exception
+import Text.Show.Pretty hiding (String)
import Control.Monad
-import qualified Data.ByteString.Char8 as C (pack, unpack)
-import qualified Data.ByteString.Lazy.Char8 as L (pack, unpack)
-import Data.ByteString.Lazy as BS hiding (reverse, putStr, putStrLn)
+import Control.Monad.State
+import Data.ByteString.Lazy hiding (reverse, putStr, putStrLn, head, empty)
+import qualified Data.ByteString.Char8 as C (pack)
+import qualified Data.ByteString.Lazy.Char8 as L (pack)
+import qualified Data.Text as T (pack)
import Data.List.Split
+import Data.Map.Lazy (Map, empty, lookup, insert, delete, size)
import Data.Aeson (encode, decode, Value(..))
import Network.HTTP.Types
import Data.Conduit
import PowerDns
import NmcRpc
import NmcDom
+import NmcTransform
confFile = "/etc/namecoin.conf"
-- HTTP/JsonRpc interface
-qReq :: Config -> ByteString -> ByteString -> Request m
+qReq :: Config -> String -> Int -> Request m
qReq cf q id = applyBasicAuth (C.pack (rpcuser cf)) (C.pack (rpcpassword cf))
$ def { host = (C.pack (rpchost cf))
, port = (rpcport cf)
, requestBody = RequestBodyLBS $ encode $
JsonRpcRequest JsonRpcV1
"name_show"
- [q]
- (String "pdns-nmc")
+ [L.pack q]
+ (String (T.pack (show id)))
, checkStatus = \_ _ _ -> Nothing
}
-- NMC interface
-queryOp :: Manager -> Config -> String -> ByteString
- -> IO (Either String ByteString)
-queryOp mgr cfg qid key = do
- rsp <- runResourceT $
- httpLbs (qReq cfg key (L.pack qid)) mgr
- return $ qRsp rsp
+queryOpNmc cfg mgr qid key =
+ runResourceT (httpLbs (qReq cfg key qid) mgr) >>= return . qRsp
-queryNmc :: Manager -> Config -> String -> String
- -> IO (Either String NmcDom)
-queryNmc mgr cfg fqdn qid = do
+queryOpFile key = catch (readFile key >>= return . Right)
+ (\e -> return (Left (show (e :: IOException))))
+
+queryDom queryOp fqdn =
case reverse (splitOn "." fqdn) of
- "bit":dn:xs -> do
- dom <- queryDom (queryOp mgr cfg qid) (L.pack ("d/" ++ dn))
- return $ case dom of
- Left err -> Left err
- Right dom -> Right $ descendNmc xs dom
- _ ->
- return $ Left "Only \".bit\" domain is supported"
+ "bit":dn:xs -> descendNmcDom queryOp xs $ seedNmcDom dn
+ _ -> return $ Left "Only \".bit\" domain is supported"
--- Main entry
+-- Main entries
-main = do
+mainPdnsNmc = do
cfg <- readConfig confFile
putStrLn $ "OK\tDnsNmc ready to serve, protocol v." ++ (show ver)
mgr <- newManager def
- forever $ do
- l <- getLine
- case pdnsParse ver l of
- Left e -> putStr $ pdnsReport e
- Right preq -> do
- case preq of
- PdnsRequestQ qname qtype id _ _ _ ->
- queryNmc mgr cfg qname id >>= putStr . (pdnsOut ver id qname qtype)
- PdnsRequestAXFR xfrreq ->
- putStr $ pdnsReport ("No support for AXFR " ++ xfrreq)
- PdnsRequestPing -> putStrLn "END"
-
--- for testing
-
-ask str = do
+ let
+ newcache count name = (insert count name)
+ . (delete (if count >= 10 then count - 10 else count + 90))
+ io = liftIO
+ mainloop = forever $ do
+ l <- io getLine
+ (count, cache) <- get
+ case pdnsParse ver l of
+ Left e -> io $ putStr $ pdnsReport e
+ Right preq -> do
+ case preq of
+ PdnsRequestQ qname qtype id _ _ _ -> do
+ io $ queryDom (queryOpNmc cfg mgr id) qname
+ >>= putStr . (pdnsOut ver count qname qtype)
+ io $ putStrLn $ "LOG\tRequest number " ++ (show count)
+ ++ " id: " ++ (show id)
+ ++ " qname: " ++ qname
+ ++ " qtype: " ++ (show qtype)
+ ++ " cache size: " ++ (show (size cache))
+ put (if count >= 99 then 0 else count + 1,
+ newcache count qname cache)
+ PdnsRequestAXFR xrq ->
+ case lookup xrq cache of
+ Nothing ->
+ io $ putStr $
+ pdnsReport ("AXFR for unknown id: " ++ (show xrq))
+ Just qname ->
+ io $ queryDom (queryOpNmc cfg mgr xrq) qname
+ >>= putStr . (pdnsOutXfr ver count qname)
+ PdnsRequestPing -> io $ putStrLn "END"
+ runStateT mainloop (0, empty) >> return ()
+
+-- query by key from Namecoin
+
+mainOne key = do
cfg <- readConfig confFile
mgr <- newManager def
- queryNmc mgr cfg str "askid" >>= putStr . (pdnsOut 1 "askid" str RRTypeANY)
+ dom <- queryDom (queryOpNmc cfg mgr (-1)) key
+ putStrLn $ ppShow dom
+ putStr $ pdnsOut 1 (-1) key RRTypeANY dom
+
+-- using file backend for testing json domain data
+
+mainFile key = do
+ dom <- queryDom queryOpFile key
+ putStrLn $ ppShow dom
+ putStr $ pdnsOut 1 (-1) key RRTypeANY dom
+
+-- Entry point
+
+main = do
+ args <- getArgs
+ case args of
+ [] -> mainPdnsNmc
+ [key] -> mainOne key
+ ["-f",key] -> mainFile key
+ _ -> error $ "usage: empty args, or \"[-f] <fqdn>\""