Anyone using Redis pubsub in Processing? Need help with syntax

I have a RPi-based project that uses the Redis PubSub capability to pass data around between Python scripts and Node.js and even a Lua app. I want to add a feature built in Processing and need my sketch to listen on a channel and publish its data to other processes as well. I have installed the Redis library which I understand is a wrapper for Jedis, the canonical Java Redis implementation. I can use the one simple example file to set and get a variable. But I have no idea what syntax to use to subscribe and publish to channels. I am fairly new to Processing and don't know much about Java. In my Python scripts publishing is easy but listening to channels involves getting a redis.pubsub instance in a Thread class instance, subscribing to my channel, and then running the pubsub.listen() method in the thread's run loop. Can anyone help me?

Answers

  • Is this the library that you have installed?

    Did you look at the documentation and usage examples for it and for Jedis? I'm not a Redis expert, but it might be easier for the forum to help you if you posted a minimal and complete code example of what you currently have and what you are trying to do -- see for comparison the Redis for Processing example sketch and Usage example.

  • Hi Jeremy, thanks for the response. I will try to be clearer. Yes that is the library I have installed and the example sketch:

    import de.voidplus.redis.*;
    Redis redis;
    
    void setup(){
        // ...
        redis = new Redis(this, "127.0.0.1", 6379);
        redis.set("key", "value");
        println(redis.get("key"));
    }
    

    works fine (returns "value" in the console). It is the only example and there is no further documentation on usage. There is the Jedis repo but I do not understand how to extrapolate Processing syntax from what I see there. It is the syntax to use the PubSub subclass that I need to figure out. Frankly I just don't know how to look at a Java class structure in the github repo and determine how to call and use JedisPubSub. I see the actual JedisPubSub.java file, I can open it and read it, but still don't know what to do.

    In Python the equivalent code goes like this:

    import redis, threading
    
    r = redis.Redis()
    
    #publish something associated with a channel
    r.publish('chan1', 'something')
    
    #to listen in on a channel make a Listener class that runs in its own thread
    class Listener(threading.Thread):
       #extend thread class
       def __init__(self, r):
            threading.Thread.__init__(self)
            self.redis = r
            #get a pubsub instance
            self.pubsub = self.redis.pubsub()
            #subscribe to the channel(s) you want to listen to
            self.pubsub.subscribe(['chan1', 'chan2'])
            ##
    
       def run(self):
            #in main loop of thread, listen for messages associated w a channel
            for item in self.pubsub.listen():
                if item['type'] == "message" and item['channel'] == 'chan1':
                   chan1data_str = item['data'] 
    

    Pubsub is really powerful way to communicate data between processes, I think many Processing users would find it invaluable way to share data with software components written in other languages. I see other people on the forum use ZeroMQ for the same purpose, but I already have a big code commitment to Redis...

    Thanks for your time.

  • edited September 2016

    I see what you mean. That is not a lot of documentation. The github code hasn't been updated for ~18 months, but it does say "Don't be shy and feel free to contact me on Twitter: @darius_morawiec " -- did you try contacting the author?

    From glancing at Redis.java wrapper, it looks like the wrapper is mainly about attaching PApplet and the documentation should be almost identical to the Jedis documentation -- the wiki, mailing list, and javadocs are all linked from the Jedis github.

    subscribe() and publish() seem to be present in almost exactly the same form as your python code -- here is publish() on line 2528. pubsub() is here.

    I haven't tested this, but my impression is that this:

    # python
    import redis
    r = redis.Redis()
    r.publish('chan1', 'something')
    

    Might be something like (untested):

    //// java
    import de.voidplus.redis.*;
    Redis r;
    void setup(){
      r = new Redis(); // args in example: this, "127.0.0.1", 6379
      r.publish('chan1', 'something');
    }
    

    I also haven't played with writing a Redis/Jedis thread listener, but if you need a simple one on a thread, use processing's thread(). It won't accept arguments, so you need to interact with it by updating global variables that it is hard-coded to check -- e.g. the variable name of your redis instance or the name / list of your channels.

    Something like (untested):

    void setup(){
      thread("myListener");
    }
    
    void myListener() {
      JedisPubSub jedisPubSub = new JedisPubSub();
      r.subscribe(jedisPubSub, "chan1") // (final JedisPubSub jedisPubSub, final String... channels)
      while(true){
        // loop through jedisPubSub and write data to global variable
      }
    }
    

    If on the other hand you need a class so that you can create and destroy a bunch of listeners and pass them parameters etc. etc. then you may have to do something more involved with full Java threading (if that isn't already built in to Jedis).

  • Thanks again Jeremy,

    I was able to publish a message and then see it while running a command line version of the redis client in a terminal. I type redis-cli to get the client running then type SUBSCRIBE chan1 to listen for messages to chan1 and then in my Processing sketch I can publish a message that shows up in the terminal. But that was always the easy part ;) Note: single quotes around 'chan1' and 'something' threw an error, but double quotes worked.

    The listening in on a channel part is not working. First stumbling block when I run the second part of your code is the error Cannot instantiate the type JedisPubSub

    I tried messing with an import statement like: import redis.clients.jedis.JedisPubSub; but that didn't work either. Not sure if its because I have the package path wrong (I confess I don't really understand how these are constructed) or whether its just the wrong idea that JedisPubSub needs a separate import line. In the Python script I get a PubSub instance by calling my redis instance: myPubSub = r.pubsub() and then I use that pubsub instance to both "subscribe" to my channel and to "listen" in on it. I don't see a listen() method anywhere in the Jedis documentation. The only example I could find on how you use JedisPubSub was in the wiki where they make a Listener class that extends JedisPubSub. Seems like that is a clue to what I am looking for but I just can't get there...

    Anyway, I appreciate the time you spent trying to help me out. I did message Darius, but not the twitter account you mentioned (never used twitter!) but here in the forum where he is a member.

  • Glancing back at JedisPubSub, I see that it is an abstract class -- so it looks like you have to extend it, then instantiate that extended version, hence the cannot instantiate error. Or use something in the library that does that for you. But this is out of my depth -- perhaps ping Darius on github if you can't get him here.

  • Ok thanks for all your help Jeremy. Just joined Twitter so I could message Darius. Determined to figure this out...

  • I think you have to extend JedisPubSub, overriding the onMessage etc methods then pass an instance of this new class as first argument to a Jedis subscribe().

    This ties in with both the Jedis code and your example.

Sign In or Register to comment.