# encoding: utf-8 require 'em-http' require 'em-http/middleware/json_response' require 'yaml' require 'json' require 'uri' module Junkie module Pyload # Class that abstracts the Pyload Api class Api include Config attr_reader :config, :cookie FILE_STATUS = { 0 => :done, 2 => :online, 3 => :queued, 4 => :skipped, 5 => :waiting, 8 => :failed, 10 => :decrypting, 12 => :downloading, 13 => :extracting, } DEFAULT_CONFIG = { protocol: 'http', host: 'localhost', port: 8000, api_user: 'user', api_password: 'password' } def initialize() @config = Config.get_config(self) api_user = @config[:api_user] api_password = @config[:api_password] unless api_password && api_user && api_password.match(/\w+/) && api_user.match(/\w+/) raise InvalidConfigError, "api_user or api_password are not configured" end end # makes a GET request with the given method name and params # # @param [Symbol] API-method e.g :getQueue, :getPackageData # @param [Hash] params that are a passed as query parameters # # @return [Object] parsed JSON Response def call(method, params={}) raise ArgumentError, "`method` is not a Symbol" unless method.is_a? Symbol query_parameter = {} params.each do |key, value| if value.is_a? Array query_parameter[key] = URI.encode_www_form_component(JSON.dump(value)) else query_parameter[key] = URI.encode_www_form_component('"' + value.to_s + '"') end end request("/#{method.to_s}", :get, query_parameter) end # Logs the api user in through sending the credentials to the Api # # @note sets cookie instance variable # @raise [Junkie::InvalidCredentialsError] is raised when the Login fails def login resp = nil begin resp = request('/login', :post, { username: @config[:api_user], password: @config[:api_password] }, true) rescue Junkie::HTTP403Error => e raise Junkie::InvalidCredentialsError, "the supplied credentials are incorrect" end # extract Cookie-ID from Login response if resp.response_header["SET_COOKIE"] header = resp.response_header["SET_COOKIE"] if md = header.match(/^(\S+);/) @cookie = md[1] end end end # builds up a URL string # # @param [String] path the method specific part of the url # @return [String] complete URI String def build_url(path="") "%s://%s:%d/api%s" % [ @config[:protocol], @config[:host], @config[:port], path ] end private # Utility function for making requests # # @param [String] method specific path e.g /getConfig or /login # @param [Symbol] HTTP method that is issued :get, :post, :delete # @param [Hash] Params that are added to the request, as query parameter # on :get requests and body on :post requests # @param [Boolean] return full response instead of body # # @return [Object] JSON Object that is send from the server or complete # response if the previous argument is set def request(path, method=:get, params={}, complete=false) f = Fiber.current request_options = {} if method == :get request_options[:query] = params elsif method == :post request_options[:body] = params end if @cookie request_options[:head] = {'cookie' => @cookie} end conn = EventMachine::HttpRequest.new(build_url(path)) conn.use EventMachine::Middleware::JSONResponse http = conn.method(method).call request_options http.callback { f.resume(http) } http.errback { f.resume(http) } Fiber.yield case http.response_header.status when 403 raise Junkie::HTTP403Error, "Response has status code 403" when 404 raise Junkie::HTTP404Error, "Response has status code 404" when 500 raise Junkie::HTTP500Error, "Response has status code 505" end return http if complete http.response end end end end