network-effectful (empty) → 0.2.0.0
raw patch · 5 files changed
+568/−0 lines, 5 filesdep +basedep +bytestringdep +effectful-core
Dependencies added: base, bytestring, effectful-core, network
Files
- CHANGELOG.md +5/−0
- LICENSE +29/−0
- network-effectful.cabal +45/−0
- src/Effectful/Network.hs +442/−0
- src/Effectful/Network/Lazy.hs +47/−0
+ CHANGELOG.md view
@@ -0,0 +1,5 @@+# Revision history for socket-effectful++## 0.1.0.0 -- YYYY-mm-dd++* First version. Released on an unsuspecting world.
+ LICENSE view
@@ -0,0 +1,29 @@+Copyright (c) 2024, Cajunvoodoo+++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of the copyright holder nor the names of its+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ network-effectful.cabal view
@@ -0,0 +1,45 @@+cabal-version: 3.0+name: network-effectful+version: 0.2.0.0+synopsis:+ Adaptation of the network library for the effectful ecosystem.++description:+ Adaptation of the @<https://hackage.haskell.org/package/network network>@ library for the @<https://hackage.haskell.org/package/effectful effectful>@ ecosystem.++homepage: https://github.com/Cajunvoodoo/network-effectful#readme+bug-reports: https://github.com/Cajunvoodoo/network-effectful/issues+license: BSD-3-Clause+license-file: LICENSE+author: Cajunvoodoo+maintainer: cajunvoodoo (discord)++-- copyright:+category: Network+build-type: Simple+extra-doc-files: CHANGELOG.md++source-repository head+ type: git+ location: https://github.com/Cajunvoodoo/network-effectful++-- extra-source-files:+common warnings+ ghc-options: -Wall++library+ import: warnings+ exposed-modules:+ Effectful.Network+ Effectful.Network.Lazy++ -- other-modules:+ -- other-extensions:+ build-depends:+ , base <5+ , bytestring <0.13+ , effectful-core >=1.0 && <3.0+ , network >=3.0 && <4.0++ hs-source-dirs: src+ default-language: GHC2021
+ src/Effectful/Network.hs view
@@ -0,0 +1,442 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ImportQualifiedPost #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# OPTIONS_GHC -Wno-deprecations #-}++-- | Wrapper of 'Network.Socket' for the 'effectful' ecosystem. Please see the+-- documentation of 'Network.Socket' on how to use this library.+module Effectful.Network+ ( Network+ , runNetwork+ , accept+ , bind+ , close+ , close'+ , connect+ , fdSocket+ , getAddrInfo+ , getCloseOnExec+ , getNameInfo+ , getNonBlock+ , getPeerCredential+ , getPeerName+ , getSockOpt+ , getSocketName+ , getSocketOption+ , getSocketType+ , gracefulClose+ , ifIndexToName+ , ifNameToIndex+ , listen+ , mkSocket+ , openSocket+ , recvBuf+ , recvBufFrom+ , recvBufMsg+ , recvFd+ , sendBuf+ , sendBufMsg+ , sendBufTo+ , sendFd+ , setCloseOnExecIfNeeded+ , setNonBlockIfNeeded+ , setSockOpt+ , setSocketOption+ , shutdown+ , socket+ , socketPair+ , socketPort+ , socketPortSafe+ , socketToFd+ , socketToHandle+ , touchSocket+ , unsafeFdSocket+ , whenSupported+ , withFdSocket+ , withSocketsDo+ , recvFrom+ , recv+ , sendAllTo+ , sendTo+ , sendAll+ , send+ , module Data.Word+ , module Foreign.C.Types+ , module Foreign.Ptr+ , module Foreign.Storable+ , module GHC.IO.Handle.Types+ , module Network.Socket+ , module System.IO+ ) where++import Effectful+ ( Dispatch (Static)+ , DispatchOf+ , Eff+ , Effect+ , IOE+ , type (:>)+ )+import Effectful.Dispatch.Static+ ( SideEffects (WithSideEffects)+ , StaticRep+ , evalStaticRep+ , unsafeEff_+ , unsafeLiftMapIO+ , unsafeSeqUnliftIO+ )++import Data.ByteString (StrictByteString)+import Data.Word (Word8)+import Foreign.C.Types (CInt, CUInt)+import Foreign.Ptr (Ptr)+import Foreign.Storable (Storable)+import GHC.IO.Handle.Types (Handle)+import Network.Socket+ ( AddrInfo (..)+ , Cmsg (..)+ , Family (..)+ , HostName+ , MsgFlag (..)+ , NameInfoFlag (..)+ , PortNumber+ , ProtocolNumber+ , ServiceName+ , ShutdownCmd (..)+ , SockAddr (..)+ , Socket+ , SocketOption (..)+ , SocketType (..)+ )+import Network.Socket qualified as S+import Network.Socket.ByteString qualified as S+import System.IO (IOMode)++-- | The Network effect.+data Network :: Effect++type instance DispatchOf Network = 'Static 'WithSideEffects+newtype instance StaticRep Network = Unit ()++-- | Run the 'Network' effect.+runNetwork :: (IOE :> es) => Eff (Network : es) a -> Eff es a+runNetwork = evalStaticRep (Unit ())++-- | Wraps 'S.getAddrInfo'.+getAddrInfo+ :: (Network :> es)+ => Maybe AddrInfo+ -> Maybe HostName+ -> Maybe ServiceName+ -> Eff es [AddrInfo]+getAddrInfo addrInfo hostName serviceName = unsafeEff_ $ S.getAddrInfo addrInfo hostName serviceName+{-# INLINE getAddrInfo #-}++-- | Wraps 'S.withSocketsDo'.+withSocketsDo :: (Network :> es) => Eff es a -> Eff es a+withSocketsDo = unsafeLiftMapIO S.withSocketsDo+{-# INLINE withSocketsDo #-}++-- | Wraps 'S.connect'.+connect :: (Network :> es) => Socket -> SockAddr -> Eff es ()+connect sock sockAddr = unsafeEff_ $ S.connect sock sockAddr+{-# INLINE connect #-}++-- | Wraps 'S.bind'.+bind :: (Network :> es) => Socket -> SockAddr -> Eff es ()+bind sock sockAddr = unsafeEff_ $ S.bind sock sockAddr+{-# INLINE bind #-}++-- | Wraps 'S.listen'.+listen :: (Network :> es) => Socket -> Int -> Eff es ()+listen sock n = unsafeEff_ $ S.listen sock n+{-# INLINE listen #-}++-- | Wraps 'S.accept'.+accept :: (Network :> es) => Socket -> Eff es (Socket, SockAddr)+accept sock = unsafeEff_ $ S.accept sock+{-# INLINE accept #-}++-- | Wraps 'S.close'.+close :: (Network :> es) => Socket -> Eff es ()+close = unsafeEff_ . S.close+{-# INLINE close #-}++-- | Wraps 'S.close''.+close' :: (Network :> es) => Socket -> Eff es ()+close' = unsafeEff_ . S.close+{-# INLINE close' #-}++-- | Wraps 'S.gracefulClose'.+gracefulClose :: (Network :> es) => Socket -> Int -> Eff es ()+gracefulClose sock = unsafeEff_ . S.gracefulClose sock+{-# INLINE gracefulClose #-}++-- | Wraps 'S.shutdown'.+shutdown+ :: (Network :> es) => Socket -> ShutdownCmd -> Eff es ()+shutdown sock = unsafeEff_ . S.shutdown sock+{-# INLINE shutdown #-}++-- | Wraps 'S.whenSupported'.+whenSupported+ :: (Network :> es) => SocketOption -> Eff es a -> Eff es ()+whenSupported = unsafeLiftMapIO . S.whenSupported+{-# INLINE whenSupported #-}++-- | Wraps 'S.getSocketOption'.+getSocketOption+ :: (Network :> es) => Socket -> SocketOption -> Eff es Int+getSocketOption sock = unsafeEff_ . S.getSocketOption sock+{-# INLINE getSocketOption #-}++-- | Wraps 'S.setSocketOption'.+setSocketOption+ :: (Network :> es) => Socket -> SocketOption -> Int -> Eff es ()+setSocketOption sock sockOpt = unsafeEff_ . S.setSocketOption sock sockOpt+{-# INLINE setSocketOption #-}++-- | Wraps 'S.getSockOpt'.+getSockOpt+ :: (Network :> es)+ => forall a+ . (Storable a)+ => Socket+ -> SocketOption+ -> Eff es a+getSockOpt sock = unsafeEff_ . S.getSockOpt sock+{-# INLINE getSockOpt #-}++-- | Wraps 'S.setSockOpt'.+setSockOpt+ :: (Network :> es) => (Storable a) => Socket -> SocketOption -> a -> Eff es ()+setSockOpt sock sockOpt = unsafeEff_ . S.setSockOpt sock sockOpt+{-# INLINE setSockOpt #-}++-- | Wraps 'S.socket'.+socket+ :: (Network :> es) => Family -> SocketType -> ProtocolNumber -> Eff es Socket+socket fam sockType = unsafeEff_ . S.socket fam sockType+{-# INLINE socket #-}++-- | Wraps 'S.openSocket'.+openSocket :: (Network :> es) => AddrInfo -> Eff es Socket+openSocket = unsafeEff_ . S.openSocket+{-# INLINE openSocket #-}++-- | Wraps 'S.withFdSocket'.+withFdSocket+ :: (Network :> es) => Socket -> (CInt -> Eff es r) -> Eff es r+withFdSocket sock cb = unsafeSeqUnliftIO $ \unlift -> do+ S.withFdSocket sock (unlift . cb)+{-# INLINE withFdSocket #-}++-- | Wraps 'S.unsafeFdSocket'.+unsafeFdSocket :: (Network :> es) => Socket -> Eff es CInt+unsafeFdSocket = unsafeEff_ . S.unsafeFdSocket+{-# INLINE unsafeFdSocket #-}++-- | Wraps 'S.touchSocket'.+touchSocket :: (Network :> es) => Socket -> Eff es ()+touchSocket = unsafeEff_ . S.touchSocket+{-# INLINE touchSocket #-}++-- | Wraps 'S.socketToFd'.+socketToFd :: (Network :> es) => Socket -> Eff es CInt+socketToFd = unsafeEff_ . S.socketToFd+{-# INLINE socketToFd #-}++-- | Wraps 'S.fdSocket'.+fdSocket :: (Network :> es) => Socket -> Eff es CInt+fdSocket = unsafeEff_ . S.fdSocket+{-# INLINE fdSocket #-}+{-# DEPRECATED fdSocket "Use withFdSocket or unsafeFdSocket instead" #-}++-- | Wraps 'S.mkSocket'.+mkSocket :: (Network :> es) => CInt -> Eff es Socket+mkSocket = unsafeEff_ . S.mkSocket+{-# INLINE mkSocket #-}++-- | Wraps 'S.socketToHandle'.+socketToHandle+ :: (Network :> es) => Socket -> IOMode -> Eff es Handle+socketToHandle sock = unsafeEff_ . S.socketToHandle sock+{-# INLINE socketToHandle #-}++-- | Wraps 'S.getSocketType'.+getSocketType :: (Network :> es) => Socket -> Eff es SocketType+getSocketType = unsafeEff_ . S.getSocketType+{-# INLINE getSocketType #-}++-- | Wraps 'S.getPeerName'.+getPeerName :: (Network :> es) => Socket -> Eff es SockAddr+getPeerName = unsafeEff_ . S.getPeerName+{-# INLINE getPeerName #-}++-- | Wraps 'S.getSocketName'.+getSocketName :: (Network :> es) => Socket -> Eff es SockAddr+getSocketName = unsafeEff_ . S.getSocketName+{-# INLINE getSocketName #-}++-- | Wraps 'S.ifNameToIndex'.+ifNameToIndex :: (Network :> es) => String -> Eff es (Maybe Int)+ifNameToIndex = unsafeEff_ . S.ifNameToIndex+{-# INLINE ifNameToIndex #-}++-- | Wraps 'S.ifIndexToName'.+ifIndexToName :: (Network :> es) => Int -> Eff es (Maybe String)+ifIndexToName = unsafeEff_ . S.ifIndexToName+{-# INLINE ifIndexToName #-}++-- | Wraps 'S.socketPortSafe'.+socketPortSafe+ :: (Network :> es) => Socket -> Eff es (Maybe PortNumber)+socketPortSafe = unsafeEff_ . S.socketPortSafe+{-# INLINE socketPortSafe #-}++-- | Wraps 'S.socketPort'.+socketPort :: (Network :> es) => Socket -> Eff es PortNumber+socketPort = unsafeEff_ . S.socketPort+{-# INLINE socketPort #-}++-- | Wraps 'S.socketPair'.+socketPair+ :: (Network :> es)+ => Family+ -> SocketType+ -> ProtocolNumber+ -> Eff es (Socket, Socket)+socketPair fam sock = unsafeEff_ . S.socketPair fam sock+{-# INLINE socketPair #-}++-- | Wraps 'S.sendFd'.+sendFd :: (Network :> es) => Socket -> CInt -> Eff es ()+sendFd sock = unsafeEff_ . S.sendFd sock+{-# INLINE sendFd #-}++-- | Wraps 'S.recvFd'.+recvFd :: (Network :> es) => Socket -> Eff es CInt+recvFd = unsafeEff_ . S.recvFd+{-# INLINE recvFd #-}++-- | Wraps 'S.getPeerCredential'.+getPeerCredential+ :: (Network :> es) => Socket -> Eff es (Maybe CUInt, Maybe CUInt, Maybe CUInt)+getPeerCredential = unsafeEff_ . S.getPeerCredential+{-# INLINE getPeerCredential #-}++-- | Wraps 'S.getNameInfo'.+getNameInfo+ :: (Network :> es)+ => [NameInfoFlag]+ -> Bool+ -> Bool+ -> SockAddr+ -> Eff es (Maybe HostName, Maybe ServiceName)+getNameInfo flag b1 b2 = unsafeEff_ . S.getNameInfo flag b1 b2+{-# INLINE getNameInfo #-}++-- | Wraps 'S.setCloseOnExecIfNeeded'.+setCloseOnExecIfNeeded :: (Network :> es) => CInt -> Eff es ()+setCloseOnExecIfNeeded = unsafeEff_ . S.setCloseOnExecIfNeeded+{-# INLINE setCloseOnExecIfNeeded #-}++-- | Wraps 'S.getCloseOnExec'.+getCloseOnExec :: (Network :> es) => CInt -> Eff es Bool+getCloseOnExec = unsafeEff_ . S.getCloseOnExec+{-# INLINE getCloseOnExec #-}++-- | Wraps 'S.setNonBlockIfNeeded'.+setNonBlockIfNeeded :: (Network :> es) => CInt -> Eff es ()+setNonBlockIfNeeded = unsafeEff_ . S.setNonBlockIfNeeded+{-# INLINE setNonBlockIfNeeded #-}++-- | Wraps 'S.getNonBlock'.+getNonBlock :: (Network :> es) => CInt -> Eff es Bool+getNonBlock = unsafeEff_ . S.getNonBlock+{-# INLINE getNonBlock #-}++-- | Wraps 'S.sendBuf'.+sendBuf+ :: (Network :> es) => Socket -> Ptr Word8 -> Int -> Eff es Int+sendBuf sock ptr = unsafeEff_ . S.sendBuf sock ptr+{-# INLINE sendBuf #-}++-- | Wraps 'S.recvBuf'.+recvBuf+ :: (Network :> es) => Socket -> Ptr Word8 -> Int -> Eff es Int+recvBuf sock ptr = unsafeEff_ . S.recvBuf sock ptr+{-# INLINE recvBuf #-}++-- | Wraps 'S.sendBufTo'.+sendBufTo+ :: (Network :> es) => Socket -> Ptr a -> Int -> SockAddr -> Eff es Int+sendBufTo sock ptr n = unsafeEff_ . S.sendBufTo sock ptr n+{-# INLINE sendBufTo #-}++-- | Wraps 'S.recvBufFrom'.+recvBufFrom+ :: (Network :> es) => Socket -> Ptr a -> Int -> Eff es (Int, SockAddr)+recvBufFrom sock ptr = unsafeEff_ . S.recvBufFrom sock ptr+{-# INLINE recvBufFrom #-}++-- | Wraps 'S.sendBufMsg'.+sendBufMsg+ :: (Network :> es)+ => Socket+ -> SockAddr+ -> [(Ptr Word8, Int)]+ -> [Cmsg]+ -> MsgFlag+ -> Eff es Int+sendBufMsg sock sockAddr ptrs cmsgs = unsafeEff_ . S.sendBufMsg sock sockAddr ptrs cmsgs+{-# INLINE sendBufMsg #-}++-- | Wraps 'S.recvBufMsg'.+recvBufMsg+ :: (Network :> es)+ => Socket+ -> [(Ptr Word8, Int)]+ -> Int+ -> MsgFlag+ -> Eff es (SockAddr, Int, [Cmsg], MsgFlag)+recvBufMsg sock ptrs n = unsafeEff_ . S.recvBufMsg sock ptrs n+{-# INLINE recvBufMsg #-}++-- | Wraps 'S.send'.+send :: (Network :> es) => Socket -> StrictByteString -> Eff es Int+send sock = unsafeEff_ . S.send sock+{-# INLINE send #-}++-- | Wraps 'S.sendAll'.+sendAll :: (Network :> es) => Socket -> StrictByteString -> Eff es ()+sendAll sock = unsafeEff_ . S.sendAll sock+{-# INLINE sendAll #-}++-- | Wraps 'S.sendTo'.+sendTo+ :: (Network :> es) => Socket -> StrictByteString -> SockAddr -> Eff es Int+sendTo sock bs = unsafeEff_ . S.sendTo sock bs+{-# INLINE sendTo #-}++-- | Wraps 'S.sendAllTo'.+sendAllTo+ :: (Network :> es) => Socket -> StrictByteString -> SockAddr -> Eff es ()+sendAllTo sock bs = unsafeEff_ . S.sendAllTo sock bs+{-# INLINE sendAllTo #-}++-- TODO: wrap more send functions++-- | Wraps 'S.recv'.+recv :: (Network :> es) => Socket -> Int -> Eff es StrictByteString+recv sock = unsafeEff_ . S.recv sock+{-# INLINE recv #-}++-- | Wraps 'S.recvFrom'.+recvFrom+ :: (Network :> es) => Socket -> Int -> Eff es (StrictByteString, SockAddr)+recvFrom sock = unsafeEff_ . S.recvFrom sock+{-# INLINE recvFrom #-}
+ src/Effectful/Network/Lazy.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ImportQualifiedPost #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# OPTIONS_GHC -Wno-deprecations #-}++-- | Wrapper of 'Network.Socket.Lazy.ByteString' for the 'effectful' ecosystem.+-- Please see the documentation of 'Network.Socket.Lazy.ByteString' on how to use+-- this library.+module Effectful.Network.Lazy where++import Effectful (Eff, type (:>))++import Effectful.Dispatch.Static (unsafeEff_)++import Data.ByteString.Lazy (LazyByteString)+import Network.Socket (Socket)+import Network.Socket.ByteString.Lazy qualified as S+import Prelude hiding (getContents)++import Data.Int (Int64)+import Effectful.Network (Network)++-- | Wraps 'S.send'.+send :: (Network :> es) => Socket -> LazyByteString -> Eff es Int64+send sock = unsafeEff_ . S.send sock++-- | Wraps 'S.sendAll'.+sendAll :: (Network :> es) => Socket -> LazyByteString -> Eff es ()+sendAll sock = unsafeEff_ . S.sendAll sock++#if MIN_VERSION_network(3,2,0)+-- | Wraps 'S.sendWithFds'.+sendWithFds :: (Network :> es) => Socket -> LazyByteString -> [Fd] -> Eff es ()+sendWithFds sock lbs = unsafeEff_ . S.sendWithFds sock lbs+#endif++-- | Wraps 'S.getContents'.+getContents :: (Network :> es) => Socket -> Eff es LazyByteString+getContents = unsafeEff_ . S.getContents++-- | Wraps 'S.recv'.+recv :: (Network :> es) => Socket -> Int64 -> Eff es LazyByteString+recv sock = unsafeEff_ . S.recv sock