Skip to content

Commit 8a22860

Browse files
committed
fix(nextflow): Improve async download of large files
Avoids hanging and blocking the UI on large files This doesn't happen with small files (1.9MB Magik) but does happen with large files (12.6MB Nextflow)
1 parent 7cc45bd commit 8a22860

File tree

3 files changed

+316
-61
lines changed

3 files changed

+316
-61
lines changed

clients/lsp-nextflow.el

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@
2121
;;; Commentary:
2222

2323
;; LSP Clients for the Nextflow Programming Language.
24-
;;
25-
;; The language server JAR will be automatically downloaded from GitHub releases.
2624

2725
;;; Code:
2826

@@ -61,29 +59,9 @@
6159
:type 'file
6260
:package-version '(lsp-mode . "9.0.0"))
6361

64-
(defun lsp-nextflow--async-download (callback error-callback)
65-
"Asynchronously download Nextflow language server JAR file."
66-
(let ((download-buffer (url-retrieve
67-
lsp-nextflow-server-download-url
68-
(lambda (status callback error-callback)
69-
(if (plist-get status :error)
70-
(progn
71-
(message "Nextflow LSP download failed: %s" (plist-get status :error))
72-
(funcall error-callback (plist-get status :error)))
73-
(unwind-protect
74-
(progn
75-
(goto-char (point-min))
76-
(re-search-forward "\n\n" nil 'noerror)
77-
(let ((jar-content (buffer-substring (point) (point-max))))
78-
(mkdir (f-parent lsp-nextflow-server-file) t)
79-
(with-temp-file lsp-nextflow-server-file
80-
(set-buffer-file-coding-system 'binary)
81-
(insert jar-content))
82-
(message "Nextflow LSP download completed: %s" lsp-nextflow-server-file)
83-
(funcall callback)))
84-
(kill-buffer (current-buffer)))))
85-
(list callback error-callback))))
86-
(message "Downloading Nextflow LSP server from %s..." lsp-nextflow-server-download-url)))
62+
(lsp-dependency 'nextflow-language-server
63+
`(:download :url lsp-nextflow-server-download-url
64+
:store-path lsp-nextflow-server-file))
8765

8866
(defun lsp-nextflow-server-command ()
8967
"Startup command for Nextflow language server."
@@ -140,7 +118,7 @@ find Java automatically."
140118
(lsp-register-client
141119
(make-lsp-client
142120
:download-server-fn (lambda (_client callback error-callback _update?)
143-
(lsp-nextflow--async-download callback error-callback))
121+
(lsp-package-ensure 'nextflow-language-server callback error-callback))
144122
:new-connection (lsp-stdio-connection
145123
(lambda ()
146124
(list

lsp-mode.el

Lines changed: 93 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8468,6 +8468,72 @@ nil."
84688468

84698469

84708470
;; Download URL handling
8471+
8472+
(defun lsp-download-install--url-retrieve (url file callback error-callback)
8473+
"Download URL to FILE using url-retrieve asynchronously.
8474+
Call CALLBACK on success or ERROR-CALLBACK on failure."
8475+
(url-retrieve
8476+
url
8477+
(lambda (status &rest args)
8478+
(cond
8479+
;; Check for errors
8480+
((plist-get status :error)
8481+
(lsp--error "Download failed: %s" (plist-get status :error))
8482+
(funcall error-callback (plist-get status :error)))
8483+
8484+
;; Success - save to file
8485+
(t
8486+
(condition-case err
8487+
(progn
8488+
;; Move past HTTP headers
8489+
(goto-char (point-min))
8490+
(re-search-forward "\n\n" nil t)
8491+
8492+
;; Write content to file
8493+
(let ((coding-system-for-write 'binary))
8494+
(write-region (point) (point-max) file nil 'silent))
8495+
8496+
;; Clean up and call success callback
8497+
(kill-buffer)
8498+
(funcall callback))
8499+
(error
8500+
(lsp--error "Failed to save downloaded file: %s" err)
8501+
(funcall error-callback err))))))
8502+
nil 'silent 'inhibit-cookies))
8503+
8504+
(defun lsp-download-install--verify-signature (main-url main-file asc-url pgp-key)
8505+
"Verify GPG signature for MAIN-FILE.
8506+
Download signature from ASC-URL and verify with PGP-KEY.
8507+
This is a synchronous operation that should be called after the main download."
8508+
(if (executable-find epg-gpg-program)
8509+
(let ((asc-download-path (concat main-file ".asc"))
8510+
(context (epg-make-context))
8511+
(fingerprint)
8512+
(signature))
8513+
(when (f-exists? asc-download-path)
8514+
(f-delete asc-download-path))
8515+
8516+
;; Download signature file - using synchronous download for simplicity
8517+
;; since signature files are typically very small
8518+
(lsp--info "Downloading signature from %s..." asc-url)
8519+
(url-copy-file asc-url asc-download-path)
8520+
(lsp--info "Downloaded signature file")
8521+
8522+
;; Import and verify
8523+
(epg-import-keys-from-string context pgp-key)
8524+
(setq fingerprint (epg-import-status-fingerprint
8525+
(car
8526+
(epg-import-result-imports
8527+
(epg-context-result-for context 'import)))))
8528+
(lsp--info "Verifying signature %s..." asc-download-path)
8529+
(epg-verify-file context asc-download-path main-file)
8530+
(setq signature (car (epg-context-result-for context 'verify)))
8531+
(unless (and
8532+
(eq (epg-signature-status signature) 'good)
8533+
(equal (epg-signature-fingerprint signature) fingerprint))
8534+
(error "Failed to verify GPG signature: %s" (epg-signature-to-string signature))))
8535+
(lsp--warn "GPG is not installed, skipping the signature check.")))
8536+
84718537
(cl-defun lsp-download-install (callback error-callback &key url asc-url pgp-key store-path decompress &allow-other-keys)
84728538
(let* ((url (lsp-resolve-value url))
84738539
(store-path (lsp-resolve-value store-path))
@@ -8479,52 +8545,44 @@ nil."
84798545
(:targz (concat store-path ".tar.gz"))
84808546
(`nil store-path)
84818547
(_ (error ":decompress must be `:gzip', `:zip', `:targz' or `nil'")))))
8482-
(make-thread
8548+
;; Clean up any existing files
8549+
(when (f-exists? download-path)
8550+
(f-delete download-path))
8551+
(when (and (f-exists? store-path) (not (equal download-path store-path)))
8552+
(f-delete store-path))
8553+
8554+
;; Create parent directory if needed
8555+
(mkdir (f-parent download-path) t)
8556+
8557+
;; Start async download
8558+
(lsp--info "Starting to download %s to %s..." url download-path)
8559+
(lsp-download-install--url-retrieve
8560+
url
8561+
download-path
84838562
(lambda ()
8563+
;; Success handler - continue with decompression and verification
8564+
(lsp--info "Finished downloading %s..." download-path)
84848565
(condition-case err
84858566
(progn
8486-
(when (f-exists? download-path)
8487-
(f-delete download-path))
8488-
(when (f-exists? store-path)
8489-
(f-delete store-path))
8490-
(lsp--info "Starting to download %s to %s..." url download-path)
8491-
(mkdir (f-parent download-path) t)
8492-
(url-copy-file url download-path)
8493-
(lsp--info "Finished downloading %s..." download-path)
8567+
;; Handle signature verification if requested
84948568
(when (and lsp-verify-signature asc-url pgp-key)
8495-
(if (executable-find epg-gpg-program)
8496-
(let ((asc-download-path (concat download-path ".asc"))
8497-
(context (epg-make-context))
8498-
(fingerprint)
8499-
(signature))
8500-
(when (f-exists? asc-download-path)
8501-
(f-delete asc-download-path))
8502-
(lsp--info "Starting to download %s to %s..." asc-url asc-download-path)
8503-
(url-copy-file asc-url asc-download-path)
8504-
(lsp--info "Finished downloading %s..." asc-download-path)
8505-
(epg-import-keys-from-string context pgp-key)
8506-
(setq fingerprint (epg-import-status-fingerprint
8507-
(car
8508-
(epg-import-result-imports
8509-
(epg-context-result-for context 'import)))))
8510-
(lsp--info "Verifying signature %s..." asc-download-path)
8511-
(epg-verify-file context asc-download-path download-path)
8512-
(setq signature (car (epg-context-result-for context 'verify)))
8513-
(unless (and
8514-
(eq (epg-signature-status signature) 'good)
8515-
(equal (epg-signature-fingerprint signature) fingerprint))
8516-
(error "Failed to verify GPG signature: %s" (epg-signature-to-string signature))))
8517-
(lsp--warn "GPG is not installed, skipping the signature check.")))
8569+
(lsp-download-install--verify-signature url download-path asc-url pgp-key))
8570+
8571+
;; Handle decompression if needed
85188572
(when decompress
85198573
(lsp--info "Decompressing %s..." download-path)
85208574
(pcase decompress
8521-
(:gzip
8522-
(lsp-gunzip download-path))
8575+
(:gzip (lsp-gunzip download-path))
85238576
(:zip (lsp-unzip download-path (f-parent store-path)))
85248577
(:targz (lsp-tar-gz-decompress download-path (f-parent store-path))))
85258578
(lsp--info "Decompressed %s..." store-path))
8579+
8580+
;; Call success callback
85268581
(funcall callback))
8527-
(error (funcall error-callback err)))))))
8582+
(error
8583+
(lsp--error "Error in post-download processing: %s" err)
8584+
(funcall error-callback err))))
8585+
error-callback)))
85288586

85298587
(cl-defun lsp-download-path (&key store-path binary-path set-executable? &allow-other-keys)
85308588
"Download URL and store it into STORE-PATH.

0 commit comments

Comments
 (0)