From b9d9f7fb9a925455ea157e8d14b1e0e7a621240d Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Tue, 25 Nov 2025 12:48:50 +0100 Subject: [PATCH] resolve require rss issue for hook ruby scripts --- manyfold/cli/manyfold.sh | 6 +- .../experience_updated/1000-scan-dir.sh | 9 +- .../experience_updated/500-mastodon-post.rb | 4 +- .../src/app/config/initializers/xrforge.rb | 12 +- manyfold/usr/src/app/config/routes.rb | 179 ++++++++++++++++++ 5 files changed, 195 insertions(+), 15 deletions(-) create mode 100644 manyfold/usr/src/app/config/routes.rb diff --git a/manyfold/cli/manyfold.sh b/manyfold/cli/manyfold.sh index 4f4d03d..a99d2e0 100755 --- a/manyfold/cli/manyfold.sh +++ b/manyfold/cli/manyfold.sh @@ -73,6 +73,7 @@ hook(){ logger "$ hook $*" cmd=$1 shift + test -d ~/hook.d/$cmd && { find -L ~/hook.d/$cmd/ -type f -executable -maxdepth 1 | sort -V | while read hook; do logger " |+ hook $hook $*" @@ -210,7 +211,7 @@ start_syslog(){ scan_libraries(){ cd /usr/src/app echocolor "scanning libraries" - bin/manyfold libraries scan + BOOT_SCAN=$BOOT_SCAN bin/manyfold libraries scan } scan_experience(){ @@ -259,7 +260,7 @@ init_database(){ set_upload_path & get_xrfragment_assets mount_dir - scan_libraries & + BOOT_SCAN=1 scan_libraries & touch ${db}.xrforgeinit } @@ -276,7 +277,6 @@ boot(){ # enable development mode (disables template caching etc) test -n "$DEV" && { -# sed -i 's|^exec.*|exec s6-setuidgid $PUID:$PGID bin/dev|g' /usr/src/app/bin/docker-entrypoint.sh sed -i 's|config.enable_reloading = false|config.enable_reloading = true|g' /usr/src/app/config/environments/production.rb apk add vim } diff --git a/manyfold/root/hook.d/experience_updated/1000-scan-dir.sh b/manyfold/root/hook.d/experience_updated/1000-scan-dir.sh index 659b605..ef07b66 100755 --- a/manyfold/root/hook.d/experience_updated/1000-scan-dir.sh +++ b/manyfold/root/hook.d/experience_updated/1000-scan-dir.sh @@ -1,9 +1,8 @@ #!/bin/sh dir="$(dirname $1)" cd "$dir" -echo "[v] scan (new) files of model" id="$(basename "$dir" | sed 's/\#//g')" -# TODO: better ratelimiting -#test -f /tmp/.scan && test $id = "$(cat /tmp/.scan)" && exit -/manyfold/cli/manyfold.sh scan_experience $id -echo $id > /tmp/.scan +echo "[v] scan (new) files of model $id" +# ratelimit +flock -n /tmp/.scan_experience_$id /manyfold/cli/manyfold.sh scan_experience $id +rm /tmp/.scan_experience_$id diff --git a/manyfold/root/hook.d/experience_updated/500-mastodon-post.rb b/manyfold/root/hook.d/experience_updated/500-mastodon-post.rb index e9aca30..53f0e43 100755 --- a/manyfold/root/hook.d/experience_updated/500-mastodon-post.rb +++ b/manyfold/root/hook.d/experience_updated/500-mastodon-post.rb @@ -1,8 +1,7 @@ #!/usr/bin/env ruby -require 'json' require 'rss' -#require '/usr/local/lib/ruby/gems/3.4.0/gems/rss-0.3.1/lib/rss.rb' +require 'json' require 'open-uri' require 'cgi' require_relative './../../xrforge.rb' @@ -26,6 +25,7 @@ begin Dir.chdir( dir ) # Read and parse the JSON file data = JSON.parse( File.read( "datapackage.json" ) ) + APHandle = false data['keywords'].any? do |tag| if tag.match?(/@.*@.*\./) # scan for activitypub handle (@foo@mastodon.online e.g.) diff --git a/manyfold/usr/src/app/config/initializers/xrforge.rb b/manyfold/usr/src/app/config/initializers/xrforge.rb index e060d90..e7232d3 100644 --- a/manyfold/usr/src/app/config/initializers/xrforge.rb +++ b/manyfold/usr/src/app/config/initializers/xrforge.rb @@ -17,7 +17,7 @@ Rails.application.config.to_prepare do file = "#{self.model.library.path}/#{self.path_within_library()}" - if File.exist?(file) + if File.exist?(file) && (ENV['BOOT_SCAN'].present? || file.match?("datapackage") ) cache_key = "ttl:file:cli_hook:#{self.id}#{Digest::MD5.file(file).hexdigest}" ttl = 60.0 # dont trigger hook twice for the same file within 60 seconds now = Time.current @@ -29,11 +29,13 @@ Rails.application.config.to_prepare do if last_run_time.nil? || (now - last_run_time) > ttl # 2. Write the new execution time to the shared cache # Use `write` to set the new time. Caching a string representation is often safer/easier. - Rails.cache.write(cache_key, now.to_s, expires_in: ttl + 1.minute) + Rails.cache.write(cache_key, now.to_s, expires_in: ttl + 3.second) - puts "[app/config/initializers/xrforge.rb] runnin hook\n" - command = "TS_SLOTS=5 ts /manyfold/cli/manyfold.sh hook experience_updated #{file} &" - system(command) + puts "[app/config/initializers/xrforge.rb] running hook\n" + Bundler.with_unbundled_env do + #`TS_SLOTS=5 ts /manyfold/cli/manyfold.sh hook experience_updated #{file} &` + `/manyfold/cli/manyfold.sh hook experience_updated #{file} &` + end else puts "[app/config/initializers/xrforge.rb] skipping hook\n" end diff --git a/manyfold/usr/src/app/config/routes.rb b/manyfold/usr/src/app/config/routes.rb new file mode 100644 index 0000000..b1a1e72 --- /dev/null +++ b/manyfold/usr/src/app/config/routes.rb @@ -0,0 +1,179 @@ +require "sidekiq/web" +require "sidekiq/cron/web" +require "federails" + +Rails.application.routes.draw do + get "/altcha", to: "altcha#new" + get ".well-known/change-password", to: redirect("/users/edit") + get "health" => "rails/health#show", :as => :rails_health_check + get "problems/index" + + #if ENV['CORS_PROXY'].present? + match '/cors/*target_url_segment', to: 'cors_proxy#proxy', via: :all, format: false + #end + + devise_controllers = { + passwords: "users/passwords", + registrations: "users/registrations", + sessions: "users/sessions" + } + devise_controllers[:omniauth_callbacks] = "users/omniauth_callbacks" if Rails.application.config.manyfold_features[:oidc] + devise_for :users, controllers: devise_controllers + + authenticate :user, lambda { |u| u.is_administrator? } do + resource :settings, only: [:show, :update] do + collection do + get :analysis + get :downloads + get :multiuser + get :reporting + get :appearance + get :discovery + get :integrations + end + resources :libraries, only: [:index] + end + mount Sidekiq::Web => "/admin/sidekiq" + mount RailsPerformance::Engine => "/admin/performance" unless Rails.env.test? || ENV["RAILS_ASSETS_PRECOMPILE"].present? + mount PgHero::Engine => "/admin/pghero" + get "/activity" => "activity#index", :as => :activity + end + + if SiteSettings.multiuser_enabled? || Rails.env.test? + authenticate :user, lambda { |u| u.is_moderator? } do + namespace :settings do + resources :users + resources :reports + end + end + if SiteSettings.federation_enabled? || Rails.env.test? + mount Federails::Engine => "/" + mount FaspClient::Engine => "/fasp" + end + + resources :follows, only: [:index, :new] + get "/authorize_interaction" => "follows#new" # for compatibility with Mastodon, which assumes this URL + + post "/remote_follow" => "follows#remote_follow", :as => :remote_follow + post "/perform_remote_follow" => "follows#perform_remote_follow", :as => :perform_remote_follow + post "/follow_remote_actor/:id" => "follows#follow_remote_actor", :as => :follow_remote_actor + delete "/follow_remote_actor/:id" => "follows#unfollow_remote_actor", :as => :unfollow_remote_actor + end + + if SiteSettings.federation_enabled? || Rails.env.test? + authenticate :user, lambda { |u| u.is_moderator? } do + namespace :settings do + resources :domain_blocks if SiteSettings.federation_enabled? + end + end + end + + root to: redirect("/models") + get "/about", to: "home#about", as: :about + resources :imports, only: [:new, :create] + resources :scans, only: [:create] + + authenticate :user do + get "/welcome", to: "home#welcome", as: :welcome + end + + resources :libraries, except: [:index] + + concern :followable do |options| + if SiteSettings.multiuser_enabled? + resources :follows, {only: [:create]}.merge(options) do + collection do + delete "/", action: "destroy" + end + end + end + end + + concern :commentable do |options| + resources :comments, {only: [:show]}.merge(options) + end + concern :reportable do |options| + resources :reports, {only: [:new, :create]}.merge(options) + end + concern :linkable do + member do + post :sync + end + end + + resources :models do + concerns :followable, followable_class: "Model" + concerns :commentable, commentable_class: "Model" + concerns :reportable, reportable_class: "Model" + concerns :linkable + member do + post "scan" + end + collection do + post "merge" + get "merge", action: "configure_merge", as: "configure_merge" + get "edit", action: "bulk_edit" + patch "/update", action: "bulk_update" + end + resources :model_files, except: [:index, :new] do + collection do + get "bulk_edit" + patch "bulk_update" + end + end + end + resources :creators do + concerns :followable, followable_class: "Creator" + concerns :commentable, commentable_class: "Creator" + concerns :reportable, reportable_class: "Creator" + concerns :linkable + member do + get :avatar + get :banner + end + end + resources :collections do + concerns :followable, followable_class: "Collection" + concerns :commentable, commentable_class: "Collection" + concerns :reportable, reportable_class: "Collection" + concerns :linkable + end + resources :problems, only: [:index, :update] do + collection do + post "resolve", action: "resolve" + end + member do + post "resolve" + end + end + resources :benchmark, only: [:index, :create, :destroy] if Rails.env.development? + + authenticate :user, lambda { |u| u.is_contributor? } do + mount Tus::Server => "/upload", :as => :upload + end + + get("/oembed", to: redirect(status: 303) { |_, request| + path = URI.parse(request.params[:url])&.path + raise ActionController::BadRequest if path.blank? + URI::HTTP.build(path: path + ".oembed", query: { + maxwidth: request.params[:maxwidth], + maxheight: request.params[:maxheight] + }.compact.to_query) + }) + + mount Rswag::Ui::Engine => "/api", :as => :api + mount Rswag::Api::Engine => "/api" + + use_doorkeeper do + skip_controllers :applications + end + resources :doorkeeper_applications, path: "/oauth/applications" + + # Fallback route for filename matching + get "/models/:model_id/model_files/*id" => "model_files#show", :as => "model_model_file_by_filename" + + # Web crawler stuff + get "/robots", to: "robots#index" + get "/sitemap", to: "robots#sitemap" +end +