emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: OPEN-NETWORK-STREAM connection timeout control?


From: Derek Davies
Subject: Re: OPEN-NETWORK-STREAM connection timeout control?
Date: Wed, 27 Mar 2024 00:31:26 -0400
User-agent: mu4e 1.2.0; emacs 26.3


The following is what I've ended up with so far on this.  Sorry if this
is not appropriate, but I am still unsure how the promises package has
been doing in the field and I have other uses planned in my own
projects.  I haven't had any trouble using this (below) for my TTS
(I am blind) which I've used every day for months now.  Feedback/gotchas
appreciated.  Thanks.  If there's interest I can say more about the use
cases for this.

Derek

==



;; magoo-cat.el -*- lexical-binding:t -*-

(require 'promise)
(require 'cl)

(defcustom magoo-cat-connection-timeout 2.0 "")
(defcustom magoo-cat-response-timeout 2.0 "")

(defun magoo-cat (host port)
  
  (magoo-cat-text host port (magoo-cat-get-text)))

(defun magoo-cat-get-text ()
  (cond
   ((use-region-p)
    
    (buffer-substring
     (region-beginning)
     (region-end)))
   (t
    (thing-at-point 'line t))))

(defun magoo-cat-text (host port text &optional read-response-p)
  (promise-new (lambda (resolve reject)
                 (let ((ostr "")
                       (prom (promise-wait magoo-cat-connection-timeout 
(magoo-cat-cnx host port))))
                   (setf prom (promise-then prom
                                            (lambda (robj)
                                              (cl-assert (equal (car robj) 
:fullfilled))
                                              (let ((pobj (cadr robj)))
                                                ;; NB: The P.F. needs to be set 
before we send input or we can lose output.
                                                (set-process-filter pobj 
(lambda (p str)
                                                                           
(setq ostr (concat ostr str))
                                                                           t))
                                                (process-send-string pobj text)
                                                (cond
                                                 (read-response-p
                                                  (sleep-for 0.02)
                                                  (delete-process pobj)
                                                  (list pobj (prog1 (substring 
ostr) (setf ostr ""))))
                                                 (t
                                                  (delete-process pobj)
                                                  t))))))
                   (setf prom (promise-then prom
                                            (lambda (robj)
                                              (cond
                                               ((not (eq t robj))
                                                (let ((pobj (car robj))
                                                      (ostr (cadr robj)))
                                                  (promise-chain
                                                      (promise-wait 
magoo-cat-response-timeout (magoo-cat-read-response pobj ostr))
                                                    (then (lambda (r2)
                                                            (funcall resolve 
r2)))
                                                    (promise-catch (lambda 
(read-err)
                                                                     (funcall 
reject :read-response-timeout))))))
                                               (t
                                                (cl-assert (eq robj t))
                                                (funcall resolve t))))))
                   (setf prom (promise-catch prom
                                             (lambda (robj)
                                               (funcall reject (list 
:connection-timeout robj)))))))))

(defun magoo-cat-cnx(host port)
  (promise-new (lambda (resolve reject)
                 (let (pobj)
                   (let ((name (concat "magoo-cat-" host ":" (format "%d" 
port)))
                         (output-buffer nil))
                     (setq pobj (open-network-stream name output-buffer host 
port :nowait t)))
                   (let ((stat (process-status pobj)))
                     (while (and ;; (not (equal stat 'connect))
                             (not (equal stat 'open))
                             (not (equal stat 'failed))
                             (not (equal stat 'closed))
                             (not (equal stat 'exit)))
                       (sleep-for 0.01)
                       (setq stat (process-status pobj)))
                     (cond
                      ((equal stat 'open)
                       (funcall resolve pobj))))))))

(defun magoo-cat-read-response (pobj ostr)
  (promise-new (lambda (resolve reject)
                 (sleep-for 0.02)
                 (while (accept-process-output pobj 0.2 nil t)
                   (sleep-for 0.02))
                 (cond
                  ((or (not ostr) (< (length ostr) 1))
                   (funcall reject :null-response))
                  (t
                   (funcall resolve ostr))))))


(provide 'magoo-cat)

;; Ends here.



DD <ddavies@ddavies.net> writes:

> I've got the following, but I'm wondering: is the promise package in
> wide use these days?  Promises seem to help with a lot of issues around
> the command loop when waiting for the results of asynchronous calls.
> I'm wondering if promises will be used more in the future or am I wrong
> about them helping to clarify this kind of code?
>
> The other thing I worry about is using process-status to poll for the
> end of connection setup rather than a process sentinel.  It says in the
> doc that the sentinel can skip states, but I don't think it will skip
> "open" here since if it does get to open it will stay there, which means
> that open will not be skipped since it's not intermittent, but isa
> "last" state??  I don't really care either way, what's better?
>
> To implement this without promises requires more state to be tracked for
> the timeout, but the promises package hides that nicely.  I would like
> to use promises more in the future -- is that I good idea?  Is there a
> better way?
>
>
> Thanks for your time and attention.
>
> Derek
>
> ;; p.el -*- lexical-binding:t -*-
>
> (require 'promise)
>
> (defun do-connect (host port)
>   (promise-new (lambda (resolve _reject)
>                  (let (sobj)
>                    (let ((name (concat "netcatbuf-" host ":" (format "%d" 
> port)))
>                          (output-buffer nil))
>                      (setq sobj (open-network-stream name output-buffer host 
> port :nowait t)))
>                    (let ((stat (process-status sobj)))
>                      (while (and ;; (not (equal stat 'connect))
>                              (not (equal stat 'open))
>                              (not (equal stat 'failed))
>                              (not (equal stat 'closed))
>                              (not (equal stat 'exit)))
>                        (sleep-for 0.2)
>                        (setq stat (process-status sobj)))
>                      (cond
>                       ((equal stat 'open)
>                        (funcall resolve sobj))))))))
>
> (defun do-netcat (host port text)
>   (promise-chain
>       (promise-wait 7.0 (do-connect host port))
>     (then (lambda (res)
>             (let ((pobj (cadr res)))
>               (message "DLD| do-connection success")
>               (process-send-string pobj text)
>               ;; NB: TCP half shutdown is needed to trigger service 
> processing.
>               (delete-process pobj))))
>     (promise-catch (lambda (reason)
>                      (netcatbuf-text "janice" 7201 (message "DLD| do-connect 
> failed due to %S" reason))))))
>
> (do-netcat "sybil" 7201 "HI THERE HOW ARE YOU?")
>
> ;; Ends here.
>
>
> DD <ddavies@ddavies.net> writes:
>
>> Hello,
>>
>> I'm using OPEN-NETWORK-STREAM and am unsure about how to control how
>> long to wait for the connection to be established or timed out.
>>
>> I'm fairly sure I would like the call to be synchronous, at least
>> until the point of establishing/timing out the connection.  It might
>> turn out that, for responsiveness perhaps, I would want to include the
>> :nowait keyword, but hopefully I can ignore that for now, because
>> after reading the doc and looking at the code I have confusion around
>> how that works wrt, at least, how the process object is delivered.
>>
>> I would like a customizable timeout value so that if a service is down
>> emacs stays responsive and times out quickly, since I'm only
>> interested in making local area connections in this situation and I
>> want to move on quickly to try fallback service(s)..
>>
>> I hoped there was a timeout keyword for O-N-S, but didn't find it.  I
>> looked at lots of other stuff regarding the process object and got
>> really side tracked.
>>
>> I guess I could set an async timer before the O-N-S call and then
>> explicitly squelch the O-N-S call if the timer expires before I reset
>> it after O-N-S returns?
>>
>> I'm looking at the elisp code for an example and coming up empty.
>> Would be grateful for any help, especially around what is idiomatic in
>> this situation, as well as alternative approches.
>> q
>> Thanks!




reply via email to

[Prev in Thread] Current Thread [Next in Thread]