ngauthier / tubesock

Websocket interface on Rack Hijack w/ Rails support
MIT License
620 stars 43 forks source link

Unable to see published message when using redis and tubesock #19

Closed mankind closed 10 years ago

mankind commented 10 years ago

While searching googling around for a solution, I stumbled on this issue https://github.com/ngauthier/tubesock/issues/8. My code is now patterned according to your example here: https://github.com/ngauthier/tubesock/issues/8#issuecomment-21299897. But still the subscribers don't get any message that is sent and no knew message is displayed on the website beside the one we defined in tubesock.onopen. I have tried it by adding the connection to redis right in the hijack block but it didn't work. I commented that out and used a global $redis , which still didn't work.

   class ChatController < ApplicationController
      include Tubesock::Hijack

     def chat
        hijack do |tubesock|

          # redis =  redis = Redis.connect(url: 'redis://user:pass@pub-redis-2xxxx.eu-west-1-1.1.ec2.garantiadata.com:9014/') 

           tubesock.onopen do
               tubesock.send_data "Hello, friend"
           end

           redis_thread = Thread.new do
                # Needs its own redis connection to pub
                # and sub at the same time
             $redis.subscribe "chat" do |on|
                on.message do |channel, data|
                   a = JSON.parse(data)
                   puts a
                  #tubesock.send_data  "#{data}"
                  tubesock.send_data  a
               end
             end
          end 

          tubesock.onmessage do |m|
             # pub the message when we get one
             # note: this echoes through the sub above

            params = JSON.parse(m)
            message = Message.new(params)
            m = message.to_json
            puts m

            ##this doesn't display on the website
            $redis.publish "chat", m
          end

          tubesock.onclose do
            # stop listening when client leaves
            redis_thread.kill
          end

      end  
   end  

end

If I replace $redis.publish with tubesock.send_data m, it works and the sent message appears on the website.

I am using thesame erb template and javascript you provided in the repo you linked to in your comment.

What else do I need to get this working.

Thanks.

ngauthier commented 10 years ago

Note that in my example I use Redis.new inside the redis thread and I also use Redis.new inside tubesock.onmessage

I was able to get that to communicate data between two clients. Can you try my example entirely on its own and see if that works? That way we could debug an issue with your system if there is one.

mankind commented 10 years ago

Thank you @ngauthier for responding so fast. You are right. I updated my code and it now sends the message to the website. However, what it sends is this {"_id":{"$oid":"52cb0dfb6170700968000000"},"body":"yes"} instead of just yes which is the message. I am using Mongoid, so Message.new in my code above is creating a mongoid model.

Thanks for your time.

mankind commented 10 years ago

I resolved the issue and it now displays just the message in the browser. I have a second controller Players controller which bare bones and doen't use redis and does not use redis but everything I make a post on the chatcontroller, the playerscontroller gets thesame message. Is this how it is supposed to work.

       class PlayersController < ApplicationController
           include Tubesock::Hijack

            respond_to :json, :html

          def player_chat

              hijack do |tubesock|
                  tubesock.onopen do
                      tubesock.send_data "Hello, play controller"
                  end

                   tubesock.onmessage do |data|
                      params = JSON.parse(data)
                     tubesock.send_data params  
                    end
               end  
           end  
       end

cheers

ngauthier commented 10 years ago

sounds like in your JS you are maybe not connecting to the players controller? I would check that you have a websocket connection for each socket in js, and that they don't share a variable or something.

mankind commented 10 years ago

Thanks @ngauthier, I created a 3rd controller that use TubeSock to see if it will also have the problem and it did. If I make a post to PlaysController or MessagesController that is the controllers that don't use redis, the post only appears on the website tab opened for them. It is only when I post from the ChatController that uses redis that the message is sent to all 3.

I have checked my javascript, it is exactly as that in your example repo with only the only changes to your example code being in the the url passed to Socket.new and the form to use as shown below for each of the 3 js files:

For chat.js

  var socket = new WebSocket("ws://" + window.location.host + "/chat/chat");

  return $("body").on("submit", "form.chat", function(event) { }

For m_chat.js for MessagController with a method called m_chat in it

 var  socket = new WebSocket("ws://" + window.location.host + "/messages/m_chat");

 return $("body").on("submit", "form.messages", function(event) { }

player_chat.js for PlaysController

 var socket = new WebSocket("ws://" + window.location.host + "/plays/player_chat");

 return $("body").on("submit", "form.player", function(event) { }

I changed var socket to var chatSocket for one of them to see if it changes anything but nope the problem is still there.

Thanks for looking at this.

ngauthier commented 10 years ago

hmm, I'm really not sure. It's odd that publishing the chat message on redis is coming back out the other tubesocks, especially since I don't use any global or class variables.

I think the next step would be if you could reduce the bug to the minimum code required to reproduce it and share the application so others can take a look.

Nick

mankind commented 10 years ago

@ngauthier I finally resolved it. The error was in the javascript like you earlier suggested and also in the erb template. While trying to create the watered down app to reproduce the bug, it occurred to me to change where socket.onmessage is appended into. Previously they were all being appended into #output.

   socket.onmessage = function(event) {
       if (event.data.length) {
          return $("#output").append("" + event.data + "<br>");
      }
    };

So for the play_chat.js that uses Playcontroller, I changed it to #play

  socket.onmessage = function(event) {
     if (event.data.length) {
         return $("#play").append("" + event.data + "<br>");
     }
  };

In the index.html.erb template that it uses, I changed the pre tag to have id="play" instead of id="output"

     <h1>Tubesock Plays controller</h1>
     <pre id="play"></pre>
    <form class="plays">
        <input placeholder="hello world" autofocus>
        <input type="submit" value="Submit">
    </form>

Thanks for your patience and willingness to help. Thanks for building Tubesock which has given us a simple alternative to other good gems like websocket-rails and by extension faye-websocket-ruby.

ngauthier commented 10 years ago

No problem, glad you sorted it out.