diff --git a/app/assets/javascripts/cable.js b/app/assets/javascripts/cable.js new file mode 100644 index 000000000..739aa5f02 --- /dev/null +++ b/app/assets/javascripts/cable.js @@ -0,0 +1,13 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. +// +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); diff --git a/app/assets/javascripts/channels/mirror_project.js b/app/assets/javascripts/channels/mirror_project.js new file mode 100644 index 000000000..3132fa8af --- /dev/null +++ b/app/assets/javascripts/channels/mirror_project.js @@ -0,0 +1,13 @@ +App.mirror_project = App.cable.subscriptions.create("MirrorProjectChannel", { + connected: function() { + // Called when the subscription is ready for use on the server + }, + + disconnected: function() { + // Called when the subscription has been terminated by the server + }, + + received: function(data) { + // Called when there's incoming data on the websocket for this channel + } +}); diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index 34286ffa4..5731b321c 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -1,4 +1,20 @@ module ApplicationCable class Connection < ActionCable::Connection::Base + identified_by :current_user + + def connect + self.current_user = find_verified_user + logger.add_tags 'ActionCable', current_user.id + end + + private + def find_verified_user + puts "############### cookies.signed[:signed_user_id]: #{cookies.signed[:user_id]}" + if current_user = User.find_by(id: cookies.signed[:user_id]) + current_user + else + reject_unauthorized_connection + end + end end end diff --git a/app/channels/mirror_project_channel.rb b/app/channels/mirror_project_channel.rb new file mode 100644 index 000000000..62d51dad7 --- /dev/null +++ b/app/channels/mirror_project_channel.rb @@ -0,0 +1,12 @@ +class MirrorProjectChannel < ApplicationCable::Channel + def subscribed + Rails.logger.info "################### channel params: #{params}" + # @project = Project.find_by_identifier params[:id] + stream_from "channel_room_#{params[:id]}" + end + + def unsubscribed + # Any cleanup needed when channel is unsubscribed + Rails.logger.info "################### unsubscribed ################### " + end +end diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index fe1c58843..46ea83a2e 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -269,7 +269,9 @@ class AccountsController < ApplicationController cookie_options = cookie_options.merge(domain: edu_setting('cookie_domain')) end cookies[autologin_cookie_name] = cookie_options - logger.info("cookies is #{cookies}") + cookies.signed[:user_id] ||= user.id + + logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]} =====> #{cookies[autologin_cookie_name]}") end def logout diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 994c6357c..68f0b2a48 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -342,7 +342,9 @@ class ApplicationController < ActionController::Base elsif params[:debug] == 'student' User.current = User.find 8686 elsif params[:debug] == 'admin' - User.current = User.find 1 + user = User.find 1 + User.current = user + cookies.signed[:user_id] = user.id end end # User.current = User.find 81403 @@ -386,7 +388,6 @@ class ApplicationController < ActionController::Base else User.current end - # User.current end ## 默认输出json diff --git a/app/controllers/concerns/login_helper.rb b/app/controllers/concerns/login_helper.rb index 8bfe7e4e5..1752e4f6c 100644 --- a/app/controllers/concerns/login_helper.rb +++ b/app/controllers/concerns/login_helper.rb @@ -24,8 +24,10 @@ module LoginHelper unless cookies[autologin_cookie_name].present? cookies[autologin_cookie_name] = cookie_options end + # for action cable + cookies.signed[:user_id] ||= user.id - Rails.logger.info("cookies is #{cookies}") + Rails.logger.info("cookies is #{cookies} ======> #{cookies.signed[:user_id]}") end def successful_authentication(user) diff --git a/app/jobs/migrate_remote_repository_job.rb b/app/jobs/migrate_remote_repository_job.rb index bdc7d5e23..6180bf5d7 100644 --- a/app/jobs/migrate_remote_repository_job.rb +++ b/app/jobs/migrate_remote_repository_job.rb @@ -2,14 +2,32 @@ class MigrateRemoteRepositoryJob < ApplicationJob queue_as :default def perform(repo_id, token, params) - puts "############ perform: repo_id: #{repo_id}, token: #{token}, params: #{params}}" repo = Repository.find_by(id: repo_id) return if repo.blank? + puts "############ MigrateRemoteRepositoryJob starting ... ############" + gitea_repository = Gitea::Repository::MigrateService.new(token, params).call if gitea_repository repo&.project&.update_columns(gpid: gitea_repository["id"]) repo&.mirror&.update_columns(status: Mirror.statuses[:succeeded]) + + project = repo.project + + json_data = { + mirror_status: repo.mirror_status, + mirror_num: repo.mirror_num, + mirror_url: repo.mirror_url, + first_sync: repo.first_sync?, + identifier: repo.identifier, + name: project.name, + id: project.id, + type: project.numerical_for_project_type + } + puts "############ broadcast start.......... ############" + cable_result = ActionCable.server.broadcast "channel_room_#{repo.identifier}", project: json_data + + puts "############ room_channel_#{repo.identifier} result : #{cable_result}" end end end diff --git a/app/services/gitea/repository/entries/list_service.rb b/app/services/gitea/repository/entries/list_service.rb index cbedc2bc7..dd62a1147 100644 --- a/app/services/gitea/repository/entries/list_service.rb +++ b/app/services/gitea/repository/entries/list_service.rb @@ -29,7 +29,6 @@ class Gitea::Repository::Entries::ListService < Gitea::ClientService when 200 body else - Rails.logger.info("########__________has_error_______##########{body['message']}") [] end end diff --git a/bin/cable b/bin/cable new file mode 100755 index 000000000..8a08d0cad --- /dev/null +++ b/bin/cable @@ -0,0 +1,2 @@ +#!/bin/bash +bundle exec puma -p 28080 cable/config.ru diff --git a/cable/config.ru b/cable/config.ru new file mode 100644 index 000000000..d23f64a98 --- /dev/null +++ b/cable/config.ru @@ -0,0 +1,4 @@ +require_relative '../config/environment' +Rails.application.eager_load! + +run ActionCable.server diff --git a/config/application.rb b/config/application.rb index f7d05dcd4..fece76ebb 100644 --- a/config/application.rb +++ b/config/application.rb @@ -29,6 +29,9 @@ module Educoderplus # job config.active_job.queue_adapter = :sidekiq + # disable actioncable development nend true + # config.action_cable.disable_request_forgery_protection = true + config.middleware.use OmniAuth::Builder do provider :cas, url: 'https://urp.tfswufe.edu.cn/cas' end diff --git a/config/cable.yml b/config/cable.yml index 3516b3fde..8aeb1df94 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -1,10 +1,12 @@ development: - adapter: async + adapter: redis + url: redis://localhost:6379 test: - adapter: async + adapter: redis + url: redis://localhost:6379 production: adapter: redis - url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> - channel_prefix: educoderplus_production + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379" } %> + channel_prefix: forgeplus_production diff --git a/config/routes.rb b/config/routes.rb index eab43b687..ffda83821 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,10 +2,12 @@ Rails.application.routes.draw do require 'sidekiq/web' require 'admin_constraint' - # mount Sidekiq::Web => '/sidekiq' mount Sidekiq::Web => '/sidekiq', :constraints => AdminConstraint.new + # Serve websocket cable requests in-process + mount ActionCable.server => '/cable' + get 'attachments/download/:id', to: 'attachments#show' get 'attachments/download/:id/:filename', to: 'attachments#show' get 'auth/qq/callback', to: 'oauth/qq#create'