From d9572cef86a987f6dd285f62562e2eb074eb8c92 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Thu, 28 Apr 2022 07:26:43 +0100 Subject: [PATCH] terminal: command to show last N items in a chat (#582) --- src/Simplex/Chat.hs | 12 ++++++++++++ src/Simplex/Chat/Controller.hs | 2 ++ src/Simplex/Chat/Messages.hs | 8 ++++++++ src/Simplex/Chat/View.hs | 1 + 4 files changed, 23 insertions(+) diff --git a/src/Simplex/Chat.hs b/src/Simplex/Chat.hs index 22f43ec461..62a0debc12 100644 --- a/src/Simplex/Chat.hs +++ b/src/Simplex/Chat.hs @@ -560,6 +560,10 @@ processChatCommand = \case editedItemId <- withStore $ \st -> getGroupChatItemIdByText st user groupId (Just localDisplayName) (safeDecodeUtf8 editedMsg) let mc = MCText $ safeDecodeUtf8 msg processChatCommand $ APIUpdateChatItem CTGroup groupId editedItemId mc + LastMessages (Just c@(ChatName cType _)) count -> do + chatId <- getChatId c + CRLastMessages . aChatItems . chat <$> (processChatCommand . APIGetChat cType chatId $ CPLast count) + LastMessages Nothing _count -> pure $ chatCmdError "not implemented" -- old file protocol -- SendFile cName f -> withUser $ \User {userId} -> do -- contactId <- withStore $ \st -> getContactIdByName st userId cName @@ -655,6 +659,11 @@ processChatCommand = \case -- use function below to make commands "synchronous" procCmd :: m ChatResponse -> m ChatResponse procCmd = id + getChatId :: ChatName -> m Int64 + getChatId (ChatName cType name) = withUser $ \user@User {userId} -> case cType of + CTDirect -> withStore $ \st -> getContactIdByName st userId name + CTGroup -> withStore $ \st -> getGroupIdByName st user name + _ -> throwChatError $ CECommandError "not supported" connectViaContact :: UserId -> ConnectionRequestUri 'CMContact -> Profile -> m ChatResponse connectViaContact userId cReq profile = withChatLock $ do let cReqHash = ConnReqUriHash . C.sha256Hash $ strEncode cReq @@ -1957,6 +1966,7 @@ chatCommandP = <|> ("\\@" <|> "\\ @") *> (DeleteMessage <$> displayName <* A.space <*> A.takeByteString) <|> ("!@" <|> "! @") *> (EditMessage <$> displayName <* A.space <*> (quotedMsg <|> pure "") <*> A.takeByteString) <|> "/feed " *> (SendMessageBroadcast <$> A.takeByteString) + <|> ("/tail" <|> "/t") *> (LastMessages <$> optional chatNameP <*> msgCountP) <|> ("/file #" <|> "/f #") *> (SendGroupFile <$> displayName <* A.space <*> filePath) <|> ("/file_v2 #" <|> "/f_v2 #") *> (SendGroupFileInv <$> displayName <* A.space <*> filePath) <|> ("/file @" <|> "/file " <|> "/f @" <|> "/f ") *> (SendFile <$> displayName <* A.space <*> filePath) @@ -2024,6 +2034,8 @@ chatCommandP = <|> (" admin" $> GRAdmin) <|> (" member" $> GRMember) <|> pure GRAdmin + chatNameP = A.space *> (ChatName <$> chatTypeP <*> displayName) + msgCountP = A.space *> A.decimal <|> pure 10 adminContactReq :: ConnReqContact adminContactReq = diff --git a/src/Simplex/Chat/Controller.hs b/src/Simplex/Chat/Controller.hs index 7adf8e2182..e3ab2dce22 100644 --- a/src/Simplex/Chat/Controller.hs +++ b/src/Simplex/Chat/Controller.hs @@ -146,6 +146,7 @@ data ChatCommand | SendGroupMessageQuote {groupName :: GroupName, contactName_ :: Maybe ContactName, quotedMsg :: ByteString, message :: ByteString} | DeleteGroupMessage GroupName ByteString | EditGroupMessage {groupName :: ContactName, editedMsg :: ByteString, message :: ByteString} + | LastMessages (Maybe ChatName) Int | SendFile ContactName FilePath | SendFileInv ContactName FilePath | SendGroupFile GroupName FilePath @@ -166,6 +167,7 @@ data ChatResponse | CRChatRunning | CRApiChats {chats :: [AChat]} | CRApiChat {chat :: AChat} + | CRLastMessages {chatItems :: [AChatItem]} | CRApiParsedMarkdown {formattedText :: Maybe MarkdownList} | CRUserSMPServers {smpServers :: [SMPServer]} | CRNewChatItem {chatItem :: AChatItem} diff --git a/src/Simplex/Chat/Messages.hs b/src/Simplex/Chat/Messages.hs index 33528b7cac..612032ca6c 100644 --- a/src/Simplex/Chat/Messages.hs +++ b/src/Simplex/Chat/Messages.hs @@ -41,6 +41,9 @@ import Simplex.Messaging.Util ((<$?>)) data ChatType = CTDirect | CTGroup | CTContactRequest | CTContactConnection deriving (Show, Generic) +data ChatName = ChatName ChatType Text + deriving (Show) + instance ToJSON ChatType where toJSON = J.genericToJSON . enumJSON $ dropPrefix "CT" toEncoding = J.genericToEncoding . enumJSON $ dropPrefix "CT" @@ -198,6 +201,11 @@ instance ToJSON AChatItem where data JSONAnyChatItem c d = JSONAnyChatItem {chatInfo :: ChatInfo c, chatItem :: ChatItem c d} deriving (Generic) +aChatItems :: AChat -> [AChatItem] +aChatItems (AChat ct Chat {chatInfo, chatItems}) = map aChatItem chatItems + where + aChatItem (CChatItem md ci) = AChatItem ct md chatInfo ci + instance MsgDirectionI d => ToJSON (JSONAnyChatItem c d) where toJSON = J.genericToJSON J.defaultOptions toEncoding = J.genericToEncoding J.defaultOptions diff --git a/src/Simplex/Chat/View.hs b/src/Simplex/Chat/View.hs index 703bcf6b59..347c6f013c 100644 --- a/src/Simplex/Chat/View.hs +++ b/src/Simplex/Chat/View.hs @@ -50,6 +50,7 @@ responseToView testView = \case CRApiParsedMarkdown ft -> [plain . bshow $ J.encode ft] CRUserSMPServers smpServers -> viewSMPServers smpServers testView CRNewChatItem (AChatItem _ _ chat item) -> viewChatItem chat item + CRLastMessages chatItems -> concatMap (\(AChatItem _ _ chat item) -> viewChatItem chat item) chatItems CRChatItemStatusUpdated _ -> [] CRChatItemUpdated (AChatItem _ _ chat item) -> viewItemUpdate chat item CRChatItemDeleted (AChatItem _ _ chat deletedItem) (AChatItem _ _ _ toItem) -> viewItemDelete chat deletedItem toItem