module Network.Skype.Command.Utils where import Control.Concurrent.STM.TChan (readTChan) import Control.Monad.Error (throwError) import Control.Monad.Reader (asks) import Control.Monad.STM (atomically) import Control.Monad.Trans import Control.Monad.Trans.Control import Data.Attoparsec.ByteString.Lazy import Data.Monoid ((<>)) import Data.Unique (newUnique, hashUnique) import System.Timeout.Lifted (timeout) import Network.Skype.Core import Network.Skype.Parser (parseNotification, parseCommandID) import Network.Skype.Protocol import qualified Data.ByteString.Char8 as BC import qualified Data.Text as T executeCommand :: (MonadBaseControl IO m, MonadIO m, MonadSkype m) => Command -> (NotificationObject -> SkypeT m (Maybe a)) -> SkypeT m a executeCommand command handler = handleCommand command $ \notification -> case parseNotification notification of Right response -> handler response Left _ -> return Nothing executeCommandWithID :: (MonadBaseControl IO m, MonadIO m, MonadSkype m) => Command -> (NotificationObject -> SkypeT m (Maybe a)) -> SkypeT m a executeCommandWithID command handler = handleCommandWithID command $ \expectID notification -> case parseCommandID notification of Done t commandID | commandID == expectID -> do case parseNotification t of Left e -> throwError $ SkypeError 0 command (T.pack e) Right object -> guardError object >> handler object | otherwise -> return Nothing _ -> return Nothing where guardError (Error code description) = throwError $ SkypeError code command description guardError _ = return () handleCommand :: (MonadBaseControl IO m, MonadIO m, MonadSkype m) => Command -> (Notification -> SkypeT m (Maybe a)) -> SkypeT m a handleCommand command handler = do chan <- dupNotificationChan sendCommand command time <- asks skypeTimeout result <- timeout time $ loop chan maybe (throwError $ SkypeError 0 command "Command timeout") return result where loop chan = do response <- liftIO $ atomically $ readTChan chan result <- handler response case result of Just value -> return value Nothing -> loop chan handleCommandWithID :: (MonadBaseControl IO m, MonadIO m, MonadSkype m) => Command -> (CommandID -> Notification -> SkypeT m (Maybe a)) -> SkypeT m a handleCommandWithID command handler = do commandID <- liftIO $ (BC.pack . show . hashUnique) `fmap` newUnique let command' = "#" <> commandID <> " " <> command handleCommand command' $ handler commandID