module System.Miniplex.Sekrit (
pathFromTag
, reallySend
, reallyRecv
, bytesFromInt
, intFromBytes
, closeOnExec
) where
import Foreign.C.Error
import Network.Socket
import Data.Bits
import System.Directory
import System.Posix.IO
import System.Posix.Types
good :: String -> Bool
good s = not (null s) && head s /= '.' && all (`elem` chs) s
where
chs =
['a' .. 'z'] ++ ['A' .. 'Z'] ++ ['0' .. '9'] ++ ",$=-#%.+_^&'@~()[]{}"
pathFromTag :: String -> String -> IO String
pathFromTag context what
| not $ good what =
ioError $ errnoToIOError context eADDRNOTAVAIL Nothing (Just what)
| otherwise = do
dir <- getAppUserDataDirectory "miniplex"
createDirectoryIfMissing False dir
return $ dir ++ "/" ++ what
reallySend :: Socket -> String -> IO ()
reallySend sock str = step (length str) str
where
step n msg
| n <= 0 = return ()
| otherwise = do
w <- send sock msg
step (n w) (drop w msg)
reallyRecv :: Socket -> Int -> IO String
reallyRecv sock = step
where
step n
| n <= 0 = return ""
| otherwise = do
(s, r) <- recvLen sock n
t <- step (n r)
return (s ++ t)
bytesFromInt :: Int -> String
bytesFromInt n = map (toEnum . (.&.) 255 . shiftR n . (*) 8) . reverse $ [0 .. 3]
intFromBytes :: String -> Int
intFromBytes = sum . zipWith (\n c -> fromEnum c `shiftL` (8 * n)) (reverse [0 .. 3])
closeOnExec :: Socket -> IO ()
closeOnExec (MkSocket fd _ _ _ _) =
setFdOption (Fd fd) CloseOnExec True