packages feed

bitcoin-rpc-0.5.0.0: Network/BitcoinRPC/Events/MarkerAddresses.hs

{-# LANGUAGE DeriveGeneric #-}

-- | Provides some glue code to use the module 'Network.BitcoinRPC.MarkerAddresses'
-- in combination with 'Network.BitcoinRPC.Events' and automatically filter
-- everything based on the marker address settings.

module Network.BitcoinRPC.Events.MarkerAddresses
    ( initialFilteredEventTaskState
    , initFilteredBitcoinEventTask
    , waitForFilteredBitcoinEvents
    , killFilteredBitcoinEventTask
    , updateMarkerAddresses
    , listPendingTransactions
    , listMarkerAdressStatus
    , FilteredBitcoinEventTaskHandle
    , FilteredEventTaskState
    , MA.PendingReason(..)
    , MA.FilteredBitcoinEvent(..)
    ) where

import Control.Concurrent
import Control.Watchdog
import Data.Serialize
import GHC.Generics

import Network.BitcoinRPC
import Network.BitcoinRPC.Events

import qualified Network.BitcoinRPC.MarkerAddresses as MA

data FilteredBitcoinEventTaskHandle = FilteredBitcoinEventTaskHandle
                                            { fbetBetHandle :: BitcoinEventTaskHandle
                                            , fbetWrappedMAStore :: MVar MA.MAStore
                                            }

data FilteredEventTaskState = FilteredEventTaskState
                                    { fetsMAStore :: MA.MAStore
                                    , fetsEventTaskState :: EventTaskState
                                    }
                              deriving (Show, Generic)

instance Serialize FilteredEventTaskState

-- | Returns an initial 'FilteredEventTaskState' with no marker addresses
-- configured. Use 'updateMarkerAddresses' to add marker addresses.
initialFilteredEventTaskState :: FilteredEventTaskState
initialFilteredEventTaskState =
    FilteredEventTaskState { fetsMAStore = MA.initMarkerAddressStore []
                           , fetsEventTaskState = initialEventTaskState
                           }

updateMarkerAddresses :: FilteredEventTaskState-> [(BitcoinAddress, BitcoinAmount)] -> FilteredEventTaskState
updateMarkerAddresses state markerAddresses =
    let maStore' = MA.updateMarkerAddresses (fetsMAStore state) markerAddresses
    in state { fetsMAStore = maStore' }

listPendingTransactions :: FilteredEventTaskState -> [(Transaction, MA.PendingReason)]
listPendingTransactions state = MA.listPendingTransactions (fetsMAStore state)

listMarkerAdressStatus :: FilteredEventTaskState-> [(BitcoinAddress, Bool, BitcoinAmount, BitcoinAmount)]
listMarkerAdressStatus state = MA.listMarkerAdressStatus (fetsMAStore state)

initFilteredBitcoinEventTask :: Maybe WatchdogLogger
                             -> RPCAuth
                             -> FilePath    -- ^  PID will be written here to get
                                            -- notifications from Bitcoin daemon
                             -> (TransactionHeader -> Bool)
                                            -- ^ test to decide whether a
                                            -- transaction can be accepted
                             -> FilteredEventTaskState  -- ^ state from
                                                        -- which to resume
                             -> IO (FilteredBitcoinEventTaskHandle)
initFilteredBitcoinEventTask mLogger auth pidfile acceptTest state = do
    betHandle <- initBitcoinEventTask mLogger auth pidfile
                                        acceptTest (fetsEventTaskState state)
    wrappedMAStore <- newMVar $ fetsMAStore state
    return $ FilteredBitcoinEventTaskHandle betHandle wrappedMAStore

-- | Wait for new Bitcoin events, but already filter them based on the
-- marker address configuration. This might sometimes return an empty list of
-- events.
waitForFilteredBitcoinEvents :: FilteredBitcoinEventTaskHandle-> IO (FilteredEventTaskState, [MA.FilteredBitcoinEvent])
waitForFilteredBitcoinEvents fbetHandle = do
    let betHandle = fbetBetHandle fbetHandle
    maStore <- readMVar $ fbetWrappedMAStore fbetHandle
    (etState', events) <- waitForBitcoinEvents betHandle
    let (maStore', fEvents) = MA.processEvents maStore events
    _ <- swapMVar (fbetWrappedMAStore fbetHandle) maStore'
    let fbetState = FilteredEventTaskState
                           { fetsMAStore = maStore'
                           , fetsEventTaskState = etState'
                           }
    return (fbetState, fEvents)

killFilteredBitcoinEventTask :: FilteredBitcoinEventTaskHandle -> IO ()
killFilteredBitcoinEventTask fbetHandle =
    killBitcoinEventTask (fbetBetHandle fbetHandle)