async def update_download(self, request): infohash = unhexlify(request.match_info['infohash']) download = tribler_utils.tribler_data.get_download_with_infohash( infohash) parameters = request.query if 'selected_files' in parameters: selected_files_list = [ str(f, 'utf-8') for f in parameters['selected_files'] ] download.set_selected_files(selected_files_list) if 'state' in parameters and parameters['state']: state = parameters['state'] if state == "resume": download.status = 3 elif state == "stop": download.status = 5 elif state == "recheck": download.status = 2 else: return RESTResponse({"error": "unknown state parameter"}, status=HTTP_BAD_REQUEST) return RESTResponse({"modified": True, "infohash": hexlify(infohash)})
async def get_torrents(self, request): my_channel = tribler_utils.tribler_data.get_my_channel() if my_channel is None: return RESTResponse({"error": "your channel has not been created"}, status=HTTP_NOT_FOUND) first, last, sort_by, sort_asc, txt_filter = MetadataEndpoint.sanitize_parameters( request.query) channel = my_channel.public_key torrents, total = tribler_utils.tribler_data.get_torrents( first, last, sort_by, sort_asc, txt_filter, channel, include_status=True) return RESTResponse({ "results": torrents, "first": first, "last": last, "sort_by": sort_by or None, "sort_asc": int(sort_asc), "dirty": my_channel.is_dirty(), })
async def get_log(self, request): # First, flush all the logs to make sure it is written to file for handler in logging.getLogger().handlers: handler.flush() # Default response response = {'content': '', 'max_lines': 0} # Get the location of log file param_process = request.query.get('process', 'core') log_file_name = self.session.config.get_log_dir() / ( f'tribler-{param_process}-info.log') # If the log file is not present in the versioned state directory, try root state directory location if not log_file_name.exists(): log_file_name = get_root_state_directory() / ( f'tribler-{param_process}-info.log') # If the log file is still not found, maybe it is not created yet, then return the default response if not log_file_name.exists(): return RESTResponse(response) # If the log file exists and return last requested 'max_lines' of log try: max_lines = int(request.query['max_lines']) with log_file_name.open(mode='r') as log_file: response['content'] = self.tail(log_file, max_lines) response['max_lines'] = max_lines except ValueError: with log_file_name.open(mode='r') as log_file: response['content'] = self.tail(log_file, 100) # default 100 lines response['max_lines'] = 0 return RESTResponse(response)
async def add_download(self, request): parameters = await request.json() if not parameters.get('uri'): return RESTResponse({"error": "uri parameter missing"}, status=HTTP_BAD_REQUEST) download_config, error = DownloadsEndpoint.create_dconfig_from_params( parameters) if error: return RESTResponse({"error": error}, status=HTTP_BAD_REQUEST) uri = parameters['uri'] if uri.startswith("file:"): filename = url2pathname(uri[5:]) download_uri = f"file:{filename}" else: download_uri = unquote_plus(uri) try: download = await self.session.dlmgr.start_download_from_uri( download_uri, config=download_config) except Exception as e: return RESTResponse({"error": str(e)}, status=HTTP_INTERNAL_SERVER_ERROR) return RESTResponse({ "started": True, "infohash": hexlify(download.get_def().get_infohash()) })
async def bootstrap(self, request): if 'MB' not in self.session.wallets: return RESTResponse({"error": "bandwidth wallet not found"}, status=HTTP_NOT_FOUND) bandwidth_wallet = self.session.wallets['MB'] available_tokens = bandwidth_wallet.get_bandwidth_tokens() args = request.query if 'amount' in args: try: amount = int(args['amount']) except ValueError: return RESTResponse( {"error": "Provided token amount is not a number"}, status=HTTP_BAD_REQUEST) if amount <= 0: return RESTResponse( {"error": "Provided token amount is zero or negative"}, status=HTTP_BAD_REQUEST) else: amount = available_tokens if amount <= 0 or amount > available_tokens: return RESTResponse( {"error": "Not enough bandwidth tokens available"}, status=HTTP_BAD_REQUEST) result = bandwidth_wallet.bootstrap_new_identity(amount) result['private_key'] = result['private_key'].decode('utf-8') result['block']['block_hash'] = result['block']['block_hash'].decode( 'utf-8') return RESTResponse(result)
async def update_torrent(self, request): parameters = request.query if 'status' not in parameters: return RESTResponse({"error": "status parameter missing"}, status=HTTP_BAD_REQUEST) my_channel = tribler_utils.tribler_data.get_my_channel() infohash = request.match_info['infohash'] torrent = my_channel.get_torrent_with_infohash(unhexlify(infohash)) if not torrent: return RESTResponse( { "error": "torrent with the specified infohash could not be found" }, status=HTTP_NOT_FOUND) new_status = int(parameters['status']) torrent.status = new_status return RESTResponse({ "success": True, "new_status": new_status, "dirty": my_channel.is_dirty() })
async def subscribe_to_channel(self, request): parameters = await request.json() if 'subscribe' not in parameters: return RESTResponse( { "success": False, "error": "subscribe parameter missing" }, status=HTTP_BAD_REQUEST) to_subscribe = bool(int(parameters['subscribe'])) channel_pk = unhexlify(request.match_info['channel_pk']) channel = tribler_utils.tribler_data.get_channel_with_public_key( channel_pk) if channel is None: return RESTResponse( {"error": "the channel with the provided cid is not known"}, status=HTTP_NOT_FOUND) if to_subscribe: tribler_utils.tribler_data.subscribed_channels.add(channel.id) channel.subscribed = True else: if channel.id in tribler_utils.tribler_data.subscribed_channels: tribler_utils.tribler_data.subscribed_channels.remove( channel.id) channel.subscribed = False return RESTResponse({"success": True})
async def get_history(self, request) -> RESTResponse: if not self.session.bandwidth_community: return RESTResponse({"error": "Bandwidth community not found"}, status=HTTP_NOT_FOUND) return RESTResponse({ 'history': self.session.bandwidth_community.database.get_history() })
async def get_statistics(self, request): if 'MB' not in self.session.wallets: return RESTResponse({"error": "TrustChain community not found"}, status=HTTP_NOT_FOUND) return RESTResponse({ 'statistics': recursive_unicode(self.session.wallets['MB'].get_statistics()) })
async def completions(self, request): if 'q' not in request.query: return RESTResponse({"error": "q parameter missing"}, status=HTTP_BAD_REQUEST) return RESTResponse({ "completions": ["tribler1", "tribler2", "tribler3", "tribler4", "tribler5"] })
async def create_remote_search_request(self, request): # Query remote results from the GigaChannel Community. # Results are returned over the Events endpoint. try: sanitized = self.sanitize_parameters(request.query) except (ValueError, KeyError) as e: return RESTResponse({"error": f"Error processing request parameters: {e}"}, status=HTTP_BAD_REQUEST) request_uuid = self.session.gigachannel_community.send_search_request(**sanitized) return RESTResponse({"request_uuid": str(request_uuid)})
async def delete_torrent(self, request): my_channel = tribler_utils.tribler_data.get_my_channel() if my_channel is None: return RESTResponse({"error": "your channel has not been created"}, status=HTTP_NOT_FOUND) for torrent in my_channel.torrents: torrent.status = TODELETE return RESTResponse({"success": True})
async def update_channel_entry(self, request): # TODO: unify checks for parts of the path, i.e. proper hex for public key, etc. try: parameters = await request.json() except (ContentTypeError, ValueError): return RESTResponse({"error": "Bad JSON input data"}, status=HTTP_BAD_REQUEST) public_key = unhexlify(request.match_info['public_key']) id_ = request.match_info['id'] error, result = self.update_entry(public_key, id_, parameters) return RESTResponse(result, status=error or 200)
async def create_channel(self, request): my_channel = tribler_utils.tribler_data.get_my_channel() if my_channel is None: return RESTResponse({"error": "your channel has not been created"}, status=HTTP_NOT_FOUND) parameters = request.query my_channel.name = parameters['name'] my_channel.description = parameters['description'] return RESTResponse({"edited": my_channel.id})
async def completions(self, request): args = request.query if 'q' not in args: return RESTResponse({"error": "query parameter missing"}, status=HTTP_BAD_REQUEST) keywords = args['q'].strip().lower() # TODO: add XXX filtering for completion terms results = self.session.mds.get_auto_complete_terms(keywords, max_terms=5) return RESTResponse({"completions": results})
async def get_channel_entries(self, request): public_key = unhexlify(request.match_info['public_key']) id_ = request.match_info['id'] with db_session: entry = self.session.mds.ChannelNode.get(public_key=database_blob(public_key), id_=id_) if entry: # TODO: handle costly attributes in a more graceful and generic way for all types of metadata entry_dict = entry.to_simple_dict(include_trackers=isinstance(entry, self.session.mds.TorrentMetadata)) else: return RESTResponse({"error": "entry not found in database"}, status=HTTP_NOT_FOUND) return RESTResponse(entry_dict)
async def skip_upgrade(self, request): parameters = await request.json() if SKIP_DB_UPGRADE_STR not in parameters: return RESTResponse({"error": "attribute to change is missing"}, status=HTTP_BAD_REQUEST) elif not self.session.upgrader: return RESTResponse({"error": "upgrader is not running"}, status=HTTP_NOT_FOUND) if self.session.upgrader and parameters[SKIP_DB_UPGRADE_STR]: self.session.upgrader.skip() return RESTResponse({SKIP_DB_UPGRADE_STR: True})
async def get_channel(self, _): my_channel = tribler_utils.tribler_data.get_my_channel() if my_channel is None: return RESTResponse({"error": "your channel has not been created"}, status=HTTP_NOT_FOUND) return RESTResponse({ 'mychannel': { 'public_key': hexlify(my_channel.public_key), 'name': my_channel.name, 'description': my_channel.description, 'dirty': my_channel.is_dirty(), } })
async def delete_channel_entries(self, request): with db_session: request_parsed = await request.json() results_list = [] for entry in request_parsed: public_key = database_blob(unhexlify(entry.pop("public_key"))) id_ = entry.pop("id") entry = self.session.mds.ChannelNode.get(public_key=public_key, id_=id_) if not entry: return RESTResponse({"error": "Entry %i not found" % id_}, status=HTTP_BAD_REQUEST) entry.delete() result = {"public_key": hexlify(public_key), "id": id_, "state": "Deleted"} results_list.append(result) return RESTResponse(results_list)
async def get_torrent(self, request): infohash = unhexlify(request.match_info['infohash']) torrent = tribler_utils.tribler_data.get_torrent_with_infohash( infohash) if not torrent: return RESTResponse( { "error": "the torrent with the specific infohash cannot be found" }, status=HTTP_NOT_FOUND) return RESTResponse( {"torrent": torrent.get_json(include_trackers=True)})
async def post_commit(self, request): channel_pk, channel_id = self.get_channel_from_request(request) with db_session: if channel_id == 0: for t in self.session.mds.CollectionNode.commit_all_channels(): self.session.gigachannel_manager.updated_my_channel(TorrentDef.load_from_dict(t)) else: coll = self.session.mds.CollectionNode.get(public_key=database_blob(channel_pk), id_=channel_id) if not coll: return RESTResponse({"success": False}, status=HTTP_NOT_FOUND) torrent_dict = coll.commit_channel_torrent() if torrent_dict: self.session.gigachannel_manager.updated_my_channel(TorrentDef.load_from_dict(torrent_dict)) return RESTResponse({"success": True})
async def update_channel_entries(self, request): try: request_parsed = await request.json() except (ContentTypeError, ValueError): return RESTResponse({"error": "Bad JSON"}, status=HTTP_BAD_REQUEST) results_list = [] for entry in request_parsed: public_key = database_blob(unhexlify(entry.pop("public_key"))) id_ = entry.pop("id") error, result = self.update_entry(public_key, id_, entry) # TODO: handle the results for a list that contains some errors in a smarter way if error: return RESTResponse(result, status=error) results_list.append(result) return RESTResponse(results_list)
async def search(self, request): try: sanitized = self.sanitize_parameters(request.query) except (ValueError, KeyError): return RESTResponse( {"error": "Error processing request parameters"}, status=HTTP_BAD_REQUEST) if not sanitized["txt_filter"]: return RESTResponse({"error": "Filter parameter missing"}, status=HTTP_BAD_REQUEST) include_total = request.query.get('include_total', '') def search_db(): try: with db_session: pony_query = self.session.mds.get_entries(**sanitized) search_results = [r.to_simple_dict() for r in pony_query] if include_total: total = self.session.mds.get_total_count(**sanitized) max_rowid = self.session.mds.get_max_rowid() else: total = max_rowid = None finally: # DB must be disconnected explicitly if run on a thread self.session.mds._db.disconnect() # pylint: disable=protected-access return search_results, total, max_rowid try: search_results, total, max_rowid = await asyncio.get_event_loop( ).run_in_executor(None, search_db) except Exception as e: # pylint: disable=broad-except; # pragma: no cover self._logger.error("Error while performing DB search: %s: %s", type(e).__name__, e) return RESTResponse(status=HTTP_BAD_REQUEST) response_dict = { "results": search_results, "first": sanitized["first"], "last": sanitized["last"], "sort_by": sanitized["sort_by"], "sort_desc": sanitized["sort_desc"], } if include_total: response_dict.update(total=total, max_rowid=max_rowid) return RESTResponse(response_dict)
async def get_exits(self, _): return RESTResponse({ "exits": [ exit_socket.to_dictionary() for exit_socket in tribler_utils.tribler_data.tunnel_exits ] })
async def get_relays(self, _request): return RESTResponse({ "relays": [ relay.to_dictionary() for relay in tribler_utils.tribler_data.tunnel_relays ] })
async def get_channels_peers(self, _): # Get debug stats for peers serving channels current_time = time.time() result = [] mapping = self.session.gigachannel_community.channels_peers with db_session: for id_tuple, peers in mapping._channels_dict.items(): # pylint:disable=W0212 channel_pk, channel_id = id_tuple chan = self.session.mds.ChannelMetadata.get( public_key=channel_pk, id_=channel_id) peers_list = [] for p in peers: peers_list.append( (hexlify(p.mid), int(current_time - p.last_response))) chan_dict = { "channel_name": chan.title if chan else None, "channel_pk": hexlify(channel_pk), "channel_id": channel_id, "peers": peers_list, } result.append(chan_dict) return RESTResponse({"channels_list": result})
async def create_channel(self, request): with db_session: _, channel_id = self.get_channel_from_request(request) request_parsed = await request.json() channel_name = request_parsed.get("name", "New channel") md = self.session.mds.ChannelMetadata.create_channel(channel_name, origin_id=channel_id) return RESTResponse({"results": [md.to_simple_dict()]})
async def create_collection(self, request): with db_session: _, channel_id = self.get_channel_from_request(request) request_parsed = await request.json() collection_name = request_parsed.get("name", "New collection") md = self.session.mds.CollectionNode(origin_id=channel_id, title=collection_name, status=NEW) return RESTResponse({"results": [md.to_simple_dict()]})
async def is_channel_dirty(self, request): channel_pk, _ = self.get_channel_from_request(request) with db_session: dirty = self.session.mds.MetadataNode.exists( lambda g: g.public_key == database_blob( channel_pk) and g.status in DIRTY_STATUSES) return RESTResponse({"dirty": dirty})
async def get_wallets(self, _): wallets = { "DUM1": { "created": True, "unlocked": True, "name": "DUM1", "address": "DUMMYADDRESS1", "balance": { "available": 50, "pending": 0.0 }, "precision": 0, }, "DUM2": { "created": True, "unlocked": True, "name": "DUM2", "address": "DUMMYADDRESS2", "balance": { "available": 90, "pending": 0.0 }, "precision": 1, }, } return RESTResponse({"wallets": wallets})