Skip to content
This repository has been archived by the owner on Aug 19, 2024. It is now read-only.

Various fixes #7

Merged
merged 3 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ruff.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ jobs:
**/*.py
- name: Run ruff
if: steps.changed-py-files.outputs.any_changed == 'true'
run: ruff check ${{ steps.changed-py-files.outputs.all_changed_files }}
run: ruff check ${{ steps.changed-py-files.outputs.all_changed_files }} --force-exclude
1 change: 1 addition & 0 deletions .ruff.toml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ exclude = [
"build",
"dist",
"node_modules",
"src/tribler/gui",
"venv",
]

Expand Down
27 changes: 18 additions & 9 deletions src/run_tribler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,30 @@

import argparse
import asyncio
import typing
from pathlib import Path
import encodings.idna # noqa: F401 (https://github.com/pyinstaller/pyinstaller/issues/1113)
import logging.config
import os
import sys

# https://github.com/pyinstaller/pyinstaller/issues/1113
import encodings.idna # pylint: disable=unused-import
import typing
from pathlib import Path

logger = logging.getLogger(__name__)


class Arguments(typing.TypedDict):
"""
The possible command-line arguments to the core process.
"""

torrent: str
core: bool
log_level: str


def parse_args() -> Arguments:
"""
Parse the command-line arguments.
"""
parser = argparse.ArgumentParser(prog='Tribler [Experimental]', description='Run Tribler BitTorrent client')
parser.add_argument('torrent', help='torrent file to download', default='', nargs='?')
parser.add_argument('--core', action="store_true", help="run core process")
Expand All @@ -33,20 +38,24 @@ def get_root_state_directory(requested_path: os.PathLike | None) -> Path:
"""
Get the default application state directory.
"""
root_state_dir = Path(requested_path) if os.path.isabs(requested_path) else Path(os.getcwd(), requested_path)
root_state_dir = (Path(requested_path) if os.path.isabs(requested_path)
else (Path(os.environ.get("APPDATA", "~")) / ".TriblerExperimental").expanduser().absolute())
root_state_dir.mkdir(parents=True, exist_ok=True)
return root_state_dir


def main():
def main() -> None:
"""
The main script entry point for either the GUI or the core process.
"""
asyncio.set_event_loop(asyncio.SelectorEventLoop())

parsed_args = parse_args()
logging.basicConfig(level=getattr(logging, parsed_args["log_level"]), stream=sys.stdout)
logger.info(f'Run Tribler: {parsed_args}')
logger.info("Run Tribler: %s", parsed_args)

root_state_dir = get_root_state_directory(os.environ.get('TSTATEDIR', 'state_directory'))
logger.info(f'Root state dir: {root_state_dir}')
logger.info("Root state dir: %s", root_state_dir)

api_port, api_key = int(os.environ.get('CORE_API_PORT', '-1')), os.environ.get('CORE_API_KEY')

Expand Down
11 changes: 8 additions & 3 deletions src/tribler/core/start_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@

import logging.config
from asyncio import run
from pathlib import Path
from typing import TYPE_CHECKING

from tribler.core.session import Session
from tribler.tribler_config import TriblerConfigManager

if TYPE_CHECKING:
from pathlib import Path

logger = logging.getLogger(__name__)
CONFIG_FILE_NAME = 'triblerd.conf'


async def run_session(config: TriblerConfigManager) -> None:
"""
Start the Session and wait for it to shut itself down.
"""
session = Session(config)
await session.start()
await session.shutdown_event.wait()
Expand All @@ -26,7 +31,7 @@ def run_core(api_port: int, api_key: str | None, state_dir: Path) -> None:

Returns an exit code value, which is non-zero if the Tribler session finished with an error.
"""
logger.info(f'Start tribler core. API port: "{api_port}". API key: "{api_key}". State dir: "{state_dir}".')
logger.info("Start tribler core. API port: %d. API key: %s. State dir: %s.", api_port, api_key, state_dir)

config = TriblerConfigManager(state_dir / "configuration.json")
config.set("state_dir", str(state_dir))
Expand Down
1 change: 1 addition & 0 deletions src/tribler/gui/widgets/tablecontentmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -640,6 +640,7 @@ def __init__(self, original_query, **kwargs):
self.original_query = original_query
self.remote_results = {}
title = self.format_title()
kwargs["text_filter"] = original_query
super().__init__(channel_info={"name": title}, **kwargs)
self.remote_results_received = False
self.postponed_remote_results = []
Expand Down
82 changes: 74 additions & 8 deletions src/tribler/tribler_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import json
import logging
import os
from json import JSONDecodeError
from os import PathLike
from pathlib import Path
from typing import TypedDict

Expand All @@ -13,6 +13,10 @@


class ApiConfig(TypedDict):
"""
Settings for the API key component.
"""

key: str
http_enabled: bool
http_port: int
Expand All @@ -23,22 +27,42 @@ class ApiConfig(TypedDict):


class ContentDiscoveryCommunityConfig(TypedDict):
"""
Settings for the content discovery component.
"""

enabled: bool


class DHTDiscoveryCommunityConfig(TypedDict):
"""
Settings for the DHT discovery component.
"""

enabled: bool


class KnowledgeCommunityConfig(TypedDict):
"""
Settings for the knowledge component.
"""

enabled: bool


class DatabaseConfig(TypedDict):
"""
Settings for the database component.
"""

enabled: bool


class DownloadDefaultsConfig(TypedDict):
"""
Settings for default downloads, used by libtorrent.
"""

anonymity_enabled: bool
number_hops: int
safeseeding_enabled: bool
Expand All @@ -51,6 +75,10 @@ class DownloadDefaultsConfig(TypedDict):


class LibtorrentConfig(TypedDict):
"""
Settings for the libtorrent component.
"""

socks_listen_ports: list[int]
port: int
proxy_type: int
Expand All @@ -70,26 +98,46 @@ class LibtorrentConfig(TypedDict):


class RendezvousConfig(TypedDict):
"""
Settings for the rendezvous component.
"""

enabled: bool


class TorrentCheckerConfig(TypedDict):
"""
Settings for the torrent checker component.
"""

enabled: bool


class TunnelCommunityConfig(TypedDict):
"""
Settings for the tunnel community component.
"""

enabled: bool
min_circuits: int
max_circuits: int


class UserActivityConfig(TypedDict):
"""
Settings for the user activity component.
"""

enabled: bool
max_query_history: int
health_check_interval: float


class TriblerConfig(TypedDict):
"""
The main Tribler settings and all of its components' sub-settings.
"""

api: ApiConfig

ipv8: dict
Expand Down Expand Up @@ -157,43 +205,58 @@ class TriblerConfig(TypedDict):
"tunnel_community": TunnelCommunityConfig(enabled=True, min_circuits=1, max_circuits=8),
"user_activity": UserActivityConfig(enabled=True, max_query_history=500, health_check_interval=5.0),

"state_dir": ".",
"state_dir": str((Path(os.environ.get("APPDATA", "~")) / ".TriblerExperimental").expanduser().absolute()),
"memory_db": False
}

# Changes to IPv8 default config
DEFAULT_CONFIG["ipv8"]["keys"].append({
'alias': "secondary",
'generation': "curve25519",
'file': "secondary_key.pem"
})
DEFAULT_CONFIG["ipv8"]["overlays"] = [overlay for overlay in DEFAULT_CONFIG["ipv8"]["overlays"]
if overlay["class"] == "DiscoveryCommunity"]
DEFAULT_CONFIG["ipv8"]["working_directory"] = DEFAULT_CONFIG["state_dir"]
for key_entry in DEFAULT_CONFIG["ipv8"]["keys"]:
if "file" in key_entry:
key_entry["file"] = str(Path(DEFAULT_CONFIG["state_dir"]) / key_entry["file"])


class TriblerConfigManager:
"""
A class that interacts with a JSON configuration file.
"""

def __init__(self, config_file: Path = Path("configuration.json")) -> None:
"""
Load a config from a file
Load a config from a file.
"""
super().__init__()
self.config_file = config_file

logger.info(f'Load: {self.config_file}.')
logger.info("Load: %s.", self.config_file)
self.configuration = {}
if config_file.exists():
try:
with open(self.config_file, "r") as f:
with open(self.config_file) as f:
self.configuration = json.load(f)
except JSONDecodeError as e:
except JSONDecodeError:
logger.exception("Failed to load stored configuration. Falling back to defaults!")
if not self.configuration:
self.configuration = DEFAULT_CONFIG

def write(self) -> None:
"""
Write the configuration to disk.
"""
with open(self.config_file, "w") as f:
json.dump(self.configuration, f, indent=4)

def get(self, option: PathLike | str) -> dict | list | str | int | float | bool | None:
def get(self, option: os.PathLike | str) -> dict | list | str | float | bool | None:
"""
Get a config option based on the path-like descriptor.
"""
out = self.configuration
for part in Path(option).parts:
if part in out:
Expand All @@ -206,7 +269,10 @@ def get(self, option: PathLike | str) -> dict | list | str | int | float | bool
break
return out

def set(self, option: PathLike | str, value: dict | list | str | int | float | bool | None) -> None:
def set(self, option: os.PathLike | str, value: dict | list | str | float | bool | None) -> None:
"""
Set a config option value based on the path-like descriptor.
"""
current = self.configuration
for part in Path(option).parts[:-1]:
current = current[part]
Expand Down
Loading