aconchillo / guile-redis

Redis module for Guile
GNU General Public License v3.0
29 stars 4 forks source link

publish and subscribe commands #3

Closed amirouche closed 3 years ago

amirouche commented 4 years ago

I think there is a bug with publish, subscribe and related commands. Those are not mere request-reply commands. It seems to me the subscribe command should take a callback as argument.

aconchillo commented 4 years ago

Your are totally right. Do you think using fibers would work? That is, you give it a channel instead of a callback.

amirouche commented 4 years ago

A callback is more general than a channel. With callback you can pass something like:

(redis-subscribe "topic" (lambda (obj) (put-message channel obj)))
amirouche commented 4 years ago

Forcing to pass a channel is not necessary.

aconchillo commented 4 years ago

That is totally true. Alright, I'll see if I have time to add that. Thanks!

soda-hobart commented 4 years ago

I set up something to get guile-redis subscribe to behave like it does in Python redis module:

(use-modules (rnrs bytevectors))
(use-modules (ice-9 iconv))
(use-modules (ice-9 binary-ports))
(use-modules (ice-9 textual-ports))
(use-modules (ice-9 rdelim))
(use-modules (redis))

(define (redis-sock-get conn)
  (let ((get-sock
     (record-accessor
      (record-type-descriptor conn)
      (caddr (record-type-fields (record-type-descriptor conn))))))
  (get-sock conn)))

(define (subscribe-listen redis-sock)
  (let ((sub-buf (make-bytevector 1024)))
    (recv! redis-sock sub-buf)
    (display (read-delimited
          "\0"
          (open-input-string (bytevector->string sub-buf "utf8"))))
    (newline)
    (subscribe-listen redis-sock)))

;; (define conn (redis-connect #:host "127.0.0.1" #:port 6379))
;; (redis-send conn (subscribe '(soda-stuff)))
;; (define redis-socket (redis-sock-get conn))
;; (subscribe-listen redis-socket)

This way, it goes into a loop and reads bytes directly from the socket and sends them to a buffer. I had tried to make a recursive procedure to loop (redis-send) to perform this behavior but found it used like 110% of the process CPU core. So I looked at Python redis and saw that they read the bytes right from the socket, so I did something like that.

Does that seem useful? If so, I can parameterize it better and clean up the code. I just started learning Scheme (and Lisp in general), so I'm not all that clear on the idiom--what should parameters for a procedure like that be? I was thinking it could take a connection and abstract the bit with obtaining the socket (that confused me a lot, the record datatype, did I do that right in using the record-accessor?). Then the other params, I suppose, should be a buffer to write the received message into, and then maybe a callback do so something with the specified buffer?

From there, I imagine one would do something asynchronous with the data. I'm trying to learn fibers, but I'm a librarian, not a hardcore CS person, so it's a bit of a steep learning curve--but really interesting to study.

I don't know exactly what I'm trying with this stuff, but I have a couple of ideas: I want to make a real-time collaborative note-taking app that's based on org-mode. Or a weird, text-based blogging-app that has a quasi-graphical interface based on ascii art (maybe a little like the Cypher language used by Neo4j graph DB).

Sorry for the rambling comment--just wanted to holler at my Guile people! Guile is for sure the most fun language to program in. If you like the subscribe-listen procedure, I can clean it up and make a PR.

aconchillo commented 3 years ago

Hi @soda-hobart! Thank you for your message. With almost 1 year delay I'm now looking into this, sorry about that. I can only work on Guile at nights when I'm not too tired from work and kids and life in general. But it's great to hear you are a librarian and working on Guile! Really surprised (and happy) you chose Guile. May I ask why did you start working on Guile?

I'm playing around and see how to implement this. I'm leaning towards something like @amirouche suggested above.

aconchillo commented 3 years ago

This is now fixed in guile-redis 2.0.0.