{-# LANGUAGE TypeFamilies #-}
module Metro.TP.Socket
  ( Socket
  , socket
  , mapTCPSocket
  , mapUDPSocket
  ) where

import           Data.List          (isPrefixOf)
import           Metro.Class        (Transport (..))
import           Metro.TP.TCPSocket
import           Metro.TP.UDPSocket

data Socket = TCP TCPSocket
    | UDP UDPSocket

instance Transport Socket where
  data TransportConfig Socket =
    TCPTC (TransportConfig TCPSocket)
    | UDPTC (TransportConfig UDPSocket)
  newTransport :: TransportConfig Socket -> IO Socket
newTransport (TCPTC c) = TCPSocket -> Socket
TCP (TCPSocket -> Socket) -> IO TCPSocket -> IO Socket
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TransportConfig TCPSocket -> IO TCPSocket
forall transport.
Transport transport =>
TransportConfig transport -> IO transport
newTransport TransportConfig TCPSocket
c
  newTransport (UDPTC c) = UDPSocket -> Socket
UDP (UDPSocket -> Socket) -> IO UDPSocket -> IO Socket
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> TransportConfig UDPSocket -> IO UDPSocket
forall transport.
Transport transport =>
TransportConfig transport -> IO transport
newTransport TransportConfig UDPSocket
c
  recvData :: Socket -> Int -> IO ByteString
recvData (TCP tp :: TCPSocket
tp) = TCPSocket -> Int -> IO ByteString
forall transport.
Transport transport =>
transport -> Int -> IO ByteString
recvData TCPSocket
tp
  recvData (UDP tp :: UDPSocket
tp) = UDPSocket -> Int -> IO ByteString
forall transport.
Transport transport =>
transport -> Int -> IO ByteString
recvData UDPSocket
tp
  sendData :: Socket -> ByteString -> IO ()
sendData (TCP tp :: TCPSocket
tp) = TCPSocket -> ByteString -> IO ()
forall transport.
Transport transport =>
transport -> ByteString -> IO ()
sendData TCPSocket
tp
  sendData (UDP tp :: UDPSocket
tp) = UDPSocket -> ByteString -> IO ()
forall transport.
Transport transport =>
transport -> ByteString -> IO ()
sendData UDPSocket
tp
  closeTransport :: Socket -> IO ()
closeTransport (TCP tp :: TCPSocket
tp) = TCPSocket -> IO ()
forall transport. Transport transport => transport -> IO ()
closeTransport TCPSocket
tp
  closeTransport (UDP tp :: UDPSocket
tp) = UDPSocket -> IO ()
forall transport. Transport transport => transport -> IO ()
closeTransport UDPSocket
tp

socket :: String -> TransportConfig Socket
socket :: String -> TransportConfig Socket
socket hostPort :: String
hostPort =
  if "udp" String -> String -> Bool
forall a. Eq a => [a] -> [a] -> Bool
`isPrefixOf` String
hostPort then TransportConfig UDPSocket -> TransportConfig Socket
UDPTC (TransportConfig UDPSocket -> TransportConfig Socket)
-> TransportConfig UDPSocket -> TransportConfig Socket
forall a b. (a -> b) -> a -> b
$ String -> TransportConfig UDPSocket
udpSocket String
hostPort
                                 else TransportConfig TCPSocket -> TransportConfig Socket
TCPTC (TransportConfig TCPSocket -> TransportConfig Socket)
-> TransportConfig TCPSocket -> TransportConfig Socket
forall a b. (a -> b) -> a -> b
$ String -> TransportConfig TCPSocket
tcpSocket String
hostPort

mapTCPSocket :: TransportConfig TCPSocket -> TransportConfig Socket
mapTCPSocket :: TransportConfig TCPSocket -> TransportConfig Socket
mapTCPSocket = TransportConfig TCPSocket -> TransportConfig Socket
TCPTC

mapUDPSocket :: TransportConfig UDPSocket -> TransportConfig Socket
mapUDPSocket :: TransportConfig UDPSocket -> TransportConfig Socket
mapUDPSocket = TransportConfig UDPSocket -> TransportConfig Socket
UDPTC