Mã Elisp để kiểm tra kết nối internet


13

Khi tôi mở Emacs, nó sẽ đánh giá tệp init của tôi, bao gồm làm mới kho lưu trữ gói của tôi thông qua kết nối internet. Đây là vấn đề khi tôi không có kết nối internet, do đó tôi cần ngăn việc thực thi mã đó khi khởi động Emacs mà không có kết nối internet. Để giải quyết vấn đề này, tôi tự hỏi liệu có cách nào để Emacs bỏ qua mã làm mới gói khi tôi không có kết nối internet không?

Dưới đây là một vài dòng đầu tiên của tôi init.el:

;; Requisites: Emacs >= 24
(require 'package)
(package-initialize)

;; PACKAGE MANAGEMENT
(add-to-list 'package-archives 
  '("melpa" . "http://melpa.milkbox.net/packages/") t)

(package-refresh-contents)       

Tôi tưởng tượng rằng tôi có thể thêm mã để tải tệp Emacs của mình như sau:

;; Requisites: Emacs >= 24
(when (connected-to-internet-p)   ; I need this predicate function
  (require 'package)
  (package-initialize)
  (add-to-list 'package-archives 
               '("melpa" . "http://melpa.milkbox.net/packages/") t)
  (package-refresh-contents))

Có một (connected-to-internet)chức năng, hoặc cách tiếp cận tương tự, để giải quyết vấn đề này?


2
Có một câu trả lời liên quan ở đây stackoverflow.com/a/21065704/3170376 .
Tên

2
Tại sao bạn muốn làm mới kho lưu trữ gói khi bạn bắt đầu Emacs?
phils

@ Tên đó liên quan nhiều hơn. Đó là những câu trả lời (giả sử nó hoạt động).
Malabarba

1
Tôi thực sự khuyên bạn không nên chạy nội dung làm mới gói trên mỗi lần khởi động. Rất có thể bạn sẽ cần chạy nó một lần khi lần đầu tiên kéo cấu hình của bạn xuống một máy mới và sau đó bạn sẽ không cần nó nữa trong nhiều tháng. Làm điều đó khi bạn có kết nối là câu trả lời sai cho vấn đề này, vấn đề thực sự là bạn đang chạy nó khi bạn không cần.
Jordon Biondo

Câu trả lời:


7

Chà, nếu bạn vẫn muốn làm mới nội dung tự động, bất cứ khi nào có thể, bạn có thể làm một cái gì đó giống như mã dưới đây:

(defun can-retreive-packages ()
  (cl-loop for url in '("http://marmalade-repo.org/packages/"
                        "http://melpa.milkbox.net/packages/"
                        "http://elpa.gnu.org/packages/")
           do (condition-case e
                  (kill-buffer (url-retrieve-synchronously url))
                (error (cl-return)))
           finally (cl-return t)))

Một số lưu ý là do:

  1. Điều này là chậm, và nó sẽ chậm khi khởi động bình thường, vì vậy tôi thay vì làm bằng tay.
  2. Không có cách nào để kiểm tra kết nối internet nói chung. Bạn chỉ có thể phát hiện ra rằng bạn không thể kết nối với một dịch vụ cụ thể sau một khoảng thời gian mà bạn đã thử. Đây cũng là một trong những lý do tại sao nó rất chậm.
  3. Mã này là một minh họa về cách tiếp cận vấn đề. Bạn có thể dễ dàng thực hiện (ignore-errors (package-refresh-contents))nếu bạn không quan tâm liệu nó có thành công hay không.

Đó rõ ràng là cách đúng đắn để làm điều đó. Tại bất kỳ thời điểm nào, một số phần của Internet có thể truy cập và một số thì không, và cách thích hợp để xử lý nó là thăm dò kết nối.
JCH

1
Điều này cũng sẽ tạo ra một loạt các bộ đệm lớn chưa từng thấy, tốt nhất nên làm (kill-buffer (url-ret ...))
Jordon Biondo

@JordonBiondo ok, lấy điểm. Không nghĩ về nó.
wvxvw

6

Một giải pháp đơn giản mà tôi đã áp dụng từ các kịch bản shell của mình là

(defun internet-up-p (&optional host)
    (= 0 (call-process "ping" nil nil nil "-c" "1" "-W" "1" 
                       (if host host "www.google.com"))))

Bạn có thể kiểm tra điều này trong *scratch*bộ đệm:

(message (if (internet-up-p) "Up" "Down"))
"Up"

Tôi thích giải pháp này nhất vì nó đơn giản, nhanh chóng và kiểm tra kết nối với internet rộng hơn.
Miguelmorin

4

Một điều bạn có thể thử là chức năng network-interface-list. Nó trả về một giao diện mạng và địa chỉ IP của chúng.

Đối với tôi, đây là những gì nó trả về khi tôi kết nối với cả Ethernet và wifi:

(("en5" .
  [10 151 0 63 0])
 ("en0" .
  [10 151 2 76 0])
 ("lo0" .
  [127 0 0 1 0]))

Và khi tôi tắt wifi, en0biến mất:

(("en5" .
  [10 151 0 63 0])
 ("lo0" .
  [127 0 0 1 0]))

Thử nghiệm điều đó và xem những gì bạn nhận được khi không có kết nối Internet. Ví dụ: để chỉ làm mới các gói khi en0hết, hãy làm một cái gì đó như:

(when (assoc "en0" (network-interface-list))
  (package-refresh-contents))

Đó là một chức năng thú vị. Tôi nhận được (("eth0" . [10 72 153 234 0]) ("lo" . [127 0 0 1 0]))bởi vì tôi được kết nối với ethernet.
Kaushal Modi

3

Để mở rộng câu trả lời của Legoscia:

(defun test-internet ()
  (remove-if (lambda (el)
                   (string-match-p "lo.*" (car el)))
                 (network-interface-list)))

Điều này sẽ trả về một danh sách các kết nối mạng đang hoạt động ( lo.*là giao diện loopback, trong một số trường hợp lokhác lo#.

Nếu kiểm tra trở lại non-nil, sau đó có kết nối mạng (wifi / ethernet, không có gì đảm bảo nó thực sự đến được mạng internet bên ngoài. Tuy nhiên, sẽ phải ping ở đâu đó để kiểm tra), nếu nó trả về nilthì không có cách nào để lấy lại gói danh sách.


2

Tôi sử dụng cách sau để loại trừ loopbackgiao diện và giao diện VirtualBox và Docker. Tôi hy vọng nó hữu ích.

(defun tzz-has-network ()
  (remove-if (lambda (i)
               (or (string-match-p "\\(vboxnet\\|docker\\).*" i)
                   (member 'loopback (nth 4 (network-interface-info i)))))
             (mapcar 'car (network-interface-list))))

2

Trên hệ thống Linux hiện đại với DBus và NetworkManager:

(defun nm-is-connected()
  (equal 70 (dbus-get-property
             :system "org.freedesktop.NetworkManager" "/org/freedesktop/NetworkManager"
             "org.freedesktop.NetworkManager" "State")))

1

Tôi nghĩ rằng bạn đang nhìn nó sai cách. Nếu bạn thực sự muốn tự động cập nhật các gói của mình, thì đừng thực hiện đồng bộ khi khởi động: thực hiện từ một bộ đếm thời gian nhàn rỗi. Ví dụ

(run-with-idle-timer 10 nil
  (lambda ()
    (package-refresh-contents)
    ..etc..))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.