ruby - 在 ActionCable 通道中使用控制器方法
问题描述
我有一个 rails api,我正在尝试为 git gui 创建一个实时流功能。我有一个控制器和一个用于提交更新的通道,我想在通道的订阅操作中使用实时流功能。这可能吗?或者有没有更好的 Rails 方法来做到这一点。我认为正确的方法是ActionCable.server.broadcast('commit_updates', { body: return_data })
在我的控制器方法中使用,但我没有在任何地方调用我的控制器方法。我在哪里/如何调用它,以便它在订阅它的客户端上运行?还是我应该将逻辑放在通道内?
这是我的 commit_updates_controller.rb
class CommitUpdatesController < ApplicationController
include ActionController::Live
require 'listen'
require 'json'
$file_path = "#{Dir.getwd}/.git/objects"
@@commits = {}
@@commits_array = []
@@edges_array = []
def index
end
def live_stream
# get folders exlcluding ".","..", "pack","info"
folders = Dir.entries($file_path).select {|folder| /^[a-z0-9]{2}$/i.match(folder) }
folders.each do |folder|
files = Dir.children("#{$file_path}/#{folder}")
files.each do |file|
CommitUpdate.find_commit_info(folder, file, @@commits_array)
end
end
generate_edges
ActionCable.server.broadcast('commit_updates', { body: return_data })
p return_data
# listens to any changes that happen to the git folder while the program is open
listener = Listen.to($file_path) do |modified, added, removed|
# puts(modified: modified, added: added, removed: removed)
added.each do |new_file_path|
split_new_file_path = new_file_path.split("/").reject!{|item| item.empty?}
folder = split_new_file_path[split_new_file_path.length() - 2]
file = split_new_file_path[split_new_file_path.length - 1]
CommitUpdate.find_commit_info(folder, file, @@commits_array)
add_edge(@@edges_array, CommitUpdate.get_commit_info(folder, file))
ActionCable.server.broadcast('commit_updates', { body: return_data })
end
end
listener.start
sleep
end
private
def generate_edges
if @@commits_array.length != 0
@@commits_array.each do |commit|
add_edge(@@commits_array, commit)
end
end
end
def add_edge(array, commit)
if commit[:parents] != []
commit[:parents].each {|parent| @@edges_array.push({from: parent, to: commit[:sha1]})}
end
end
def return_data
ret = {
:nodes => @@commits_array,
:links => @@edges_array
}
return ret.to_json
end
end
这是我的 commit_updates_channel.rb
class CommitUpdatesChannel < ApplicationCable::Channel
def subscribed
stream_from 'commit_updates'
end
end
这是我的 commit_updates.rb 模型
class CommitUpdate < ApplicationRecord
def self.find_commit_info(folder, file, array)
file_type = self.check_sha1_type(folder, file)
if file_type == "commit"
array.push(
self.get_commit_info(folder, file)
)
end
end
def self.get_commit_info(folder, file)
author = ""
parents = []
commit_message = ""
unixtime = ""
decoded_file = `git cat-file -p #{folder}#{file}`
file_data_array = decoded_file.split("\n").reject!{|item| item.empty?}
p file_data_array
file_data_array.each do |item|
split_item = item.split(" ")
case split_item[0]
when "author"
author = split_item[1..split_item.length() - 4].join(" ")
when "parent"
parents.push(split_item[1])
when "tree"
next
when "blob"
next
when "committer"
unixtime = split_item[split_item.length - 2]
else
commit_message = split_item.join(" ")
end
end
commit_info = {
:sha1 => "#{folder}#{file}",
:parents => parents,
:commit_message => commit_message,
:author => author,
:unixtime => unixtime,
:id => "#{folder}#{file}",
:label => "#{folder}#{file[0..4]}...",
:font => "18px verdana blue",
}
return commit_info
end
private
def self.check_sha1_type(folder, file)
return `git cat-file -t #{folder}#{file}`.chomp
end
end
解决方案
使用控制器live_stream
,需要请求这个方法,例如,编写js程序定期调用它。或者一些正在调用它的 bash 脚本。不好。
另一种解决方案是将live_stream
逻辑放入后台作业中,该作业将每 X 分钟检查一次提交更新。如果工作发现变化,它就会广播。
更常见的是将广播放在模型回调after_save
中,after_commit
. 但它看起来不是你的解决方案。
推荐阅读
- python - Curve_Fit 函数似乎不起作用。我有相同长度的数组中的 xdata 和 ydata,但曲线拟合会产生错误。我的错误是什么?
- ios - iOS Spin UIImageView 在随机位置减速运动
- laravel - 参数 1 必须是字符串类型或 null,给定对象
- python-3.x - 从 .pb 文件中查找输入和输出张量
- javascript - 在特定网页上同步两个可编辑文本框的方法?
- html - 如何使onmouseover图像大小相对于onmouseout img?
- java - 将变量传递给不同的方法?
- database - 如何将多个“输入字段”添加为对象或数组
- sql-server - 尝试使用 导入值时数据转换失败。精确
- video - 使用 GStreamer 将 M3U8 播放列表转换为 MP4