From 7ed29c4dc940a871562aaa802ac53ddee4c66a27 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sat, 8 Nov 2014 14:12:42 -0500 Subject: Re-work filtering and caching * sx-auth.el - Use new symbolic cache access * sx-cache.el - Implement symbolic cache access * sx-filter.el - Use symbolic cache access - Compile and save filters on-demand (more work to be done to this end) * sx-question.el - Symbolic filters * sx-request.el - Protection against infinitely recursing when compiling a filter This will be re-worked into requests (a front-end function) and 'raw' requests (a back-end function). The front-end will add convenience to the back-end. * test/tests.el Remove outdated tests --- sx-request.el | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'sx-request.el') diff --git a/sx-request.el b/sx-request.el index a62ee0e..8ca0314 100644 --- a/sx-request.el +++ b/sx-request.el @@ -26,6 +26,7 @@ (require 'json) (require 'url) (require 'sx) +(require 'sx-filter) (defcustom sx-request-silent-p t @@ -95,8 +96,11 @@ entire response as a complex alist." (call (sx-request--build method - (append `((filter . ,(cond (filter filter) - ((boundp 'stack-filter) stack-filter))) + (append `((filter . ,(unless (string-equal method "filter/create") + (sx-filter-get-var + (cond (filter filter) + ((boundp 'stack-filter) + stack-filter))))) (key . ,sx-request-api-key)) (if keyword-arguments keyword-arguments (sx-request--get-default-keyword-arguments method)))))) -- cgit v1.2.3 From bbcbcea7d944e2ca6ae081b04b2aa71a92bec799 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sat, 8 Nov 2014 14:32:32 -0500 Subject: Add internal request function --- sx-request.el | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'sx-request.el') diff --git a/sx-request.el b/sx-request.el index 8ca0314..f24294e 100644 --- a/sx-request.el +++ b/sx-request.el @@ -84,6 +84,58 @@ See `sx-request-get-default-keyword-arguments' and "0TE6s1tveCpP9K5r5JNDNQ((" "When passed, this key provides a higher request quota.") +(defun sx-request--make + (method &optional args silent) + (let ((url-automatic-caching sx-request-cache-p) + (url-inhibit-uncompression t) + (silent (or silent sx-request-silent-p)) + (call (sx-request--build method args))) + (unless silent (sx-message "Request: %S" call)) + (let ((response-buffer (cond + ((equal '(24 . 4) (cons emacs-major-version emacs-minor-version)) + (url-retrieve-synchronously call silent)) + (t (url-retrieve-synchronously call))))) + (if (not response-buffer) + (error "Something went wrong in `url-retrieve-synchronously'") + (with-current-buffer response-buffer + (let* ((data (progn + (goto-char (point-min)) + (if (not (search-forward "\n\n" nil t)) + (error "Response headers missing; response corrupt") + (delete-region (point-min) (point)) + (buffer-string)))) + (response (ignore-errors + (json-read-from-string data)))) + ;; If the response isn't nil, the response was in plain text + (unless response + ;; try to decompress the response + (setq response + (with-demoted-errors "`json-read' error: %S" + (shell-command-on-region + (point-min) (point-max) + sx-request-unzip-program + nil t) + (json-read-from-string + (buffer-substring + (point-min) (point-max))))) + ;; if it still fails, error outline + (unless response + (sx-message "Unable to parse response: %S" response) + (error "Response could not be read by `json-read-from-string'"))) + ;; If we get here, the response is a valid data structure + (when (assoc 'error_id response) + (error "Request failed: (%s) [%i %s] %S" + method + (cdr (assoc 'error_id response)) + (cdr (assoc 'error_name response)) + (cdr (assoc 'error_message response)))) + (when (< (setq sx-request-remaining-api-requests + (cdr (assoc 'quote_remaining response))) + sx-request-remaining-api-requests-message-threshold) + (sx-message "%d API requests reamining" + sx-request-remaining-api-requests)) + (cdr (assoc 'items response)))))))) + (defun sx-request-make (method &optional keyword-arguments filter silent) "Make a request to the StackExchange API using METHOD and -- cgit v1.2.3 From 606a886fa65571c649ad15337b5b5e4bcb18e953 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sat, 8 Nov 2014 14:41:06 -0500 Subject: Use the key for every request; no exceptions --- sx-request.el | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sx-request.el') diff --git a/sx-request.el b/sx-request.el index f24294e..99c26c3 100644 --- a/sx-request.el +++ b/sx-request.el @@ -89,7 +89,10 @@ See `sx-request-get-default-keyword-arguments' and (let ((url-automatic-caching sx-request-cache-p) (url-inhibit-uncompression t) (silent (or silent sx-request-silent-p)) - (call (sx-request--build method args))) + (call (sx-request--build + method + (cons (cons 'key sx-request-api-key) + args)))) (unless silent (sx-message "Request: %S" call)) (let ((response-buffer (cond ((equal '(24 . 4) (cons emacs-major-version emacs-minor-version)) -- cgit v1.2.3 From 7c5cc6faf61f58cd1534dcab2c4dbb667c00476d Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sat, 8 Nov 2014 14:41:23 -0500 Subject: Implement front-end with back-end --- sx-request.el | 71 ++++++----------------------------------------------------- 1 file changed, 7 insertions(+), 64 deletions(-) (limited to 'sx-request.el') diff --git a/sx-request.el b/sx-request.el index 99c26c3..3656b94 100644 --- a/sx-request.el +++ b/sx-request.el @@ -145,70 +145,13 @@ See `sx-request-get-default-keyword-arguments' and optional KEYWORD-ARGUMENTS. If no KEYWORD-ARGUMENTS are given, `sx-default-keyword-arguments-alist' is used. Return the entire response as a complex alist." - (let ((url-automatic-caching sx-request-cache-p) - (url-inhibit-uncompression t) - (silent (or silent sx-request-silent-p)) - (call - (sx-request--build - method - (append `((filter . ,(unless (string-equal method "filter/create") - (sx-filter-get-var - (cond (filter filter) - ((boundp 'stack-filter) - stack-filter))))) - (key . ,sx-request-api-key)) - (if keyword-arguments keyword-arguments - (sx-request--get-default-keyword-arguments method)))))) - ;; TODO: url-retrieve-synchronously can return nil if the call is - ;; unsuccessful should handle this case - (unless silent (sx-message "Request: %S" call)) - (let ((response-buffer (cond - ((= emacs-minor-version 4) - (url-retrieve-synchronously call silent)) - (t (url-retrieve-synchronously call))))) - (if (not response-buffer) - (error "Something went wrong in `url-retrieve-synchronously'") - (with-current-buffer response-buffer - (let* ((data (progn - (goto-char (point-min)) - (if (not (search-forward "\n\n" nil t)) - (error "Response headers missing") - (delete-region (point-min) (point)) - (buffer-string)))) - (response (ignore-errors - (json-read-from-string data)))) - ;; if response isn't nil, the response was in plain text - (unless response - ;; try to decompress the response - (setq response - (with-demoted-errors "JSON Error: %s" - (shell-command-on-region - (point-min) (point-max) - sx-request-unzip-program - nil t) - (json-read-from-string - (buffer-substring - (point-min) (point-max))))) - ;; If it still fails, error out - (unless response - (sx-message "Unable to parse response") - (sx-message "Printing response as message") - (message "%S" response) - (error "Response could not be read by json-read-string"))) - ;; At this point, either response is a valid data structure - ;; or we have already thrown an error - (when (assoc 'error_id response) - (error "Request failed: (%s) [%i %s] %s" - method - (cdr (assoc 'error_id response)) - (cdr (assoc 'error_name response)) - (cdr (assoc 'error_message response)))) - (when (< (setq sx-request-remaining-api-requests - (cdr (assoc 'quota_remaining response))) - sx-request-remaining-api-requests-message-threshold) - (sx-message "%d API requests remaining" - sx-request-remaining-api-requests)) - (cdr (assoc 'items response)))))))) + (sx-request--make + method + (cons (cons 'filter + (sx-filter-get-var + (cond (filter filter) + ((boundp 'stack-filter) stack-filter)))) + keyword-arguments))) (defun sx-request--build (method keyword-arguments &optional kv-value-sep) "Build the request string that will be used to process REQUEST -- cgit v1.2.3 From 6aa21b85ace92b01676c6da66372b409fe639920 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sat, 8 Nov 2014 15:49:17 -0500 Subject: Abstract out method calls Keeping method calls within `sx-request.el' was causing circular requirements. This commit sorts through all of the requirements for each of the files and ensures that this does not happen. Much of the content removed was for `sx-request-default-keyword-arguments-alist' and related items. It was unused, so it was pruned. If it is deemed necessary in the future, it should be included in `sx-method.el'. --- sx-auth.el | 19 +++++------ sx-filter.el | 4 +-- sx-method.el | 48 ++++++++++++++++++++++++++ sx-question-list.el | 6 ++-- sx-question.el | 6 ++-- sx-request.el | 98 +++++++++++++++++------------------------------------ sx.el | 3 +- test/tests.el | 1 + 8 files changed, 99 insertions(+), 86 deletions(-) create mode 100644 sx-method.el (limited to 'sx-request.el') diff --git a/sx-auth.el b/sx-auth.el index 049827d..7912508 100644 --- a/sx-auth.el +++ b/sx-auth.el @@ -50,16 +50,15 @@ questions)." (interactive) (setq sx-auth-access-token - (let* ((sx-request-api-root sx-auth-root) - (url (sx-request--build - "dialog" - `((client_id . ,sx-auth-client-id) - (scope . (read_inbox - no_expiry - write_access)) - (redirect_uri . ,(url-hexify-string - sx-auth-redirect-uri))) - ","))) + (let ((url (sx-request-build + "dialog" + `((client_id . ,sx-auth-client-id) + (scope . (read_inbox + no_expiry + write_access)) + (redirect_uri . ,(url-hexify-string + sx-auth-redirect-uri))) + "," sx-auth-root))) (browse-url url) (read-string "Enter the access token displayed on the webpage: "))) (if (string-equal "" sx-auth-access-token) diff --git a/sx-filter.el b/sx-filter.el index 0ba8186..4ed3dbe 100644 --- a/sx-filter.el +++ b/sx-filter.el @@ -28,6 +28,7 @@ (require 'sx) (require 'sx-cache) +(require 'sx-request) ;;; Customizations @@ -53,8 +54,7 @@ or string." "filter/create" keyword-arguments))) (url-hexify-string - (cdr (assoc 'filter - (elt response 0))))))) + (cdr (assoc 'filter (elt response 0))))))) ;;; Storage and Retrieval diff --git a/sx-method.el b/sx-method.el new file mode 100644 index 0000000..8dc5a65 --- /dev/null +++ b/sx-method.el @@ -0,0 +1,48 @@ +;;; sx-request.el --- requests for stack-mode + +;; Copyright (C) 2014 Sean Allred + +;; Author: Sean Allred +;; Keywords: + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; + +;;; Code: +(require 'json) +(require 'url) +(require 'sx) +(require 'sx-request) +(require 'sx-filter) + +(defun sx-method-call + (method &optional keyword-arguments filter silent) + "Call METHOD with KEYWORD-ARGUMENTS using FILTER. + +If SILENT is non-nil, no messages will be printed. + +Return the entire response as a complex alist." + (sx-request-make + method + (cons (cons 'filter + (sx-filter-get-var + (cond (filter filter) + ((boundp 'stack-filter) stack-filter)))) + keyword-arguments))) + +(provide 'sx-method) +;;; sx-request.el ends here diff --git a/sx-question-list.el b/sx-question-list.el index 86e9194..caf24b1 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -20,11 +20,13 @@ ;;; Commentary: ;;; Code: -(require 'sx-question) -(require 'sx-time) (require 'tabulated-list) (require 'cl-lib) +(require 'sx) +(require 'sx-time) +(require 'sx-question) + ;;; Customization (defcustom sx-question-list-height 12 diff --git a/sx-question.el b/sx-question.el index 8957e6f..20a71cc 100644 --- a/sx-question.el +++ b/sx-question.el @@ -27,16 +27,14 @@ (require 'sx) (require 'sx-filter) (require 'sx-lto) -(require 'sx-request) +(require 'sx-method) -;; I don't know why this is here, but it was causing an API request on require. (defvar sx-question-browse-filter - ;; Remember: INCLUDE EXCLUDE BASE '(nil (user.profile_image shallow_user.profile_image))) (defun sx-question-get-questions (site &optional page) "Get the page PAGE of questions from SITE." - (sx-request-make + (sx-method-call "questions" `((site . ,site) (page . ,page)) diff --git a/sx-request.el b/sx-request.el index 3656b94..f987d2c 100644 --- a/sx-request.el +++ b/sx-request.el @@ -1,9 +1,9 @@ -;;; sx-request.el --- requests for stack-mode +;;; sx-request.el --- requests and url manipulation -*- lexical-binding: t; -*- ;; Copyright (C) 2014 Sean Allred -;; Author: Sean Allred -;; Keywords: +;; Author: Sean Allred +;; Keywords: help ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -23,10 +23,26 @@ ;; ;;; Code: -(require 'json) + (require 'url) +(require 'json) + (require 'sx) -(require 'sx-filter) + + +;;; Variables + +(defconst sx-request-api-key + "0TE6s1tveCpP9K5r5JNDNQ((" + "When passed, this key provides a higher request quota.") + +(defconst sx-request-api-version + "2.2" + "The current version of the API.") + +(defconst sx-request-api-root + (format "http://api.stackexchange.com/%s/" sx-request-api-version) + "The base URL to make requests from.") (defcustom sx-request-silent-p t @@ -51,45 +67,15 @@ recent call. Set by `sx-request-make'.") number, `sx-request-make' will begin printing out the number of requests left every time it finishes a call.") -(defcustom sx-request-default-keyword-arguments-alist - '(("filters/create") - ("sites") - ("questions" (site . emacs)) - (t nil)) - "Keywords to use as the default for a given method. - -The first element of each list is the method call the keywords -apply to. The remaining cons cells (and they must be conses) are -the values for each keyword. - -For each list, if no keywords are provided, the method's -arguments are forced to the default as determined by the API. - -For each cons cell, if the cdr is `nil', then the keyword will be -forced to the default as determined by the API. + +;;; Making Requests -See `sx-request-get-default-keyword-arguments' and -`sx-request-build-keyword-arguments'. -") - -(defconst sx-request-api-version - "2.2" - "The current version of the API.") - -(defconst sx-request-api-root - (format "http://api.stackexchange.com/%s/" sx-request-api-version) - "The base URL to make requests from.") - -(defconst sx-request-api-key - "0TE6s1tveCpP9K5r5JNDNQ((" - "When passed, this key provides a higher request quota.") - -(defun sx-request--make +(defun sx-request-make (method &optional args silent) (let ((url-automatic-caching sx-request-cache-p) (url-inhibit-uncompression t) (silent (or silent sx-request-silent-p)) - (call (sx-request--build + (call (sx-request-build method (cons (cons 'key sx-request-api-key) args)))) @@ -133,30 +119,19 @@ See `sx-request-get-default-keyword-arguments' and (cdr (assoc 'error_name response)) (cdr (assoc 'error_message response)))) (when (< (setq sx-request-remaining-api-requests - (cdr (assoc 'quote_remaining response))) + (cdr (assoc 'quota_remaining response))) sx-request-remaining-api-requests-message-threshold) (sx-message "%d API requests reamining" sx-request-remaining-api-requests)) (cdr (assoc 'items response)))))))) -(defun sx-request-make - (method &optional keyword-arguments filter silent) - "Make a request to the StackExchange API using METHOD and -optional KEYWORD-ARGUMENTS. If no KEYWORD-ARGUMENTS are given, -`sx-default-keyword-arguments-alist' is used. Return the -entire response as a complex alist." - (sx-request--make - method - (cons (cons 'filter - (sx-filter-get-var - (cond (filter filter) - ((boundp 'stack-filter) stack-filter)))) - keyword-arguments))) - -(defun sx-request--build (method keyword-arguments &optional kv-value-sep) + +;;; Support Functions + +(defun sx-request-build (method keyword-arguments &optional kv-value-sep root) "Build the request string that will be used to process REQUEST with the given KEYWORD-ARGUMENTS." - (let ((base (concat sx-request-api-root method)) + (let ((base (concat (or root sx-request-api-root) method)) (args (sx-request--build-keyword-arguments keyword-arguments kv-value-sep))) (if (string-equal "" args) @@ -181,16 +156,5 @@ false, use the symbol `false'. Each element is processed with alist)) "&")) -(defun sx-request--get-default-keyword-arguments (method) - "Gets the correct keyword arguments for METHOD." - (let ((entry (assoc method sx-request-default-keyword-arguments-alist))) - (cdr (or entry (assoc t sx-request-default-keyword-arguments-alist))))) - -;;; @todo sx-request-change-default-keyword-arguments -;;; (method new-keyword-arguments) -;;; @todo sx-request-change-default-keyword-arguments-for-key -;;; (method key new-value) - - (provide 'sx-request) ;;; sx-request.el ends here diff --git a/sx.el b/sx.el index 54ad8d0..2f7b6a7 100644 --- a/sx.el +++ b/sx.el @@ -25,7 +25,8 @@ ;;; Code: -;;; Requirements +;;; Utility Functions + (defun sx-message (format-string &rest args) "Display a message" (message "[stack] %s" (apply #'format format-string args))) diff --git a/test/tests.el b/test/tests.el index 7915ac0..a66394c 100644 --- a/test/tests.el +++ b/test/tests.el @@ -35,6 +35,7 @@ (expand-file-name (format "../../.cask/%s/elpa" emacs-version) sx-test-data-dir)) (package-initialize) + (require 'cl-lib) (require 'sx) (require 'sx-question) -- cgit v1.2.3 From b8da42344ebe3f380bb6f615c2ab13bb12c24876 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sat, 8 Nov 2014 16:54:51 -0500 Subject: Use macro --- sx-request.el | 22 ++++++++++------------ sx.el | 5 +++++ 2 files changed, 15 insertions(+), 12 deletions(-) (limited to 'sx-request.el') diff --git a/sx-request.el b/sx-request.el index f987d2c..4e2ba5c 100644 --- a/sx-request.el +++ b/sx-request.el @@ -112,18 +112,16 @@ number of requests left every time it finishes a call.") (sx-message "Unable to parse response: %S" response) (error "Response could not be read by `json-read-from-string'"))) ;; If we get here, the response is a valid data structure - (when (assoc 'error_id response) - (error "Request failed: (%s) [%i %s] %S" - method - (cdr (assoc 'error_id response)) - (cdr (assoc 'error_name response)) - (cdr (assoc 'error_message response)))) - (when (< (setq sx-request-remaining-api-requests - (cdr (assoc 'quota_remaining response))) - sx-request-remaining-api-requests-message-threshold) - (sx-message "%d API requests reamining" - sx-request-remaining-api-requests)) - (cdr (assoc 'items response)))))))) + (sx-assoc-let response + (when error_id + (error "Request failed: (%s) [%i %s] %S" + method error_id error_name error_message)) + (when (< (setq sx-request-remaining-api-requests + quota_remaining) + sx-request-remaining-api-requests-message-threshold) + (sx-message "%d API requests reamining" + sx-request-remaining-api-requests)) + items))))))) ;;; Support Functions diff --git a/sx.el b/sx.el index 2f7b6a7..00fda40 100644 --- a/sx.el +++ b/sx.el @@ -87,7 +87,11 @@ a string, just return it." display_name downvoted edited + error_id + error_name + error_message favorite_count + items is_accepted is_answered last_activity_date @@ -97,6 +101,7 @@ a string, just return it." owner profile_image question_id + quota_remaining reopen_vote_count reputation score -- cgit v1.2.3 From 4207f8a4764ad3a0bca402160a24cca714cf0cde Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Sat, 8 Nov 2014 18:02:36 -0500 Subject: Consolidate keywords, update emails --- stack-exchange.el | 30 ++++++++++++++++++++++++++++++ sx-cache.el | 3 +-- sx-encoding.el | 3 +-- sx-request.el | 3 +-- sx-time.el | 3 +-- 5 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 stack-exchange.el (limited to 'sx-request.el') diff --git a/stack-exchange.el b/stack-exchange.el new file mode 100644 index 0000000..bca777b --- /dev/null +++ b/stack-exchange.el @@ -0,0 +1,30 @@ +;;; stack-exchange.el --- A StackExchange Mode -*- lexical-binding: t; -*- + +;; Copyright (C) 2014 Sean Allred + +;; Author: Sean Allred +;; Keywords: help, hypermedia, mail, news, tools + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program. If not, see . + +;;; Commentary: + +;; + +;;; Code: + +(mapc #'load (file-expand-wildcards "sx*.el")) + +(provide 'stack-exchange) +;;; stack-exchange.el ends here diff --git a/sx-cache.el b/sx-cache.el index a090982..ed4895a 100644 --- a/sx-cache.el +++ b/sx-cache.el @@ -2,8 +2,7 @@ ;; Copyright (C) 2014 Sean Allred -;; Author: Sean Allred -;; Keywords: help +;; Author: Sean Allred ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by diff --git a/sx-encoding.el b/sx-encoding.el index efb333e..8ac12ca 100644 --- a/sx-encoding.el +++ b/sx-encoding.el @@ -2,8 +2,7 @@ ;; Copyright (C) 2014 Sean Allred -;; Author: Sean Allred -;; Keywords: help +;; Author: Sean Allred ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by diff --git a/sx-request.el b/sx-request.el index a62ee0e..e9f52f3 100644 --- a/sx-request.el +++ b/sx-request.el @@ -2,8 +2,7 @@ ;; Copyright (C) 2014 Sean Allred -;; Author: Sean Allred -;; Keywords: +;; Author: Sean Allred ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by diff --git a/sx-time.el b/sx-time.el index 1cea76f..1c8e353 100644 --- a/sx-time.el +++ b/sx-time.el @@ -2,8 +2,7 @@ ;; Copyright (C) 2014 Sean Allred -;; Author: Sean Allred -;; Keywords: help +;; Author: Sean Allred ;; This program is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by -- cgit v1.2.3 From 302be04d826a3f09c8cd3d313592f7976fa8c0cb Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Mon, 10 Nov 2014 22:53:10 -0500 Subject: Proper GZIP testing Test for a GZIP'd using magic bytes. See the appropriate answer on Emacs.SE (1) for details. (1): http://emacs.stackexchange.com/a/2978 --- sx-encoding.el | 29 +++++++++++++++++++++++++++++ sx-request.el | 28 +++++++++++----------------- 2 files changed, 40 insertions(+), 17 deletions(-) (limited to 'sx-request.el') diff --git a/sx-encoding.el b/sx-encoding.el index 8ac12ca..98f3a7c 100644 --- a/sx-encoding.el +++ b/sx-encoding.el @@ -74,6 +74,35 @@ (substring ss 1)))))))) (replace-regexp-in-string "&[^; ]*;" get-function string))) +(defun sx-encoding-gzipped-p (data) + "Checks for magic bytes in DATA. + +Check if the first two bytes of a string in DATA match magic +numbers identifying the gzip file format. See [1] for the file +format description. + +http://www.gzip.org/zlib/rfc-gzip.html + +http://emacs.stackexchange.com/a/2978" + (equal (substring (string-as-unibyte data) 0 2) + (unibyte-string 31 139))) + +(defun sx-encoding-gzipped-buffer-p (filename) + "Check if the BUFFER is gzip-compressed. + +See `gzip-check-magic' for details." + (sx-encoding-gzip-check-magic (buffer-string))) + +(defun sx-encoding-gzipped-file-p (file) + "Check if the FILE is gzip-compressed. + +See `gzip-check-magic' for details." + (let ((first-two-bytes (with-temp-buffer + (set-buffer-multibyte nil) + (insert-file-contents-literally file nil 0 2) + (buffer-string)))) + (gzip-check-magic first-two-bytes))) + (provide 'sx-encoding) ;;; sx-encoding.el ends here diff --git a/sx-request.el b/sx-request.el index 9d9dca4..12d2b14 100644 --- a/sx-request.el +++ b/sx-request.el @@ -92,24 +92,18 @@ number of requests left every time it finishes a call.") (error "Response headers missing; response corrupt") (delete-region (point-min) (point)) (buffer-string)))) - (response (ignore-errors + (response-zipped-p (sx-encoding-gzipped-p data)) + (data (if (not response-zipped-p) data + (shell-command-on-region + (point-min) (point-max) + sx-request-unzip-program + nil t) + (buffer-string))) + (response (with-demoted-errors "`json' error: %S" (json-read-from-string data)))) - ;; If the response isn't nil, the response was in plain text - (unless response - ;; try to decompress the response - (setq response - (with-demoted-errors "`json-read' error: %S" - (shell-command-on-region - (point-min) (point-max) - sx-request-unzip-program - nil t) - (json-read-from-string - (buffer-substring - (point-min) (point-max))))) - ;; if it still fails, error outline - (unless response - (sx-message "Unable to parse response: %S" response) - (error "Response could not be read by `json-read-from-string'"))) + (unless (not (and (not response) (string-equal data "{}"))) + (sx-message "Unable to parse response: %S" response) + (error "Response could not be read by `json-read-from-string'")) ;; If we get here, the response is a valid data structure (sx-assoc-let response (when error_id -- cgit v1.2.3 From 2e9b78adcb7f10c6ef645db3f11e6e444acc26e3 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Mon, 10 Nov 2014 22:57:31 -0500 Subject: Include encoding functions --- sx-request.el | 1 + 1 file changed, 1 insertion(+) (limited to 'sx-request.el') diff --git a/sx-request.el b/sx-request.el index 12d2b14..92c3041 100644 --- a/sx-request.el +++ b/sx-request.el @@ -27,6 +27,7 @@ (require 'json) (require 'sx) +(require 'sx-encoding) ;;; Variables -- cgit v1.2.3 From 94e649f7318b2518fe31af7cdea74b7f7bfde1e3 Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Tue, 11 Nov 2014 08:47:46 -0500 Subject: Simplify logical structure --- sx-request.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sx-request.el') diff --git a/sx-request.el b/sx-request.el index 92c3041..56362fc 100644 --- a/sx-request.el +++ b/sx-request.el @@ -102,7 +102,7 @@ number of requests left every time it finishes a call.") (buffer-string))) (response (with-demoted-errors "`json' error: %S" (json-read-from-string data)))) - (unless (not (and (not response) (string-equal data "{}"))) + (when (and (not response) (string-equal data "{}")) (sx-message "Unable to parse response: %S" response) (error "Response could not be read by `json-read-from-string'")) ;; If we get here, the response is a valid data structure -- cgit v1.2.3 From 08eea895f1a445156c2e1c382bf167ba6d9d4515 Mon Sep 17 00:00:00 2001 From: Artur Malabarba Date: Wed, 12 Nov 2014 21:19:31 +0000 Subject: Update code to new assoc-let --- sx-filter.el | 2 +- sx-question-list.el | 16 ++++++++-------- sx-request.el | 9 +++++---- sx.el | 2 +- 4 files changed, 15 insertions(+), 14 deletions(-) (limited to 'sx-request.el') diff --git a/sx-filter.el b/sx-filter.el index aa815a2..acd8fc1 100644 --- a/sx-filter.el +++ b/sx-filter.el @@ -54,7 +54,7 @@ or string." "filter/create" keyword-arguments))) (sx-assoc-let (elt response 0) - (url-hexify-string filter))))) + (url-hexify-string .filter))))) ;;; Storage and Retrieval diff --git a/sx-question-list.el b/sx-question-list.el index caf24b1..ebd4e97 100644 --- a/sx-question-list.el +++ b/sx-question-list.el @@ -205,26 +205,26 @@ Used in the questions list to indicate a question was updated \"4d ago\"." (list data (vector - (list (int-to-string score) - 'face (if upvoted 'sx-question-list-score-upvoted + (list (int-to-string .score) + 'face (if .upvoted 'sx-question-list-score-upvoted 'sx-question-list-score)) - (list (int-to-string answer_count) - 'face (if (sx-question--accepted-answer data) + (list (int-to-string .answer_count) + 'face (if (sx-question--accepted-answer .data) 'sx-question-list-answers-accepted 'sx-question-list-answers)) (concat (propertize - title - 'face (if (sx-question--read-p data) + .title + 'face (if (sx-question--read-p .data) 'sx-question-list-read-question ;; Increment `sx-question-list--unread-count' for the mode-line. (cl-incf sx-question-list--unread-count) 'sx-question-list-unread-question)) (propertize " " 'display "\n ") - (propertize (concat (sx-time-since last_activity_date) + (propertize (concat (sx-time-since .last_activity_date) sx-question-list-ago-string) 'face 'sx-question-list-date) - (propertize (concat " [" (mapconcat #'identity tags "] [") "]") + (propertize (concat " [" (mapconcat #'identity .tags "] [") "]") 'face 'sx-question-list-tags) (propertize " " 'display "\n")))))) diff --git a/sx-request.el b/sx-request.el index 56362fc..f8feb22 100644 --- a/sx-request.el +++ b/sx-request.el @@ -107,15 +107,16 @@ number of requests left every time it finishes a call.") (error "Response could not be read by `json-read-from-string'")) ;; If we get here, the response is a valid data structure (sx-assoc-let response - (when error_id + (when .error_id (error "Request failed: (%s) [%i %s] %S" - method error_id error_name error_message)) + .method .error_id .error_name .error_message)) (when (< (setq sx-request-remaining-api-requests - quota_remaining) + .quota_remaining) sx-request-remaining-api-requests-message-threshold) (sx-message "%d API requests reamining" sx-request-remaining-api-requests)) - items))))))) + :hi + .items))))))) ;;; Support Functions diff --git a/sx.el b/sx.el index 34be85e..7ed56d3 100644 --- a/sx.el +++ b/sx.el @@ -81,7 +81,7 @@ symbol, the cdr is the symbol without the `.'." (when (string-match "\\`\\." name) ;; Return the cons cell inside a list, so it can be appended ;; with other results in the clause below. - (list (cons data (intern (replace-match "" name))))))) + (list (cons data (intern (replace-match "" nil nil name))))))) ((not (listp data)) nil) (t (apply #'append -- cgit v1.2.3 From 9c2e07f01f41c223b07356c4bd495e6f7edd1d0f Mon Sep 17 00:00:00 2001 From: Sean Allred Date: Wed, 12 Nov 2014 17:56:00 -0500 Subject: Remove spurious line --- sx-request.el | 1 - 1 file changed, 1 deletion(-) (limited to 'sx-request.el') diff --git a/sx-request.el b/sx-request.el index f8feb22..dd98ead 100644 --- a/sx-request.el +++ b/sx-request.el @@ -115,7 +115,6 @@ number of requests left every time it finishes a call.") sx-request-remaining-api-requests-message-threshold) (sx-message "%d API requests reamining" sx-request-remaining-api-requests)) - :hi .items))))))) -- cgit v1.2.3