diff --git a/doc/source/index.rst b/doc/source/index.rst index cc408b5..0acb838 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -263,6 +263,8 @@ Notebook .. el:variable:: ein:notebook-discard-output-on-save .. el:variable:: ein:notebook-modes .. el:variable:: ein:notebook-kill-buffer-ask +.. el:variable:: ein:notebook-querty-timeout-open +.. el:variable:: ein:notebook-querty-timeout-save .. el:variable:: ein:notebook-console-security-dir .. el:variable:: ein:notebook-console-executable .. el:variable:: ein:notebook-console-args diff --git a/ein-kernel.el b/ein-kernel.el index 0782bd0..30e8d6a 100644 --- a/ein-kernel.el +++ b/ein-kernel.el @@ -110,7 +110,8 @@ FIXME: document other slots." (defun ein:kernel-start (kernel notebook-id) "Start kernel of the notebook whose id is NOTEBOOK-ID." (unless (ein:$kernel-running kernel) - (ein:query-ajax + (ein:query-singleton-ajax + (list 'kernel-start (ein:$kernel-kernel-id kernel)) (concat (ein:url (ein:$kernel-url-or-port kernel) (ein:$kernel-base-url kernel)) "?" (format "notebook=%s" notebook-id)) @@ -125,7 +126,8 @@ FIXME: document other slots." (ein:log 'info "Restarting kernel") (when (ein:$kernel-running kernel) (ein:kernel-stop-channels kernel) - (ein:query-ajax + (ein:query-singleton-ajax + (list 'kernel-restart (ein:$kernel-kernel-id kernel)) (ein:url (ein:$kernel-url-or-port kernel) (ein:$kernel-kernel-url kernel) "restart") @@ -391,7 +393,8 @@ http://ipython.org/ipython-doc/dev/development/messaging.html#complete (defun ein:kernel-interrupt (kernel) (when (ein:$kernel-running kernel) (ein:log 'info "Interrupting kernel") - (ein:query-ajax + (ein:query-singleton-ajax + (list 'kernel-interrupt (ein:$kernel-kernel-id kernel)) (ein:url (ein:$kernel-url-or-port kernel) (ein:$kernel-kernel-url kernel) "interrupt") @@ -403,7 +406,8 @@ http://ipython.org/ipython-doc/dev/development/messaging.html#complete (defun ein:kernel-kill (kernel &optional callback cbargs) (when (ein:$kernel-running kernel) - (ein:query-ajax + (ein:query-singleton-ajax + (list 'kernel-kill (ein:$kernel-kernel-id kernel)) (ein:url (ein:$kernel-url-or-port kernel) (ein:$kernel-kernel-url kernel)) :cache nil diff --git a/ein-notebook.el b/ein-notebook.el index 6b8831e..c917380 100644 --- a/ein-notebook.el +++ b/ein-notebook.el @@ -115,6 +115,28 @@ yet. So be careful when using EIN functions. They may change." (yes t) (t (funcall ein:notebook-discard-output-on-save notebook cell)))) +;; As opening/saving notebook treats possibly huge data, define these +;; timeouts separately: + +(defcustom ein:notebook-querty-timeout-open (* 60 1000) ; 1 min + "Query timeout for opening notebook. +If you cannot open large notebook because of timeout error, try +to increase this value. Setting this value to `nil' means to use +global setting. For global setting and more information, see +`ein:query-timeout'." + :type '(choice (integer :tag "Timeout [ms]" 5000) + (const :tag "Use global setting" nil)) + :group 'ein) + +(defcustom ein:notebook-querty-timeout-save (* 60 1000) ; 1 min + "Query timeout for saving notebook. +Similar to `ein:notebook-querty-timeout-open', but for saving +notebook. For global setting and more information, see +`ein:query-timeout'." + :type '(choice (integer :tag "Timeout [ms]" 5000) + (const :tag "Use global setting" nil)) + :group 'ein) + ;;; Class and variable @@ -285,8 +307,10 @@ See `ein:notebook-open' for more information." (let ((url (ein:notebook-url-from-url-and-id url-or-port notebook-id)) (notebook (ein:notebook-new url-or-port notebook-id))) (ein:log 'debug "Opening notebook at %s" url) - (ein:query-ajax + (ein:query-singleton-ajax + (list 'notebook-open url-or-port notebook-id) url + :timeout ein:notebook-querty-timeout-open :parser #'ein:json-read :success (cons #'ein:notebook-request-open-callback-with-callback (list notebook callback cbargs))) @@ -994,8 +1018,12 @@ shared output buffer. You can open the buffer by the command (push `(nbformat . ,(ein:$notebook-nbformat notebook)) data) (ein:events-trigger (ein:$notebook-events notebook) 'notebook_saving.Notebook) - (ein:query-ajax + (ein:query-singleton-ajax + (list 'notebook-save + (ein:$notebook-url-or-port notebook) + (ein:$notebook-notebook-id notebook)) (ein:notebook-url notebook) + :timeout ein:notebook-querty-timeout-save :type "PUT" :headers '(("Content-Type" . "application/json")) :cache nil @@ -1041,10 +1069,13 @@ shared output buffer. You can open the buffer by the command (ein:events-trigger (ein:$notebook-events notebook) 'notebook_saved.Notebook)) -(defun ein:notebook-save-notebook-error (notebook &rest ignore) - (ein:log 'info "Failed to save notebook!") - (ein:events-trigger (ein:$notebook-events notebook) - 'notebook_save_failed.Notebook)) +(defun* ein:notebook-save-notebook-error (notebook &key symbol-status + &allow-other-keys) + (if (eq symbol-status 'user-cancel) + (ein:log 'info "Cancel saving notebook.") + (ein:log 'info "Failed to save notebook!") + (ein:events-trigger (ein:$notebook-events notebook) + 'notebook_save_failed.Notebook))) (defun ein:notebook-rename-command (name) "Rename current notebook and save it immediately. diff --git a/ein-notebooklist.el b/ein-notebooklist.el index c2554e6..302c20b 100644 --- a/ein-notebooklist.el +++ b/ein-notebooklist.el @@ -91,7 +91,8 @@ (lambda (&rest args) (pop-to-buffer (apply #'ein:notebooklist-url-retrieve-callback args)))))) - (ein:query-ajax + (ein:query-singleton-ajax + (list 'notebooklist-open url-or-port) (ein:notebooklist-url url-or-port) :cache nil :parser #'ein:json-read @@ -146,7 +147,8 @@ (assert url-or-port nil (concat "URL-OR-PORT is not given and the current buffer " "is not the notebook list buffer.")) - (ein:query-ajax + (ein:query-singleton-ajax + (list 'notebooklist-new-notebook url-or-port) (ein:notebooklist-new-url url-or-port) :parser (lambda () (ein:notebooklist-get-data-in-body-tag "data-notebook-id")) @@ -200,7 +202,9 @@ This value is used from `ein:notebooklist-new-scratch-notebook'." (defun ein:notebooklist-delete-notebook (notebook-id name) (message "Deleting notebook %s..." name) - (ein:query-ajax + (ein:query-singleton-ajax + (list 'notebooklist-delete-notebook + (ein:$notebooklist-url-or-port ein:notebooklist) notebook-id) (ein:notebook-url-from-url-and-id (ein:$notebooklist-url-or-port ein:notebooklist) notebook-id) diff --git a/ein-query.el b/ein-query.el index e0267ef..f98effc 100644 --- a/ein-query.el +++ b/ein-query.el @@ -46,8 +46,24 @@ ;;; Variables -(defcustom ein:query-timeout 5000 - "Default query timeout for HTTP access in millisecond." +(defcustom ein:query-timeout 1000 + "Default query timeout for HTTP access in millisecond. + +Setting this to `nil' means no timeout. + +If you do the same operation before the timeout, old operation +will be canceled \(see also `ein:query-singleton-ajax'). + +.. note:: This value exists because it looks like `url-retrieve' + occasionally fails to finish \(start?) querying. Timeout is + used to let user notice that their operation is not finished. + It also prevent opening a lot of useless process buffers. + You will see them when closing Emacs if there is no timeout. + + If you know how to fix the problem with `url-retrieve', please + let me know or send pull request at github! + \(Related bug report in Emacs bug tracker: + http://debbugs.gnu.org/cgi/bugreport.cgi?bug=11469)" :type '(choice (integer :tag "Timeout [ms]" 5000) (const :tag "No timeout" nil)) :group 'ein) @@ -199,7 +215,7 @@ is killed immediately after the execution of this function. (defun* ein:query-ajax-timeout-callback (buffer &key (error nil) &allow-other-keys) - (ein:log 'debug "EIN:QUERY-AJAX-TIMEOUT-CALLBACK buffer = %s" buffer) + (ein:log 'debug "EIN:QUERY-AJAX-TIMEOUT-CALLBACK buffer = %S" buffer) (ein:with-live-buffer buffer (setq ein:query-ajax-canceled 'timeout) (let ((proc (get-buffer-process buffer))) @@ -212,6 +228,31 @@ is killed immediately after the execution of this function. (cancel-timer ein:query-ajax-timer) (setq ein:query-ajax-timer nil))) +(defvar ein:query-running-process-table (make-hash-table :test 'equal)) + +(defun ein:query-singleton-ajax (key &rest args) + "Cancel the old process if there is a process associated with +KEY, then call `ein:query-ajax' with ARGS. KEY is compared by +`equal'." + (ein:query-gc-running-process-table) + (ein:aif (gethash key ein:query-running-process-table) + (ein:with-live-buffer it + (setq ein:query-ajax-canceled 'user-cancel) + (let ((proc (get-buffer-process it))) + ;; This will call `ein:query-ajax-callback'. + (delete-process proc)))) + (let ((buffer (apply #'ein:query-ajax args))) + (puthash key buffer ein:query-running-process-table) + buffer)) + +(defun ein:query-gc-running-process-table () + "Garbage collect dead processes in `ein:query-running-process-table'." + (maphash + (lambda (key buffer) + (unless (buffer-live-p buffer) + (remhash key ein:query-running-process-table))) + ein:query-running-process-table)) + (provide 'ein-query) ;;; ein-query.el ends here