module Filbunke class Client UPDATES_ACTION = 'updates' FILES_ACTION = 'files' URL_KEY = 'url' FROM_CHECKPOINT_KEY = 'from_checkpoint' HASH_KEY = 'hash' def initialize(repository) @repository = repository end def with_updated_files(last_checkpoint, local_path) updates = get_updated_file_list(last_checkpoint) updated_files = updates["files"] || [] updated_files.each do |raw_file| file = File.new(raw_file) if file.url.start_with?("http://") local_file_path = File.join(local_path, file.path) update_http_file!(file, local_file_path) yield file else raise "Unsupported protocol for file: #{file.inspect}" end end updates["checkpoint"] || last_checkpoint end def register_updated_file!(path, url, hash = nil) register_http = Net::HTTP.new(@repository.host, @repository.port) register_http.start do |http| register_path = "/#{FILES_ACTION}/#{@repository.name}/#{path}?#{URL_KEY}=#{url}" register_path += "&#{HASH_KEY}=#{hash}" if hash request = Net::HTTP::Put.new(register_path) response = http.request(request) if response.code.to_i != 204 raise "Failed to register updated file: #{path}" end end end def register_deleted_file!(path) register_http = Net::HTTP.new(@repository.host, @repository.port) register_http.start do |http| register_path = "/#{FILES_ACTION}/#{@repository.name}/#{path}" request = Net::HTTP::Delete.new(register_path) response = http.request(request) if response.code.to_i != 204 raise "Failed to register deleted file: #{path}" end end end private def get_updated_file_list(last_checkpoint) updates_http = Net::HTTP.new(@repository.host, @repository.port) updates_http.start do |http| updates_path = "/#{UPDATES_ACTION}/#{@repository.name}?#{FROM_CHECKPOINT_KEY}=#{last_checkpoint}" request = Net::HTTP::Get.new(updates_path) response = http.request(request) if response.code.to_i == 200 JSON.parse(response.body) else raise "Failed to download updates for #{@repository.name}, error code = #{response.code}" end end end def update_http_file!(file, local_file_path) uri = URI.parse(file.url) file_http=Net::HTTP.new(uri.host, uri.port) file_http.start do |http| request = Net::HTTP::Get.new(uri.path) request.basic_auth @repository.user, @repository.pass if @repository.user response = http.request(request) if response.code.to_i == 200 write_file!(local_file_path, response.body) elsif response.code.to_i == 404 delete_file!(local_file_path) else raise "Failed to update file #{uri}, error code = #{response.code}" end end end def write_file!(file_path, contents) FileUtils.mkdir_p(File.dirname(file_path)) File.open(file_path, 'w') do |file| file.write(contents); file.close end end def delete_file!(file_path) File.delete(file_path) end end end