Class: Abqari::Syndication::Dispatcher
- Inherits:
-
Object
- Object
- Abqari::Syndication::Dispatcher
- Defined in:
- lib/abqari/syndication.rb
Overview
Build-time orchestrator. Walks recent posts, dispatches to each configured network, accumulates a per-post log.
Instance Method Summary collapse
- #enabled? ⇒ Boolean
-
#initialize(site) ⇒ Dispatcher
constructor
A new instance of Dispatcher.
- #log_path ⇒ Object
- #networks ⇒ Object
- #run ⇒ Object
- #window_days ⇒ Object
Constructor Details
#initialize(site) ⇒ Dispatcher
Returns a new instance of Dispatcher.
83 84 85 86 |
# File 'lib/abqari/syndication.rb', line 83 def initialize(site) @site = site @cfg = Syndication.config_for(site) end |
Instance Method Details
#enabled? ⇒ Boolean
88 89 90 |
# File 'lib/abqari/syndication.rb', line 88 def enabled? Syndication.enabled?(@site) end |
#log_path ⇒ Object
92 93 94 |
# File 'lib/abqari/syndication.rb', line 92 def log_path File.join(@site.site_root, 'vendor', 'syndication', 'sent.yml') end |
#networks ⇒ Object
100 101 102 103 104 105 106 107 |
# File 'lib/abqari/syndication.rb', line 100 def networks @networks ||= begin out = [] out << Networks::Mastodon.new(@site) if network_enabled?('mastodon') out << Networks::Bluesky.new(@site) if network_enabled?('bluesky') out end end |
#run ⇒ Object
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/abqari/syndication.rb', line 109 def run return unless enabled? # Hard production gate. POSSE is an irreversible outbound side # effect (public posts to Mastodon/Bluesky). `Site#build` runs # in every environment — including `bin/serve`'s dev rebuilds, # which include drafts and future-dated posts and resolve URLs # against the dev `url` (e.g. http://localhost:4000). Broadcasting # from anywhere but production would leak unpublished content and # ship localhost links. No env override — this must not fire by # accident. return unless @site.respond_to?(:env) && @site.env == :production return if networks.empty? FileUtils.mkdir_p(File.dirname(log_path)) log = load_log cutoff = Date.today - window_days syndicated = 0 recent_posts(cutoff).each do |post| url = absolute_url_for(post) next if url.nil? networks.each do |net| next unless net.configured? key = "#{net.name}|#{url}" # Skip only when previously SENT successfully. Failures # are recorded for visibility but get retried on the next # build — a transient API outage shouldn't permanently # skip syndication for a post. prev = log['sent'][key] next if prev && prev['status'] == 'sent' text = Formatter.snippet_for(post, url, limit: LIMITS[net.name]) result = net.post(text: text, url: url) if result log['sent'][key] = { 'status' => 'sent', 'at' => Time.now.utc.iso8601, 'syndicated_url' => result } syndicated += 1 Log.info "Syndicated to #{net.name}: #{url} → #{result}" else log['sent'][key] = { 'status' => 'failed', 'at' => Time.now.utc.iso8601 } end end end save_log(log) if syndicated.positive? || log_dirty?(log) Log.info "Syndication: posted #{syndicated} new entry/entries" if syndicated.positive? end |
#window_days ⇒ Object
96 97 98 |
# File 'lib/abqari/syndication.rb', line 96 def window_days @cfg.fetch('window_days', 14).to_i end |