gKrokod / botReborn

try handle pattern
BSD 3-Clause "New" or "Revised" License
0 stars 0 forks source link

Использование Handle Pattern #9

Closed roman-bodavskiy closed 1 week ago

roman-bodavskiy commented 2 weeks ago

Так и есть. Можно оставить пустым, но компилятор со всеми флагами требует, чтобы структура была задана в начале программы. Данная функция определяется диспетчером для каждого потока отдельно.

module Handlers.Dispatcher (Handle (..), dispatcher, watcherForNewMessage, getMessage) where
...
let forUserBotHandle =                
                botHandle
                  { Handlers.Bot.getMessage = getMessage h user,
                    Handlers.Bot.sendMessage = sendMessage h                                                                                                                 
                  }

решил по этому поводу создать отдельное ишью А зачем вообще getMessage и sendMessage у тебя внутри хендлера?

data Handle m = Handle
  { getMessage :: m Message,
    sendMessage :: Message -> m (),
    ...

getMessage :: (Monad m) => Handle m -> User -> m Message
...
sendMessage :: (Monad m) => Handle m -> Message -> m ()

В хендлер нужно записывать функции которые требуют вызова IO и не могут быть протестированы, либо какие-то чистые данные, которые отличаются в тестах и самой программе, либо другие хендлеры Мне кажется, если убрать эти функции из хендлера, то и не нужно будет передавать какие-то фейковые значения

roman-bodavskiy commented 2 weeks ago

getMessage вполне может быть протестирована в юнит тестах, а вот внутренние функцииHandlers.Base.readStackMessage, Handlers.Base.eraseMessage уже требуют вызова IO, то есть должны быть внутри хендлера, тут все верно

gKrokod commented 2 weeks ago

Мне это позволило персонализировать каждый поток под конкретного пользователя, потому что у них разные Handle. У одного потока getMessage and sendMessage настроены на конкретного User, у другого на другого User. При этом код самого бота одинаковый. Если я выну их из обработчика бота, то эта идея будет утеряна.

roman-bodavskiy commented 2 weeks ago

Не совсем пойму, что значит персонализировать каждый поток под конкретного пользователя? У тебя отличается только UserId, весь остальной код тот же самый. Поэтому можно просто userId передать в функцию doWork

forkForUser h (Handlers.Bot.doWork h userId)
...........

doWork :: (Monad m) => Handle m -> UserId -> m ()
doWork h = do
  let logHandle = logger h
  Handlers.Logger.logMessage logHandle Debug "Bot. Run the bot logic: get message -> make reaction"
  message <- getMessage h userId
  makeReaction h message

getMessage :: (Monad m) => Handle m -> UserId -> m Message
getMessage h user = do
...
sendMessage :: (Monad m) => Handle m -> Message -> m ()
sendMessage h msg = do
...

А для функции sendMessage даже UserId не нужен, она одинаковая для всех юзеров

roman-bodavskiy commented 2 weeks ago

Кстати,наименование типа не очень понятно newtype User = User {giveUser :: Int} Обычно User это большая структура из множества полей, как имя, фамилия, email и другие данные юзера. Здесь у тебя скорей UserId