84 lines
2.4 KiB
Ruby
84 lines
2.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'csv'
|
|
require 'time'
|
|
require 'fileutils'
|
|
require_relative '../model/message_model'
|
|
|
|
# Multi-board store. Each board ("general", "tech", "offtopic"…) maps to one
|
|
# CSV file inside +base_dir+. Lazy-loaded the first time a board is touched.
|
|
class BoardRepository
|
|
BoardMeta = Struct.new(:id, :title, :description)
|
|
|
|
DEFAULT_BOARDS = [
|
|
BoardMeta.new('general', 'General', 'Open chat, anything goes'),
|
|
BoardMeta.new('tech', 'Tech', 'Hardware, software, code'),
|
|
BoardMeta.new('offtopic', 'Off-Topic','Random topics, jokes'),
|
|
BoardMeta.new('sysop', 'Sysop', 'Notes from the operator'),
|
|
].freeze
|
|
|
|
attr_reader :boards
|
|
|
|
def initialize(base_dir, boards: DEFAULT_BOARDS, legacy_path: nil)
|
|
@base_dir = base_dir
|
|
@boards = boards
|
|
@cache = {}
|
|
@mu = Mutex.new
|
|
FileUtils.mkdir_p(@base_dir)
|
|
migrate_legacy!(legacy_path) if legacy_path
|
|
end
|
|
|
|
def append(board_id, username, text)
|
|
msg = MessageModel.new(Time.now.strftime('%m-%d %H:%M'), username, text)
|
|
@mu.synchronize do
|
|
load_board(board_id) << msg
|
|
CSV.open(path_for(board_id), 'a') { |csv| csv << [msg.timestamp, msg.username, msg.text] }
|
|
end
|
|
msg
|
|
end
|
|
|
|
def last(board_id, n = 30)
|
|
@mu.synchronize { load_board(board_id).last(n) }
|
|
end
|
|
|
|
def count(board_id)
|
|
@mu.synchronize { load_board(board_id).size }
|
|
end
|
|
|
|
def total_count
|
|
@mu.synchronize { @boards.sum { |b| load_board(b.id).size } }
|
|
end
|
|
|
|
private
|
|
|
|
def migrate_legacy!(legacy_path)
|
|
return unless File.exist?(legacy_path)
|
|
target = path_for('general')
|
|
return if File.exist?(target) # already migrated or general has its own data
|
|
rows = []
|
|
CSV.foreach(legacy_path) { |row| rows << row }
|
|
return if rows.empty?
|
|
CSV.open(target, 'w') { |csv| rows.each { |r| csv << r } }
|
|
warn "BoardRepository: migrated #{rows.size} legacy messages " \
|
|
"from #{legacy_path} to #{target}"
|
|
rescue StandardError => e
|
|
warn "BoardRepository: legacy migration failed: #{e}"
|
|
end
|
|
|
|
def path_for(id)
|
|
File.join(@base_dir, "#{id}.csv")
|
|
end
|
|
|
|
def load_board(id)
|
|
return @cache[id] if @cache.key?(id)
|
|
list = []
|
|
if File.exist?(path_for(id))
|
|
CSV.foreach(path_for(id)) { |row| list << MessageModel.new(*row) }
|
|
end
|
|
@cache[id] = list
|
|
rescue StandardError => e
|
|
warn "BoardRepository load error (#{id}): #{e}"
|
|
@cache[id] = []
|
|
end
|
|
end
|