aboutsummaryrefslogtreecommitdiff
path: root/src/Main.hs
blob: c8290db4bb6f9ff278f6a2d1e5c9591f02d83980 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
{-# LANGUAGE OverloadedStrings, LambdaCase #-}

module Main (main) where

import Control.Concurrent.STM.TChan
import Control.Monad (forever)
import Data.Aeson
import Data.ByteString (ByteString, toStrict)
import GHC.Conc
import Network.HTTP.Simple (Response, httpJSON, getResponseBody)
import System.AtomicWrite.Writer.LazyByteString (atomicWriteFile)
import Yesod

import qualified Data.ByteString as BS

import Bangs

data Search = Search {
    ownBangs :: TVar Bangs,
    ddgBangs :: TVar Bangs,
    serializedBangs :: TVar ByteString,
    syncFileNotifications :: TChan ()
}

reserialize :: Search -> STM ()
reserialize s = do
    own <- readTVar $ ownBangs s
    ddg <- readTVar $ ddgBangs s
    writeTVar (serializedBangs s) $ toStrict $ encode $ own <> ddg -- left biased union
    writeTChan (syncFileNotifications s) ()

-- second argument: readable tchan, duped from the tchan in 'Search'
fileSyncThread :: Search -> TChan () -> IO a
fileSyncThread s rc = forever $ do
    nextBangs <- atomically $ do
        readTChan rc
        readTVar (ownBangs s)
    atomicWriteFile "bangs.json" $ encode nextBangs

spawnFileSyncThread :: Search -> IO ()
spawnFileSyncThread s = do
    readableChan <- atomically $ dupTChan (syncFileNotifications s)
    forkIO $ fileSyncThread s readableChan
    return ()

loadOwnBangs :: IO Bangs
loadOwnBangs = eitherDecodeFileStrict "bangs.json" >>= \case
    Left e -> error e
    Right b -> return b

main :: IO ()
main = do
    ans <- (httpJSON "https://duckduckgo.com/bang.v255.js") :: IO (Response DDGBangs)
    s <- Search
        <$> (loadOwnBangs >>= newTVarIO)
        <*> newTVarIO (toBangs $ getResponseBody ans)
        <*> newTVarIO BS.empty
        <*> newBroadcastTChanIO

    spawnFileSyncThread s
    atomically $ reserialize s

    print =<< readTVarIO (serializedBangs s)
    _ <- getLine
    return ()