Skip to content

Commit 753640c

Browse files
authored
Added software architecture documentation (#8235)
2 parents 8594e11 + 34993f0 commit 753640c

File tree

13 files changed

+295
-22
lines changed

13 files changed

+295
-22
lines changed

doc/.readthedocs.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ build:
1212
tools:
1313
# Check https://docs.readthedocs.io/en/stable/config-file/v2.html#build-tools-python
1414
python: "3.10"
15+
apt_packages:
16+
- graphviz
1517

1618
python:
1719
install:

doc/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,5 @@ help:
1616
# Catch-all target: route all unknown targets to Sphinx using the new
1717
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
1818
%: Makefile
19+
@dot -Tsvg "$(SOURCEDIR)/reference/software_architecture.dot" -o "$(SOURCEDIR)/reference/software_architecture.svg";
1920
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

doc/basics/docker.rst

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Currently, only running the (unstable!) ``latest`` release is supported.
88

99

1010
Preparation
11-
-----
11+
-----------
1212

1313
Fetch the docker image:
1414

@@ -17,7 +17,7 @@ Fetch the docker image:
1717
docker pull ghcr.io/tribler/tribler:latest
1818
1919
Running
20-
-----
20+
-------
2121

2222
Choose a SECRET key for the background communication with Tribler.
2323
In the following example, we use the key ``changeme`` (don't use this yourself).
@@ -44,7 +44,7 @@ By default, the REST API is bound to localhost inside the container so to
4444
access the APIs, network needs to be set to host (--net="host").
4545

4646
Stopping
47-
-----
47+
--------
4848

4949
To stop Tribler, you should get the container id of your process and then stop it.
5050
You can view all active docker containers using ``docker ps`` and you can stop a container id using ``docker stop``.

doc/basics/running.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,14 @@ You can link or copy ``libsodium.dylib`` into the Tribler root directory:
6767
6868
6969
Apple Silicon
70-
-------
70+
-------------
7171
There are currently no python bindings available to install from pip.
7272
Therefore you need to build them from source.
7373

7474
To do this, please install openssl and boost first:
7575

7676
.. code-block:: bash
77+
7778
brew install openssl boost boost-build boost-python3
7879
7980
And then follow the `instruction <https://github.com/arvidn/libtorrent/blob/v1.2.18/docs/python_binding.rst>`_.

doc/conf.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@
1616
# import os
1717
# import sys
1818
# sys.path.insert(0, os.path.abspath('.'))
19+
from __future__ import annotations
1920

21+
from typing import TYPE_CHECKING
22+
23+
if TYPE_CHECKING:
24+
from sphinx.application import Sphinx
25+
from sphinx.domains.python import PyObject
2026

2127
# -- Project information -----------------------------------------------------
2228

@@ -80,7 +86,7 @@
8086
exclude_patterns = []
8187

8288
# The name of the Pygments (syntax highlighting) style to use.
83-
pygments_style = None
89+
pygments_style = 'sphinx'
8490

8591

8692
# -- Options for HTML output -------------------------------------------------
@@ -198,3 +204,18 @@
198204

199205
# If true, `todo` and `todoList` produce output, else they produce nothing.
200206
todo_include_todos = True
207+
208+
209+
def skip_illegal_classes(app: Sphinx, what: str, name: str, obj: PyObject, skip: bool, options: list[str]) -> bool:
210+
"""
211+
Sphinx errors out on ``tribler.core.libtorrent.torrentdef.FileDict.__init__``. We get rid of it here.
212+
"""
213+
if what == "class" and name == "tribler.core.libtorrent.torrentdef.FileDict":
214+
return True
215+
return skip
216+
217+
def setup(sphinx: Sphinx) -> None:
218+
"""
219+
Callback for when Sphinx is setup. We install a workaround for an illegal class here.
220+
"""
221+
sphinx.connect("autoapi-skip-member", skip_illegal_classes)

doc/index.rst

+6
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ Table of contents
2626
building/mac.rst
2727
building/windows.rst
2828

29+
.. toctree::
30+
:maxdepth: 2
31+
:caption: Reference:
32+
33+
reference/software_architecture.rst
34+
2935

3036
Search
3137
======
+147
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
digraph G {
2+
fontname="Helvetica,Arial,sans-serif";
3+
node [fontname="Helvetica,Arial,sans-serif"];
4+
edge [fontname="Helvetica,Arial,sans-serif"];
5+
compound=true;
6+
forcelabels=true;
7+
8+
subgraph cluster_0 {
9+
label = "[PYTHON]";
10+
style=filled;
11+
color=floralwhite;
12+
13+
subgraph cluster_0_0 {
14+
label = "src.tribler.core";
15+
style=filled;
16+
color=lightgrey;
17+
node [style=filled, fillcolor=white, color=black];
18+
19+
session [label="session.py"];
20+
21+
db [label="TriblerDatabase", shape=rectangle, style="filled,dashed", fillcolor=gray90];
22+
session -> db;
23+
24+
mds [label="MetadataStore", shape=rectangle, style="filled,dashed", fillcolor=gray90];
25+
session -> mds;
26+
27+
torrentchecker [label="TorrentChecker", shape=rectangle, style="filled,dashed", fillcolor=gray90];
28+
session -> torrentchecker;
29+
30+
configmgr [label="TriblerConfigManager", shape=rectangle];
31+
session -> configmgr;
32+
33+
notifier [label="Notifier", shape=rectangle];
34+
session -> notifier;
35+
36+
dlmgr [label="DownloadManager", shape=rectangle];
37+
configmgr -> dlmgr;
38+
session -> dlmgr;
39+
40+
restmgr [label="RESTManager", shape=rectangle];
41+
configmgr -> restmgr;
42+
session -> restmgr;
43+
44+
loader [label="IPv8CommunityLoader", shape=rectangle];
45+
configmgr -> loader;
46+
session -> loader;
47+
48+
ipv8 [label="IPv8", shape=rectangle];
49+
loader -> ipv8;
50+
configmgr -> ipv8;
51+
session -> ipv8;
52+
}
53+
54+
subgraph cluster_0_1 {
55+
label = "src.tribler.core.components";
56+
style=filled;
57+
fillcolor=lightgrey;
58+
color=white;
59+
node [style=filled, fillcolor=white, color=black];
60+
61+
baselauncher [label="BaseLauncher", shape=rectangle];
62+
componentlauncher [label="ComponentLauncher", shape=rectangle];
63+
{rank=same baselauncher; componentlauncher}
64+
65+
versioning [label="Versioning", shape=rectangle];
66+
componentlauncher -> versioning;
67+
68+
dbcomp [label="TriblerDatabase", shape=rectangle];
69+
componentlauncher -> dbcomp;
70+
71+
triblerdb [label="TriblerDatabase", shape=rectangle];
72+
dbcomp -> triblerdb;
73+
74+
dhtdisc [label="DHTDiscovery", shape=rectangle];
75+
baselauncher -> dhtdisc;
76+
77+
recomm [label="Recommender", shape=rectangle];
78+
baselauncher -> recomm;
79+
80+
tunnel [label="Tunnel", shape=rectangle];
81+
baselauncher -> tunnel;
82+
83+
mddb [label="MetadataStore", shape=rectangle];
84+
dbcomp -> mddb;
85+
86+
tchecker [label="TorrentChecker", shape=rectangle];
87+
componentlauncher -> tchecker;
88+
89+
contentdiscovery [label="ContentDiscovery", shape=rectangle];
90+
baselauncher -> contentdiscovery;
91+
dbcomp -> contentdiscovery;
92+
tchecker -> contentdiscovery;
93+
94+
knowledge [label="Knowledge", shape=rectangle];
95+
baselauncher -> knowledge;
96+
dbcomp -> knowledge;
97+
98+
rendezvous [label="Rendezvous", shape=rectangle];
99+
baselauncher -> rendezvous;
100+
dbcomp -> rendezvous;
101+
}
102+
}
103+
104+
subgraph cluster_1 {
105+
label = "[TYPESCRIPT]\nsrc/tribler/ui";
106+
style=filled;
107+
color=aliceblue;
108+
node [style=filled,fillcolor=white, color=black];
109+
110+
htmlindex [label="App", shape=rectangle];
111+
112+
ipv8service [label="IPv8Service", shape=rectangle];
113+
triblerservice [label="TriblerService", shape=rectangle];
114+
115+
error_popup [label="error_popup", shape=rectangle];
116+
htmlindex -> error_popup;
117+
118+
router [label="RouterProvider", shape=rectangle];
119+
htmlindex -> router;
120+
121+
pagedebug [label="Debug", shape=rectangle];
122+
router -> pagedebug;
123+
124+
pagedownloads [label="Downloads", shape=rectangle];
125+
router -> pagedownloads;
126+
127+
pagepopular [label="Popular", shape=rectangle];
128+
router -> pagepopular;
129+
130+
pagesearch [label="Search", shape=rectangle];
131+
router -> pagesearch;
132+
133+
pagesettings [label="Settings", shape=rectangle];
134+
router -> pagesettings;
135+
}
136+
137+
start -> session [lhead=cluster_0_0, minlen="2"];
138+
start -> htmlindex [lhead=cluster_1, minlen="2", headlabel=" webbrowser.open_new_tab()", labeldistance=8];
139+
140+
ipv8 -> baselauncher [style="invis"];
141+
loader -> componentlauncher [style="invis"];
142+
143+
ipv8service -> restmgr [dir="both", style="dotted", arrowhead="vee", arrowtail="vee"];
144+
triblerservice -> restmgr [dir="both", style="dotted", arrowhead="vee", arrowtail="vee"];
145+
146+
start [label="src/run_tribler.py", shape=doubleoctagon, style=filled, fillcolor=floralwhite];
147+
}
+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
Software Architecture
2+
=====================
3+
4+
This reference provides a high-level overview of Tribler's software architecture.
5+
6+
The main entry point of Tribler is the ``run_tribler.py`` script and it has two main modes.
7+
The first mode launches Tribler with default settings.
8+
This causes a new browser tab to open that displays a web page generated with TypeScript.
9+
The second "headless" mode, does not open a browser tab.
10+
However, in both modes the core Tribler Python process runs.
11+
12+
An overview of the most important functional components of Tribler is given in the following graph.
13+
We will provide a short description of each of these components.
14+
15+
.. figure:: software_architecture.svg
16+
17+
Session
18+
-------
19+
20+
The ``Session`` object (in ``session.py``) manages the core managers of Tribler:
21+
22+
- The ``Notifier`` allows components to publish and subscribe to events.
23+
In some special cases, this is preferred over class inheritance or composition.
24+
Architectural spaghetti can sometimes be avoided by using ``Notifier`` events.
25+
- The ``TriblerConfigManager`` manages writing to and reading from user configuration files.
26+
This class manages defaults and the regeneration of (partially) missing configurations.
27+
- The ``DownloadManager`` allows management of torrent downloads.
28+
Functionality involves fetching torrent meta information, adding and removing downloads, and changing their anonymity level.
29+
- The ``RESTManager`` sets up a REST API.
30+
The API is used by Tribler's GUI, but can also be used programmatically by users in "headless" mode.
31+
- ``IPv8`` is used to manage peer-to-peer network overlays.
32+
All peer-to-peer traffic is handled by ``IPv8`` with the exception of non-anonymized torrent downloads.
33+
Functionality involves decentralized search and sharing popular torrents.
34+
- The ``IPv8CommunityLoader`` is used to launch all optional parts of Tribler.
35+
This includes launching ``IPv8`` overlays and registering REST API endpoints.
36+
37+
The ``TriblerDatabase``, ``MetadataStore`` and the ``TorrentChecker`` are optionally available through the ``Session``.
38+
If requested, they are launched through the ``IPv8CommunityLoader``.
39+
40+
Components
41+
----------
42+
43+
The optional components of Tribler are given in ``components.py``.
44+
They can be divided into two groups: those that require a network overlay (inheriting from ``ComponentLauncher``) and those that do not (inheriting from ``ComponentLauncher``).
45+
Furthermore, the components can have complex relationships, like only launching after other components.
46+
47+
The following list contains a high-level description of the components:
48+
49+
- The ``DatabaseComponent`` is responsible for the two main databases.
50+
The first is the ``MetadataStore``, which stores all torrent and torrent tracker meta data and "health" (seeders and leechers).
51+
The second is the ``TriblerDatabase``, which stores torrent tags.
52+
- The ``TorrentCheckerComponent`` is responsible for retrieving the "health" information of torrents and trackers.
53+
This component may contact trackers for random torrents to determine whether they are reachable.
54+
The component also periodically updates the health information for known torrents based on tracker and DHT information.
55+
- The ``VersioningComponent`` is responsible for Tribler version management.
56+
Functionality includes upgrading data from local old Tribler versions to new Tribler versions and determining whether a new Tribler version has been published online.
57+
- The ``TunnelComponent`` allows for anonymization of torrent downloads.
58+
This component manages routing downloads over Tor-like circuits, including circuit construction and destruction.
59+
- The ``DHTDiscoveryComponent`` allows ``IPv8`` to decentrally search for overlays and peers with given public keys.
60+
- The ``ContentDiscoveryComment`` serves remote user searches and content popularity.
61+
Both outgoing and incoming user searches are served through this component.
62+
- The ``KnowledgeComponent`` handles extraction and search for torrent tags.
63+
- The ``RendezvousComponent`` keeps track of peers that have been connected to in the past.
64+
This is an experimental component that aims to serve as a source of decentral reputation.
65+
- The ``RecommenderComponent`` keeps track of local user searches and the preferred download for the search query.
66+
This is an experimental component that aims to serve as a source for Artificial Intelligence based personalized recommendations.
67+
68+
Web UI
69+
------
70+
71+
The Web UI serves to view and control the state of the Tribler process.
72+
Essentially, the Web UI uses three main classes:
73+
74+
- The ``IPv8Service`` binds to the REST API of the ``IPv8`` component in the Tribler process.
75+
- The ``TriblerService`` binds to the REST API of anything that is not in the ``IPv8`` service.
76+
- The ``App`` is the React application entrypoint.
77+
78+
The ``App`` contains a component to route information, the ``RouterProvider``, and a means to report errors that have been sent from the Tribler process.
79+
The architecture closely resembles the information in the GUI.
80+
Essentially, the ``RouterProvider`` mirrors the visible pages:
81+
82+
- ``src/pages/Debug`` queries the Tribler process for debug information.
83+
- ``src/pages/Downloads`` includes components to render torrent downloads.
84+
- ``src/pages/Popular`` queries for popular torrents.
85+
- ``src/pages/Search`` manages pending searches, combining local and remote results.
86+
- ``src/pages/Settings`` reads and writes the Tribler configuration (through the REST API).

src/run_tribler.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ async def mac_event_loop() -> None:
160160
"""
161161
Consume Mac events on the asyncio main thread.
162162
163-
WARNING: sendEvent_ can block on some events. In particular, while the tray menu is open.
163+
WARNING: ``sendEvent_`` can block on some events. In particular, while the tray menu is open.
164164
"""
165165
from AppKit import NSApp, NSEventMaskAny
166166
from Foundation import NSDate, NSDefaultRunLoopMode

src/tribler/core/database/orm_bindings/torrent_metadata.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ def to_simple_dict(self) -> dict[str, str | bytes | float | None]: ... # noqa:
8181

8282
def infohash_to_id(infohash: bytes) -> int:
8383
"""
84-
This function is used to devise id_ from infohash in deterministic way. Used in FFA channels.
84+
This function is used to devise ``id_`` from infohash in deterministic way. Used in FFA channels.
8585
"""
8686
return abs(unpack(">q", infohash[:8])[0])
8787

@@ -107,7 +107,7 @@ def tdef_to_metadata_dict(tdef: TorrentDef) -> dict:
107107
"title": tdef.get_name_as_unicode()[:300],
108108
"tags": tags[:200],
109109
"size": tdef.get_length(),
110-
"torrent_date": torrent_date if torrent_date >= EPOCH else EPOCH,
110+
"torrent_date": max(torrent_date, EPOCH),
111111
"tracker_info": tracker_info,
112112
}
113113

src/tribler/core/libtorrent/torrentdef.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -566,8 +566,7 @@ def get_files_with_length(self, exts: set[str] | None = None) -> list[tuple[Path
566566
"""
567567
The list of files in the torrent def.
568568
569-
:param exts: (Optional) list of filename extensions (without leading .)
570-
to search for.
569+
:param exts: (Optional) list of filename extensions (without leading .) to search for.
571570
:return: A list of filenames.
572571
"""
573572
videofiles = []

0 commit comments

Comments
 (0)