module System.Miniplex.Sekrit (
pathFromTag
, reallySend
, reallyRecv
, bytesFromInt
, intFromBytes
, closeOnExec
, enoents
, eexists
, mode644
) where
import Control.Exception
import Control.Monad
import Foreign.C.Error
import Network.Socket
import Data.Bits
import System.Directory
import System.IO.Error
import System.Posix.Files
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, String, String)
pathFromTag context what
| not $ good what =
ioError $ errnoToIOError context eADDRNOTAVAIL Nothing (Just what)
| otherwise = do
dir <- getAppUserDataDirectory "miniplex"
createDirectoryIfMissing False dir
let d x = dir ++ "/" ++ x
return (d what, d $ "L$$", d $ "R$" ++ what)
reallySend :: Socket -> String -> IO ()
reallySend sock = step
where
step "" = return ()
step msg = do
w <- send sock msg
step (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
enoents :: Exception -> Maybe Exception
enoents e = do
io <- ioErrors e
guard $ isDoesNotExistError io
return e
eexists :: Exception -> Maybe Exception
eexists e = do
io <- ioErrors e
guard $ isAlreadyExistsError io
return e
mode644 :: FileMode
mode644 = ownerReadMode .|. ownerWriteMode .|. groupReadMode .|. otherReadMode