aboutsummaryrefslogtreecommitdiff
path: root/app/Main.hs
blob: a4e15eff7cf9fa92fcdcbf9bedd3379c92d49fe0 (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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
{-# LANGUAGE OverloadedStrings #-}

module Main where


import Data.Char
import Data.Text (Text)
import Data.List (intercalate)
import Data.Time
import Data.Time.Clock.POSIX

import qualified Data.Text as Text

import Text.Read (readMaybe)

import Control.Monad.Writer

import Telegram.Bot.API
import Telegram.Bot.Simple
import Telegram.Bot.Simple.UpdateParser (updateMessageText)

data Event = Event { eventTime :: Integer, eventChatId :: ChatId, eventMsgId :: MessageId }

data Action
  = TextMsg { textMsgText :: Text, textMsgChatId :: ChatId , textMsgId :: MessageId }
  | AddEvent Event
  | FireEvents Integer

type Model = [Event]

main :: IO ()
main = do
  content <- readFile "tgtoken"
  let token = Token $ Text.pack $ strip content
  run token

currentTimestamp :: IO Integer
currentTimestamp = fmap (floor . utcTimeToPOSIXSeconds) getCurrentTime

botApp :: BotApp Model Action
botApp = BotApp
  { botInitialModel = []
  , botAction = updateToAction
  , botHandler = handleAction
  , botJobs = [
      BotJob
        { botJobSchedule = "* * * * *"  -- every minute
        , botJobTask = eventHandler
        }]
  }

eventHandler :: Model -> Eff Action Model
eventHandler model = Eff $ do
  let acts = do
       ts <- liftIO $ currentTimestamp
       return $ Just $ FireEvents ts
  tell [acts]
  return model

updateToAction :: Update -> Model -> Maybe Action
updateToAction update _ = do
    text <- updateMessageText update
    cid <- fmap chatId $ fmap messageChat $ updateMessage update
    mid <- fmap messageMessageId $ updateMessage update
    return $ TextMsg text cid mid

replyTextEff :: Model -> ChatId -> MessageId -> Text -> Eff Action Model
replyTextEff model cid mid msg = Eff $ do  
    let acts = do
         replyToMessage cid mid msg
         return Nothing
    tell [acts]
    return model

handleAction :: Action -> Model -> Eff Action Model
handleAction action model = case action of
  TextMsg tmsg cid mid -> case (words $ Text.unpack tmsg) of
    (command:args) ->
      case (takeWhile (/='@') command) of
        "/timer" -> handleTimerCmd model cid mid args
        _ -> return model
    [] -> return model
  AddEvent e -> return (e:model)
  FireEvents ts -> fireEvents model ts

replyToMessage:: ChatId -> MessageId -> Text -> BotM ()
replyToMessage cid mid t = replyTo (SomeChatId cid) $ ReplyMessage
    t Nothing Nothing Nothing Nothing Nothing Nothing (Just mid) Nothing Nothing 

fireEvents :: Model -> Integer -> Eff Action Model
fireEvents model ts = Eff $ do
    let acts = do
         let sendEvent e = do
              replyToMessage (eventChatId e) (eventMsgId e) "时间到了哦"
         mapM_ sendEvent $ filter (\e -> (eventTime e) <= ts) model
         return Nothing
    tell [acts]
    return $ filter (\e -> (eventTime e) > ts) model

handleTimerCmd :: Model -> ChatId -> MessageId -> [String] -> Eff Action Model
handleTimerCmd model chatId mid args =
  let minutes :: Maybe Integer = readMaybe $ intercalate " " args in
    case minutes of
      Nothing -> replyTextEff model chatId mid "格式:/timer <分钟数>" 
      Just num ->
        Eff $ do
          let validNumAction = do
                replyToMessage chatId mid $ Text.pack $ "已设置" ++ (show num) ++ "分钟提醒"
                curTime <- liftIO $ currentTimestamp
                return $ Just $ AddEvent $ Event (curTime + (toInteger num) * 60) chatId mid
          let invalidNumAction = do
                replyToMessage chatId mid $ Text.pack $ "只能设置一天内的提醒"
                return Nothing
          let queueFullAction = do
                replyToMessage chatId mid $ Text.pack $ "提醒队列已满"
                return Nothing
          if num > 1440 then tell [invalidNumAction]
          else
            if (length model) > 4096 then  tell [queueFullAction]
            else tell [validNumAction]
          return model

run :: Token -> IO ()
run token = do
  env <- defaultTelegramClientEnv token
  startBot_ botApp env

strip :: String -> String
strip = reverse . dropWhile isSpace . reverse . dropWhile isSpace