{-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TypeFamilies #-} module Metro.TP.XOR ( xorBS , XOR , xorConfig ) where import Data.Bits (xor) import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as LB import Metro.Class (Transport (..)) import qualified Metro.Lock as L import UnliftIO data XOR tp = XOR { transport :: tp , sn :: TVar LB.ByteString , rn :: TVar LB.ByteString , sl :: L.Lock , rl :: L.Lock } instance Transport tp => Transport (XOR tp) where data TransportConfig (XOR tp) = XORConfig FilePath (TransportConfig tp) newTransport (XORConfig fn config) = do transport <- newTransport config key <- LB.readFile fn sn <- newTVarIO $ LB.cycle key rn <- newTVarIO $ LB.cycle key sl <- L.new rl <- L.new return XOR {..} recvData XOR {..} nbytes = L.with rl $ xorBS rn =<< recvData transport nbytes sendData XOR {..} bs = L.with sl $ xorBS sn bs >>= sendData transport closeTransport XOR {..} = closeTransport transport xorBS :: TVar LB.ByteString -> B.ByteString -> IO B.ByteString xorBS ref bs = atomically $ do buf <- readTVar ref writeTVar ref $! LB.drop len buf return . xor' $! LB.take len buf where bs' = LB.fromStrict bs len = LB.length bs' xor' = B.pack . LB.zipWith xor bs' xorConfig :: FilePath -> TransportConfig tp -> TransportConfig (XOR tp) xorConfig = XORConfig