packages feed

musicScroll-0.3.0.0: src/MusicScroll/RealMain.hs

{-# language ScopedTypeVariables #-}
module MusicScroll.RealMain (realMain) where

import Control.Concurrent.Async (withAsync, withAsyncBound, waitAnyCancel)
import Control.Concurrent.STM.TBQueue (newTBQueue)
import Control.Concurrent.STM.TVar
import Control.Concurrent.STM.TMVar
import Control.Concurrent.MVar
import Data.Functor (void)
import Control.Exception (bracket)
import Database.SQLite.Simple
import Pipes.Concurrent

import MusicScroll.Pipeline
import MusicScroll.MPRIS
import MusicScroll.UI
import MusicScroll.EventLoop
import MusicScroll.DatabaseUtils (getDBPath, sqlDBCreate)

realMain :: IO ()
realMain = do
  appCtxTMvar  <- atomically newEmptyTMVar
  suplTVar <- atomically (newTVar Nothing)
  uiCallbackTB <- atomically (newTBQueue 5)
  withAsyncBound (uiThread appCtxTMvar uiCallbackTB suplTVar) $ \uiA -> do
    (trackin, errorin, singleProd, trackout, errorout) <- musicSpawn
    withAsync (dbusThread trackout errorout) $ \dbusA -> do
      dbPath <- getDBPath
      bracket (open dbPath) close $ \conn -> do
        execute_ conn sqlDBCreate
        mconn <- newMVar conn
        ctx   <- atomically (takeTMVar appCtxTMvar)
        let state = AppState ctx mconn suplTVar (trackin, errorin) singleProd
        let evState = EventLoopState state uiCallbackTB Nothing
        withAsync (staticPipeline state) $ \staticA ->
          withAsync (eventLoop evState) $ \evLoopA ->
            void $ waitAnyCancel [ staticA, evLoopA, uiA, dbusA ]