#ifndef _TOREST_SESSION_HPP_ #define _TOREST_SESSION_HPP_ #include #include #include #include namespace session { class basic_manager { public: virtual ~basic_manager()=0; virtual nlohmann::json get_json() const = 0; virtual bool patch(const nlohmann::json &data) = 0; virtual bool is_valid() const = 0; virtual int listen_port() const = 0; virtual void set_session(std::shared_ptr) = 0; virtual void set_listen_port() = 0; }; class manager : public basic_manager { public: void set_session(std::shared_ptr session) override { handle=session; } nlohmann::json get_json() const override ; bool is_valid() const override { return handle && handle->is_valid(); } bool patch(const nlohmann::json &data) override ; private: std::shared_ptr handle; }; class basic_resource { public: virtual ~basic_resource() {} virtual void set_session(std::shared_ptr)=0; }; class resource : public basic_resource { public: void set_session(std::shared_ptr session_manager) override { mgr=session_manager; } virtual void get(nlohmann::json arg=nullptr) { if(mgr && mgr->is_valid()){ response.set_status(http::ok); response.set_body(mgr->get_json()); }else{ response.set_status(http::service_unavailable); } } /** * PATCH /session * -------------- * \brief Change values on the session. * @param[in] data takes an JSON object with at least one `action` set. * available `action`s are `is_paused` `listen_port` */ void patch(const nlohmann::json&data=nlohmann::json::object()); // @todo should we return service unavailable or just method not allowed? void del(nlohmann::json arg=nullptr) { response.set_status(http::method_not_allowed); } void put(nlohmann::json arg=nullptr) { response.set_status(http::method_not_allowed); } virtual void post(nlohmann::json arg=nullptr) { response.set_status(http::method_not_allowed); } protected: std::shared_ptr mgr; http::response response; }; } #endif // _TOREST_RESOURCE_HPP_ /*! Resource: torrents Other: - If multiple headers with the same key is posted, the server uses only the last. - Server can return 503 Service Unavailable if for some reason a service is down */ /* class torrents : public Resource,std::shared_ptr> { public: torrents(libtorrent::session &session); }; */ // std::function /*! API-End-point: [POST] /v1/session/torrents Requirements: - Content-Type: application/json * This header must be set, otherwise toREST will return 403 Forbidden. - Data: * A valid JSON-object is required. * A valid format: ```json { "torrent": "", "save_path": "" } ``` * Fields `torrent` and `save_path` can not be empty. toREST will return 400 Bad Request * The `torrent` field can be a `local torrent file`, a `magnet-uri` or a HTTP-resource. toREST will Accept every file with a valid url, uri or path, but will not download or create torrents if the path is a invalid torrent file. * The `save_path` field can be any location on the server machine, in which the invoking user has write permissions. If the save_path is a directory, the torrent will download into the directory. If the save_path is a file, toREST will return 400 Bad Request. Side-Effects: - 202 Accepted, if the request is valid. * The `Location` header is set if the torrent info_hash is available * If a WebSocket is open a TORRENT_ADDED action is posted when the torrent resource is available. * POST=[&session](std::shared_ptr resp,std::shared_ptr req){ http::request_handler handler(req,resp); // If session is invalid there is no point hanging around. if(!session.is_valid()) return handler.respond(i18N::session_unavailable,http::service_unavailable); // At least one header named with Content-Type, then check if the last one set is application/json if(handler.header_equals("Content-Type","application/json")) return handler.respond(i18N::content_type_not_set,http::forbidden); // If the supplied JSON is invalid, bad request auto request_json=util::json::parse(req->content); if(!request_json.is_object() || request_json.is_null()) return handler.respond(nlohmann::json(i18N::unable_to_parse_json),http::bad_request); // handle required fields std::vector required_fields={ request_json.value("torrent",""), request_json.value("save_path","") }; std::vector empty_fields; std::copy_if(required_fields.begin(),required_fields.end(),empty_fields.begin(),[](const std::string &field){return field.empty();}); if(!empty_fields.empty()){ std::string message; for(auto &field:empty_fields) message+=" The required field `"+field+"` is empty"; return handler.respond(nlohmann::json(i18N::wrong_format + message),http::bad_request); } auto torrent_field=required_fields.front(); libtorrent::add_torrent_params torrent_options; boost::system::error_code ec; if(torrent_field.substr(0,6)=="magnet"){ libtorrent::parse_magnet_uri(torrent_field,torrent_options,ec); ECERROR(ec); } else if(boost::filesystem::exists(torrent_field,ec) && !boost::filesystem::is_directory(torrent_field,ec)) torrent_options.ti=boost::make_shared(libtorrent::torrent_info(torrent_field,ec)); else if(boost::regex_match(torrent_field,util::regex)) torrent_options.url=torrent_field; else { ECERROR(ec); return handler.respond(nlohmann::json(i18N::unable_to_parse_torrent_uri),http::bad_request); } boost::filesystem::path save_path(required_fields.back()); auto status=boost::filesystem::status(save_path,ec); if(!ec){ if(boost::filesystem::exists(status) && !boost::filesystem::is_directory(status)) return handler.respond(nlohmann::json(i18N::wrong_format + " The save path is invalid"),http::bad_request); else { // TODO chroot try { boost::filesystem::create_directories(save_path); } catch(const std::exception &ex){ return handler.respond(nlohmann::json(i18N::write_error),http::forbidden); } } } else { // invalid file status ECERROR(ec); } torrent_options.save_path=save_path.generic_string(); session.async_add_torrent(torrent_options); // TODO add websocket event std::string info_hash(torrent_options.info_hash.data()); if(info_hash!="undefined"){ std::stringstream ss; ss << torrent_options.info_hash; info_hash=ss.str(); handler.headers["Location:"]= "/torrents/" + info_hash; } return handler.respond(nlohmann::json(http::http_code(http::accepted).second), http::accepted); }; }*/