<commit_before>{-# LANGUAGE TemplateHaskell, OverloadedStrings, GeneralizedNewtypeDeriving  #-}
module SecondTransfer.IOCallbacks.WrapSocket (
                 socketIOCallbacks

               , SocketIOCallbacks
               , socket_SS
     ) where


---import           Control.Concurrent
import qualified Control.Exception                                  as E
import           Control.Lens                                       (makeLenses, (^.))

import qualified Data.ByteString                                    as B
import qualified Data.ByteString.Lazy                               as LB
--import           Data.ByteString.Char8                              (pack, unpack)
--import           Data.List                                          (find)

import qualified Network.Socket                                     as NS
import qualified Network.Socket.ByteString                          as NSB


import           SecondTransfer.IOCallbacks.Types
import           SecondTransfer.Exception

#include "instruments.cpphs"

-- | IOCallbacks around an active socket
data SocketIOCallbacks = SocketIOCallbacks {
    _socket_SS    :: NS.Socket
  , _callbacks_SS :: IOCallbacks
    }

makeLenses ''SocketIOCallbacks

instance IOChannels SocketIOCallbacks where
    handshake s = return ( s ^. callbacks_SS )

-- | This function wraps an active socket (e.g., one where it is possible to send and receive data)
--   in something with a set of active callbacks
socketIOCallbacks :: NS.Socket -> IO SocketIOCallbacks
socketIOCallbacks socket = do
    let
        uhandler = ((\ e -> do
                               -- Preserve sockets!!
                               close_action
                               E.throwIO NoMoreDataException
                    ) :: E.SomeException -> IO a )

        push_action lazy_bs = keyedReportExceptions "pushAtSocket" $
            E.catch
                (NSB.sendMany socket . LB.toChunks $ lazy_bs)
                uhandler
        -- Unfortunately we are forced to totally rely on sockets blocking or not nature
        -- TODO:  Check if ignoring the flag here becomes a problem.
        best_effort_pull_action _ = do
            datum <- E.catch (NSB.recv socket 4096) uhandler
            if B.length datum == 0
                then do
                   -- Pre-emptively close the socket, don't wait for anything else
                   close_action
                   E.throwIO NoMoreDataException
                else do
                   return datum

        -- Exceptions are close are possible
        close_action = E.catch ( do
            --REPORT_EVENT("socket-close-called")
            NS.shutdown socket NS.ShutdownBoth
            REPORT_EVENT("socket-shutdown-executed")
            NS.close socket
            REPORT_EVENT("socket-close-executed")
            return ()
            ) (( \ _ -> return () ) :: E.SomeException -> IO () )
    pull_action_wrapping <- newPullActionWrapping  best_effort_pull_action
    let<commit_msg>- Added support for reporting some data to<commit_after>{-# LANGUAGE TemplateHaskell, OverloadedStrings, GeneralizedNewtypeDeriving, GADTs  #-}
module SecondTransfer.IOCallbacks.WrapSocket (
                 socketIOCallbacks

               , SocketIOCallbacks
               , socket_SS

               , HasSocketPeer                                     (..)
               , SomeHasSocketPeer                                 (..)
     ) where


---import           Control.Concurrent
import qualified Control.Exception                                  as E
import           Control.Lens                                       (makeLenses, (^.))

import qualified Data.ByteString                                    as B
import qualified Data.ByteString.Lazy                               as LB
--import           Data.ByteString.Char8                              (pack, unpack)
--import           Data.List                                          (find)

import qualified Network.Socket                                     as NS
import qualified Network.Socket.ByteString                          as NSB


import           SecondTransfer.IOCallbacks.Types
import           SecondTransfer.Exception

#include "instruments.cpphs"

-- | IOCallbacks around an active socket
data SocketIOCallbacks = SocketIOCallbacks {
    _socket_SS    :: NS.Socket
  , _callbacks_SS :: IOCallbacks
    }

makeLenses ''SocketIOCallbacks

instance IOChannels SocketIOCallbacks where
    handshake s = return ( s ^. callbacks_SS )


class HasSocketPeer a where
    getSocketPeerAddress :: a -> IO NS.SockAddr

data SomeHasSocketPeer where
  -- = forall a . HasSocketPeer a => SomeHasSocketPeer a
  SomeHasSocketPeer :: HasSocketPeer a => a -> SomeHasSocketPeer


instance HasSocketPeer SocketIOCallbacks where
    getSocketPeerAddress s = NS.getPeerName $ s ^. socket_SS


-- | This function wraps an active socket (e.g., one where it is possible to send and receive data)
--   in something with a set of active callbacks
socketIOCallbacks :: NS.Socket -> IO SocketIOCallbacks
socketIOCallbacks socket = do
    let
        uhandler :: E.SomeException -> IO a
        uhandler = ((\ _e -> do
                               -- Preserve sockets!!
                               close_action
                               E.throwIO NoMoreDataException
                    ) :: E.SomeException -> IO a )

        push_action lazy_bs = keyedReportExceptions "pushAtSocket" $
            E.catch
                (NSB.sendMany socket . LB.toChunks $ lazy_bs)
                uhandler
        -- Unfortunately we are forced to totally rely on sockets blocking or not nature
        -- TODO:  Check if ignoring the flag here becomes a problem.
        best_effort_pull_action _ = do
            datum <- E.catch (NSB.recv socket 4096) uhandler
            if B.length datum == 0
                then do
                   -- Pre-emptively close the socket, don't wait for anything else
                   close_action
                   E.throwIO NoMoreDataException
                else do
                   return datum

        -- Exceptions are close are possible
        close_action = E.catch ( do
            REPORT_EVENT("socket-close-called")
            NS.shutdown socket NS.ShutdownBoth
            REPORT_EVENT("socket-shutdown-executed")
            NS.close socket
            REPORT_EVENT("socket-close-executed")
            return ()
            ) (( \ _ -> return () ) :: E.SomeException -> IO () )
    pull_action_wrapping <- newPullActionWrapping  best_effort_pull_action
    let
{'fraction_non_alphanumeric': 0.06334497949263254, 'fraction_numerical': 0.0018228771077016558, 'mean_word_length': 1.5206738131699846, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1362298', 'n_tokens_mistral': 1647, 'n_tokens_neox': 1598, 'n_words': 460}