require "net/http" require "cgi" require "set" require "restclient" require "filezor/file" require "json" class Filezor::Client class Unauthorized < RuntimeError; end class InvalidArgument < RuntimeError; end attr_reader :options def self.last_exception @e end def self.last_exception=(e) @e = e end def initialize(host, port, password, options = {}) @root = "http://admin:#{password}@#{host}:#{port}" @options ||= stringify_keys(options) @options.update JSON.parse(post("info", options.to_json, "/")) end # This method acts like an rsync --delete. It deletes all files in the root, # and then puts the new files in. TODO: make atomic def sync(*files) options = files.last.is_a?(Hash) ? files.pop : {} files = files.flatten.uniq test(files) # # files.each do |f| # f.path = File.join(root, f.path) # end cached_md5s = caching? ? Set.new(cached(files)) : [] params = files.inject({}) do |memo, file| memo[file.path] = cached_md5s.include?(file.md5) ? file.md5 : file.tempfile memo end params["--delete"] = options[:delete] if options[:delete] params["--root"] = options[:root] if options[:root] post("", params) end # Simple file upload def put(*files) test(files) params = files.flatten.inject({}) do |memo, file| memo[file.path] = file.tempfile memo end post("", params) end def set_options(options = {}) @options = JSON.parse(post("info", options.to_json, "/")) end def ping get("ping", "/").code == 200 end def cached(*files) JSON.parse(post("cached", files.flatten.map{|f| f.md5 }.to_json, "/")) end def get(path, prefix = "/file/") _get("#{http_root}#{prefix}#{path}") rescue RestClient::Unauthorized raise Unauthorized end def post(path, params, prefix = "/file/") _post("#{http_root}#{prefix}#{path}", params) rescue RestClient::Unauthorized raise Unauthorized end def http_root "#{@root}#{app_root}" end def app_root options["app_root"] || "" end def caching? options["caching"] end private def _get(*args) puts args.inspect if ENV["FILEZOR_DEBUG"] RestClient.get(*args) rescue => e self.class.last_exception = e raise end def _post(*args) puts args.inspect if ENV["FILEZOR_DEBUG"] RestClient.post(*args) rescue => e self.class.last_exception = e raise end def test(*files) files.flatten.each do |file| unless file.is_a?(Filezor::File) raise InvalidArgument.new(file.inspect) end end end def stringify_keys(hash) hash.inject({}) {|memo, (k, v)| memo.update k.to_s => v } end end