ATrade-QUIK connector
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

83 lines
3.0 KiB

{-# LANGUAGE ExistentialQuantification #-}
module QuoteSource.DataImport
(
initDataImportServer,
ServerState
) where
import Foreign.Marshal.Alloc
import System.Win32.DLL
import System.Win32.Types
import Foreign
import Foreign.C.Types
import Foreign.C.String
import QuoteSource.DDE
import QuoteSource.XlParser
import QuoteSource.TableParser
import QuoteSource.TableParsers.AllParamsTableParser
import Data.IORef
import Text.Printf
import Data.Binary.Get
import Data.Time.Clock
import Control.Monad.State.Strict
import qualified Data.ByteString.Lazy as BL
data TableParserInstance = forall a . TableParser a => MkTableParser a
instance TableParser TableParserInstance where
parseXlTable = parseXlTable
getTableId (MkTableParser a) = getTableId a
giveTimestampHint (MkTableParser a) t = MkTableParser (giveTimestampHint a t)
data ServerState = ServerState {
dde :: DdeState,
appName :: String,
parser :: TableParserInstance
}
ddeCallback :: IORef ServerState -> CUInt -> CUInt -> HANDLE -> HANDLE -> HANDLE -> HANDLE -> LPDWORD -> LPDWORD -> IO HANDLE
ddeCallback state msgType format hConv hsz1 hsz2 hData dwData1 dwData2
| msgType == ddeXtypConnect = handleConnect state hsz1 hsz2
| msgType == ddeXtypPoke = handlePoke state hsz1 hData
| otherwise = return nullHANDLE
where
handleConnect state hsz1 hsz2 = do
myAppName <- appName <$> readIORef state
myDdeState <- dde <$> readIORef state
maybeAppName <- queryString myDdeState 256 hsz2
case maybeAppName of
Just incomingAppName -> do
putStrLn incomingAppName
return $ if incomingAppName == myAppName
then ddeResultTrue
else ddeResultFalse
Nothing -> return ddeResultFalse
handlePoke state hsz1 hData = do
myDdeState <- dde <$> readIORef state
maybeTopic <- queryString myDdeState 256 hsz1
case maybeTopic of
Nothing -> return ddeResultFalse
Just topic -> withDdeData hData (\xlData -> case runGetOrFail xlParser $ BL.fromStrict xlData of
Left (_, _, errmsg) -> return ddeResultFalse
Right (_, _, table) -> do
myParser <- parser <$> readIORef state
when (topic == getTableId myParser) $ do
timeHint <- getCurrentTime
modifyIORef state (\s -> s { parser = giveTimestampHint (parser s) timeHint })
(MkTableParser myParser) <- parser <$> readIORef state
let (ticks, newState) = runState (parseXlTable table) myParser
modifyIORef state (\s -> s { parser = MkTableParser newState })
return ddeResultAck)
initDataImportServer :: String -> IO (IORef ServerState)
initDataImportServer applicationName = do
s <- newIORef ServerState { appName = applicationName, dde = nullDdeState, parser = MkTableParser $ mkAllParamsTableParser "allparams" }
d <- initializeDde applicationName "default" (ddeCallback s)
modifyIORef s (\state -> state {dde = d})
putStrLn "DataImportServer initialized"
return s