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

NF: explaining the bridge between languages #3572

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

Arthur-Milchior
Copy link
Contributor

It was, honestly, quite confusing. And if I got it wrong, I guess this code review will be the time for me to learn what was wrong.

@dae
Copy link
Member

dae commented Nov 17, 2024

The technical details appear to be correct. This reads like some rough notes though, and needs some polishing before it's ready for inclusion (things like "as far as I understand" don't really belong in a document that is telling people what to do!)

@Arthur-Milchior
Copy link
Contributor Author

Appart from the sentence you quoted, is there anything you believe needs more polishing? I would have hoped everything is understandable.
I'm happy you confirm everything seems to be correct, it took me some time to understand what I wrote down. Hope it'll help other devs. And great that my "as far as I understand" ensured you confirmed the understanding

Copy link
Member

@dae dae left a comment

Choose a reason for hiding this comment

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

This still feels pretty rough at the moment I'm afraid. Maybe someone else would like to take a stab at rewriting it?

docs/protobuf.md Outdated

# Communication between languages

Currently, Rust does not send message to Python or Ts. That is, the
Copy link
Member

Choose a reason for hiding this comment

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

'send' is somewhat misleading here, since the request does not return until the call has completed and a return value is provided - I'd use things like "call" or "invoke" a method instead.

I would lede with something like:

Anki's codebase uses three layers:

  1. The core Rust layer
  2. The Python layer
  3. The web frontend/TypeScript layer

Each layer only makes RPC calls to the layer below it. TypeScript code makes calls to the Python-level HTTP server. Python code makes calls to the underlying Rust layer. The Rust layer never makes RPC calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'd appreciate that, except that it's currently false. We have calls from Python to ts. And as far as I can see, it won't be going away soon, given that both of them have part of the UI responsibilities. We can aim to reduce the number of such calls.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also, given that the C of RPC is already "call", I admit I would not feel okay using "RPC call", but if you really want it, I can do that

Copy link
Member

Choose a reason for hiding this comment

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

RPC call is tautological, but pretty common in my experience. But my point was more that Python→Rust and web→Python are 'calls' in the sense that they block until they receive a reply (assuming the TS promise is awaited). As you know, web.eval(WithCallback) is more akin to injecting some text into the JavaScript console, and it's not possible for the Python code to block until the reply is received.

This commit explains how to calls a method implemented in a language
from a different language.

This explains how to declare the RPCs, how to call them and how to
implement them. This is based on examples of code at main at the time
of writting. I used permalink to ensure that the links remains
relevant even if the specific examples change later.

The last section is about the special case of calling TypeScript from
Python, which does not use RPC but is still relevant in a bridge
document.

This commit also add a paragraph explaining what protobuf is in the
protobuf documentation, so that new contributors who don't know what
protobuf is can understand why we use it.
@Arthur-Milchior
Copy link
Contributor Author

In order to take your feedback into account I:

  • splitted the bridge document from the protobuf document. This ensure that explaining how to call TS from python is not out of place
  • Rewrote the document using declaration, then calls, then definition of the RPCs. I used current examples (with permalink) so that a contributor can look at the code and imitate it.

Copy link
Member

@dae dae left a comment

Choose a reason for hiding this comment

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

The new structure is better, thank you. There's still a number of minor grammatical mistakes. It's 2025, and we shouldn't need to go back and forth on these - please use an LLM to fix your wording.


Read [protobuf](./protobuf.md) to learn more about how those input and output types are defined.

If the RPC implementation is in Python, it should be declared in [frontend.proto](https://github.com/ankitects/anki/blob/acaeee91fa853e4a7a78dcddbb832d009ec3529a/proto/anki/frontend.proto#L24C3-L24C66)'s `FrontendService`. Otherwise, it can be declared in any other service. Obviously, the service should be consistent with what the method do.
Copy link
Member

Choose a reason for hiding this comment

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

While you mention it below, you should probably explicitly state here that all RPCs are implement at the Rust layer, except when they are placed in frontend.proto.


If the RPC implementation is in Python, it should be declared in [frontend.proto](https://github.com/ankitects/anki/blob/acaeee91fa853e4a7a78dcddbb832d009ec3529a/proto/anki/frontend.proto#L24C3-L24C66)'s `FrontendService`. Otherwise, it can be declared in any other service. Obviously, the service should be consistent with what the method do.

## Making RPC
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
## Making RPC
## Making a Remote Procedure Call


It must be noted that:

- the RPC is not received on main. In order to do any work with window, we should call `aqt.mw.taskman.run_on_main`.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
- the RPC is not received on main. In order to do any work with window, we should call `aqt.mw.taskman.run_on_main`.
- the incoming HTTP request is not processed on the main thread. In order to do any work with the GUI, we should call `aqt.mw.taskman.run_on_main`.


- the RPC is not received on main. In order to do any work with window, we should call `aqt.mw.taskman.run_on_main`.
- at the time the RPC is received, we have no guarantee that the main view's active window is a DeckOptionsDialog. So this should be checked before doing anything else. If it's not the case, the call should be ignored.
- While MediaServer handles all request from typescript, it's not the appropriate place for most implementation. So it's expected that, once it has determined that the active view has the expected type, this active view actually handle the request.
Copy link
Member

Choose a reason for hiding this comment

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

The last two points seem somewhat specific to this particular RPC, and I'm not sure they're adding much.

Note that if the function is asynchronous, you can't directly send the
result to a callback. Instead your function will have to call a post
method that will be sent to Python or Rust. Which leads us to the next
section.
Copy link
Member

Choose a reason for hiding this comment

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

What next section?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants