Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

READY: Channel description and thumbnails #6025

Merged
merged 19 commits into from
Mar 23, 2021

Conversation

ichorid
Copy link
Contributor

@ichorid ichorid commented Mar 13, 2021

изображение

This PR enables the user to add thumbnails and Markdown-based descriptions to their channels. The GUI is based on wireframes devised by @drew2a.

Technical details

The feature required extending the whole software stack: GUI -> database -> transport layer.

GUI changes

Thumbnail and description are displayed by the ChannelDescriptionWidget (channel_description.ui). The widget is initialized as a member object of ChannelContentsWidget.

Whenever a channel is opened in ChannelContentsWidget, it sends GET requests to a pair of new routes (description and thumbnail) in the corresponding channel endpoint (see details below). If at least one of those responds with properly formed data, the description widget is shown. Otherwise, a "Create description" button is shown (for personal channels only).

Important dev notes on the GUI side:

  • one of the biggest challenges during GUI development was applying CSS styles properly. Currently, the .ui file for the widget lacks any styling. Instead, styles are inherited from the mainwindow.ui. It was especially hard and unintuitive to figure out that PyQT still applies CSS styles to child class widgets if the *base classCSS is defined somewhere in the.ui` file. Managing to set all the "sizing" stuff properly to make the widget achieve the right size was especially painful, and basically got down to brute-forcing all the possible combinations of parameters of the widget and its parent, together with doing a manual binary search on the widget tree for offending sub-widgets;
  • another challenge was managing all the different possible states of the description widget, especially in combination with the asynchronous nature of the problem. The widget could probably be refactored in a number of subclassed widgets to simplify the logic, though PyQT's way of handling subclassing makes the option less appealing;
  • hiding a widget triggers a bug in QT that results in the table size not being adjusted correctly, so brain_dead_refresh 🧟 🧠 is back.

REST endpoint changes

Two new routes are added to the channels\<pk>\<id>\... enpoint, serving GET and PUT requests:

  • description route returns a JSON dict with contents stored in a description_text field.
  • thumbnail route returns a binary HTTP transfer with a set Content-Type header (e.q. image/png).

Database changes

New subclasses of the ChannelNode ORM class are added:

  • ChannelThumbnail <- BinaryNode <- ChannelNode
  • ChannelDescription <- JsonNode <- ChannelNode

The purpose of these classes is to store arbitrary binary and JSON-formatted text data, while still using all the transport/signing/updating logic available to ChannelNode class (e.g. serving through RemoteQueryCommunity, packing into .mdblobs, dumping into channel torrents on disk, etc.)

Each channel can now have child entries of these types, the same way it can have torrent and folder children. A channel is supposed to have only one of these. (Though, nothing in the code prevents distribution of channels with more than a single thumbnail/description entry. Locally, only a single instance of those will be used.)

BinaryNode and ChannelThumbnail

These new classes extend ChannelNode by adding two new fields/columns:

  • binary_data stores arbitrary data in binary form
  • data_type stores the MIME type for the data (as a plaintext string)

JsonNode and ChannelDescription

These classes extend ChannelNode by adding a single new field/column:

  • json_text stores JSON-encoded dict (as a plaintext string)

Important dev notes on the database side:

  • unfortunately, PonyORM's wonderful JSON column support is incompatible with the way serialization and signatures work in Channels. Thus the plaintext format.
  • adding support for big blobs required only a small change to entries_to_chunk procedure, which now puts bigger-than-chunk-limit entries into separate chunks instead of raising an exception.
  • database schema must be upgraded to support the new format. Fortunately, adding new columns is essentially free.

Community and transport changes

Big blob transport

RemoteQueryCommunity now inherits fro the EVAProtocol mixin (developed by @drew2a), which enables sending bigger-than-UDP-packet blobs reliably.
The changes to RQC were minimal and backwards-compatible. It works like this: whenever Alice queries Bob for entries through RQC, if Bob has to respond with an entry that is too big to fit into a single UDP packet, the whole payload is serialized and pushed to Alice through EVAProtocol eva_send_binary. When Alice receives the complete binary transfer, she feeds the received binary raw to the IPv8's on_packet method, which then triggers the appropriate response from the RQC community. Thus, the transport is completely transparent for RQC (maintaining all the safety checks, etc.).

Channel preview logic changes

A couple of new triggers are added to RQC:

  • whenever Alice receives a new channel entry from Bob, she will query back Bob for channel thumbnail and description entries for the channel
  • whenever Alice receives an updated channel entry from Bob, she will query back Bob for channel thumbnail and description entries that are newer than those Alice already got. Thus, no waste of bandwidth on sending redundant copies of binary data.

@ghost
Copy link

ghost commented Mar 13, 2021

Congratulations 🎉. DeepCode analyzed your code in 2.651 seconds and we found no issues. Enjoy a moment of no bugs ☀️.

👉 View analysis in DeepCode’s Dashboard | Configure the bot

@ichorid
Copy link
Contributor Author

ichorid commented Mar 15, 2021

retest this please

@ichorid ichorid force-pushed the feature/channel_description branch 3 times, most recently from a052941 to 7641fe0 Compare March 16, 2021 09:43
@ichorid ichorid linked an issue Mar 16, 2021 that may be closed by this pull request
@ichorid ichorid requested review from devos50, drew2a and kozlovsky March 16, 2021 11:25
@ichorid ichorid force-pushed the feature/channel_description branch 8 times, most recently from dec6395 to 3d31cb8 Compare March 19, 2021 18:11
@ichorid ichorid marked this pull request as ready for review March 19, 2021 18:12
@ichorid ichorid changed the title WIP: Channel description and thumbnails READY: Channel description and thumbnails Mar 19, 2021
ichorid added 2 commits March 19, 2021 19:29
This PR enables the user to add thumbnails and Markdown-based descriptions to their channels.
@ichorid ichorid force-pushed the feature/channel_description branch from 3d31cb8 to ff7d83a Compare March 19, 2021 18:30
Comment on lines 268 to 279
def from_unpack_list(
cls, metadata_type, reserved_flags, public_key,
id_, origin_id, timestamp,
binary_data, data_type,
**kwargs
):
return cls(
metadata_type, reserved_flags, public_key,
id_, origin_id, timestamp,
binary_data, data_type,
**kwargs
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: same here:

Suggested change
def from_unpack_list(
cls, metadata_type, reserved_flags, public_key,
id_, origin_id, timestamp,
binary_data, data_type,
**kwargs
):
return cls(
metadata_type, reserved_flags, public_key,
id_, origin_id, timestamp,
binary_data, data_type,
**kwargs
)
def from_unpack_list(cls, metadata_type, reserved_flags, public_key, id_,
origin_id, timestamp, binary_data, data_type, **kwargs):
return cls(metadata_type, reserved_flags, public_key, id_, origin_id,
timestamp, binary_data, data_type, **kwargs)

@ichorid ichorid requested a review from drew2a March 22, 2021 20:40
@drew2a
Copy link
Contributor

drew2a commented Mar 23, 2021

PR looks good to me in general.
Thank you for all changes that you made.

5 failing checks from 15 is too much for approval.

Probably some of them are unnecessary. We can discuss it with the team and (probably) change some of them.

@sonarqubecloud
Copy link

Kudos, SonarCloud Quality Gate passed!

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 0 Code Smells

No Coverage information No Coverage information
No Duplication information No Duplication information

Copy link
Contributor

@drew2a drew2a left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@ichorid ichorid merged commit 984241f into Tribler:main Mar 23, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

[Wireframes] Channel's home page
2 participants