packages feed

moffy-samples-events-0.2.2.2: src/Control/Moffy/Samples/Followbox/Event.hs

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE BlockArguments, LambdaCase #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE DataKinds, TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DeriveGeneric #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs -fno-warn-orphans #-}

module Control.Moffy.Samples.Followbox.Event (
	-- * Followbox Event
	SigF, ReactF, FollowboxEv,
	-- * Store and Load Jsons
	StoreJsons(..), pattern OccStoreJsons, LoadJsons, pattern OccLoadJsons,
	clearJsons, storeJsons, loadJsons,
	-- * Request Data
	-- ** Http Get
	HttpGet(..), pattern OccHttpGet, httpGet,
--	-- ** Calc Text Extents
--	CalcTextExtents(..), pattern OccCalcTextExtents, calcTextExtents,
	-- ** Get Time Zone
	GetTimeZone, pattern OccGetTimeZone, getTimeZone,
	-- * Browse
	Browse(..), pattern OccBrowse, browse,
	-- * Sleep
	BeginSleep(..), pattern OccBeginSleep, EndSleep, pattern OccEndSleep,
	beginSleep, checkBeginSleep, endSleep,
	-- * Raise Error
	RaiseError(..), pattern OccRaiseError, Error(..), ErrorResult(..),
	raiseError, checkTerminate ) where

import GHC.Generics (Generic)
import Control.DeepSeq

import Control.Moffy (Sig, React, Request(..), await)
import Control.Moffy.Event.ThreadId (GetThreadId)
import Control.Moffy.Event.Lock (LockEv)
import Control.Moffy.Samples.Event.Random (RandomEv)
import Control.Moffy.Samples.Event.Delete (DeleteEvent)
import Control.Moffy.Samples.Event.Mouse qualified as Mouse (Move, Down, Up)
import Control.Moffy.Samples.Event.CalcTextExtents
import Data.Type.Set (Set(Nil), Singleton, numbered, (:-), (:+:))
import Data.OneOrMore (Selectable(..))
import Data.Bool (bool)
import Data.Aeson (Object)
import Data.Time (UTCTime, TimeZone)
import Network.HTTP.Simple (Header)

import qualified Data.ByteString.Lazy as LBS

import Control.Moffy.Samples.Followbox.TypeSynonym (Uri, ErrorMessage)

import Control.Moffy.Samples.Event.Area

---------------------------------------------------------------------------

-- * STORE AND LOAD JSON OBJECT LIST
-- * REQUEST DATA
-- 	+ HTTP GET
--	+ CALC TEXT EXTENTS
--	+ TIME ZONE
-- * BROWSE
-- * SLEEP
-- * RAISE ERROR
-- * FOLLOWBOX EVENT TYPE

---------------------------------------------------------------------------
-- STORE AND LOAD JSON OBJECT LIST
---------------------------------------------------------------------------

newtype StoreJsons = StoreJsonsReq [Object] deriving Show
numbered [t| StoreJsons |]
instance Selectable StoreJsons where l `select` _r = l
instance Request StoreJsons where
	data Occurred StoreJsons = OccStoreJsons [Object]

clearJsons :: React s (Singleton StoreJsons) ()
clearJsons = storeJsons []

storeJsons :: [Object] -> React s (Singleton StoreJsons) ()
storeJsons os = bool (storeJsons os) (pure ())
	=<< await (StoreJsonsReq os) \(OccStoreJsons os') -> os == os'

data LoadJsons = LoadJsonsReq deriving (Show, Eq, Ord)
numbered [t| LoadJsons |]
instance Request LoadJsons where data Occurred LoadJsons = OccLoadJsons [Object]

loadJsons :: React s (Singleton LoadJsons) [Object]
loadJsons = await LoadJsonsReq \(OccLoadJsons os) -> os

---------------------------------------------------------------------------
-- REQUEST DATA
---------------------------------------------------------------------------

-- HTTP GET

newtype HttpGet = HttpGetReq Uri deriving (Show, Eq, Ord)
numbered [t| HttpGet |]
instance Request HttpGet where
	data Occurred HttpGet = OccHttpGet Uri [Header] LBS.ByteString

httpGet :: Uri -> React s (Singleton HttpGet) ([Header], LBS.ByteString)
httpGet u = maybe (httpGet u) pure =<< await (HttpGetReq u)
	\(OccHttpGet u' hs c) -> bool Nothing (Just (hs, c)) $ u == u'

-- TIME ZONE

data GetTimeZone = GetTimeZoneReq deriving (Show, Eq, Ord)
numbered [t| GetTimeZone |]
instance Request GetTimeZone where
	data Occurred GetTimeZone = OccGetTimeZone TimeZone deriving Show

getTimeZone :: React s (Singleton GetTimeZone) TimeZone
getTimeZone = await GetTimeZoneReq \(OccGetTimeZone tz) -> tz

---------------------------------------------------------------------------
-- BROWSE
---------------------------------------------------------------------------

newtype Browse = Browse Uri deriving (Show, Eq, Ord)
numbered [t| Browse |]
instance Request Browse where data Occurred Browse = OccBrowse deriving Show

browse :: Uri -> React s (Singleton Browse) ()
browse u = await (Browse u) \OccBrowse -> ()

---------------------------------------------------------------------------
-- SLEEP
---------------------------------------------------------------------------

data BeginSleep = BeginSleep UTCTime | CheckBeginSleep deriving (Show, Eq, Ord)
numbered [t| BeginSleep |]
instance Request BeginSleep where
	data Occurred BeginSleep = OccBeginSleep UTCTime deriving Show

beginSleep :: UTCTime -> React s (Singleton BeginSleep) ()
beginSleep t = bool (beginSleep t) (pure ()) =<< await (BeginSleep t) \case
	OccBeginSleep t' | t == t' -> True; _ -> False

checkBeginSleep :: React s (Singleton BeginSleep) UTCTime
checkBeginSleep = await CheckBeginSleep \case OccBeginSleep t -> t

data EndSleep = EndSleepReq deriving (Show, Eq, Ord)
numbered [t| EndSleep |]
instance Request EndSleep where
	data Occurred EndSleep = OccEndSleep deriving Show

endSleep :: React s (Singleton EndSleep) ()
endSleep = await EndSleepReq \OccEndSleep -> ()

---------------------------------------------------------------------------
-- RAISE ERROR
---------------------------------------------------------------------------

data Error
	= NoRateLimitRemaining | NoRateLimitReset
	| NotJson | EmptyJson | NoLoginName | NoAvatarAddress | NoAvatar
	| NoHtmlUrl | Trace | CatchError deriving (Show, Eq, Ord, Generic)

instance NFData Error

data ErrorResult = Continue | Terminate deriving Show

data RaiseError = RaiseError Error ErrorMessage deriving (Show, Eq, Ord)
numbered [t| RaiseError |]
instance Request RaiseError where
	data Occurred RaiseError = OccRaiseError Error ErrorResult

raiseError :: Error -> ErrorMessage -> React s (Singleton RaiseError) ()
raiseError e em = bool (raiseError e em) (pure ())
	=<< await (RaiseError e em) \(OccRaiseError e' _er) -> e == e'

catchError :: React s (Singleton RaiseError) ErrorResult
catchError = await (RaiseError CatchError "") \(OccRaiseError _ er) -> er

checkTerminate :: React s (Singleton RaiseError) ()
checkTerminate = catchError
	>>= \case Continue -> checkTerminate; Terminate -> pure ()

---------------------------------------------------------------------------
-- FOLLOWBOX EVENT TYPE
---------------------------------------------------------------------------

type SigF s = Sig s FollowboxEv
type ReactF s r = React s FollowboxEv r

type FollowboxEv = SetArea :- GetArea :-
	GetThreadId :- LockEv :+: RandomEv :+: DeleteEvent :- MouseEv :+:
	StoreJsons :- LoadJsons :- HttpGet :- CalcTextExtents :- GetTimeZone :-
	Browse :- BeginSleep :- EndSleep :- RaiseError :- 'Nil

type MouseEv = Mouse.Move :- Mouse.Down :- Mouse.Up :- 'Nil