2012-05-25 20:57:48 +02:00
|
|
|
;;; ein-query.el --- jQuery like interface on to of url-retrieve
|
|
|
|
|
|
|
|
;; Copyright (C) 2012- Takafumi Arakaki
|
|
|
|
|
|
|
|
;; Author: Takafumi Arakaki
|
|
|
|
|
|
|
|
;; This file is NOT part of GNU Emacs.
|
|
|
|
|
|
|
|
;; ein-query.el 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.
|
|
|
|
|
|
|
|
;; ein-query.el 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 ein-query.el. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
;;; Commentary:
|
|
|
|
|
|
|
|
;;
|
|
|
|
|
|
|
|
;;; Code:
|
|
|
|
|
|
|
|
(eval-when-compile (require 'cl))
|
|
|
|
(require 'url)
|
|
|
|
|
|
|
|
(require 'ein-utils)
|
|
|
|
(require 'ein-log)
|
|
|
|
|
|
|
|
(defun ein:safe-funcall-packed (packed &rest args)
|
|
|
|
(when packed
|
|
|
|
(ein:log-ignore-errors (apply #'ein:funcall-packed packed args))))
|
|
|
|
|
2012-05-26 19:08:15 +02:00
|
|
|
(defmacro ein:with-live-buffer (buffer &rest body)
|
|
|
|
"Execute BODY if BUFFER is alive."
|
|
|
|
(declare (indent 1) (debug t))
|
|
|
|
`(when (buffer-live-p ,buffer) (with-current-buffer ,buffer ,@body)))
|
|
|
|
|
2012-05-27 01:58:39 +02:00
|
|
|
|
|
|
|
(defcustom ein:query-timeout 5000
|
|
|
|
"Default query timeout."
|
|
|
|
:type '(choice (integer :tag "Timeout [ms]" 5000)
|
|
|
|
(const :tag "No timeout" nil))
|
|
|
|
:group 'ein)
|
|
|
|
|
2012-05-26 16:34:04 +02:00
|
|
|
(ein:deflocal ein:query-ajax-timer nil)
|
|
|
|
|
2012-05-25 20:57:48 +02:00
|
|
|
(defun* ein:query-ajax (url &rest settings
|
|
|
|
&key
|
|
|
|
(cache t)
|
|
|
|
(type "GET")
|
|
|
|
(data nil)
|
2012-05-26 20:23:22 +02:00
|
|
|
(parser nil)
|
2012-05-25 20:57:48 +02:00
|
|
|
(headers nil)
|
|
|
|
(success nil)
|
|
|
|
(error nil)
|
|
|
|
(timeout nil)
|
|
|
|
(status-code nil))
|
|
|
|
"Mimic `$.ajax'.
|
|
|
|
|
|
|
|
:CACHE (nil/t) : append time-stamp to URL so the URL is always loaded.
|
|
|
|
:TYPE (string) : sets `url-request-method'
|
|
|
|
:DATA (string) : sets `url-request-data'
|
2012-05-26 20:23:22 +02:00
|
|
|
:PARSER (symbol) : a function that reads current buffer and return data
|
2012-05-25 20:57:48 +02:00
|
|
|
:HEADERS (alist) : sets `url-request-extra-headers'
|
|
|
|
:SUCCESS (cons) : called on success
|
|
|
|
:ERROR (cons) : called on error
|
|
|
|
:TIMEOUT (number) : timeout in millisecond
|
|
|
|
:STATUS-CODE (alist) : map status code (int) to callback (cons)
|
|
|
|
|
|
|
|
* Callback functions
|
|
|
|
|
|
|
|
All callbacks must be given as `cons' where car is a FUNCTION and
|
|
|
|
cdr is its first ARGUMENT. It is analogous of `$.proxy'. Call
|
|
|
|
signature is like this:
|
|
|
|
\(FUNCTION ARGUMENT [other callback specific arguments])
|
|
|
|
|
2012-05-26 20:00:17 +02:00
|
|
|
Also note that the callback FUNCTION must be defined
|
2012-05-25 20:57:48 +02:00
|
|
|
using `defun*' with `&key' and `&allow-other-keys' to ignore
|
|
|
|
missing/extra arguments as some callback (namely :ERROR) changes
|
|
|
|
arguments to be passed, depending on situation.
|
|
|
|
|
|
|
|
* :ERROR callback
|
|
|
|
|
|
|
|
:SYMBOL-STATUS (`error'/`timeout') : analogous of `textStatus'
|
|
|
|
:STATUS (list) : see `url-retrieve'
|
2012-05-26 20:00:17 +02:00
|
|
|
:RESPONSE-STATUS : = `url-http-response-status'
|
|
|
|
|
|
|
|
* :SUCCESS callback
|
2012-05-25 20:57:48 +02:00
|
|
|
|
2012-05-26 20:00:17 +02:00
|
|
|
This callback takes :DATA (object), which is a data object parsed
|
2012-05-26 20:23:22 +02:00
|
|
|
by :PARSER. If :PARSER is not specified, this is nil.
|
2012-05-26 20:00:17 +02:00
|
|
|
The :SUCCESS callback also takes the :STATUS and :RESPONSE-STATUS
|
|
|
|
argument.
|
2012-05-25 20:57:48 +02:00
|
|
|
|
2012-05-26 19:25:00 +02:00
|
|
|
* :STATUS-CODE callback
|
|
|
|
|
|
|
|
Each value of this alist is a callback which is similar to :ERROR
|
|
|
|
or :SUCCESS callback. However, current buffer of this callback
|
|
|
|
is not guaranteed to be the process buffer.
|
|
|
|
|
2012-05-26 20:23:22 +02:00
|
|
|
* :PARSER function
|
|
|
|
|
|
|
|
This is analogous to the `dataType' argument of `$.ajax'.
|
|
|
|
Only this function can accuses to the process buffer, which
|
|
|
|
is killed immediately after the execution of this function.
|
|
|
|
|
2012-05-25 20:57:48 +02:00
|
|
|
* See also: http://api.jquery.com/jQuery.ajax/"
|
2012-05-26 16:34:04 +02:00
|
|
|
(ein:log 'debug "EIN:QUERY-AJAX")
|
2012-05-25 20:57:48 +02:00
|
|
|
(unless cache
|
|
|
|
(setq url (ein:url-no-cache url)))
|
|
|
|
(let* ((url-request-extra-headers headers)
|
|
|
|
(url-request-method type)
|
|
|
|
(url-request-data data)
|
|
|
|
(buffer (url-retrieve url #'ein:query-ajax-callback settings)))
|
2012-05-27 01:58:39 +02:00
|
|
|
(unless timeout (setq timeout ein:query-timeout))
|
2012-05-25 20:57:48 +02:00
|
|
|
(when timeout
|
2012-05-26 16:34:04 +02:00
|
|
|
(ein:log 'debug "Start timer: timeout=%s ms" timeout)
|
|
|
|
(with-current-buffer buffer
|
|
|
|
(setq ein:query-ajax-timer
|
2012-05-26 17:01:23 +02:00
|
|
|
(apply #'run-at-time
|
|
|
|
(/ timeout 1000.0) nil
|
|
|
|
#'ein:query-ajax-timeout-callback
|
|
|
|
(cons buffer settings)))))
|
2012-05-25 20:57:48 +02:00
|
|
|
buffer))
|
|
|
|
|
|
|
|
(defun* ein:query-ajax-callback (status &key
|
|
|
|
(headers nil)
|
2012-05-26 20:23:22 +02:00
|
|
|
(parser nil)
|
2012-05-25 20:57:48 +02:00
|
|
|
(success nil)
|
|
|
|
(error nil)
|
|
|
|
(timeout nil)
|
|
|
|
(status-code nil)
|
|
|
|
&allow-other-keys)
|
2012-05-26 17:21:47 +02:00
|
|
|
(declare (special url-http-response-status))
|
2012-05-26 20:00:17 +02:00
|
|
|
|
|
|
|
(ein:log 'debug "EIN:QUERY-AJAX-CALLBACK")
|
|
|
|
(ein:log 'debug "status = %S" status)
|
|
|
|
(ein:log 'debug "url-http-response-status = %s" url-http-response-status)
|
|
|
|
(ein:log 'debug "(buffer-string) =\n%s" (buffer-string))
|
|
|
|
|
|
|
|
(ein:query-ajax-cancel-timer)
|
2012-05-26 20:23:22 +02:00
|
|
|
(let* ((buffer (current-buffer)) ; `parser' could change buffer...
|
2012-05-26 20:00:17 +02:00
|
|
|
(response-status url-http-response-status)
|
|
|
|
(status-code-callback (cdr (assq response-status status-code)))
|
|
|
|
(status-error (plist-get status :error))
|
2012-05-26 20:23:22 +02:00
|
|
|
(data (if (and parser (not status-error))
|
2012-05-26 20:00:17 +02:00
|
|
|
(unwind-protect
|
2012-05-26 20:23:22 +02:00
|
|
|
(funcall parser)
|
2012-05-26 20:00:17 +02:00
|
|
|
(kill-buffer buffer)))))
|
2012-05-26 20:41:21 +02:00
|
|
|
(ein:log 'debug "data = %s" data)
|
2012-05-26 20:00:17 +02:00
|
|
|
|
|
|
|
(ein:log 'debug "Executing success/error callback.")
|
|
|
|
(apply #'ein:safe-funcall-packed
|
2012-05-26 22:55:23 +02:00
|
|
|
(append (if (plist-get status :error)
|
|
|
|
(list error :symbol-status 'error)
|
|
|
|
(list success))
|
|
|
|
(list :status status :data data
|
|
|
|
:response-status response-status)))
|
2012-05-26 20:00:17 +02:00
|
|
|
|
|
|
|
(ein:log 'debug "Executing status-code callback.")
|
|
|
|
(ein:safe-funcall-packed status-code-callback
|
|
|
|
:status status :data data)))
|
2012-05-25 20:57:48 +02:00
|
|
|
|
|
|
|
(defun* ein:query-ajax-timeout-callback (buffer &key
|
|
|
|
(error nil)
|
|
|
|
&allow-other-keys)
|
2012-05-26 17:01:23 +02:00
|
|
|
(ein:log 'debug "EIN:QUERY-AJAX-TIMEOUT-CALLBACK buffer = %s" buffer)
|
2012-05-26 19:08:15 +02:00
|
|
|
(ein:with-live-buffer buffer
|
|
|
|
(ein:safe-funcall-packed error :symbol-status 'timeout)
|
2012-06-08 00:37:48 +02:00
|
|
|
(let ((proc (get-buffer-process buffer)))
|
|
|
|
(delete-process proc)
|
2012-05-26 19:08:15 +02:00
|
|
|
(kill-buffer buffer))))
|
2012-05-25 20:57:48 +02:00
|
|
|
|
2012-05-26 16:34:04 +02:00
|
|
|
(defun ein:query-ajax-cancel-timer ()
|
|
|
|
(ein:log 'debug "EIN:QUERY-AJAX-CANCEL-TIMER")
|
|
|
|
(when ein:query-ajax-timer
|
2012-05-26 17:00:21 +02:00
|
|
|
(cancel-timer ein:query-ajax-timer)
|
|
|
|
(setq ein:query-ajax-timer nil)))
|
2012-05-26 16:34:04 +02:00
|
|
|
|
2012-05-25 20:57:48 +02:00
|
|
|
(provide 'ein-query)
|
|
|
|
|
|
|
|
;;; ein-query.el ends here
|