packages feed

sc2-lowlevel-0.1.0.0: src/Network/SC2/LowLevel/Protocol.hs

{-# LANGUAGE ConstraintKinds, AllowAmbiguousTypes#-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeOperators #-}
{-#LANGUAGE OverloadedLabels #-}
module Network.SC2.LowLevel.Protocol
       ( module Control.Monad.Freer
       , module Network.SC2.LowLevel.Split
       , SC2Control(..)
       , SC2
       , SC2LowLevel
       , unsafeRequest
       , unsafeResponse
       , getStatus
       , request
       , syncRequest'
       , syncRequest
       , runSC2Control
       , runSC2
       ) where

import Control.Monad.Freer
import Control.Monad.Freer.Internal
import Control.Monad.Freer.Error
import Data.Traversable
import Data.Foldable
import Control.Monad
import Data.Text
import qualified Proto.S2clientprotocol.Sc2api as A
import Network.SC2.LowLevel.Requestable
import Network.SC2.LowLevel.Process
import Network.SC2.LowLevel.Split
import Lens.Labels.Unwrapped ()
import Control.Lens
import Numeric.Natural
import Data.ProtoLens (defMessage)

data SC2Control a where
  SC2Request :: A.Request -> SC2Control()
  SC2Requests :: [A.Request] -> SC2Control()
  SC2Response :: SC2Control(Either Text A.Response)
  SC2Responses :: forall t. Traversable t => Natural -> SC2Control (t (Either Text A.Response)) -- TODO
  SC2Status :: SC2Control A.Status

unsafeRequest :: (Member SC2Control r) => A.Request -> Eff r ()
unsafeRequest = send . SC2Request

unsafeResponse :: (Member SC2Control r) => Eff r (Either Text A.Response)
unsafeResponse = send SC2Response

getStatus :: (Member SC2Control r) => Eff r A.Status
getStatus = send SC2Status

type SC2 r = (Member SC2Control r, Member Split r)

request :: (SC2 r, Requestable a) => a -> Eff r ()
request r = unsafeRequest (toRequest r) >> fork (void unsafeResponse)

syncRequest' :: (SC2 r, Requestable a) => a -> Eff r () -> Eff r (Either Text (ResponseOf a))
--FIXME: use Control.Monad.Freer.Error
syncRequest' r act = do
  unsafeRequest (toRequest r)
  act
  suspend
  resp <- unsafeResponse
  return (resp >>= fromResponse (pure r))

syncRequest :: (SC2 r, Requestable a) => a -> Eff r (Either Text (ResponseOf a))
syncRequest r = syncRequest' r (pure ())

runSC2Control :: Member IO r => Eff (SC2Control ': r) a -> Starcraft ->  Eff r a
runSC2Control m sc = runNatS A.Launched go m
  where
    go :: Member IO r =>  A.Status -> SC2Control a -> Eff r (A.Status, a)
    go s (SC2Request r) = (s,) <$> sendRequest sc r
    go s (SC2Requests rs) = do
      responses <- traverse (sendRequest sc) rs
      return (s, fold responses)
    go s SC2Response = getResponse s
    go s (SC2Responses n) = error "Network.SC2.LowLevel.Protocol.SC2Control.Responses: Not implemented" -- TODO
    go s SC2Status = return (s, s)
    getResponse :: Member IO r => A.Status -> Eff r (A.Status, Either Text A.Response)
    getResponse s = do
      resp <- readResponse sc
      case resp of --TODO: horrible, lens it instead
                   --FIXME: use Control.Monad.Freer.Error
        Left _ -> return (s, resp)
        Right r -> case r^. #maybe'status of
          Nothing -> return (s, resp)
          Just s' -> return (s', resp)
    
    

    runNatS :: s -> (forall a. s -> eff a -> Eff effs (s, a)) -> Eff (eff ': effs) b -> Eff effs b
    runNatS s0 f = handleRelayS s0 (const pure) $ \s e -> ((f s e) >>=) . uncurry


--type SC2LowLevel' rest a = (Members '[SC2Control, Split] rest) => Eff rest a
type SC2LowLevel' effs a = Eff ('[SC2Control, Split] :++: (effs )) a
type SC2LowLevel effs a = SC2LowLevel' (effs :++: '[IO]) a
runSC2:: Member IO effs => SC2LowLevel' ( effs) () -> Starcraft -> Eff (effs) ()--IO (Either Text ())
runSC2 bot  s= runSplit $ runSC2Control bot s