branch: elpa/hyperdrive
commit 5dbf46f7a346948f8a105055652ac3eeb456712c
Merge: 2262879bbe 877d784815
Author: Adam Porter <[email protected]>
Commit: Adam Porter <[email protected]>
Merge: Add h/install command, refactor gateway customization
---
.dir-locals.el | 5 +-
CHANGELOG.org | 30 +++++-
CONTRIBUTING.org | 32 ++++--
DEV.org | 59 ++++++++++
doc/hyperdrive.org | 163 ++++++++++++++++++----------
doc/hyperdrive.texi | 199 ++++++++++++++++++++++++----------
hyperdrive-lib.el | 297 ++++++++++++++++++++++++---------------------------
hyperdrive-menu.el | 38 +++++--
hyperdrive-mirror.el | 13 +--
hyperdrive-vars.el | 78 ++++++++++++--
hyperdrive.el | 230 +++++++++++++++++++++++++++++++++------
tests/org links.org | 2 +-
12 files changed, 810 insertions(+), 336 deletions(-)
diff --git a/.dir-locals.el b/.dir-locals.el
index 65d6493da8..4de6f4bdb6 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -1,6 +1,7 @@
;;; Directory Local Variables -*- no-byte-compile: t -*-
;;; For more information see (info "(emacs) Directory Variables")
-((nil . ((ispell-buffer-session-localwords . ("dir" "hypercore" "hyperdrive"
"hyperdrives" "hyperdrive's" "args" "systemd" "minibuffer" "petname" "petnames"
"org" "plist" "plists" "alist" "alists" "existsp" "ETag" "streamable" "DNSLink"
"ewoc" "struct" "ENTRY's" "localhost" "imenu" "mtime" "accessor" "http"
"prepended" "prepend" "hostname" "whitespace" "namespace" "filesystem"
"hostnames" "subdirectories" "unsets" "finalizer" "subprocess" "autodetect"
"transclusion"))))
+((nil . ((ispell-buffer-session-localwords . ("dir" "hypercore" "hyperdrive"
"hyperdrives" "hyperdrive's" "args" "systemd" "minibuffer" "petname" "petnames"
"org" "plist" "plists" "alist" "alists" "existsp" "ETag" "streamable" "DNSLink"
"ewoc" "struct" "ENTRY's" "localhost" "imenu" "mtime" "accessor" "http"
"prepended" "prepend" "hostname" "whitespace" "namespace" "filesystem"
"hostnames" "subdirectories" "unsets" "finalizer" "subprocess" "autodetect"
"transclusion" "ushin"))))
(emacs-lisp-mode . ((eval . (display-fill-column-indicator-mode))
- (fill-column . 80))))
+ (fill-column . 80)))
+ (org-mode . ((org-id-link-to-org-use-id . nil))))
diff --git a/CHANGELOG.org b/CHANGELOG.org
index c1ba21ff25..1711e059c0 100644
--- a/CHANGELOG.org
+++ b/CHANGELOG.org
@@ -6,6 +6,9 @@ This project adheres to
[[https://semver.org/spec/v2.0.0.html][Semantic Versioni
* 0.4-pre
+Version ~0.4~ features
[[https://ushin.org/hyperdrive/hyperdrive-manual.html#Org_002dtransclusion-integration][org-transclusion
integration]], easy gateway
+installation with ~M-x hyperdrive-install~, and a faster directory UI!
+
** Security
- By default, don't automatically load major mode when browsing
@@ -14,6 +17,13 @@ This project adheres to
[[https://semver.org/spec/v2.0.0.html][Semantic Versioni
** Added
+- Easy installation: After ~M-x package-install hyperdrive.el~, run ~M-x
+ hyperdrive-install~ to install the gateway.
+- Cancel installation in progress with ~hyperdrive-cancel-install~.
+- Add ~hyperdrive-install~ and ~hyperdrive-cancel-install~ bindings to
+ ~hyperdrive-menu~ and menu bar.
+- Add ~hyperdrive-restart~ to restart the gateway, also bound in
+ ~hyperdrive-menu~ and menu bar.
- When visiting an old version of a hyperdrive file, press ~n~ and ~p~ to
traverse the version history. Press ~q~ to kill the current buffer.
@@ -23,11 +33,24 @@ This project adheres to
[[https://semver.org/spec/v2.0.0.html][Semantic Versioni
follow the [installation
instructions](https://git.sr.ht/~ushin/hyper-gateway-ushin#installation).
- Directory listings load faster
-- Improved defcustom types
-- Better error message when ~hyper-gateway-ushin~ is not installed.
+- Improve gateway status indicators in ~hyperdrive-menu~ to update
+ asynchronously with "starting", "installing", "upgrading", etc.
+- Improve messages and errors when starting and stopping gateway.
+- Remove gateway status indicator in hyperdrive menu bar since menu
+ bar labels cannot be updated while the menu bar is open.
+- Better error message when the gateway is not installed.
Thanks to ~magnum~ on XMPP for reporting.
-- Removed ~hyperdrive-reuse-buffers~ user option to ensure consistent
+- Remove ~hyperdrive-reuse-buffers~ user option to ensure consistent
behavior when uniquifying buffer names.
+- Remove ~hyperdrive-gateway-process-type~ user option. To customize
+ gateway startup, see options ~hyperdrive-gateway-start-function~,
+ ~hyperdrive-gateway-stop-function~, ~hyperdrive-gateway-live-predicate~.
+- Remove ~hyperdrive-gateway-command~ user option. To customize gateway
+ command, see options ~hyperdrive-gateway-directory~,
+ ~hyperdrive-gateway-program~, ~hyperdrive-gateway-command-args~.
+- Rename and alias ~hyperdrive-hyper-gateway-ushin-port~ to
+ ~hyperdrive-gateway-port~. Alias will be removed in a later version.
+- Improve defcustom types
** Fixed
@@ -35,6 +58,7 @@ This project adheres to
[[https://semver.org/spec/v2.0.0.html][Semantic Versioni
- More reliably kill intermediate buffers when generating a diff.
- Avoid unnecessarily updating ~hyperdrive-version-ranges~.
- Include the first file in a directory as an ~imenu~ candidate.
+- Start gateway subprocess on ~hyperdrive-gateway-port~.
** Internal
diff --git a/CONTRIBUTING.org b/CONTRIBUTING.org
index e4aa0317cf..63960ebfce 100644
--- a/CONTRIBUTING.org
+++ b/CONTRIBUTING.org
@@ -28,9 +28,6 @@ As well, sometimes two keywords might be used together if the
lines between them
These checklists should be followed when releasing new versions:
** Commit new pre-release
-:PROPERTIES:
-:ID: 5f7859bc-5f9b-4e35-806e-b727f492dade
-:END:
In ~master~ branch:
@@ -45,13 +42,14 @@ These checklists should be followed when releasing new
versions:
1. [ ] Update package main file header version (removing ~-pre~ suffix).
2. [ ] Update CHANGELOG (with release date and version).
- 3. [ ] Rebuild .texi manual (use ~pre-commit~ hook; see below).
- 4. [ ] Commit changes.
- 5. [ ] Merge ~master~ branch into ~stable~ branch.
- 6. [ ] Make new git tag for new release (tagging the commit on ~stable~).
- 7. [ ] Push ~master~ and ~stable~ branches to remote.
- 8. [ ] Push git tags.
- 9. [ ] [[id:5f7859bc-5f9b-4e35-806e-b727f492dade][Commit new pre-release]]
before adding more changes.
+ 3. [ ] Update [[*Version number locations][Version number locations]] if
necessary (e.g. if gateway version changes).
+ 4. [ ] Rebuild .texi manual (use ~pre-commit~ hook; see below).
+ 5. [ ] Commit changes.
+ 6. [ ] Merge ~master~ branch into ~stable~ branch.
+ 7. [ ] Make new git tag for new release (tagging the commit on ~stable~).
+ 8. [ ] Push ~master~ and ~stable~ branches to remote.
+ 9. [ ] Push git tags.
+ 10. [ ] [[*Commit new pre-release][Commit new pre-release]] before adding
more changes.
** Release new bugfix version (when applying bug fixes to a stable release,
not to ~master~)
@@ -70,6 +68,20 @@ These checklists should be followed when releasing new
versions:
11. [ ] Push ~master~ branch to remote.
12. [ ] Push git tags.
+* Version number locations
+
+/A list of the places where version numbers are present and need to be
updated./
+
+** Gateway version numbers
+
++ [ ] [[file:hyperdrive.el::(defvar
h/gateway-urls-and-hashes][h/gateway-urls-and-hashes variable]]
++ [ ] [[file:hyperdrive-vars.el::defvar h/gateway-version-expected
"3.7.0"][h/gateway-version-expected variable]]
+
+*** Getting ~sha256sum~ for each release
+
+- [[https://ci.codeberg.org/repos/13334/pipeline/27/6][Codeberg Woodpecker CI
output]]
+- [[https://git.sr.ht/~ushin/hyper-gateway-ushin/refs/][SourceHut refs page]]
+
* Git hooks
Please consider using the following git hooks:
diff --git a/DEV.org b/DEV.org
index 3d0cf942aa..52e9c42aee 100644
--- a/DEV.org
+++ b/DEV.org
@@ -1,4 +1,7 @@
#+title: Hyperdrive.el notes
+#+TODO: TODO WAITING | DONE CANCELED
+#+TODO: PROJECT | COMPLETED CANCELED
+#+TODO: DECIDE | DECISION
* Reference
@@ -16,6 +19,48 @@ So, e.g. ~makem~'s ~lint-declare~ rule, which uses
~check-declare~, gives false
- State "TODO" from [2023-11-28 Tue 16:31]
:END:
+* Gateway version automatic installation/upgrading
+
++ Design :: As simple as possible.
+ - We do /not/ attempt to automatically detect the latest gateway release on
Sourcehut's Web page.
+ - We include with ~hyperdrive.el~ the known-latest version, with URL and
hash.
+ - When we want to release a new version of the gateway, we will then release
a new version of ~hyperdrive.el~ with the corresponding information.
+ - The client will, upon first use, check the installed version of the
gateway and prompt the user to upgrade it if necessary.
+
+** Considerations
+
++ Gateway :: The status could be:
+ - [ ] Gateway may or may not be running
+ - [ ] Gateway may or may not have been downloaded at correct version
+ - [ ] Gateway may or may not have been downloaded at different version
+ - [ ] Gateway may be installed at location in PATH but not the one we expect
+
+** Decisions
+
++ We don't want to delete or install the gateway anywhere other than
~~/.local/lib/hyperdrive.el~. :: In case the user has installed a different
version at a different location, we want to respect that.
++ ::
+
+** Testing gateway commands
+
+| Should test | 👍 install | 👍 start | 👍 stop |
gateway-in-expected-place | gateway-only-in-path | running-as-subprocess |
running-outside-Emacs |
+|-----------------------+------------+----------+---------+---------------------------+----------------------+-----------------------+-----------------------|
+| no (impossible) | | | | yes
| yes | yes | yes |
+| no (impossible) | | | | yes
| no | yes | yes |
+| no (impossible) | | | | no
| yes | yes | yes |
+| no (impossible) | | | | no
| no | yes | yes |
+| no (unlikely) | | | | yes
| no | no | yes |
+| no (unlikely) | | | | no
| no | no | yes |
+| no (unlikely) | | | | no
| no | yes | no |
+| no (won't check PATH) | | | | yes
| yes | no | yes |
+| no (won't check PATH) | | | | yes
| yes | yes | no |
+| no (won't check PATH) | | | | yes
| yes | no | no |
+|-----------------------+------------+----------+---------+---------------------------+----------------------+-----------------------+-----------------------|
+| yes | yes | yes | yes | no
| no | no | no |
+| yes | yes | yes | yes | no
| yes | no | no |
+| yes | yes | yes | yes | no
| yes | no | yes |
+| yes | yes | yes | yes | no
| yes | yes | no |
+| yes | yes | yes | yes | yes
| no | no | no |
+| yes | yes | yes | yes | yes
| no | yes | no |
* PROJECT Petnames
:PROPERTIES:
:ID: e5b0c0f1-7ebc-4e8c-9712-cd2cd4a055ce
@@ -422,3 +467,17 @@ Depending on the resolution of
[[https://github.com/jrblevin/markdown-mode/issue
Targets are not currently implemented.
+* UI
+
+** Menu bar
+
+*** DECISION Don't show status indicators in menu bar
+
+Since the menu bar's items can't be updated while the menu is displayed,
showing an indicator could be misleading to the user, since it could become
outdated while the menu is displayed (e.g. while starting the gateway).
+
+So we won't show such indicators in the menu bar. Instead, the Transient
~hyperdrive-menu~ UI is a suitable "dashboard" for such indicators, because the
Transient can be refreshed while it's displayed.
+
+** DECISION No uninstall command
+
++ [X] Should we add an uninstall command? :: Probably not, due to issues with
potentially shared data and data loss. Probably sufficient to document the
file/directory locations in a manual section and allow the user to delete them
if desired.
+
diff --git a/doc/hyperdrive.org b/doc/hyperdrive.org
index 8817fdcb93..47fae0873b 100644
--- a/doc/hyperdrive.org
+++ b/doc/hyperdrive.org
@@ -43,11 +43,6 @@ modify this GNU manual."
~hyperdrive.el~ requires [[https://www.gnu.org/software/emacs/][GNU Emacs]]
version 28.1 or later.
-** Install hyper-gateway-ushin
-
-~hyperdrive.el~ relies on
[[https://git.sr.ht/~ushin/hyper-gateway-ushin/][hyper-gateway-ushin]] for
talking to the
-hypercore network
([[https://git.sr.ht/~ushin/hyper-gateway-ushin#installation][installation
instructions]]).
-
** Install hyperdrive.el
~hyperdrive.el~ can be installed from
[[https://elpa.nongnu.org/nongnu/hyperdrive.html][NonGNU ELPA]] with ~M-x
@@ -59,6 +54,16 @@ version of ~hyperdrive.el~ by running ~M-x
package-refresh-contents~ then
is not available as a command, display the list of packages with ~M-x
list-packages~, select ~hyperdrive~, and click the ~Install~ button.
+** Install hyper-gateway-ushin
+
+~hyperdrive.el~ relies on
[[https://git.sr.ht/~ushin/hyper-gateway-ushin/][hyper-gateway-ushin]] for
talking to the
+hypercore network.
+
+After installing ~hyperdrive.el~ (see [[*Install hyperdrive.el][Install
hyperdrive.el]]), run ~M-x
+hyperdrive-install~ to download and install the gateway.
+
+Alternatively, follow the
[[https://git.sr.ht/~ushin/hyper-gateway-ushin#installation][manual
installation instructions]].
+
* Example configuration
After following the [[*Installation][installation instructions]], you can add
this
@@ -91,6 +96,20 @@ When you upload a file, beware:
On the network it still may be there.
#+end_verse
+** Install the gateway
+
+Run ~M-x hyperdrive-install~ to download and install the gateway program
+(see [[*hyper-gateway-ushin]]):
+
+- Command: hyperdrive-install ::
+
+ Download and install the gateway. Prompts for confirmation before
+ downloading.
+
+- Command: hyperdrive-cancel-install ::
+
+ Cancel installation in progress.
+
** Menu bar support
#+findex: menu-bar-mode
@@ -132,41 +151,47 @@ documentation]]. To learn about the commands available in
** Start/stop the gateway
-To connect with peers, you'll need to start ~hyper-gateway-ushin~ (see
-[[*hyper-gateway-ushin]]). The current running status of the gateway can
-be seen in ~hyperdrive-menu~ (see [[*Hyperdrive menu command]]) and in the
-"Hyperdrive" menu bar (see [[*Menu bar support]]).
+To connect with peers, you'll need to start the gateway (see
+[[*hyper-gateway-ushin]]). The current running status of the gateway
+can be seen in ~hyperdrive-menu~ (see [[*Hyperdrive menu command]])
+and in the "Hyperdrive" menu bar (see [[*Menu bar support]]).
- Command: hyperdrive-start ::
- Start ~hyper-gateway-ushin~.
+ Start the gateway.
+
+- User Option: hyperdrive-gateway-ready-hook ::
+
+ Hook run when the gateway becomes responsive after ~hyperdrive-start~.
+ One of the default hooks, ~hyperdrive-check-gateway-version~, will
+ warn you if you're running an outdated version of the gateway.
- Command: hyperdrive-stop ::
- Stop ~hyper-gateway-ushin~.
+ Stop the gateway.
-- User Option: hyperdrive-gateway-process-type ::
+- Command: hyperdrive-restart ::
- How to start and stop ~hyper-gateway-ushin~. By default,
- ~hyperdrive.el~ will autodetect the appropriate process type. If you
- have configured
[[https://git.sr.ht/~ushin/hyper-gateway-ushin#how-do-i-run-hyper-gateway-ushin-as-a-background-process-on-gnulinux--systemd][hyper-gateway-ushin
to run as a systemd service]],
- then ~hyperdrive.el~ will automatically use ~systemd~ to manage the
- gateway. Otherwise, ~hyperdrive.el~ will start ~hyper-gateway-ushin~
- as an Emacs subprocess.
+ Restart the gateway.
-- User Option: hyperdrive-gateway-command ::
+- Command: hyperdrive-gateway-version ::
- The command run to start ~hyper-gateway-ushin~ as an Emacs subprocess. This
- option only takes effect when ~hyperdrive-gateway-process-type~ is set
- to ~subprocess~.
+ Say the version of the gateway which is running.
-Alternatively, you can start ~hyper-gateway-ushin~ manually by running:
+*** Advanced gateway customization
-#+begin_src sh
-hyper-gateway-ushin run --writable true
-#+end_src
+- User Option: hyperdrive-gateway-start-function ::
-For full usage instructions, see the
[[https://git.sr.ht/~ushin/hyper-gateway-ushin#usage][hyper-gateway-ushin
README]].
+ Function run to start the gateway. By default, ~hyperdrive.el~ will
+ start the gateway as an Emacs subprocess.
+
+- User Option: hyperdrive-gateway-stop-function ::
+
+ Function run to stop the gateway.
+
+- User Option: hyperdrive-gateway-live-predicate ::
+
+ Function run to check that the gateway process is live.
** Open a hyperdrive
@@ -932,14 +957,13 @@ your hyperdrive was actually created at version 51 of
your hyperdrive:
| 1-50 | unknown |
Running ~hyperdrive-previous~ while looking at ~/bar.org~ at version 51 or
-52 will send a request for ~/bar.org~ at version 50.
-~hyper-gateway-ushin~ will report that ~/bar.org~ does not exist at
-version 50, but it won't report whether ~/bar.org~ ever existed /before/
-version 50. For example, ~/bar.org~ might have been created at version
-6, deleted at 14, then created again at version 51. ~hyperdrive.el~
-will keep sending requests to the network (up to
-~hyperdrive-fill-version-ranges-limit~) until the history view looks
-like:
+52 will send a request for ~/bar.org~ at version 50. The gateway will
+report that ~/bar.org~ does not exist at version 50, but it won't report
+whether ~/bar.org~ ever existed /before/ version 50. For example,
+~/bar.org~ might have been created at version 6, deleted at 14, then
+created again at version 51. ~hyperdrive.el~ will keep sending requests
+to the network (up to ~hyperdrive-fill-version-ranges-limit~) until the
+history view looks like:
| Version range | exists |
|---------------+---------|
@@ -966,7 +990,7 @@ and technical reason:
The secret master key is combined with a seed (see [[*Seeds]]) to generate
a new public key for a hyperdrive when you run ~hyperdrive-new~. Your
-master key is generated automatically by ~hyper-gateway-ushin~.
+master key is generated automatically by the gateway.
** hyper-gateway-ushin
#+cindex: hyper-gateway-ushin
@@ -1003,8 +1027,8 @@ Public keys are globally unique identifiers for
hyperdrives. They
make up the first part of a ~hyper://~ URL. Public keys are
52-character-long
[[https://en.wikipedia.org/wiki/Base32#z-base-32][z-base-32]] encoded keys
generated from your master
key (see [[*Master key]]) and a [[*Seeds][seed]] string. When you run
~hyperdrive-new~
-and type a new seed, ~hyper-gateway-ushin~ automatically generates a
-new public key.
+and type a new seed, the gateway automatically generates a new public
+key.
*** Nicknames
#+cindex: Nicknames
@@ -1053,10 +1077,29 @@ DNS domains are checked for suspicious characters (see
You can adjust the following options in the customization interface by
running ~M-x customize-group RET hyperdrive RET~:
-- User Option: hyperdrive-hyper-gateway-ushin-port ::
+- User Option: hyperdrive-gateway-program ::
+
+ Name of executable to run when starting the gateway with
+ ~hyperdrive-gateway-start-function~. ~hyperdrive-install~ will install
+ the gateway to this file in ~hyperdrive-gateway-directory~.
+
+- User Option: hyperdrive-gateway-directory ::
+
+ Filesystem directory in which the gateway is expected to be found.
+ ~hyperdrive-install~ will install the gateway to this location. When
+ starting the gateway, if ~hyperdrive-gateway-program~ is not found in
+ this directory, Emacs searches ~PATH~ for ~hyperdrive-gateway-program~.
+
+- User Option: hyperdrive-gateway-command-args ::
+
+ Command line arguments passed to the gateway when starting the
+ gateway with the default ~hyperdrive-gateway-start-function~.
- ~hyperdrive.el~ will send HTTP requests to ~hyper-gateway-ushin~ on this
port.
- Defaults to ~4973~.
+- User Option: hyperdrive-gateway-port ::
+
+ ~hyperdrive.el~ will send HTTP requests to the gateway on this port.
+ Defaults to ~4973~. The default ~hyperdrive-gateway-start-function~
+ will start the gateway on this port.
- User Option: hyperdrive-persist-location ::
@@ -1071,8 +1114,8 @@ running ~M-x customize-group RET hyperdrive RET~:
- User Option: hyperdrive-queue-limit ::
- Default number of request sent to ~hyper-gateway-ushin~ at a time in
- a queue. Defaults to ~20~.
+ Default number of request sent to the gateway at a time in a queue.
+ Defaults to ~20~.
- User Option: hyperdrive-fill-version-ranges-limit ::
@@ -1186,24 +1229,24 @@ to the relevant section in the ~hyperdrive.el~ manual.
* Troubleshooting
-If you run into issues, please first try resetting the values of
-~hyperdrive-hyperdrives~ and ~hyperdrive-version-ranges~:
+** Reinstall/upgrade the gateway
+
+Please ensure that you have the expected version of the gateway by
+running ~M-x hyperdrive-install~.
+
+** Reset bad persist variables
+
+It is possible that the persisted values of ~hyperdrive-hyperdrives~
+and/or ~hyperdrive-version-ranges~ are wrong. Reset them by evaluating:
#+begin_src emacs-lisp
(progn
- (setf hyperdrive-hyperdrives (make-hash-table :test #'equal))
+ (persist-reset 'hyperdrive-hyperdrives)
(persist-save 'hyperdrive-hyperdrives)
- (setf hyperdrive-version-ranges (make-hash-table :test #'equal))
+ (persist-reset 'hyperdrive-version-ranges)
(persist-save 'hyperdrive-version-ranges))
#+end_src
-Please ensure that your version of ~hyper-gateway-ushin~ (~M-x
-hyperdrive-hyper-gateway-ushin-version~) is version `3.8.0` ([download
-from
-Codeberg](https://codeberg.org/USHIN/hyper-gateway-ushin/releases/tag/v3.8.0)
-or [download from
-SourceHut](https://git.sr.ht/~ushin/hyper-gateway-ushin/refs/v3.8.0)).
-
* Contributing/Getting help
You're welcome to join our public XMPP chat room!
@@ -1214,6 +1257,18 @@ You're welcome to join our public XMPP chat room!
Bugs can be submitted to the [[https://todo.sr.ht/~ushin/ushin][ushin issue
tracker]]. Patches, comments or
questions can be submitted to the [[https://lists.sr.ht/~ushin/ushin][ushin
public inbox]].
+* Uninstallation
+
+If you have installed the gateway with ~hyperdrive-install~, you can
+delete the gateway which Emacs downloaded according to the values of
+~hyperdrive-gateway-directory~ and ~hyperdrive-gateway-program~, which is
+~~/.local/lib/hyperdrive.el/hyper-gateway-ushin~ by default.
+
+You can delete the user data which ~hyper-gateway-ushin~ stores by
+default in ~~/.local/share/hyper-gateway-nodejs~.
+
+You can remove ~hyperdrive.el~ with ~M-x package-delete hyperdrive~.
+
* Acknowledgments
[[https://github.com/alphapapa/][Adam Porter]] for rewriting ~hyperdrive.el~
and for his work on ~plz.el~.
diff --git a/doc/hyperdrive.texi b/doc/hyperdrive.texi
index e47ff36557..9062b697d6 100644
--- a/doc/hyperdrive.texi
+++ b/doc/hyperdrive.texi
@@ -59,6 +59,7 @@ This manual is for @code{hyperdrive.el} version 0.4-pre.
* Tips::
* Troubleshooting::
* Contributing/Getting help::
+* Uninstallation::
* Acknowledgments::
* Indices::
* GNU Free Documentation License::
@@ -69,11 +70,12 @@ This manual is for @code{hyperdrive.el} version 0.4-pre.
Installation
* Install Emacs::
-* Install hyper-gateway-ushin::
* Install hyperdrive.el: Install hyperdriveel.
+* Install hyper-gateway-ushin::
Usage
+* Install the gateway::
* Menu bar support::
* Hyperdrive menu command::
* Start/stop the gateway::
@@ -94,6 +96,10 @@ Usage
* Org-transclusion integration::
* Miscellaneous features::
+Start/stop the gateway
+
+* Advanced gateway customization::
+
Open a hyperdrive
* Directory view::
@@ -165,6 +171,11 @@ Tips
* Quick documentation access::
+Troubleshooting
+
+* Reinstall/upgrade the gateway::
+* Reset bad persist variables::
+
Indices
* Keystroke index::
@@ -198,8 +209,8 @@ modify this GNU manual.''
@menu
* Install Emacs::
-* Install hyper-gateway-ushin::
* Install hyperdrive.el: Install hyperdriveel.
+* Install hyper-gateway-ushin::
@end menu
@node Install Emacs
@@ -207,12 +218,6 @@ modify this GNU manual.''
@code{hyperdrive.el} requires @uref{https://www.gnu.org/software/emacs/, GNU
Emacs} version 28.1 or later.
-@node Install hyper-gateway-ushin
-@section Install hyper-gateway-ushin
-
-@code{hyperdrive.el} relies on
@uref{https://git.sr.ht/~ushin/hyper-gateway-ushin/, hyper-gateway-ushin} for
talking to the
-hypercore network
(@uref{https://git.sr.ht/~ushin/hyper-gateway-ushin#installation, installation
instructions}).
-
@node Install hyperdriveel
@section Install hyperdrive.el
@@ -225,6 +230,17 @@ version of @code{hyperdrive.el} by running @code{M-x
package-refresh-contents} t
is not available as a command, display the list of packages with @code{M-x
list-packages}, select @code{hyperdrive}, and click the @code{Install} button.
+@node Install hyper-gateway-ushin
+@section Install hyper-gateway-ushin
+
+@code{hyperdrive.el} relies on
@uref{https://git.sr.ht/~ushin/hyper-gateway-ushin/, hyper-gateway-ushin} for
talking to the
+hypercore network.
+
+After installing @code{hyperdrive.el} (see @ref{Install hyperdriveel, ,
Install hyperdrive.el}), run @code{M-x
+hyperdrive-install} to download and install the gateway.
+
+Alternatively, follow the
@uref{https://git.sr.ht/~ushin/hyper-gateway-ushin#installation, manual
installation instructions}.
+
@node Example configuration
@chapter Example configuration
@@ -260,6 +276,7 @@ On the network it still may be there.
@end display
@menu
+* Install the gateway::
* Menu bar support::
* Hyperdrive menu command::
* Start/stop the gateway::
@@ -281,6 +298,21 @@ On the network it still may be there.
* Miscellaneous features::
@end menu
+@node Install the gateway
+@section Install the gateway
+
+Run @code{M-x hyperdrive-install} to download and install the gateway program
+(see @ref{hyper-gateway-ushin}):
+
+@deffn Command hyperdrive-install
+Download and install the gateway. Prompts for confirmation before
+downloading.
+@end deffn
+
+@deffn Command hyperdrive-cancel-install
+Cancel installation in progress.
+@end deffn
+
@node Menu bar support
@section Menu bar support
@@ -326,41 +358,52 @@ documentation,,transient,}. To learn about the commands
available in
@node Start/stop the gateway
@section Start/stop the gateway
-To connect with peers, you'll need to start @code{hyper-gateway-ushin} (see
-@ref{hyper-gateway-ushin}). The current running status of the gateway can
-be seen in @code{hyperdrive-menu} (see @ref{Hyperdrive menu command}) and in
the
-``Hyperdrive'' menu bar (see @ref{Menu bar support}).
+To connect with peers, you'll need to start the gateway (see
+@ref{hyper-gateway-ushin}). The current running status of the gateway
+can be seen in @code{hyperdrive-menu} (see @ref{Hyperdrive menu command})
+and in the ``Hyperdrive'' menu bar (see @ref{Menu bar support}).
@deffn Command hyperdrive-start
-Start @code{hyper-gateway-ushin}.
+Start the gateway.
@end deffn
+@defopt hyperdrive-gateway-ready-hook
+Hook run when the gateway becomes responsive after @code{hyperdrive-start}.
+One of the default hooks, @code{hyperdrive-check-gateway-version}, will
+warn you if you're running an outdated version of the gateway.
+@end defopt
+
@deffn Command hyperdrive-stop
-Stop @code{hyper-gateway-ushin}.
+Stop the gateway.
@end deffn
-@defopt hyperdrive-gateway-process-type
-How to start and stop @code{hyper-gateway-ushin}. By default,
-@code{hyperdrive.el} will autodetect the appropriate process type. If you
-have configured
@uref{https://git.sr.ht/~ushin/hyper-gateway-ushin#how-do-i-run-hyper-gateway-ushin-as-a-background-process-on-gnulinux--systemd,
hyper-gateway-ushin to run as a systemd service},
-then @code{hyperdrive.el} will automatically use @code{systemd} to manage the
-gateway. Otherwise, @code{hyperdrive.el} will start @code{hyper-gateway-ushin}
-as an Emacs subprocess.
-@end defopt
+@deffn Command hyperdrive-restart
+Restart the gateway.
+@end deffn
-@defopt hyperdrive-gateway-command
-The command run to start @code{hyper-gateway-ushin} as an Emacs subprocess.
This
-option only takes effect when @code{hyperdrive-gateway-process-type} is set
-to @code{subprocess}.
-@end defopt
+@deffn Command hyperdrive-gateway-version
+Say the version of the gateway which is running.
+@end deffn
-Alternatively, you can start @code{hyper-gateway-ushin} manually by running:
+@menu
+* Advanced gateway customization::
+@end menu
-@example
-hyper-gateway-ushin run --writable true
-@end example
+@node Advanced gateway customization
+@subsection Advanced gateway customization
-For full usage instructions, see the
@uref{https://git.sr.ht/~ushin/hyper-gateway-ushin#usage, hyper-gateway-ushin
README}.
+@defopt hyperdrive-gateway-start-function
+Function run to start the gateway. By default, @code{hyperdrive.el} will
+start the gateway as an Emacs subprocess.
+@end defopt
+
+@defopt hyperdrive-gateway-stop-function
+Function run to stop the gateway.
+@end defopt
+
+@defopt hyperdrive-gateway-live-predicate
+Function run to check that the gateway process is live.
+@end defopt
@node Open a hyperdrive
@section Open a hyperdrive
@@ -1284,14 +1327,13 @@ your hyperdrive was actually created at version 51 of
your hyperdrive:
@end multitable
Running @code{hyperdrive-previous} while looking at @code{/bar.org} at version
51 or
-52 will send a request for @code{/bar.org} at version 50.
-@code{hyper-gateway-ushin} will report that @code{/bar.org} does not exist at
-version 50, but it won't report whether @code{/bar.org} ever existed
@emph{before}
-version 50. For example, @code{/bar.org} might have been created at version
-6, deleted at 14, then created again at version 51. @code{hyperdrive.el}
-will keep sending requests to the network (up to
-@code{hyperdrive-fill-version-ranges-limit}) until the history view looks
-like:
+52 will send a request for @code{/bar.org} at version 50. The gateway will
+report that @code{/bar.org} does not exist at version 50, but it won't report
+whether @code{/bar.org} ever existed @emph{before} version 50. For example,
+@code{/bar.org} might have been created at version 6, deleted at 14, then
+created again at version 51. @code{hyperdrive.el} will keep sending requests
+to the network (up to @code{hyperdrive-fill-version-ranges-limit}) until the
+history view looks like:
@multitable {aaaaaaaaaaaaa} {aaaaaa}
@headitem Version range
@@ -1332,7 +1374,7 @@ contains, which can never prove that a directory doesn't
exist.
The secret master key is combined with a seed (see @ref{Seeds}) to generate
a new public key for a hyperdrive when you run @code{hyperdrive-new}. Your
-master key is generated automatically by @code{hyper-gateway-ushin}.
+master key is generated automatically by the gateway.
@node hyper-gateway-ushin
@section hyper-gateway-ushin
@@ -1392,8 +1434,8 @@ Public keys are globally unique identifiers for
hyperdrives. They
make up the first part of a @code{hyper://} URL@. Public keys are
52-character-long @uref{https://en.wikipedia.org/wiki/Base32#z-base-32,
z-base-32} encoded keys generated from your master
key (see @ref{Master key}) and a @ref{Seeds, , seed} string. When you run
@code{hyperdrive-new}
-and type a new seed, @code{hyper-gateway-ushin} automatically generates a
-new public key.
+and type a new seed, the gateway automatically generates a new public
+key.
@node Nicknames
@subsection Nicknames
@@ -1451,9 +1493,28 @@ DNS domains are checked for suspicious characters (see
You can adjust the following options in the customization interface by
running @code{M-x customize-group RET hyperdrive RET}:
-@defopt hyperdrive-hyper-gateway-ushin-port
-@code{hyperdrive.el} will send HTTP requests to @code{hyper-gateway-ushin} on
this port.
-Defaults to @code{4973}.
+@defopt hyperdrive-gateway-program
+Name of executable to run when starting the gateway with
+@code{hyperdrive-gateway-start-function}. @code{hyperdrive-install} will
install
+the gateway to this file in @code{hyperdrive-gateway-directory}.
+@end defopt
+
+@defopt hyperdrive-gateway-directory
+Filesystem directory in which the gateway is expected to be found.
+@code{hyperdrive-install} will install the gateway to this location. When
+starting the gateway, if @code{hyperdrive-gateway-program} is not found in
+this directory, Emacs searches @code{PATH} for
@code{hyperdrive-gateway-program}.
+@end defopt
+
+@defopt hyperdrive-gateway-command-args
+Command line arguments passed to the gateway when starting the
+gateway with the default @code{hyperdrive-gateway-start-function}.
+@end defopt
+
+@defopt hyperdrive-gateway-port
+@code{hyperdrive.el} will send HTTP requests to the gateway on this port.
+Defaults to @code{4973}. The default @code{hyperdrive-gateway-start-function}
+will start the gateway on this port.
@end defopt
@defopt hyperdrive-persist-location
@@ -1468,8 +1529,8 @@ which see.
@end defopt
@defopt hyperdrive-queue-limit
-Default number of request sent to @code{hyper-gateway-ushin} at a time in
-a queue. Defaults to @code{20}.
+Default number of request sent to the gateway at a time in a queue.
+Defaults to @code{20}.
@end defopt
@defopt hyperdrive-fill-version-ranges-limit
@@ -1614,24 +1675,31 @@ to the relevant section in the @code{hyperdrive.el}
manual.
@node Troubleshooting
@chapter Troubleshooting
-If you run into issues, please first try resetting the values of
-@code{hyperdrive-hyperdrives} and @code{hyperdrive-version-ranges}:
+@menu
+* Reinstall/upgrade the gateway::
+* Reset bad persist variables::
+@end menu
+
+@node Reinstall/upgrade the gateway
+@section Reinstall/upgrade the gateway
+
+Please ensure that you have the expected version of the gateway by
+running @code{M-x hyperdrive-install}.
+
+@node Reset bad persist variables
+@section Reset bad persist variables
+
+It is possible that the persisted values of @code{hyperdrive-hyperdrives}
+and/or @code{hyperdrive-version-ranges} are wrong. Reset them by evaluating:
@lisp
(progn
- (setf hyperdrive-hyperdrives (make-hash-table :test #'equal))
+ (persist-reset 'hyperdrive-hyperdrives)
(persist-save 'hyperdrive-hyperdrives)
- (setf hyperdrive-version-ranges (make-hash-table :test #'equal))
+ (persist-reset 'hyperdrive-version-ranges)
(persist-save 'hyperdrive-version-ranges))
@end lisp
-Please ensure that your version of @code{hyper-gateway-ushin} (@code{M-x
-hyperdrive-hyper-gateway-ushin-version}) is version `3.8.0` ([download
-from
-Codeberg](@uref{https://codeberg.org/USHIN/hyper-gateway-ushin/releases/tag/v3.8.0})
-or [download from
-SourceHut](@uref{https://git.sr.ht/~ushin/hyper-gateway-ushin/refs/v3.8.0})).
-
@node Contributing/Getting help
@chapter Contributing/Getting help
@@ -1647,6 +1715,19 @@ You're welcome to join our public XMPP chat room!
Bugs can be submitted to the @uref{https://todo.sr.ht/~ushin/ushin, ushin
issue tracker}. Patches, comments or
questions can be submitted to the @uref{https://lists.sr.ht/~ushin/ushin,
ushin public inbox}.
+@node Uninstallation
+@chapter Uninstallation
+
+If you have installed the gateway with @code{hyperdrive-install}, you can
+delete the gateway which Emacs downloaded according to the values of
+@code{hyperdrive-gateway-directory} and @code{hyperdrive-gateway-program},
which is
+@code{~/.local/lib/hyperdrive.el/hyper-gateway-ushin} by default.
+
+You can delete the user data which @code{hyper-gateway-ushin} stores by
+default in @code{~/.local/share/hyper-gateway-nodejs}.
+
+You can remove @code{hyperdrive.el} with @code{M-x package-delete hyperdrive}.
+
@node Acknowledgments
@chapter Acknowledgments
diff --git a/hyperdrive-lib.el b/hyperdrive-lib.el
index ddac1e80f2..3941e7424d 100644
--- a/hyperdrive-lib.el
+++ b/hyperdrive-lib.el
@@ -36,6 +36,7 @@
(require 'compat)
(require 'persist)
(require 'plz)
+(require 'transient)
(require 'hyperdrive-vars)
@@ -153,7 +154,7 @@ See `hyperdrive-directory-sort' for the type of DIRECTION."
Calls `hyperdrive--httpify-url' to convert HYPER-URL starting
with `hyperdrive--hyper-prefix' to a URL starting with
\"http://localhost:4973/hyper/\" (assuming that
-`hyperdrive-hyper-gateway-ushin-port' is \"4973\").
+`hyperdrive-gateway-port' is \"4973\").
REST is passed to `plz', which see.
@@ -197,6 +198,33 @@ make the request."
;; We pass only the `plz-error' struct to the ELSE* function.
(funcall else* (caddr err))))))
+(defun h/gateway-needs-upgrade-p ()
+ "Return non-nil if the gateway is responsive and needs upgraded."
+ (and (h//gateway-ready-p)
+ (not (equal h/gateway-version-expected (h//gateway-version)))))
+
+(defun h/check-gateway-version ()
+ "Warn if gateway is responsive and not at the expected version.
+Unconditionally sets `h/gateway-version-checked-p' to t."
+ (when (h/gateway-needs-upgrade-p)
+ (display-warning
+ 'hyperdrive
+ (substitute-command-keys
+ (format
+ "Gateway version %S not expected %S; consider installing the latest
version with \\[hyperdrive-install]"
+ (h//gateway-version) h/gateway-version-expected))
+ :warning))
+ (setf h/gateway-version-checked-p t))
+
+(defun h//gateway-version ()
+ "Return the name and version number of gateway as a plist.
+If it's not running, signal an error."
+ (condition-case err
+ (pcase-let* ((url (format "http://localhost:%d/" h/gateway-port))
+ ((map name version) (plz 'get url :as #'json-read)))
+ (list :name name :version version))
+ (plz-error (h/api-default-else nil (caddr err)))))
+
(defun h/api-default-else (else plz-err)
"Handle common errors, overriding ELSE.
Checks for common errors; if none are found, calls ELSE with
@@ -207,26 +235,17 @@ PLZ-ERR should be a `plz-error' struct."
;; Curl error 7 is "Failed to connect to host."
(h/user-error "Gateway not running. Use \\[hyperdrive-start] to start
it"))
((app plz-error-response (cl-struct plz-response (status (or 403 405))
body))
- ;; 403 Forbidden or 405 Method Not Allowed: Display message from
- ;; hyper-gateway-ushin.
+ ;; 403 Forbidden or 405 Method Not Allowed: Display message from gateway.
(h/error "%s" body))
((guard else)
(funcall else plz-err))
(_
(signal 'plz-error (list "plz error" plz-err)))))
-;;;###autoload
-(defun hyperdrive-status ()
- "Return non-nil if `hyper-gateway-ushin' is running and accessible."
- ;; FIXME: Ensure a very short timeout for this request.
- (condition-case nil
- (plz 'get (format "http://localhost:%d/" h/hyper-gateway-ushin-port))
- (error nil)))
-
(defun h//httpify-url (url)
"Return localhost HTTP URL for HYPER-URL."
(format "http://localhost:%d/hyper/%s"
- h/hyper-gateway-ushin-port
+ h/gateway-port
(substring url (length h//hyper-prefix))))
(cl-defun h//write (url &key body then else queue)
@@ -276,7 +295,7 @@ before making the entry struct."
;; not recognizable anyway.
(unless (y-or-n-p
(format "Suspicious domain: %s; continue
anyway?" host))
- (user-error "Suspicious domain %s" host)))
+ (h/user-error "Suspicious domain %s" host)))
(h/create :domains (list host)))
(_ ;; Assume host is a public-key
(or (gethash host h/hyperdrives)
@@ -584,7 +603,7 @@ echo area when the request for the file is made."
(not-found-action))))
(500 ;; Generic error, likely a mistyped URL
(h/message
- "Generic hyper-gateway-ushin status 500 error. %s %s"
+ "Generic gateway status 500 error. %s %s"
"Is this URL correct?" (he/url entry)))
(_ (h/message "Unable to load URL \"%s\": %S"
(he/url entry) err))))))
@@ -943,7 +962,7 @@ HYPERDRIVE's public metadata file."
(cl-defun h/purge-no-prompt (hyperdrive &key then else)
"Purge all data corresponding to HYPERDRIVE, then call THEN with response.
-- HYPERDRIVE file content and metadata managed by hyper-gateway-ushin
+- HYPERDRIVE file content and metadata managed by the gateway
- hash table entry for HYPERDRIVE in `hyperdrive-hyperdrives'
- hash table entries for HYPERDRIVE in `hyperdrive-version-ranges'
@@ -1396,155 +1415,121 @@ Then calls THEN if given."
;;;; Gateway process
-;; NOTE: The below involves some slightly hacky workarounds due to using a
-;; setter for the `h/gateway-process-type' option. The setter gets called
-;; unexpectedly early in the compilation and/or load process, which causes
-;; errors if the functions/methods and variables involved are not yet defined.
-;; So we define the variable first, giving it a nil value, and define a default
-;; for the running-p method (because the setter gets called before the option
is
-;; given its default value), and then the variable is redefined as an option
and
-;; given its default value.
-
-(defvar h/gateway-process-type nil)
+(defun h//gateway-path ()
+ "Return path to gateway executable, or nil if not found.
+See user options `hyperdrive-gateway-program' and
+`hyperdrive-gateway-directory'."
+ (cond ((file-exists-p
+ (expand-file-name h/gateway-program h/gateway-directory))
+ (expand-file-name h/gateway-program h/gateway-directory))
+ ((executable-find h/gateway-program))))
-(cl-defmethod h//gateway-running-p ()
- "Return non-nil if the gateway process is running.")
+(defun h//gateway-start-default ()
+ "Start the gateway as an Emacs subprocess.
+Default function; see variable `h/gateway-start-function'."
+ (setf h/gateway-process
+ (make-process
+ :name "hyperdrive-gateway"
+ :buffer " *hyperdrive-start*"
+ :command (cons (h//gateway-path)
+ (append (split-string-and-unquote
h/gateway-command-args)
+ (list "--port" (number-to-string
h/gateway-port))))
+ :connection-type 'pipe)))
+
+(defun h/announce-gateway-ready ()
+ "Announce that the gateway is ready."
+ (h/message "Gateway ready."))
+
+(defun h/menu-refresh ()
+ "Refresh `hyperdrive-menu' if it's open."
+ ;; TODO(transient): Doesn't work if hyperdrive-start called outside with M-x,
+ ;; not from menu. Jonas might add a variable like `transient-active-command'
+ ;; to DTRT.
+ (when (and (eq transient-current-command 'h/menu)
+ ;; Depending on transient-show-popup customization, there
+ ;; might be no popup (yet).
+ transient--showp
+ ;; FIXME(transient): This probably does not detect all cases of a
+ ;; suspended transient, but I think there is no proper way to
query
+ ;; that state yet. I'll look into that. --Jonas
+ (not (active-minibuffer-window)))
+ (transient--refresh-transient)))
+
+(defun h//gateway-stop-default ()
+ "Stop the gateway subprocess."
+ (unless (h/gateway-live-p-default)
+ ;; NOTE: We do not try to stop the process if we didn't start it ourselves.
+ (h/user-error "Gateway not running as subprocess"))
+ (interrupt-process h/gateway-process)
+ (with-timeout (4 (h/error "Gateway still running"))
+ (cl-loop while (h/gateway-live-p)
+ do (sleep-for 0.2)))
+ (kill-buffer (process-buffer h/gateway-process))
+ (setf h/gateway-process nil)
+ (when (timerp h//gateway-starting-timer)
+ (cancel-timer h//gateway-starting-timer))
+ (h/message "Gateway stopped."))
-(cl-defmethod h//gateway-running-p (&context (h/gateway-process-type (eql
'systemd)))
+(defun h/gateway-live-p ()
"Return non-nil if the gateway process is running.
+Calls function set in option `hyperdrive-gateway-live-predicate'.
This does not mean that the gateway is responsive, only that the
-process is running. Used when HYPERDRIVE-GATEWAY-PROCESS-TYPE
-is the symbol `systemd'."
- (zerop (call-process "systemctl" nil nil nil
- "--user" "is-active" "hyper-gateway-ushin.service")))
+process is running. See also function
+`hyperdrive--gateway-ready-p'."
+ (funcall h/gateway-live-predicate))
-(cl-defmethod h//gateway-running-p (&context (h/gateway-process-type (eql
'subprocess)))
- "Return non-nil if the gateway process is running.
+(defun h/gateway-live-p-default ()
+ "Return non-nil if the gateway is running as an Emacs subprocess.
This does not mean that the gateway is responsive, only that the
-process is running. Used when HYPERDRIVE-GATEWAY-PROCESS-TYPE
-is the symbol `subprocess'."
+process is running."
(process-live-p h/gateway-process))
-(defcustom h/gateway-process-type nil
- "How to run the gateway process.
-Value may be one of
-
-- nil :: Autodetect
-- \\+`systemd' :: systemd user-level service
-- \\+`subprocess' :: Emacs subprocess
-
-To customize the command run as a subprocess, see
-`hyperdrive-gateway-command'."
- ;; TODO: Can or should we use the :initialize function here?
- :set (lambda (option value)
- "Stop the gateway process before changing the type."
- (let ((value-changing-p (not (equal h/gateway-process-type value))))
- (unless value
- ;; Try to autodetect whether the gateway is already installed as a
- ;; systemd service. (If systemd is not installed, it will
default to
- ;; `subprocess'.)
- (setf value
- (if (ignore-errors
- (zerop (call-process
- "systemctl" nil nil nil "--user" "is-enabled"
- "hyper-gateway-ushin.service")))
- 'systemd
- 'subprocess)))
- (let ((runningp (h//gateway-running-p)))
- (when (and runningp value-changing-p)
- (h//gateway-stop))
- (set-default option value)
- (when (and runningp value-changing-p)
- (h//gateway-start)))))
- :type '(choice (const :tag "systemd service" systemd)
- (const :tag "Emacs subprocess"
- :description "When Emacs exits, the gateway will be
terminated."
- subprocess)
- (const :tag "Autodetect" nil))
- :group 'hyperdrive)
-
-(defcustom h/gateway-command
- "hyper-gateway-ushin run --writable true --silent true"
- ;; TODO: File Emacs bug report because the customization formatter handles
the
- ;; "symbol `subprocess'" part differently than `describe-variable' does.
- "Command used to run hyper-gateway-ushin.
-Only used when `hyperdrive-gateway-process-type' is the symbol `subprocess'."
- :type 'string
- :group 'hyperdrive)
-
-(cl-defmethod h//gateway-start (&context (h/gateway-process-type (eql
'systemd)))
- "Start the gateway as a systemd service.
-Used when HYPERDRIVE-GATEWAY-PROCESS-TYPE is the symbol
-`systemd'."
- (when (h//gateway-running-p)
- (user-error "Gateway already running"))
- (let ((buffer (get-buffer-create " *hyperdrive-start*")))
- (unwind-protect
- (unless (zerop (call-process
- "systemctl" nil (list buffer t) nil
- "--user" "start" "hyper-gateway-ushin.service"))
- (h/error "Unable to start hyper-gateway-ushin: %S"
- (with-current-buffer buffer
- (string-trim-right (buffer-string)))))
- (kill-buffer buffer))))
-
-(cl-defmethod h//gateway-start (&context (h/gateway-process-type (eql
'subprocess)))
- "Start the gateway as an Emacs subprocess.
-Used when HYPERDRIVE-GATEWAY-PROCESS-TYPE is the symbol
-`subprocess'."
- (when (h//gateway-running-p)
- (user-error "Gateway already running"))
- (condition-case nil
- (setf h/gateway-process
- (make-process :name "hyper-gateway-ushin"
- :buffer " *hyperdrive-start*"
- :command (split-string-and-unquote h/gateway-command)
- :connection-type 'pipe))
- (file-missing
- (info "(hyperdrive) hyper-gateway-ushin")
- (user-error
- "hyper-gateway-ushin not found; Please see installation instructions")))
- (sleep-for 0.5)
- (unless (process-live-p h/gateway-process)
- (if (h/status)
- (user-error "Gateway is already running outside of Emacs (see option
`hyperdrive-gateway-process-type')")
- (pop-to-buffer " *hyperdrive-start*")
- (h/error "Gateway failed to start (see process buffer for errors)"))))
-
-(cl-defmethod h//gateway-stop (&context (h/gateway-process-type (eql
'systemd)))
- "Stop the gateway service.
-Used when HYPERDRIVE-GATEWAY-PROCESS-TYPE is the symbol
-`systemd'."
- (unless (h//gateway-running-p)
- (user-error "Gateway not running"))
- (let ((buffer (get-buffer-create " *hyperdrive-stop*")))
- (unwind-protect
- (unless (zerop (call-process "systemctl" nil (list buffer t) nil
- "--user" "stop"
"hyper-gateway-ushin.service"))
- (h/error "Unable to stop hyper-gateway-ushin: %S"
- (with-current-buffer buffer
- (string-trim-right (buffer-string)))))
- (cl-loop for i below 40
- do (sleep-for 0.1)
- while (h//gateway-running-p))
- (when (h//gateway-running-p)
- (h/error "Gateway still running"))
- (kill-buffer buffer))))
-
-(cl-defmethod h//gateway-stop (&context (h/gateway-process-type (eql
'subprocess)))
- "Stop the gateway subprocess.
-Used when HYPERDRIVE-GATEWAY-PROCESS-TYPE is the symbol
-`subprocess'."
- (unless (h//gateway-running-p)
- (user-error "Gateway not running"))
- (interrupt-process h/gateway-process)
- (cl-loop for i below 40
- do (sleep-for 0.1)
- while (h//gateway-running-p))
- (when (h//gateway-running-p)
- (h/error "Gateway still running"))
- (kill-buffer (process-buffer h/gateway-process))
- (setf h/gateway-process nil))
+(defun h/gateway-installing-p ()
+ "Return non-nil if the gateway program is being installed."
+ ;; If this variable is non-nil, it might be a dead process, but it is
+ ;; interpreted to mean that we are still trying to download and install the
+ ;; gateway, because we are still trying other sources; we will set the
+ ;; variable nil when we succeed, give up, or are canceled.
+ h/install-process)
+
+(defun h/gateway-installed-p ()
+ "Return non-nil if the gateway program is installed."
+ (and-let* ((gateway-path (hyperdrive--gateway-path)))
+ (file-executable-p gateway-path)))
+
+(defun h//gateway-ready-p ()
+ "Return non-nil if the gateway is running and accessible.
+Times out after 2 seconds."
+ (ignore-errors
+ (plz 'get (format "http://localhost:%d/" h/gateway-port)
+ :connect-timeout 2 :timeout 2)))
+
+(defun h//gateway-wait-for-ready ()
+ "Run `hyperdrive-gateway-ready-hook' after gateway is ready.
+Or if gateway isn't ready within timeout, show an error."
+ (letrec
+ ((start-time (current-time))
+ (check
+ (lambda ()
+ (cond ((h//gateway-ready-p)
+ (run-hooks 'h/gateway-ready-hook))
+ ((< 10 (float-time (time-subtract nil start-time)))
+ ;; Gateway still not responsive: show error.
+ (if-let (((equal h/gateway-start-function
+ (eval (car (get 'h/gateway-start-function
+ 'standard-value)))))
+ (process-buffer (process-buffer h/gateway-process)))
+ (progn
+ ;; User has not customized the start function: show the
+ ;; process buffer.
+ (pop-to-buffer process-buffer)
+ (h/error "Gateway failed to start (see process buffer
for errors)"))
+ ;; User appears to have customized the start function: don't
+ ;; show the process buffer.
+ (h/error "Gateway failed to start")))
+ (t
+ (setf h//gateway-starting-timer (run-at-time 0.1 nil
check)))))))
+ (funcall check)))
;;;; Misc.
diff --git a/hyperdrive-menu.el b/hyperdrive-menu.el
index f0c89acbf8..cd91e98649 100644
--- a/hyperdrive-menu.el
+++ b/hyperdrive-menu.el
@@ -205,14 +205,40 @@
:description
(lambda ()
(concat (propertize "Gateway: " 'face 'transient-heading)
- (propertize (if (h/status) "on" "off")
- 'face 'transient-value)))
+ (propertize
+ (cond ((h//gateway-ready-p) "on")
+ ((h/gateway-live-p) "starting")
+ ((and (h/gateway-installed-p) (h/gateway-installing-p))
+ "upgrading")
+ ((h/gateway-installing-p) "installing")
+ ((h/gateway-installed-p) "off")
+ (t "not found"))
+ 'face 'transient-value)))
+ ("G i" "Install" h/install
+ :description
+ (lambda () (if (h/gateway-needs-upgrade-p) "Upgrade" "Install"))
+ :transient t
+ :if (lambda ()
+ (and (not (h/gateway-installing-p))
+ (or (not (h/gateway-installed-p))
+ (h/gateway-needs-upgrade-p)))))
+ ("G c" "Cancel install" h/cancel-install
+ :transient t
+ :if h/gateway-installing-p)
("G s" "Start" h/start
- :transient t)
+ :transient t
+ :inapt-if-not (lambda () (h/gateway-installed-p))
+ :if-not (lambda () (or (h/gateway-live-p) (h//gateway-ready-p))))
+ ("G r" "Restart" h/restart
+ :transient t
+ :inapt-if-not (lambda () (h/gateway-installed-p))
+ :if (lambda () (or (h/gateway-live-p) (h//gateway-ready-p))))
("G S" "Stop" h/stop
- :transient t)
- ("G v" "Version" h/hyper-gateway-ushin-version
- :transient t)]
+ :transient t
+ :inapt-if-not (lambda () (or (h/gateway-live-p) (h//gateway-ready-p))))
+ ("G v" "Version" h/gateway-version
+ :transient t
+ :inapt-if-not (lambda () (h//gateway-ready-p)))]
["Bookmark"
("b j" "Jump" h/bookmark-jump)
("b l" "List" h/bookmark-list)
diff --git a/hyperdrive-mirror.el b/hyperdrive-mirror.el
index 2748e2f35e..324db6b5a0 100644
--- a/hyperdrive-mirror.el
+++ b/hyperdrive-mirror.el
@@ -144,9 +144,10 @@ After uploading files, open PARENT-ENTRY."
:then (lambda (_)
(progress-reporter-update progress-reporter (cl-incf
count))))))))
-(cl-defun h/mirror--check-items (source files hyperdrive target-dir &key then
progress-fn)
+(cl-defun h/mirror--check-items (source files hyperdrive target-dir &key then
progress-fun)
"Call THEN with list of FILES to mirror from SOURCE to TARGET-DIR in
HYPERDRIVE.
-If PROGRESS-FN, call it with no arguments after each item has been checked."
+If PROGRESS-FUN, call it with no arguments after each item has
+been checked."
(let* ((items)
(metadata-queue (make-plz-queue
:limit h/queue-limit
@@ -167,8 +168,8 @@ If PROGRESS-FN, call it with no arguments after each item
has been checked."
(url (he/url entry)))
(push (make-hyperdrive-mirror-item :file file :url url
:status status)
items)
- (when progress-fn
- (funcall progress-fn))))
+ (when progress-fun
+ (funcall progress-fun))))
:else (lambda (plz-error)
(let ((status-code (plz-response-status (plz-error-response
plz-error))))
(pcase status-code
@@ -178,8 +179,8 @@ If PROGRESS-FN, call it with no arguments after each item
has been checked."
(push (make-hyperdrive-mirror-item
:file file :url (he/url entry) :status 'new)
items)
- (when progress-fn
- (funcall progress-fn)))
+ (when progress-fun
+ (funcall progress-fun)))
(_
(h/error "Unable to get metadata for URL \"%s\": %S"
(he/url entry) plz-error))))))))))
diff --git a/hyperdrive-vars.el b/hyperdrive-vars.el
index 672e3106ba..5ee8722882 100644
--- a/hyperdrive-vars.el
+++ b/hyperdrive-vars.el
@@ -38,10 +38,34 @@
:group 'external
:prefix "hyperdrive-")
-(defalias 'hyperdrive-hyper-gateway-port 'hyperdrive-hyper-gateway-ushin-port
- "Renamed in hyperdrive.el v0.4.0 to reflect update to hyper-gateway-ushin.")
-(defcustom h/hyper-gateway-ushin-port 4973
- "Port to use to send requests to the hyper-gateway-ushin server."
+(defcustom h/gateway-directory (expand-file-name "~/.local/lib/hyperdrive.el")
+ "Where the hyper-gateway executable is found.
+If not found here, the \"PATH\" environment variable is checked
+with `executable-find'. Command `hyperdrive-install' installs to
+this directory."
+ :type 'directory)
+
+(defcustom h/gateway-program "hyper-gateway-ushin"
+ "Name of gateway executable.
+Command `hyperdrive-install' installs to this name inside
+`hyperdrive-gateway-directory'. Function
+`h//gateway-path' looks for executable by this name."
+ :type 'string)
+
+(defcustom h/gateway-command-args "run --writable true --silent true"
+ "Arguments passed to the gateway.
+Note that the \"--port\" argument should not be included here, as
+it is added automatically at runtime using the value of
+`hyperdrive-gateway-port'."
+ :type 'string
+ :group 'hyperdrive)
+
+(define-obsolete-variable-alias
+ ;; TODO(v0.5.0) Remove this alias.
+ 'hyperdrive-hyper-gateway-port 'hyperdrive-gateway-port "0.4.0")
+
+(defcustom h/gateway-port 4973
+ "Port to use to send requests to the gateway server."
:type 'natnum)
(defcustom h/safe-hyperdrives nil
@@ -355,9 +379,22 @@ values are alists mapping version range starts to plists
with
;;;;; Internals
+(defvar h/gateway-version-expected
+ '(:name "hyper-gateway-ushin" :version "3.8.0"))
+
+(defvar h/gateway-version-checked-p nil
+ "Non-nil if the gateway's version has been checked.
+If the version was unexpected,
+`hyperdrive-check-gateway-version' displayed a warning.")
+
(defvar h/gateway-process nil
- "Hyper-gateway-ushin process.
-Only used when `hyperdrive-gateway-process-type' is `subprocess'.")
+ "Gateway process.")
+
+(defvar h/install-process nil
+ "When non-nil, the curl process downloading the gateway for
install/upgrade.")
+
+(defvar h//gateway-starting-timer nil
+ "The timer used when the gateway is starting.")
(defvar-local h/current-entry nil
"Entry for current buffer.")
@@ -389,6 +426,35 @@ Keys are regexps matched against MIME types.")
:desc "Name"))
"Fields for sorting hyperdrive directory buffer columns.")
+(declare-function h//gateway-start-default "hyperdrive-lib")
+(defcustom h/gateway-start-function #'h//gateway-start-default
+ "Function called to start the gateway.
+If this function signals an error, the `h/gateway-ready-hook'
+will not be run; otherwise, the hook will be run when the gateway
+appears to be ready."
+ :type 'function)
+
+(declare-function h//gateway-stop-default "hyperdrive-lib")
+(defcustom h/gateway-stop-function #'h//gateway-stop-default
+ "Function called to stop the gateway.
+This function should signal an error if it fails to stop the
+gateway process."
+ :type 'function)
+
+(declare-function h/gateway-live-p-default "hyperdrive-lib")
+(defcustom h/gateway-live-predicate #'h/gateway-live-p-default
+ "Predicate function which returns non-nil if the gateway process is live."
+ :type 'function)
+
+(defcustom h/gateway-ready-hook
+ '( h/check-gateway-version
+ h/announce-gateway-ready
+ h/menu-refresh)
+ "Hook called when gateway is ready after starting it.
+This hook is called by `hyperdrive--gateway-wait-for-ready' after
+`hyperdrive-start'."
+ :type 'hook)
+
;;;; Footer
(provide 'hyperdrive-vars)
diff --git a/hyperdrive.el b/hyperdrive.el
index 196d041681..c800e6c74a 100644
--- a/hyperdrive.el
+++ b/hyperdrive.el
@@ -33,19 +33,14 @@
;;;; Installation:
-;; hyperdrive.el requires Emacs version 28.1 or later.
+;; hyperdrive.el can be installed on Emacs version 28.1 or later with
-;; hyperdrive.el is available on MELPA:
-;; https://melpa.org/#/getting-started
+;; M-x package-install hyperdrive
-;; Once you've set up MELPA, run
-;; M-x package-install RET hyperdrive RET
+;; hyperdrive.el relies on hyper-gateway-ushin for connecting to the P2P
+;; network. You can download and install the gateway by running
-;; hyperdrive.el relies on hyper-gateway-ushin for connecting to the P2P
network:
-;; https://git.sr.ht/~ushin/hyper-gateway-ushin
-
-;; Installation instructions:
-;; https://git.sr.ht/~ushin/hyper-gateway-ushin/#installation
+;; M-x hyperdrive-install
;;; Code:
@@ -95,29 +90,43 @@
;;;###autoload
(defun hyperdrive-start ()
- "Start `hyper-gateway-ushin' if not already running.
-Customize behavior with `hyperdrive-gateway-process-type', which see."
+ "Start the gateway if not already running.
+Calls function set in option `hyperdrive-gateway-start-function',
+which see."
(interactive)
- ;; TODO: Verify that the expected version, e.g., 3.7.0, is installed.
- (h//gateway-start))
+ (let ((gateway-installed-p (h/gateway-installed-p)))
+ (cond ((and (h//gateway-ready-p) (h/gateway-live-p))
+ (h/message "Gateway already running."))
+ ((h//gateway-ready-p)
+ (h/message "Gateway already running outside of Emacs."))
+ ((h/gateway-live-p)
+ (h/message "Gateway already starting."))
+ ((and (not gateway-installed-p) (h/gateway-installing-p))
+ (h/user-error "Gateway installation in-progress"))
+ ((not gateway-installed-p)
+ (h/user-error "Gateway not installed; try \\[hyperdrive-install]"))
+ (t
+ (h/message
+ (if (h/gateway-installing-p)
+ "Gateway installation in-progress; starting old gateway
anyway."
+ "Starting gateway."))
+ (funcall h/gateway-start-function))))
+ (h//gateway-wait-for-ready))
;;;###autoload
(defun hyperdrive-stop ()
- "Stop `hyper-gateway-ushin' if running.
-Customize behavior with `hyperdrive-gateway-process-type', which see."
+ "Stop the gateway if running.
+Calls function set in option `hyperdrive-gateway-stop-function',
+which see."
(interactive)
- (h//gateway-stop))
+ (funcall h/gateway-stop-function))
;;;###autoload
-(defun hyperdrive-hyper-gateway-ushin-version ()
- "Say version number of `hyper-gateway-ushin'.
-Gateway must be running."
+(defun hyperdrive-gateway-version ()
+ "Say version number of gateway.
+Return version if gateway is running; otherwise signal an error."
(interactive)
- (condition-case err
- (let ((url (format "http://localhost:%d/" h/hyper-gateway-ushin-port)))
- (h/message "hyper-gateway-ushin version %s"
- (alist-get 'version (plz 'get url :as #'json-read))))
- (plz-error (h/api-default-else nil (caddr err)))))
+ (h/message "%S" (h//gateway-version)))
;;;###autoload
(defun hyperdrive-new (seed)
@@ -464,7 +473,7 @@ use, see `hyperdrive-write'."
;; 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
- ;; value than hyper-gateway-ushin's Content-Length header.
+ ;; value than the gateway's Content-Length header.
(setf (he/size entry) (buffer-size))
;; FIXME: Will entry type ever be anything besides
text/plain?
;; /.well-known/host-meta.json ?
@@ -510,7 +519,7 @@ Interactively, use the `hyperdrive-current-entry'. If
THEN, pass
it to `hyperdrive-open'."
(interactive (progn
(unless (and h/mode h/current-entry)
- (user-error "Not a hyperdrive buffer"))
+ (h/user-error "Not a hyperdrive buffer"))
(list h/current-entry))
h/mode)
(if-let ((parent (h/parent entry)))
@@ -811,14 +820,27 @@ The return value of this function is the retrieval
buffer."
(defvar h/menu-bar-menu
'(("Gateway"
- :label
- (format "Gateway (%s)" (if (h/status) "on" "off"))
["Start Gateway" h/start
- :help "Start hyper-gateway-ushin"]
+ :help "Start the gateway"
+ :visible (not (or (h/gateway-live-p) (h//gateway-ready-p)))]
+ ["Restart Gateway" h/restart
+ :help "Restart the gateway"
+ :visible (or (h/gateway-live-p) (h//gateway-ready-p))]
["Stop Gateway" h/stop
- :help "Stop hyper-gateway-ushin"]
- ["Gateway version" h/hyper-gateway-ushin-version
- :help "Say hyper-gateway-ushin version"])
+ :help "Stop the gateway"
+ :active (or (h/gateway-live-p) (h//gateway-ready-p))]
+ ["Gateway Version" h/gateway-version
+ :help "Say gateway version"
+ :active (h//gateway-ready-p)]
+ ["Install Gateway" h/install
+ :label (if (h/gateway-needs-upgrade-p) "Upgrade" "Install")
+ :visible (and (not (h/gateway-installing-p))
+ (or (not (h/gateway-installed-p))
+ (h/gateway-needs-upgrade-p)))
+ :help "Download and install gateway"]
+ ["Cancel Install" h/cancel-install
+ :visible (hyperdrive-gateway-installing-p)
+ :help "Cancel running download/installation"])
"---"
["Open URL" h/open-url
:help "Load a hyperdrive URL"]
@@ -1261,6 +1283,148 @@ Intended for relative (i.e. non-full) URLs."
(add-to-list 'embark-keymap-alist '(hyperdrive . h/embark-hyperdrive-map)))
+;;;;; Installation
+
+(defvar h/gateway-urls-and-hashes
+ '((gnu/linux
+ ( :url
"https://codeberg.org/USHIN/hyper-gateway-ushin/releases/download/v3.8.0/hyper-gateway-ushin-linux"
+ :sha256
"8ff669bd378e88a3c80d65861f4088071852afaedf7bba56c88c1a162ed9e4f3")
+ ( :url
"https://git.sr.ht/~ushin/hyper-gateway-ushin/refs/download/v3.8.0/hyper-gateway-linux-v3.8.0"
+ :sha256 ""))
+ (darwin
+ ( :url
"https://codeberg.org/USHIN/hyper-gateway-ushin/releases/download/v3.8.0/hyper-gateway-ushin-macos"
+ :sha256
"22f6131f48d740f429690f16baac19b20a2211250360a89580db95415398d03c")
+ ( :url
"https://git.sr.ht/~ushin/hyper-gateway-ushin/refs/download/v3.8.0/hyper-gateway-macos-v3.8.0"
+ :sha256 ""))
+ (windows-nt
+ ( :url
"https://codeberg.org/USHIN/hyper-gateway-ushin/releases/download/v3.8.0/hyper-gateway-ushin-windows.exe"
+ :sha256
"c347255d3fc5e6499fc10bea4d20e62798fb5968960dbbe26d507d11688326bb")
+ ( :url
"https://git.sr.ht/~ushin/hyper-gateway-ushin/refs/download/v3.8.0/hyper-gateway-windows-v3.8.0.exe"
+ :sha256 "")))
+ "Alist mapping `system-type' to URLs where the gateway can be downloaded.")
+
+;;;###autoload
+(defun hyperdrive-install (&optional forcep)
+ "Download and install the gateway.
+If FORCEP, don't prompt for confirmation before downloading."
+ (interactive (list current-prefix-arg))
+ (when (h/gateway-installing-p)
+ (h/user-error "Installation of gateway already in progress"))
+ (unless forcep
+ (when (h/gateway-installed-p)
+ (unless (yes-or-no-p "Download and reinstall/upgrade the gateway? ")
+ (h/user-error "Not downloading; aborted"))))
+ (let ((urls-and-hashes (alist-get system-type h/gateway-urls-and-hashes))
+ (destination (expand-file-name h/gateway-program h/gateway-directory))
+ size)
+ (cl-labels
+ ((try ()
+ (pcase-let (((map :url :sha256) (pop urls-and-hashes)))
+ (unless size
+ ;; Only successfully get size once.
+ (ignore-errors
+ (h/message "Checking server %S..."
+ (url-host (url-generic-parse-url url)))
+ (setf size (file-size-human-readable
+ (head-size url)))))
+ (if size
+ (if (or forcep
+ (yes-or-no-p
+ (format "Download and install gateway (%s)? " size)))
+ (progn
+ (setf forcep t) ;; Don't prompt again.
+ (download url sha256))
+ (h/message "Installation canceled."))
+ ;; HEAD request failed: try next URL.
+ (h/message "Server %S unresponsive. Trying next server..."
+ (url-host (url-generic-parse-url url)))
+ (if urls-and-hashes
+ (try)
+ (setf h/install-process nil)
+ (hyperdrive-menu-refresh)
+ (hyperdrive-error "Downloading failed; no more mirrors
available")))))
+ (head-size (url)
+ (when-let ((response (plz 'head url :as 'response :connect-timeout
5)))
+ (cl-parse-integer
+ (alist-get 'content-length (plz-response-headers response)))))
+ (download (url sha256)
+ (let ((temp-file (make-temp-name "hyperdrive-gateway-")))
+ (setf h/install-process
+ (plz 'get url :as `(file ,temp-file) :timeout nil
+ :then (lambda (filename)
+ (check filename sha256 url))
+ :else (lambda (plz-error)
+ (pcase (plz-error-curl-error plz-error)
+ (`(2 . ,_)
+ ;; "Failed to initialize", likely due to
+ ;; `interrupt-process' in `h/cancel-install'.
+ (h/message "Canceled install"))
+ (_ ; Otherwise, display error and try next
URL.
+ (h/message "Trying next source because
downloading from URL %S failed: %S"
+ url plz-error)
+ (try)))
+ (when (file-exists-p temp-file)
+ (delete-file temp-file)))))
+ (h/message "Downloading %s from %S to %S" size url destination)))
+ (check (file-name sha256 url)
+ (if (with-temp-buffer
+ (insert-file-contents-literally file-name)
+ (equal sha256 (secure-hash 'sha256 (current-buffer))))
+ ;; Hash matches: finish installation.
+ (then file-name)
+ ;; Hash doesn't match: delete file and try next source.
+ (delete-file file-name)
+ (h/message "Trying next source because hash comparison failed
from URL: %s"
+ url)
+ (try)))
+ (then (file-name)
+ (when (file-exists-p destination)
+ (move-file-to-trash destination))
+ (unless (file-directory-p h/gateway-directory)
+ (mkdir h/gateway-directory t))
+ (rename-file file-name destination)
+ (chmod destination #o755)
+ (setf h/install-process nil)
+ (h/menu-refresh)
+ (h/message "Gateway installed. Try \\[%s]"
+ (if (h//gateway-ready-p)
+ "hyperdrive-restart"
+ "hyperdrive-start"))))
+ (try))))
+
+(defun h/cancel-install ()
+ "Stop downloading/installing the gateway."
+ (interactive)
+ (unless (h/gateway-installing-p)
+ (h/user-error "No installation in progress"))
+ (h/message "Cancelling install")
+ (interrupt-process h/install-process)
+ (setf h/install-process nil))
+
+(defun h/restart ()
+ "Restart the gateway."
+ (interactive)
+ (h/message "Restarting gateway...")
+ (when (or (h/gateway-live-p) (h//gateway-ready-p))
+ (h/stop))
+ (with-timeout (5 (h/message "Timed out waiting for gateway to stop"))
+ (cl-loop while (h/gateway-live-p)
+ do (sleep-for 0.2)))
+ (h/start))
+
+;; (defun h//gateway-appears-valid-p ()
+;; "Return non-nil if a local installation of the gateway appears valid.
+;; That is, if an executable file exists at the expected location
+;; with an expected hash."
+;; (when-let ((file-name (h//gateway-path)))
+;; (let* ((file-hash (with-temp-buffer
+;; (insert-file-contents-literally file-name)
+;; (secure-hash 'sha256 (current-buffer))))
+;; (urls-and-hashes (alist-get system-type
h/gateway-urls-and-hashes)))
+;; (cl-loop for pair in urls-and-hashes
+;; for expected-hash = (plist-get pair :sha256)
+;; thereis (equal expected-hash file-hash)))))
+
;;;; Footer
(provide 'hyperdrive)
diff --git a/tests/org links.org b/tests/org links.org
index f264e63593..e907d61960 100644
--- a/tests/org links.org
+++ b/tests/org links.org
@@ -34,7 +34,7 @@ Here are various link types which we want to test.
+ [[hyper://PUBLIC_KEY/links%20test.org]]
+ hyper://PUBLIC_KEY/links%20test.org
-+ [2023-08-30 Wed 14:43] Getting this error (with the public key changed to
the real one), for both the bracketed and unbracketed links: ~Hyperdrive:
Generic hyper-gateway-ushin status 500 error. Is this URL correct?
hyper:////wnqpdr9xdy1p9wofqbj7e7csueg7aynqbot8gt53ueunezry6any/links%20test.org~
++ [2023-08-30 Wed 14:43] Getting this error (with the public key changed to
the real one), for both the bracketed and unbracketed links: ~Hyperdrive:
Generic gateway status 500 error. Is this URL correct?
hyper:////wnqpdr9xdy1p9wofqbj7e7csueg7aynqbot8gt53ueunezry6any/links%20test.org~
+ There are FOUR SLASHES.