From 3f6d7bd9ac7075cf4943d0bd6a1f9857ca955a6e Mon Sep 17 00:00:00 2001 From: Johann Pardanaud Date: Thu, 8 Oct 2020 14:06:38 +0200 Subject: [PATCH 1/6] Start the architecture guide --- docs/architecture.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 docs/architecture.md diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..fbff4e8 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,14 @@ +# Understanding the code architecture behind Rialto + +This guide is here to help you understand how Rialto works behind the scene. Before reading it, make sure you understand the basic usage of Rialto [by reading the tutorial](https://github.com/rialto-php/rialto/blob/dev/docs/tutorial.md). + +## Process communication + +Basically, when you instanciate the entrypoint of a Rialto implementation, a Node process is spawned with some configuration provided by PHP. Once running, the Node process opens a socket on a random port (provided by the operating system) and outputs the port on the stdout stream, which will be retrieved by the PHP process. Once the Node port is retrieved, the PHP process connects to the socket with the provided port. The processes are now communicating! + +# TODO + +- entrypoint and js delegate +- instruction flow +- resource repository +- php delegate From 202b141b00b183607e195f8d77959f266153d6b8 Mon Sep 17 00:00:00 2001 From: Johann Pardanaud Date: Sat, 10 Oct 2020 09:37:43 +0200 Subject: [PATCH 2/6] Architecture guide: entrypoint --- docs/architecture.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index fbff4e8..1fdb1ee 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -6,9 +6,19 @@ This guide is here to help you understand how Rialto works behind the scene. Bef Basically, when you instanciate the entrypoint of a Rialto implementation, a Node process is spawned with some configuration provided by PHP. Once running, the Node process opens a socket on a random port (provided by the operating system) and outputs the port on the stdout stream, which will be retrieved by the PHP process. Once the Node port is retrieved, the PHP process connects to the socket with the provided port. The processes are now communicating! +## The entrypoint + +When you write a Rialto implementation, you start by creating an entrypoint, it's a simple PHP class inheriting the [`AbstractEntryPoint`](https://github.com/rialto-php/rialto/blob/architecture-guide/src/AbstractEntryPoint.php) class. It has 2 roles: + +- Once instanciated, it starts the Node process (via the [`ProcessSupervisor`](https://github.com/rialto-php/rialto/blob/architecture-guide/src/ProcessSupervisor.php) class) and opens a connection with it. +- All instructions made on the entrypoint (property read/write, method call, etc…) will be intercepted and send to the default resource set in the connection handler. + +## The connection delegate + +- default resource + # TODO -- entrypoint and js delegate - instruction flow -- resource repository +- basic resource, specific resources, and resource repository - php delegate From 9581452011a350cdc4c3a36ad6d5566a17cda008 Mon Sep 17 00:00:00 2001 From: Johann Pardanaud Date: Wed, 14 Oct 2020 18:45:24 +0200 Subject: [PATCH 3/6] Update architecture.md --- docs/architecture.md | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/docs/architecture.md b/docs/architecture.md index 1fdb1ee..de0ad71 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -15,7 +15,42 @@ When you write a Rialto implementation, you start by creating an entrypoint, it' ## The connection delegate -- default resource +The connection delegate is required and its main task is to define the default resource used by Rialto. + +### The default resource + +The default resource is the underlying JavaScript object you will use when calling instructions on the PHP entrypoint. + +For example, [PuPHPeteer defines its default resource](https://github.com/rialto-php/puphpeteer/blob/f9a9c17d62076e5e5652df38d38fe26fc565b6f8/src/PuppeteerConnectionDelegate.js#L31) with the result of `require('puppeteer')`: + +```js +const puppeteer = require('puppeteer') +instruction.setDefaultResource(puppeteer) +``` + +That means, when you instanciate the `Nesk\Puphpeteer\Puppeteer` class and call a method on it, on the JS side the method will be called on the default resource. + +When you write: + +```php +$puppeteer = new Nesk\Puphpeteer\Puppeteer; +$puppeteer->launch(); +``` + +Node will execute: + +```js +const puppeteer = require('puppeteer') +puppeteer.launch() +``` + +### Other usages + +- useful things, like closing the puppeteer browsers + +## Instruction flow + +- describe basic resources and the way they are used in the whole communication # TODO From 621263c506f17029b21f2acb6b2505805f2f20d4 Mon Sep 17 00:00:00 2001 From: Johann Pardanaud Date: Mon, 19 Oct 2020 13:19:33 +0200 Subject: [PATCH 4/6] Finish connection delegate doc --- docs/architecture.md | 42 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/docs/architecture.md b/docs/architecture.md index de0ad71..7caf0c0 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -15,7 +15,11 @@ When you write a Rialto implementation, you start by creating an entrypoint, it' ## The connection delegate -The connection delegate is required and its main task is to define the default resource used by Rialto. +The connection delegate is required and its main tasks are: + +- defining the default resource; +- executing the instructions; +- handling errors. ### The default resource @@ -24,8 +28,12 @@ The default resource is the underlying JavaScript object you will use when calli For example, [PuPHPeteer defines its default resource](https://github.com/rialto-php/puphpeteer/blob/f9a9c17d62076e5e5652df38d38fe26fc565b6f8/src/PuppeteerConnectionDelegate.js#L31) with the result of `require('puppeteer')`: ```js -const puppeteer = require('puppeteer') -instruction.setDefaultResource(puppeteer) +async handleInstruction(instruction, responseHandler, errorHandler) { + const puppeteer = require('puppeteer') + instruction.setDefaultResource(puppeteer) + + // ... +} ``` That means, when you instanciate the `Nesk\Puphpeteer\Puppeteer` class and call a method on it, on the JS side the method will be called on the default resource. @@ -44,9 +52,35 @@ const puppeteer = require('puppeteer') puppeteer.launch() ``` +### Instruction execution and error handling + +Instructions are not automatically executed by Rialto, instead it provides the necessary objects to let the connection delegate execute the instructions the way it wants. For example, [here's how PuPHPeteer implements this whole process](https://github.com/rialto-php/puphpeteer/blob/f9a9c17d62076e5e5652df38d38fe26fc565b6f8/src/PuppeteerConnectionDelegate.js#L35-L43): + +```js +async handleInstruction(instruction, responseHandler, errorHandler) { + // ... + + try { + // The "instruction" object has a simple "execute()" method which will run the code sent by PHP. + value = await instruction.execute() + } catch (error) { + // We always catch the errors, however we rethrow them if the code + // sent by PHP doesn't explicitly require the errors to be catched. + // See: https://github.com/rialto-php/rialto/blob/3f3420ad/docs/api.md#node-errors + if (instruction.shouldCatchErrors()) { + return errorHandler(error) + } + + throw error + } + + responseHandler(value) +} +``` + ### Other usages -- useful things, like closing the puppeteer browsers +The connection delegate can also be used to track some resources for various tasks. For example, PuPHPeteer tracks [the `Page` objects](https://pptr.dev/#?product=Puppeteer&version=v5.3.1&show=api-class-page) to [log the console messages](https://github.com/rialto-php/puphpeteer/blob/f9a9c17d62076e5e5652df38d38fe26fc565b6f8/src/PuppeteerConnectionDelegate.js#L54-L56) and output them in the PHP logger [if the user asked for it](https://github.com/rialto-php/puphpeteer/tree/f9a9c17d62076e5e5652df38d38fe26fc565b6f8#puppeteers-class-must-be-instantiated). ## Instruction flow From 1151f65e2e3ce364dad63a479763616d8c7d64e2 Mon Sep 17 00:00:00 2001 From: Johann Pardanaud Date: Thu, 5 Nov 2020 14:04:12 +0100 Subject: [PATCH 5/6] Update architecture.md --- docs/architecture.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/docs/architecture.md b/docs/architecture.md index 7caf0c0..e94e6f0 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -84,7 +84,22 @@ The connection delegate can also be used to track some resources for various tas ## Instruction flow -- describe basic resources and the way they are used in the whole communication +When you execute an instruction on the PHP side, it will be: + +- intercepted by the [`CommunicatesWithProcessSupervisor` trait](https://github.com/rialto-php/rialto/blob/df5a6b1b2c15a742773f48baaf1ac763664591de/src/Traits/CommunicatesWithProcessSupervisor.php); +- converted to a [PHP `Instruction`](https://github.com/rialto-php/rialto/blob/df5a6b1b2c15a742773f48baaf1ac763664591de/src/Instruction.php#L10) and serialized; +- sent to the Node process; +- [unserialized](https://github.com/rialto-php/rialto/blob/df5a6b1b2c15a742773f48baaf1ac763664591de/src/node-process/Data/Unserializer.js) and converted to a [JS `Instruction`](https://github.com/rialto-php/rialto/blob/df5a6b1b2c15a742773f48baaf1ac763664591de/src/node-process/Instruction.js); +- sent to the connection delegate. + +Once the connection delegate produces a return value, it will be: + +- [serialized](https://github.com/rialto-php/rialto/blob/df5a6b1b2c15a742773f48baaf1ac763664591de/src/node-process/Data/Serializer.js); +- sent back to the PHP process, which is in a blocking state until a response is provided (or until [`read_timeout`](https://github.com/rialto-php/rialto/blob/df5a6b1b2c15a742773f48baaf1ac763664591de/docs/api.md#options) is reached); +- [unserialized](https://github.com/rialto-php/rialto/blob/df5a6b1b2c15a742773f48baaf1ac763664591de/src/Data/UnserializesData.php); +- provided as the return value of the original instruction. + +>describe resources and how they are tracked # TODO From b10a3b4f275d87b40f2d02baf98968a1505fe77b Mon Sep 17 00:00:00 2001 From: Johann Pardanaud Date: Thu, 5 Nov 2020 14:04:47 +0100 Subject: [PATCH 6/6] Update architecture.md --- docs/architecture.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/architecture.md b/docs/architecture.md index e94e6f0..4908266 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,6 +1,6 @@ # Understanding the code architecture behind Rialto -This guide is here to help you understand how Rialto works behind the scene. Before reading it, make sure you understand the basic usage of Rialto [by reading the tutorial](https://github.com/rialto-php/rialto/blob/dev/docs/tutorial.md). +This guide is here to help you understand how Rialto works behind the scene and ease code contributions. Before reading it, make sure you understand the basic usage of Rialto [by reading the tutorial](https://github.com/rialto-php/rialto/blob/dev/docs/tutorial.md). ## Process communication