Implement PrivateAgent (#2318)

* Implement PrivateAgent, Separate Threaded into PublicAgent & PrivateAgent.

* Add migration docs.

* Update docs.
This commit is contained in:
Kaede Hoshikawa 2022-01-02 03:45:11 +09:00 committed by GitHub
parent c46cda1e6f
commit 6f6519dab4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 90 additions and 27 deletions

View File

@ -1,5 +1,5 @@
use agents::native_worker::Worker;
use yew_agent::Threaded;
use yew_agent::PublicAgent;
fn main() {
wasm_logger::init(wasm_logger::Config::default());

View File

@ -5,7 +5,7 @@ pub mod agent;
pub mod app;
use app::Model;
use wasm_bindgen::prelude::*;
use yew_agent::Threaded;
use yew_agent::PublicAgent;
#[wasm_bindgen(start)]
pub fn start() {

View File

@ -1,4 +1,4 @@
//! This module contains types to support multi-threading and state management.
//! This module contains Yew's web worker implementation.
mod hooks;
mod link;
@ -10,7 +10,7 @@ pub use link::AgentLink;
pub(crate) use link::*;
pub(crate) use pool::*;
pub use pool::{Dispatched, Dispatcher};
pub use worker::{Private, Public, Threaded};
pub use worker::{Private, PrivateAgent, Public, PublicAgent};
use serde::{Deserialize, Serialize};
use std::fmt;

View File

@ -2,8 +2,8 @@ mod private;
mod public;
mod queue;
pub use private::Private;
pub use public::Public;
pub use private::{Private, PrivateAgent};
pub use public::{Public, PublicAgent};
use super::*;
use js_sys::{Array, Reflect, Uint8Array};
@ -13,11 +13,19 @@ use web_sys::{
Blob, BlobPropertyBag, DedicatedWorkerGlobalScope, MessageEvent, Url, Worker, WorkerOptions,
};
/// Implements rules to register a worker in a separate thread.
pub trait Threaded {
/// Executes an agent in the current environment.
/// Uses in `main` function of a worker.
fn register();
pub(crate) struct WorkerResponder {}
impl<AGN> Responder<AGN> for WorkerResponder
where
AGN: Agent,
<AGN as Agent>::Input: Serialize + for<'de> Deserialize<'de>,
<AGN as Agent>::Output: Serialize + for<'de> Deserialize<'de>,
{
fn respond(&self, id: HandlerId, output: AGN::Output) {
let msg = FromWorker::ProcessOutput(id, output);
let data = msg.pack();
worker_self().post_message_vec(data);
}
}
/// Message packager, based on serde::Serialize/Deserialize

View File

@ -21,6 +21,56 @@ pub struct Private<AGN> {
_agent: PhantomData<AGN>,
}
/// A trait to enable private agents being registered in a web worker.
pub trait PrivateAgent {
/// Executes an agent in the current environment.
/// Uses in `main` function of a worker.
fn register();
}
impl<AGN> PrivateAgent for AGN
where
AGN: Agent<Reach = Private<AGN>>,
<AGN as Agent>::Input: Serialize + for<'de> Deserialize<'de>,
<AGN as Agent>::Output: Serialize + for<'de> Deserialize<'de>,
{
fn register() {
let scope = AgentScope::<AGN>::new();
let responder = WorkerResponder {};
let link = AgentLink::connect(&scope, responder);
let upd = AgentLifecycleEvent::Create(link);
scope.send(upd);
let handler = move |data: Vec<u8>| {
let msg = ToWorker::<AGN::Input>::unpack(&data);
match msg {
ToWorker::Connected(_id) => {
let upd = AgentLifecycleEvent::Connected(SINGLETON_ID);
scope.send(upd);
}
ToWorker::ProcessInput(_id, value) => {
let upd = AgentLifecycleEvent::Input(value, SINGLETON_ID);
scope.send(upd);
}
ToWorker::Disconnected(_id) => {
let upd = AgentLifecycleEvent::Disconnected(SINGLETON_ID);
scope.send(upd);
}
ToWorker::Destroy => {
let upd = AgentLifecycleEvent::Destroy;
scope.send(upd);
// Terminates web worker
worker_self().close();
}
}
};
let loaded: FromWorker<AGN::Output> = FromWorker::WorkerLoaded;
let loaded = loaded.pack();
let worker = worker_self();
worker.set_onmessage_closure(handler);
worker.post_message_vec(loaded);
}
}
impl<AGN> Discoverer for Private<AGN>
where
AGN: Agent,

View File

@ -181,22 +181,14 @@ where
}
}
struct WorkerResponder {}
impl<AGN> Responder<AGN> for WorkerResponder
where
AGN: Agent,
<AGN as Agent>::Input: Serialize + for<'de> Deserialize<'de>,
<AGN as Agent>::Output: Serialize + for<'de> Deserialize<'de>,
{
fn respond(&self, id: HandlerId, output: AGN::Output) {
let msg = FromWorker::ProcessOutput(id, output);
let data = msg.pack();
worker_self().post_message_vec(data);
}
/// A trait to enable public agents being registered in a web worker.
pub trait PublicAgent {
/// Executes an agent in the current environment.
/// Uses in `main` function of a worker.
fn register();
}
impl<AGN> Threaded for AGN
impl<AGN> PublicAgent for AGN
where
AGN: Agent<Reach = Public<AGN>>,
<AGN as Agent>::Input: Serialize + for<'de> Deserialize<'de>,

View File

@ -36,8 +36,8 @@ The code can be found in the <desc> tag of the svgs.
When no bridges are connected to this agent, the agent will disappear.
* Private - Spawn a new agent in a web worker for every new bridge. This is good for moving shared but
independent behavior that communicates with the browser out of components. \(TODO verify\) When
the task is done, the agent will disappear.
independent behavior that communicates with the browser out of components. When
the the connected bridge is dropped, the agent will disappear.
* Global \(WIP\)

View File

@ -2,8 +2,21 @@
title: "From 0.1.0 to 0.2.0"
---
## Removal of `Context` and `Job` Agents
The `Context` and `Job` Agents have been removed in favour of Yew's Context API.
You can see the updated [`pub_sub`](https://github.com/yewstack/yew/tree/master/examples/pub_sub) example about how to use Context API.
For users of `yew_agent::utils::store`, you may switch to third party solutions like: [Yewdux](https://github.com/intendednull/yewdux) or [Bounce](https://github.com/futursolo/bounce).
## `Threaded` is separated into `PublicAgent` and `PrivateAgent`
Replace `use yew_agent::Threaded;` with `use yew_agent::PublicAgent;`.
:::note
`Threaded` was never implemented for Private Agents.
All existing web worker-based agents are Public Agents.
:::