我有一个rails api,我正试图为gitgui创建一个实时流功能。我有一个控制器和一个用于提交更新的通道,我想在通道中的订阅操作中使用实时流功能。这可能吗?或者有没有更好的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
中放置广播。但看起来这不是你的解决方案。