branch: elpa/hyperdrive commit 79541d4aab9f165c861ea32f3f2890be0d7cb31f Merge: 2ad91d4c68 f044f39bf8 Author: Adam Porter <a...@alphapapa.net> Commit: Adam Porter <a...@alphapapa.net>
Merge: (he/api) Consolidate hyperdrive filling logic into callback --- hyperdrive-describe.el | 2 +- hyperdrive-diff.el | 14 +-- hyperdrive-dir.el | 10 +-- hyperdrive-history.el | 4 +- hyperdrive-lib.el | 238 +++++++++++++++++++++---------------------------- hyperdrive-mirror.el | 2 +- hyperdrive-vars.el | 2 +- hyperdrive.el | 85 ++++++++---------- 8 files changed, 154 insertions(+), 203 deletions(-) diff --git a/hyperdrive-describe.el b/hyperdrive-describe.el index 8eb6c6e428..c7cf1baeb9 100644 --- a/hyperdrive-describe.el +++ b/hyperdrive-describe.el @@ -48,7 +48,7 @@ Universal prefix argument \\[universal-argument] forces `hyperdrive-complete-hyperdrive' to prompt for a hyperdrive." (interactive (list (h/complete-hyperdrive :force-prompt current-prefix-arg))) ;; TODO: Do we want to asynchronously fill the hyperdrive's latest version? - (h/fill-latest-version hyperdrive) + (h/fill hyperdrive) (with-current-buffer (get-buffer-create (h//format hyperdrive "*Hyperdrive: %k")) (with-silent-modifications diff --git a/hyperdrive-diff.el b/hyperdrive-diff.el index 9885d00aa5..3f633da749 100644 --- a/hyperdrive-diff.el +++ b/hyperdrive-diff.el @@ -103,16 +103,10 @@ This function is intended to diff files, not directories." (kill-buffer old-buffer)) (when (buffer-live-p new-buffer) (kill-buffer new-buffer)))))))) - (h/api 'get (he/url old-entry) - :queue queue :as 'response :else #'ignore - :then (lambda (response) - (h//fill old-entry (plz-response-headers response)) - (setf old-response response))) - (h/api 'get (he/url new-entry) - :queue queue :as 'response :else #'ignore - :then (lambda (response) - (h//fill new-entry (plz-response-headers response)) - (setf new-response response))))) + (he/api 'get old-entry :queue queue :else #'ignore + :then (lambda (response) (setf old-response response))) + (he/api 'get new-entry :queue queue :else #'ignore + :then (lambda (response) (setf new-response response))))) ;;;; Mode diff --git a/hyperdrive-dir.el b/hyperdrive-dir.el index b379422f6b..2dd6b622d8 100644 --- a/hyperdrive-dir.el +++ b/hyperdrive-dir.el @@ -40,7 +40,6 @@ If THEN, call it in the directory buffer with no arguments." ;; NOTE: ENTRY is not necessarily "filled" yet. (pcase-let* (((cl-struct hyperdrive-entry hyperdrive version) directory-entry) - (url (he/url directory-entry)) (header (progn ;; Fill metadata first to get the current nickname. ;; TODO: Consider filling metadata earlier, outside @@ -63,7 +62,7 @@ If THEN, call it in the directory buffer with no arguments." (when-let ((node (h/ewoc-find-node ewoc entry :predicate #'he/equal-p))) (goto-char (ewoc-location node))))) - (h/api 'get url :as 'response :noquery t + (he/api 'get directory-entry :noquery t ;; Get "full" listing with metadata :headers `(("Accept" . "application/json; metadata=full")) :then (lambda (response) @@ -73,7 +72,7 @@ If THEN, call it in the directory buffer with no arguments." (json-read-from-string body) hyperdrive version)) (parent-entry (h/parent directory-entry))) - (setf directory-entry (h//fill directory-entry headers)) + (setf directory-entry (he//fill directory-entry headers)) (when parent-entry (setf (alist-get 'display-name (he/etc parent-entry)) "../") (push parent-entry entries)) @@ -205,6 +204,7 @@ With point on header, returns directory entry." ;; `h/menu' is defined with `transient-define-prefix', which ;; `check-declare' doesn't recognize. (declare-function h/menu "hyperdrive-menu" nil t) +(declare-function h/forget-file "hyperdrive") (defvar-keymap h/dir-mode-map :parent h/ewoc-mode-map @@ -350,10 +350,8 @@ see Info node `(elisp)Yanking Media'." hyperdrive) :predicate #'h/writablep :default-path path :latest-version t))) - (h/api 'put (he/url entry) - :body-type 'binary + (he/api 'put entry :body image :body-type 'binary ;; TODO: Pass MIME type in a header? hyper-gateway detects it for us. - :body image :as 'response :then (lambda (_res) (h/open entry)) :else (lambda (plz-error) (h/message "Unable to yank media: %S" plz-error))))) diff --git a/hyperdrive-history.el b/hyperdrive-history.el index 928011a246..744ea88e86 100644 --- a/hyperdrive-history.el +++ b/hyperdrive-history.el @@ -202,7 +202,7 @@ prefix argument \\[universal-argument], prompt for ENTRY." (with-silent-modifications (h/history-mode) (setq-local h/history-current-entry entry) - (setf ewoc h/ewoc) ; Bind this for the h/fill lambda. + (setf ewoc h/ewoc) ; Bind this for the he/fill lambda. (ewoc-filter h/ewoc #'ignore) (erase-buffer) (ewoc-set-hf h/ewoc header "") @@ -234,7 +234,7 @@ prefix argument \\[universal-argument], prompt for ENTRY." (mapc (lambda (range-entry) (when (eq t (h/range-entry-exists-p range-entry)) ;; TODO: Handle failures? - (h/fill (cdr range-entry) :queue queue :then #'ignore))) + (he/fill (cdr range-entry) :queue queue :then #'ignore))) range-entries) (set-buffer-modified-p nil) (goto-char (point-min))))) diff --git a/hyperdrive-lib.el b/hyperdrive-lib.el index 21e24b382a..907991b3d0 100644 --- a/hyperdrive-lib.el +++ b/hyperdrive-lib.el @@ -71,6 +71,7 @@ Passes ARGS to `format-message'." (size nil :documentation "Size of file.") (version nil :documentation "Hyperdrive version specified in entry's URL.") (type nil :documentation "MIME type of the entry.") + ;; TODO: Consider adding gv-setters for etc slot keys (etc nil :documentation "Alist for extra data about the entry. - display-name :: Displayed in directory view instead of name. - target :: Link fragment to jump to.")) @@ -86,6 +87,7 @@ Passes ARGS to `format-message'." (domains nil :documentation "List of DNSLink domains which resolve to the drive's public-key.") (metadata nil :documentation "Public metadata alist.") (latest-version nil :documentation "Latest known version of hyperdrive.") + ;; TODO: Consider adding gv-setters for etc slot keys (etc nil :documentation "Alist of extra data. - disk-usage :: Number of bytes occupied locally by the drive. - safep :: Whether or not to treat this hyperdrive as safe.")) @@ -151,8 +153,6 @@ See `hyperdrive-directory-sort' for the type of DIRECTION." ;;;; API -;; These functions take a URL argument, not a hyperdrive-entry struct. - (cl-defun h/api (method url &rest rest) "Make hyperdrive API request by METHOD to URL. Calls `hyperdrive--httpify-url' to convert HYPER-URL starting @@ -163,16 +163,12 @@ with `hyperdrive--hyper-prefix' to a URL starting with REST is passed to `plz', which see. REST may include the argument `:queue', a `plz-queue' in which to -make the request." +make the request. + +This low-level function should only be used when sending requests +to the gateway which do not involve an entry. Otherwise, use +`hyperdrive-entry-api', which automatically fills metadata." ;; TODO: Document that the request/queue is returned. - ;; TODO: Should we create a wrapper for `h/api' which calls - ;; `h//fill-latest-version' for requests to directories/requests which modify - ;; the drive (and therefore always return the latest version number). If we - ;; did this, we could remove redundant calls to `h//fill-latest-version' - ;; everywhere else. X-Drive-Size is returned by many types of requests, and it - ;; would simplify the code to handle updating the hyperdrive disk-usage in one - ;; place. Once implemented, go through each call to `h/api' to verify that - ;; disk-usage is updated correctly. (declare (indent defun)) (pcase method ((and (or 'get 'head) @@ -204,6 +200,68 @@ make the request." ;; We pass only the `plz-error' struct to the ELSE* function. (funcall else* (caddr err)))))) +(defun he/api (method entry &rest rest) + "Make hyperdrive API request by METHOD for ENTRY. +REST is passed to `hyperdrive-api', which see. AS keyword should +be nil, because it is always set to `response'. Automatically +calls `hyperdrive-entry--api-then' to update metadata from the +response." + (declare (indent defun)) + ;; Always use :as 'response + (cl-assert (null (plist-get rest :as))) + (setf (plist-get rest :as) 'response) + (pcase-let* (((map :then) rest)) + (when then + (setf (plist-get rest :then) + (lambda (response) + (he//api-then entry response) + (funcall then response)))) + (let ((response (apply #'h/api method (he/url entry) rest))) + (unless then (funcall 'he//api-then entry response)) + response))) + +(defun he//api-then (entry response) + "Update ENTRY's metadata according to RESPONSE. +Sets ENTRY's hyperdrive to the persisted version of the drive if +it exists. Updates ENTRY's hyperdrive's disk usage and latest +version. Finally, persists ENTRY's hyperdrive." + (pcase-let* + (((cl-struct plz-response + (headers (map link allow x-drive-size x-drive-version))) + response) + ;; RESPONSE is guaranteed to have a "Link" header with the public key, + ;; while ENTRY may have a DNSLink domain but no public key yet. + (public-key (progn (string-match h//public-key-re link) + (match-string 1 link))) + ;; NOTE: Don't destructure `persisted-hyperdrive' with `pcase' here since it may be nil. + (persisted-hyperdrive (gethash public-key h/hyperdrives))) + + (when persisted-hyperdrive + ;; ENTRY's hyperdrive already persisted: merge domains into persisted + ;; hyperdrive and set ENTRY's hyperdrive slot to the persisted copy. + (setf (h/domains persisted-hyperdrive) + (delete-dups (append (h/domains persisted-hyperdrive) + (h/domains (he/hyperdrive entry))))) + (setf (he/hyperdrive entry) persisted-hyperdrive)) + + ;; Ensure that ENTRY's hyperdrive has a public key. + (setf (h/public-key (he/hyperdrive entry)) public-key) + + ;; Fill hyperdrive. + (when allow + ;; NOTE: "Allow" header is only present on HEAD requests. We can change + ;; this, but it's fine as-is since we only need to check writability once. + (setf (h/writablep (he/hyperdrive entry)) (string-match-p "PUT" allow))) + (when x-drive-size + (setf (map-elt (h/etc (he/hyperdrive entry)) 'disk-usage) + (cl-parse-integer x-drive-size))) + (when x-drive-version + (setf (h/latest-version (he/hyperdrive entry)) + (string-to-number x-drive-version))) + ;; TODO: Update buffers like h/describe-hyperdrive after updating drive. + ;; TODO: Consider debouncing or something for hyperdrive-persist to minimize I/O. + (h/persist (he/hyperdrive entry)))) + (defun h/gateway-needs-upgrade-p () "Return non-nil if the gateway is responsive and needs upgraded." (and (h//gateway-ready-p) @@ -254,16 +312,6 @@ PLZ-ERR should be a `plz-error' struct." h/gateway-port (substring url (length h//hyper-prefix)))) -(cl-defun h//write (url &key body then else queue) - "Save BODY (a string) to hyperdrive URL. -THEN and ELSE are passed to `hyperdrive-api', which see." - (declare (indent defun)) - (h/api 'put url - ;; TODO: Investigate whether we should use 'text body type for text buffers. - :body-type 'binary - ;; TODO: plz accepts buffer as a body, we should refactor calls to h//write to pass in a buffer instead of a buffer-string. - :body body :as 'response :then then :else else :queue queue)) - (defun h/parent (entry) "Return parent entry for ENTRY. If already at top-level directory, return nil." @@ -468,7 +516,7 @@ When VERSION is nil, return latest version of ENTRY." (setf (he/version entry) version) (condition-case err ;; FIXME: Requests to out of range version currently hang. - (h/fill entry) + (he/fill entry) (plz-error (pcase (plz-response-status (plz-error-response (caddr err))) ;; FIXME: If plz-error is a curl-error, this block will fail. @@ -489,7 +537,7 @@ Sends a request to the gateway for hyperdrive's latest version." ;; ENTRY's version is not nil. (let ((next-entry (h/copy-tree entry t)) - (latest-version (h/fill-latest-version (he/hyperdrive entry)))) + (latest-version (h/fill (he/hyperdrive entry)))) ;; ENTRY version is the latest version: return ENTRY with nil version. (when (eq latest-version (he/version entry)) @@ -554,16 +602,11 @@ echo area when the request for the file is made." ;; FIXME: Some of the synchronous filling functions we've added now cause this to be blocking, ;; which is very noticeable when a file can't be loaded from the gateway and eventually times out. (let ((hyperdrive (he/hyperdrive entry))) - (h/fill entry + (he/fill entry :then (lambda (entry) (pcase-let* (((cl-struct hyperdrive-entry type) entry) (handler (alist-get type h/type-handlers nil nil #'string-match-p))) - (unless (h//entry-directory-p entry) - ;; No need to fill latest version for directories, - ;; since we do it in `h//fill' already. - (h/fill-latest-version hyperdrive)) - (h/persist hyperdrive) (funcall (or handler #'h/handler-default) entry :then then))) :else (lambda (err) (cl-labels ((not-found-action () @@ -622,7 +665,7 @@ echo area when the request for the file is made." (when messagep (h/message "Opening <%s>..." (he/url entry))))) -(cl-defun h/fill (entry &key queue (then 'sync) else) +(cl-defun he/fill (entry &key queue (then 'sync) else) "Fill ENTRY's metadata and call THEN. If THEN is `sync', return the filled entry and ignore ELSE. Otherwise, make request asynchronously and call THEN with the @@ -642,15 +685,11 @@ the given `plz-queue'" ;; (e.g. if the user reverted too quickly). nil) (_ - (h/message "hyperdrive-fill: error: %S" plz-error)))))) + (h/message "hyperdrive-entry-fill: error: %S" plz-error)))))) (pcase then ('sync (condition-case err - (h//fill entry - (plz-response-headers - (h/api 'head (he/url entry) - :as 'response - :then 'sync - :noquery t))) + (he//fill entry (plz-response-headers + (he/api 'head entry :then 'sync :noquery t))) (plz-error (pcase (plz-response-status (plz-error-response (caddr err))) ;; FIXME: If plz-error is a curl-error, this block will fail. @@ -658,11 +697,10 @@ the given `plz-queue'" (h/update-nonexistent-version-range entry))) ;; Re-signal error for, e.g. `he/at'. (signal (car err) (cdr err))))) - (_ (h/api 'head (he/url entry) + (_ (he/api 'head entry :queue queue - :as 'response :then (lambda (response) - (funcall then (h//fill entry (plz-response-headers response)))) + (funcall then (he//fill entry (plz-response-headers response)))) :else (lambda (&rest args) (when (he/version entry) ;; If request is canceled, the entry may not have a version. @@ -671,72 +709,28 @@ the given `plz-queue'" (apply else args)) :noquery t)))) -(defun h//fill (entry headers) - "Fill ENTRY and its hyperdrive from HEADERS. +(defun he//fill (entry headers) + "Fill ENTRY slots from HEADERS. -The following ENTRY slots are filled: - \\+`type' - \\+`mtime' - \\+`size' -- \\+`hyperdrive' (from persisted value if it exists) -The following ENTRY hyperdrive slots are filled: -- \\+`public-key' -- \\+`writablep' (when headers include Allow) -- \\+`domains' (merged with current persisted value) -- \\+`etc' (disk-usage) +Also fills existent range in `hyperdrive-version-ranges'. Returns filled ENTRY." (pcase-let* - (((cl-struct hyperdrive-entry hyperdrive) entry) - ((cl-struct hyperdrive writablep domains etc) hyperdrive) - ((map link content-length content-type etag - last-modified allow x-drive-size) - headers) - ;; If URL hostname was a DNSLink domain, - ;; entry doesn't yet have a public-key slot. - (public-key (progn (string-match h//public-key-re link) - (match-string 1 link))) - (persisted-hyperdrive (gethash public-key h/hyperdrives)) - (domain (car domains))) + (((map content-length content-type etag last-modified) headers)) (when last-modified (setf last-modified (encode-time (parse-time-string last-modified)))) - (when (and allow (eq 'unknown writablep)) - (setf (h/writablep hyperdrive) (string-match-p "PUT" allow))) (setf (he/size entry) (and content-length (ignore-errors (cl-parse-integer content-length)))) (setf (he/type entry) content-type) (setf (he/mtime entry) last-modified) - (when x-drive-size - (setf (map-elt etc 'disk-usage) (cl-parse-integer x-drive-size))) - (setf (h/etc hyperdrive) etc) - (if persisted-hyperdrive - (progn - ;; Ensure that entry's hyperdrive is the persisted - ;; hyperdrive, since it may be used later as part of a - ;; `h/version-ranges' key and compared using `eq'. - ;; Also, we want the call to `h//fill-latest-version' - ;; below to update the persisted hyperdrive. - (setf (he/hyperdrive entry) persisted-hyperdrive) - (when domain - ;; The previous call to he/url may not have retrieved - ;; the persisted hyperdrive if we had only a domain - ;; but no public-key. - (cl-pushnew domain (h/domains (he/hyperdrive entry)) :test #'equal))) - (setf (h/public-key hyperdrive) public-key)) - (when etag - (if (and (h//entry-directory-p entry) - (null (he/version entry))) - ;; Version-less directory HEAD/GET request ETag header always have the - ;; hyperdrive's latest version. We don't currently store - ;; version ranges for directories (since they don't - ;; technically have versions in hyperdrive). - (h//fill-latest-version hyperdrive headers) - ;; File HEAD/GET request ETag header does not retrieve the - ;; hyperdrive's latest version, so `h/update-existent-version-range' - ;; will not necessarily fill in the entry's last range. - (h/update-existent-version-range entry (string-to-number etag)))) + (when (and etag (not (h//entry-directory-p entry))) + ;; Directory version ranges are not supported. + (h/update-existent-version-range entry (string-to-number etag))) entry)) (defun h//fill-listing-entries (listing hyperdrive version) @@ -761,30 +755,9 @@ entry as a side-effect." entry)) listing)) -(defun h/fill-latest-version (hyperdrive) - "Synchronously fill the latest version slot in HYPERDRIVE. -Returns the latest version number." - (pcase-let (((cl-struct plz-response headers) - (h/api - 'head (he/url - (he/create - :hyperdrive hyperdrive :path "/")) - :as 'response))) - (h//fill-latest-version hyperdrive headers))) - -(defun h//fill-latest-version (hyperdrive headers) - "Fill the latest version slot in HYPERDRIVE from HEADERS. -HEADERS must from a HEAD/GET request to a directory or a -PUT/DELETE request to a file or directory, as only those requests -return the correct ETag header. Returns latest version number." - ;; TODO: Update relevant buffers when hyperdrive latest version - ;; updates, at the least describe-hyperdrive buffers. - ;; TODO: Consider updating version range here. First check all the - ;; places where this function is called. Better yet, update - ;; `h/version-ranges' (and `h/hyperdrives'?) in a - ;; lower-level function, perhaps a wrapper for `h/api'? - (setf (h/latest-version hyperdrive) - (string-to-number (map-elt headers 'etag)))) +(defun h/fill (hyperdrive) + "Synchronously fill the latest version slot in HYPERDRIVE." + (he/api 'head (he/create :hyperdrive hyperdrive :path "/"))) ;; TODO: Consider using symbol-macrolet to simplify place access. @@ -909,9 +882,8 @@ Once all requests return, call FINALLY with no arguments." ;; existent/nonexistent entry, or at the limit. (setf finishedp t) (cl-return)) - (h/api 'head (he/url prev-entry) + (he/api 'head prev-entry :queue nonexistent-queue - :as 'response :then (pcase-lambda ((cl-struct plz-response (headers (map etag)))) (pcase-let* ((range-start (string-to-number etag)) ((map :existsp) (map-elt copy-entry-version-ranges range-start))) @@ -933,9 +905,8 @@ Once all requests return, call FINALLY with no arguments." (let ((copy-entry (h/copy-tree entry t))) (setf (he/version copy-entry) version) (cl-decf total-requests-limit) - (h/api 'head (he/url copy-entry) + (he/api 'head copy-entry :queue fill-entry-queue - :as 'response :then (pcase-lambda ((cl-struct plz-response (headers (map etag)))) (pcase-let* ((range-start (string-to-number etag)) ((map :existsp) @@ -969,11 +940,10 @@ HYPERDRIVE's public metadata file." ;; NOTE: Don't attempt to fill hyperdrive struct with old metadata :version nil)) (metadata (condition-case err - ;; TODO: Refactor to use :as 'response-with-buffer and call h/fill + ;; TODO: Refactor to use :as 'response-with-buffer and call he/fill (pcase-let - (((cl-struct plz-response headers body) - (h/api 'get (he/url entry) :as 'response :noquery t))) - (h//fill entry headers) + (((cl-struct plz-response body) + (he/api 'get entry :noquery t))) (with-temp-buffer (insert body) (goto-char (point-min)) @@ -999,8 +969,7 @@ HYPERDRIVE's public metadata file." Call ELSE if request fails." (declare (indent defun)) - (h/api 'delete (he/url (he/create :hyperdrive hyperdrive)) - :as 'response + (he/api 'delete (he/create :hyperdrive hyperdrive) :then (lambda (response) (h/persist hyperdrive :purge t) (h/purge-version-ranges hyperdrive) @@ -1008,9 +977,14 @@ Call ELSE if request fails." :else else)) (cl-defun h/write (entry &key body then else queue) - "Write BODY to hyperdrive ENTRY's URL." + "Write BODY to hyperdrive ENTRY's URL. +THEN and ELSE are passed to `hyperdrive-entry-api', which see." (declare (indent defun)) - (h//write (he/url entry) + (he/api 'put entry + ;; TODO: Investigate whether we should use 'text body type for text buffers. + :body-type 'binary + ;; TODO: plz accepts buffer as a body, we should refactor calls to h/write + ;; to pass in a buffer instead of a buffer-string. :body body :then then :else else :queue queue)) (cl-defun h//format-entry-url @@ -1329,9 +1303,7 @@ hyperdrive." (h/api 'get (format "hyper://localhost/?key=%s" (url-hexify-string seed)) :as 'response :noquery t))) - ;; TODO: Update hyperdrive disk-usage. The following doesn't work - ;; because the response doesn't have the proper ETag header: - ;; (h//fill (h/url-entry url) headers) + (h/fill (h/url-entry url)) url) (plz-error (if (= 400 (plz-response-status (plz-error-response (caddr err)))) ;; FIXME: If plz-error is a curl-error, this block will fail. @@ -1361,12 +1333,10 @@ Otherwise, return nil. SLOT may be one of "Load ENTRY's file into an Emacs buffer. If then, then call THEN with no arguments. Default handler." (pcase-let* - (((cl-struct plz-response headers body) + (((cl-struct plz-response body) ;; TODO: Handle errors ;; TODO: When plz adds :as 'response-with-buffer, use that. - (h/api 'get (he/url entry) :noquery t :as 'response)) - ;; Filling entry is necessary in order to update hyperdrive disk-usage. - (_ (h//fill entry headers)) + (he/api 'get entry :noquery t)) ((cl-struct hyperdrive-entry hyperdrive version etc) entry) ((map target) etc)) (with-current-buffer (h//get-buffer-create entry) diff --git a/hyperdrive-mirror.el b/hyperdrive-mirror.el index 324db6b5a0..1dbd3ae93c 100644 --- a/hyperdrive-mirror.el +++ b/hyperdrive-mirror.el @@ -157,7 +157,7 @@ been checked." (let ((entry (he/create :hyperdrive hyperdrive :path (expand-file-name (file-relative-name file source) target-dir)))) - (h/fill entry :queue metadata-queue + (he/fill entry :queue metadata-queue :then (lambda (entry) (let* ((drive-mtime (floor (float-time (he/mtime entry)))) (local-mtime (floor (float-time (file-attribute-modification-time (file-attributes file))))) diff --git a/hyperdrive-vars.el b/hyperdrive-vars.el index 2c9c26ebef..05ff6ce914 100644 --- a/hyperdrive-vars.el +++ b/hyperdrive-vars.el @@ -380,7 +380,7 @@ values are alists mapping version range starts to plists with ;;;;; Internals (defvar h/gateway-version-expected - '(:name "hyper-gateway-ushin" :version "3.9.2")) + '(:name "hyper-gateway-ushin" :version "3.10.1")) (defvar h/gateway-version-checked-p nil "Non-nil if the gateway's version has been checked. diff --git a/hyperdrive.el b/hyperdrive.el index 19bae3470e..ef0c40192a 100644 --- a/hyperdrive.el +++ b/hyperdrive.el @@ -138,7 +138,7 @@ hyperdrive, the new hyperdrive's petname will be set to SEED." (pcase-let* (((cl-struct plz-response (body url)) (h/api 'post (concat "hyper://localhost/?key=" (url-hexify-string seed)) - :as 'response)) + :as 'response)) (hyperdrive (he/hyperdrive (h/url-entry url)))) (setf (h/seed hyperdrive) seed) (setf (h/writablep hyperdrive) t) @@ -194,20 +194,17 @@ modified; file blobs may be recoverable from other peers." (interactive (list (h//context-entry))) (when (yes-or-no-p (format-message - "Clear local copy of entry (data may not be recoverable—see manual):`%s'? " + "Clear local copy of entry (data may not be recoverable—see manual):`%s'? " (h//format-entry entry))) - (let ((url (he/url entry))) - (h/api 'post url - :headers '(("Cache-Control" . "no-store")) - :as 'response - :else (lambda (err) - (h/error "Unable to clear cache for `%s': %S" url err)) - :then (lambda (response) - (h//fill entry (plz-response-headers response)) - (h/message "Cleared `%s'" (h//format-entry entry)) - ;; TODO: When file sizes in hyperdrive-dir-mode are colorized - ;; based locally downloaded sizes, refresh ewoc entry here. - ))))) + (he/api 'post entry + :headers '(("Cache-Control" . "no-store")) + :else (lambda (err) + (h/error "Unable to clear cache for `%s': %S" (he/url entry) err)) + :then (lambda (_response) + (h/message "Cleared `%s'" (h//format-entry entry)) + ;; TODO: When file sizes in hyperdrive-dir-mode are colorized + ;; based locally downloaded sizes, refresh ewoc entry here. + )))) ;;;###autoload (defun hyperdrive-purge (hyperdrive) @@ -279,16 +276,10 @@ Universal prefix argument \\[universal-argument] forces (progn (cl-callf map-delete (h/metadata hyperdrive) 'name) (h/put-metadata hyperdrive - :then (pcase-lambda ((cl-struct plz-response headers)) - (h//fill-latest-version hyperdrive headers) - (h/persist hyperdrive) - (funcall then hyperdrive)))) + :then (lambda (_response) (funcall then hyperdrive)))) (setf (alist-get 'name (h/metadata hyperdrive)) nickname) (h/put-metadata hyperdrive - :then (pcase-lambda ((cl-struct plz-response headers)) - (h//fill-latest-version hyperdrive headers) - (h/persist hyperdrive) - (funcall then hyperdrive)))) + :then (lambda (_response) (funcall then hyperdrive)))) ;; TODO: Consider refreshing buffer names, directory headers, etc, especially host-meta.json entry buffer. ) hyperdrive) @@ -429,14 +420,12 @@ directory. Otherwise, or with universal prefix argument (h/message "Deleted: `%s' (Deleted files can be accessed from prior versions of the hyperdrive.)" description)) :else (lambda (plz-error) (h/message "Unable to delete `%s': %S" description plz-error)))))) - (h/api 'delete (he/url entry) - :as 'response + (he/api 'delete entry :then (lambda (response) (pcase-let* (((cl-struct plz-response headers) response) ((map etag) headers) (nonexistent-entry (h/copy-tree entry t))) (setf (he/version nonexistent-entry) (string-to-number etag)) - (h//fill-latest-version (he/hyperdrive entry) headers) (h/update-nonexistent-version-range nonexistent-entry) ;; Since there's no way for `h//write-contents' to run when ;; `buffer-modified-p' returns nil, this is a workaround to ensure that @@ -462,6 +451,7 @@ in a directory. Otherwise, or with universal prefix argument ;;;###autoload (defun hyperdrive-download-url (url filename) "Load contents at URL as a file to store on disk at FILENAME." + ;; TODO: Implement entry-based version of this function, or change callers to use entries. ;; TODO: Handle directory URLs (recursively download contents?) (interactive (let* ((read-url (h/read-url :prompt "Download hyperdrive URL")) @@ -475,9 +465,9 @@ in a directory. Otherwise, or with universal prefix argument (delete-file filename)) (h/api 'get url :as `(file ,filename)) ;; TODO: If plz adds support for getting response headers when downloading - ;; as a file, use it here. + ;; as a file (<https://github.com/alphapapa/plz.el/issues/61>), use it here. ;; Filling entry is necessary in order to update hyperdrive disk-usage. - (h/fill (h/url-entry url)))) + (he/fill (h/url-entry url)))) ;;;###autoload (defun hyperdrive-write-buffer (entry &optional overwritep) @@ -520,11 +510,7 @@ use, see `hyperdrive-write'." (let ((buffer-file-name (he/name entry))) (set-auto-mode))) (h/mode)) - ;; NOTE: `h/fill-latest-version' must come before - ;; `h//fill' because the latter calls - ;; `h/update-existent-version-range' internally. - (h/fill-latest-version hyperdrive) - (h//fill entry (plz-response-headers response)) + (he//fill entry (plz-response-headers response)) ;; PUT responses only include ETag and Last-Modified ;; headers, so we need to set other entry metadata manually. ;; FIXME: For large buffers, `buffer-size' returns a different @@ -714,19 +700,18 @@ After successful upload, call THEN. When QUEUE, use it." (h/read-entry :predicate #'h/writablep :default-path (file-name-nondirectory filename) :latest-version t)))) - (let ((url (he/url entry)) - (last-modified (let ((system-time-locale "C")) + (let ((last-modified (let ((system-time-locale "C")) (format-time-string "%Y-%m-%dT%T.%3NZ" ;; "%a, %-d %b %Y %T %Z" (file-attribute-modification-time (file-attributes filename)) t)))) - (h/api 'put url :queue queue + (he/api 'put entry :queue queue :body `(file ,filename) :headers `(("Last-Modified" . ,last-modified)) :then then) ;; TODO: Hyperdrive disk usage should be set here. (unless queue - (h/message "Uploading to \"%s\"..." url)))) + (h/message "Uploading to \"%s\"..." (he/url entry))))) (defun h/read-files () "Return list of files read from the user." @@ -818,12 +803,16 @@ The return value of this function is the retrieval buffer." ;; TODO: When `plz.el' adds :as 'response-with-buffer, use that. ;; response-buffer will contain the loaded HTML, and will be deleted at the end of `eww-render'. ((cl-struct plz-response headers body) - (h/api 'get url :as 'response))) - ;; Filling entry is necessary in order to update hyperdrive disk-usage. - (h//fill (h/url-entry url) headers) + (he/api 'get (h/url-entry url)))) (with-current-buffer (generate-new-buffer " *hyperdrive-eww*") (widen) (goto-char (point-min)) + ;; TODO: When `plz' gains `:as '(response :with buffer)' or whatever, use it instead of this hack. + ;; HACK: Insert headers because `eww-render' expects them to be in the buffer. + (map-do (lambda (header value) + (insert (format "%s: %s\n" header value))) + headers) + (insert "\n\n") (insert body) (while (search-forward (string ?\C-m) nil t) ;; Strip CRLF from headers so that `eww-parse-headers' works correctly. @@ -1400,21 +1389,21 @@ Intended for relative (i.e. non-full) URLs." ;; TODO: sr.ht build (<https://builds.sr.ht/~ushin/job/1247130#task-setup>) ;; fail due to a kernel issue: https://github.com/nodejs/node/issues/53051 '((gnu/linux - ( :url "https://codeberg.org/USHIN/hyper-gateway-ushin/releases/download/v3.9.2/hyper-gateway-ushin-linux" - :sha256 "f0cb3e793b3d27ce159e8e034e03b5a14cbdc53d47bd8f0761310792d5b6a7aa") - ;; ( :url "https://git.sr.ht/~ushin/hyper-gateway-ushin/refs/download/v3.9.2/hyper-gateway-linux-v3.9.2" + ( :url "https://codeberg.org/USHIN/hyper-gateway-ushin/releases/download/v3.10.1/hyper-gateway-ushin-linux" + :sha256 "6a93dd6f5b023cc2cc2e99aba728cbcccd4c9ed426b506da0a4b24d8c0ea5afa") + ;; ( :url "https://git.sr.ht/~ushin/hyper-gateway-ushin/refs/download/v3.10.1/hyper-gateway-linux-v3.10.1" ;; :sha256 "331dbc0048decd42d197667f96aabdaf25306ba4e7ba0451dd9a2f31868fa86c") ) (darwin - ( :url "https://codeberg.org/USHIN/hyper-gateway-ushin/releases/download/v3.9.2/hyper-gateway-ushin-macos" - :sha256 "bb472bf7a536eb30bc2443ce90cfca1bf2aa71177afdc1377f4fc9b61414c24c") - ;; ( :url "https://git.sr.ht/~ushin/hyper-gateway-ushin/refs/download/v3.9.2/hyper-gateway-macos-v3.9.2" + ( :url "https://codeberg.org/USHIN/hyper-gateway-ushin/releases/download/v3.10.1/hyper-gateway-ushin-macos" + :sha256 "7072e7fd52626affe5a17380845b50ec5116210d70f409c23bcb5415142a4053") + ;; ( :url "https://git.sr.ht/~ushin/hyper-gateway-ushin/refs/download/v3.10.1/hyper-gateway-macos-v3.10.1" ;; :sha256 "e78d3c1394774fc49212d86827eb615d46ae1a04c82fc0328ac31bbbdb201aa0") ) (windows-nt - ( :url "https://codeberg.org/USHIN/hyper-gateway-ushin/releases/download/v3.9.2/hyper-gateway-ushin-windows.exe" - :sha256 "7a72010cd7bc1b0357673838f5ccb069e58bf3c229bc873bedd0ee9faa805188") - ;; ( :url "https://git.sr.ht/~ushin/hyper-gateway-ushin/refs/download/v3.9.2/hyper-gateway-windows-v3.9.2.exe" + ( :url "https://codeberg.org/USHIN/hyper-gateway-ushin/releases/download/v3.10.1/hyper-gateway-ushin-windows.exe" + :sha256 "b87aa17bc92c6f5a1c388f5e352a47b228d33c5f177ab6a11aad0312e891df0d") + ;; ( :url "https://git.sr.ht/~ushin/hyper-gateway-ushin/refs/download/v3.10.1/hyper-gateway-windows-v3.10.1.exe" ;; :sha256 "d4fa29aca473148e2d13215d042e4be40657080035caa2d3a699b741b6a45845") )) "Alist mapping `system-type' to URLs where the gateway can be downloaded.")