我第一次使用redis
在我的rails应用中添加聊天功能,this
我有我的javascript`
$(document).ready ->
source = new EventSource('/messages/events')
source.addEventListener 'messages.create', (e) ->
message = $.parseJSON(e.data).message
console.log(message)
$(".chat-messages").append "#some code"
并在我的消息控制器中
def create
response.headers["Content-Type"] = "text/javascript"
attributes = params.require(:message).permit(:content, :sender_id, :sendee_id)
@message = Message.create(attributes)
respond_to do |format|
format.js { render 'messages/create.js.erb' }
end
$redis.publish('messages.create', @message.to_json)
end
def events
response.headers["Content-Type"] = "text/event-stream"
redis = Redis.new
redis.subscribe('messages.*') do |on|
on.message do |pattern, event, data|
response.stream.write("event: #{event}\n")
response.stream.write("data: #{data}\n\n")
end
end
rescue IOError
logger.info "Stream closed"
ensure
redis.quit
response.stream.close
end
问题是,首先,我的控制台中没有记录任何内容,其次我得到了大量随机ConnectionTimeoutError
错误。有人想知道发生了什么
答案 0 :(得分:2)
在redis.rb
目录中创建config/initializers
初始化文件,全球化redis
的实例。设置heartbeat
线程也是一个好主意(根据您的要求,5秒至5分钟的任何时间都可以):
$redis = Redis.new
heartbeat_thread = Thread.new do
while true
$redis.publish("heartbeat","thump")
sleep 15.seconds
end
end
at_exit do
# not sure this is needed, but just in case
heartbeat_thread.kill
$redis.quit
end
您需要向ChatController
,pub
和sub
添加两种方法。 pub
的作用是将聊天事件和消息发布到redis
,并sub
订阅这些事件。看起来应该是这样的:
class ChatController < ApplicationController
include ActionController::Live
skip_before_filter :verify_authenticity_token
def index
end
def pub
$redis.publish 'chat_event', params[:chat_data].to_json
render json: {}, status: 200
end
def sub
response.headers["Content-Type"] = "text/event-stream"
redis = Redis.new
redis.subscribe(['chat_event']) do |on|
on.message do |event, data|
response.stream.write "event: #{event}\ndata: #{data}\n\n"
end
end
rescue IOError
logger.info "Stream Closed"
ensure
redis.quit
response.stream.close
end
end
在routes
中,将 pub 设为POST
和 sub a GET
,并将路径与/chat/publish
和/chat/subscribe
匹配。
假设您的聊天应用的实际网页位于/chat
,您需要编写一些 Javascript 来实际发送和接收聊天消息。
为了便于理解,我们假设您的网页只有一个文本框和一个按钮。点击按钮应该将文本框的内容发布到聊天流,我们可以使用AJAX:
$('button#send').click (e) ->
e.preventDefault()
$.ajax '/chat/publish',
type: 'POST'
data: {
chat_data: {
message: $("input#message").val(),
timestamp: $.now()
}
}
error: (jqXHR, textStatus, errorThrown) ->
console.log "Failed: " + textStatus
success: (data, textStatus, jqXHR) ->
console.log "Success: " + textStatus
现在,您还需要能够订阅和接收聊天消息。您需要使用EventSource
。使用 EventSource ,打开SSE的通道,以便您可以接收事件,并使用该数据更新视图。在这个例子中,我们只将它们记录到javascript控制台。
代码看起来像这样:
$(document).ready ->
source = new EventSource('/chat/subscribe')
source.addEventListener 'chat_event', (e) ->
console.log(e.data)
在您的开发环境中,您必须通过将这两行添加到config/environments/development.rb
来启用并行请求:
config.preload_frameworks = true
config.allow_concurrency = true
现在启动浏览器,浏览到/chat
并查看魔法。当您键入消息并单击该按钮时,该网页的所有实例都将收到该消息。
这就是您使用rails
和ActionController::Live
在Redis
中制作基本聊天应用程序的方法。根据您的要求,最终的代码显然会有很大不同,但这应该可以帮助您入门。
您应该查看更多资源:
答案 1 :(得分:1)
虽然我没有使用redis
这个容量(“实时”数据的调解员),但我设法让这个功能与Pusher
一起使用
<强> Redis的强>
我不明白你是如何保持你的app&amp; Redis的。您需要某种Web套接字或并发连接技术来处理更新 - 据我所知,Redis不直接处理此问题
如果您查看this example,它会使用名为Goliath的服务器来处理asynchronous
连接:
当微型聊天连接到服务器时,它会发送一个GET请求 / subscribe / everyone其中每个人都是频道的名称和 “Accept”标头设置为text / event-stream。流媒体中间件 (上面)收到此请求并订阅redis Pub / Sub 渠道。由于Goliath是非阻塞的,因此多个客户端都可以 在没有捆绑Heroku dyno的情况下聆听事件。一个有效载荷 服务器发送的事件如下所示:
基本上使用中间件将您连接到redis服务器 - 允许您根据需要接收更新
<强>代码强>
虽然我无法明确指出任何错误,但我可以给你一些我们正在使用的代码(使用Pusher):
#config/initializers/pusher.rb
Pusher.url = ENV["PUSHER_URL"]
Pusher.app_id = ENV["PUSHER_APP_ID"]
Pusher.key = ENV["PUSHER_KEY"]
Pusher.secret = ENV["PUSHER_SECRET"]
#app/controllers/messages_controller.rb
def send_message
id = params[:id]
message = Message.find(id).broadcast!
public_key = self.user.public_key
Pusher['private-user-' + public_key].trigger('message_sent', {
message: "Message Sent"
})
end
#app/views/layouts/application.html.erb
<%= javascript_include_tag "http://js.pusher.com/2.1/pusher.min.js" %>
#app/assets/javascripts/application.js
$(document).ready(function(){
#Pusher
pusher = new Pusher("************",
cluster: 'eu'
)
channel = pusher.subscribe("private-user-#{gon.user}")
channel.bind "multi_destroy", (data) ->
alert data.message
channel.bind "message_sent", (data) ->
alert data.message
});