diff --git a/mattermost.el b/mattermost.el index 926aadc..612bee7 100644 --- a/mattermost.el +++ b/mattermost.el @@ -52,7 +52,7 @@ ;; ToDo: probably not the best way to get a keyword from a string (defun mattermost-string->keyword (str) "Returns a keyword from a string" - (read (concat ":" str))) + (intern (concat ":" str))) (defun mattermost-json-parse-string (string) "Parses a JSON string" @@ -67,7 +67,8 @@ (json-array-type 'list) (json-key-type 'keyword)) (set-buffer-multibyte t) - (goto-char url-http-end-of-headers) + (if (boundp 'url-http-end-of-headers) + (goto-char url-http-end-of-headers)) (json-read))) (defun mattermost-read-password () @@ -96,16 +97,40 @@ if the user is not present" :action "authentication_challenge" :data (:token ,mattermost-token)))) +(defun mattermost--ws-posted-to-post (msg) + "Extracts the post from a ws posted frame and transforms it to +conform to a post plist" + (let* ((post (plist-get (plist-get msg :data) :post))) + (mattermost-json-parse-string post))) + +(defun mattermost--process-ws-posted (msg) + "Processes a websocket posted message" + (let* ((channel-name (plist-get (plist-get msg :data) :channel_name)) + (channel-display-name (plist-get (plist-get msg :data) :channel_display_name)) + (chanb (or (get-buffer (format "> %s <" channel-name)) + (get-buffer (format "> %s <" channel-display-name)))) + (post (mattermost--ws-posted-to-post msg))) + (if (not (null chanb)) + (with-current-buffer chanb + (save-excursion + (goto-char mattermost-insert-marker) + (mattermost-insert-post post)))))) + +(defun mattermost--process-ws-frame (_ws frame) + "Processes a websocket frame" + (let* ((text (websocket-frame-text frame)) + (msg (mattermost-json-parse-string text)) + (event (plist-get msg :event))) + (cond ((string= event "posted") (mattermost--process-ws-posted msg)) + (t (lwarn 'mattermost :debug (format "INCOMING> %s" msg)))))) + (defun mattermost--connect-websocket () "Returns a websocket configured to connect to the Mattermost host and to dispatch and process the incoming messages" (websocket-open (format "wss://%s/api/v4/websocket" mattermost-host) :on-open (lambda (ws) (websocket-send-text ws (mattermost--get-auth-challenge))) - :on-message (lambda (ws frame) - (let* ((text (websocket-frame-text frame)) - (msg (json-parse-string text))) - (lwarn 'mattermost :debug (format "INCOMING> %s" msg)))) + :on-message 'mattermost--process-ws-frame :on-close (lambda (ws) (lwarn 'mattermost :error "websocket connection closed")))) @@ -124,7 +149,7 @@ if the user is not present" (response (mattermost-read-json))) (setq mattermost-token token) (setq mattermost-user-id (plist-get response :id)) - (mattermost--connect-websocket) + (setq mattermost-websocket (mattermost--connect-websocket)) token)))) ;; ToDo: update to parse headers as well @@ -169,13 +194,22 @@ if the user is not present" "Creates a post on a channel" (mattermost-request "POST" "/posts" `(:channel_id ,channel-id :message ,message))) +(defun mattermost--get-channel-display-name (channel) + "Returns the string to be used as channel display name" + (let ((channel-display-name (plist-get channel :display_name)) + (channel-name (plist-get channel :name)) + (channel-type (plist-get channel :type))) + (cond ((string= channel-type "D") + (let* ((direct-message-user-id (car (split-string channel-name "__"))) + (user (mattermost--get-user direct-message-user-id))) + (format "@%s" (plist-get user :username)))) + (t (if (string-empty-p channel-display-name) + channel-name + channel-display-name))))) + (defun mattermost-insert-channel (channel) "Inserts a channel button in the current buffer" - (let* ((channel-display-name (plist-get channel :display_name)) - (channel-name (plist-get channel :name)) - (name (if (string-empty-p channel-display-name) - channel-name - channel-display-name))) + (let* ((name (mattermost--get-channel-display-name channel))) (insert-text-button (format "> %s\n" name) :type 'mattermost-channel 'channel channel))) @@ -249,16 +283,21 @@ user to check their status and select between them") (defun mattermost-insert-post (post) "Inserts a post message in the current buffer" - (let* ((user-id (plist-get post :user_id)) + (let* ((inhibit-read-only t) + (user-id (plist-get post :user_id)) (user (mattermost--get-user user-id)) (username (plist-get user :username)) - (msg (plist-get post :message))) - (insert-text-button (format "[%s]" username) - :type 'mattermost-username - 'user user) - (insert-text-button (format " %s\n" msg) - :type 'mattermost-post - 'post post))) + (msg (plist-get post :message)) + (username-text (format "[%s]" username)) + (post-text (format " %s\n" msg))) + (insert-before-markers username-text) + (make-text-button (- (point) (length username-text)) (point) + :type 'mattermost-username + 'user user) + (insert-before-markers post-text) + (make-text-button (- (point) (length post-text)) (point) + :type 'mattermost-post + 'post post))) (defun mattermost-prompt () "Shows the message prompt" @@ -301,10 +340,8 @@ user to check their status and select between them") "Populates the channel buffer with posts and the prompt" (let* ((inhibit-read-only t) (id (plist-get channel :id)) - (display-name (plist-get channel :display_name)) - (name (plist-get channel :name)) - (cname (if (string-empty-p display-name) name display-name)) - (chanb (get-buffer-create (format "> %s <" cname)))) + (name (mattermost--get-channel-display-name channel)) + (chanb (get-buffer-create (format "> %s <" name)))) ;; ToDo: somehow check if the buffer already exists to populate it ;; only if it doesn't