shadowsocks-1.20150811: Shadowsocks/Util.hs
{-# LANGUAGE DeriveGeneric #-}
module Shadowsocks.Util
( Config (..)
, parseConfigOptions
, cryptConduit
) where
import Conduit (Conduit, awaitForever, yield, liftIO)
import Control.Monad (liftM)
import Data.Aeson (decode', FromJSON)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as L
import Data.Maybe (fromMaybe)
import GHC.Generics (Generic)
import Options.Applicative
data Config = Config
{ server :: String
, server_port :: Int
, local_port :: Int
, password :: String
, timeout :: Int
, method :: String
} deriving (Show, Generic)
instance FromJSON Config
data Options = Options
{ _server :: Maybe String
, _server_port :: Maybe Int
, _local_port :: Maybe Int
, _password :: Maybe String
, _method :: Maybe String
, _config :: Maybe String
} deriving (Show, Generic)
nullConfig :: Config
nullConfig = Config "" 0 0 "" 0 ""
readConfig :: FilePath -> IO (Maybe Config)
readConfig fp = liftM decode' $ L.readFile fp
configOptions :: Parser Options
configOptions = Options
<$> optional (strOption (long "server" <> short 's' <> metavar "ADDR"
<> help "server address"))
<*> optional (option auto (long "server-port" <> short 'p' <> metavar "PORT"
<> help "server port"))
<*> optional (option auto (long "local-port" <> short 'l' <> metavar "PORT"
<> help "local port"))
<*> optional (strOption (long "password" <> short 'k' <> metavar "PASSWORD"
<> help "password"))
<*> optional (strOption (long "method" <> short 'm' <> metavar "METHOD"
<> help "encryption method, for example, aes-256-cfb"))
<*> optional (strOption (long "config" <> short 'c' <> metavar "CONFIG"
<> help "path to config file"))
parseConfigOptions :: IO Config
parseConfigOptions = do
o <- execParser $ info (helper <*> configOptions)
(fullDesc <> header "shadowsocks - a fast tunnel proxy")
let configFile = fromMaybe "config.json" (_config o)
mconfig <- readConfig configFile
let c = fromMaybe nullConfig mconfig
return $ c { server = fromMaybe (server c) (_server o)
, server_port = fromMaybe (server_port c) (_server_port o)
, local_port = fromMaybe (local_port c) (_local_port o)
, password = fromMaybe (password c) (_password o)
, method = fromMaybe (method c) (_method o)
}
cryptConduit :: (ByteString -> IO ByteString)
-> Conduit ByteString IO ByteString
cryptConduit crypt = awaitForever $ \input -> do
output <- liftIO $ crypt input
yield output