refact
This commit is contained in:
83
lib/domain/repository/board_repository.rb
Normal file
83
lib/domain/repository/board_repository.rb
Normal file
@@ -0,0 +1,83 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user