aboutsummaryrefslogtreecommitdiff
path: root/lisp/mastodon-http.el
blob: 9dbad6f08046471b98ce5aecaa8157ec45b70376 (plain) (blame)
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
;;; mastodon-http.el --- HTTP request/response functions for mastodon.el

;;; Commentary:

;; mastodon.el is an Emacs client for Mastodon, the federated microblogging
;; social network. It is very much a work-in-progress, but it is a labor of
;; love.

;; mastodon-http.el provides HTTP request/response functions.

;;; Code:

(require 'mastodon)
(require 'json)

(defgroup mastodon-http nil
  "HTTP requests and responses for Mastodon."
  :prefix "mastodon-http-"
  :group 'mastodon)

(defun mastodon--api-for (endpoint)
  "Return Mastondon API URL for ENDPOINT."
  (concat mastodon-instance-url "/api/" mastodon--api-version "/" endpoint))

(defun mastodon--http-post (url callback args &optional headers)
  "Make POST request to URL.

Response buffer is passed to CALLBACK function.
ARGS and HEADERS alist arguments are part of the POST request."
  (let ((url-request-method "POST")
        (url-request-extra-headers
         (append '(("Content-Type" . "application/x-www-form-urlencoded")) headers))
        (url-request-data
         (mapconcat (lambda (arg)
                      (concat (url-hexify-string (car arg))
                              "="
                              (url-hexify-string (cdr arg))))
                    args
                    "&")))
    (url-retrieve url callback)))

(defun mastodon--response-buffer ()
  "Capture response buffer content as string."
  (with-current-buffer (current-buffer)
    (buffer-substring-no-properties (point-min) (point-max))))

(defun mastodon--response-body-substring (pattern)
  "Return substring matching PATTERN from `mastodon--response-buffer'."
  (let ((resp (mastodon--response-buffer)))
    (progn
      (string-match pattern resp)
      (match-string 0 resp))))

(defun mastodon--response-match-p (pattern)
  "Return non-nil if `mastodon--response-buffer' matches PATTERN."
  (let ((resp (mastodon--response-buffer)))
    (string-match-p pattern resp)))

(defun mastodon--response-status-p ()
  "Return non-nil if `mastodon--response-buffer' has an HTTP Response Status-Line."
  (when (mastodon--response-match-p "^HTTP/1.*$") t))

(defun mastodon--response-json ()
  "Return string of JSON response body from `mastodon--response-buffer'."
  (mastodon--response-body-substring "\{.*\}"))

(defun mastodon--response-code ()
  "Return HTTP Response Status Code from `mastodon--response-buffer'."
  (let* ((status-line (mastodon--response-body-substring "^HTTP/1.*$")))
    (progn
      (string-match "[0-9][0-9][0-9]" status-line)
      (match-string 0 status-line))))

(defun mastodon--json-hash-table ()
  "Read JSON from `mastodon--response-json' into a hash table."
  (let ((json-object-type 'hash-table)
        (json-array-type 'list)
        (json-key-type 'string))
    (json-read-from-string (mastodon--response-json))))

(defun mastodon--http-response-triage (status success)
  "Callback function to triage an HTTP response.

Recursively waits for `mastodon--response-buffer' to contain a Status-Line.

STATUS is passed by `url-retrieve'.
SUCCESS is a function called on a 2XX level response code.
If response code is not 2XX, switches to the response buffer created by `url-retrieve'."
  (when (not (mastodon--response-status-p))
    (mastodon--http-response-triage status))
  (if (string-prefix-p "2" (mastodon--response-code))
      (funcall success)
    (switch-to-buffer (current-buffer))))

(provide 'mastodon-http)
;;; mastodon-http.el ends here