Skip to content

Commit

Permalink
Implement PrivateAgent (#2318)
Browse files Browse the repository at this point in the history
* Implement PrivateAgent, Separate Threaded into PublicAgent & PrivateAgent.

* Add migration docs.

* Update docs.
  • Loading branch information
futursolo authored Jan 1, 2022
1 parent c46cda1 commit 6f6519d
Show file tree
Hide file tree
Showing 8 changed files with 90 additions and 27 deletions.
2 changes: 1 addition & 1 deletion examples/agents/src/bin/worker.rs
Original file line number Diff line number Diff line change
@@ -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());
Expand Down
2 changes: 1 addition & 1 deletion examples/web_worker_fib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
4 changes: 2 additions & 2 deletions packages/yew-agent/src/lib.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down
22 changes: 15 additions & 7 deletions packages/yew-agent/src/worker/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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
Expand Down
50 changes: 50 additions & 0 deletions packages/yew-agent/src/worker/private.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
20 changes: 6 additions & 14 deletions packages/yew-agent/src/worker/public.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down
4 changes: 2 additions & 2 deletions website/docs/concepts/agents.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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\)

Expand Down
13 changes: 13 additions & 0 deletions website/docs/migration-guides/yew-agent/from-0_1_0-to-0_2_0.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.

:::

0 comments on commit 6f6519d

Please sign in to comment.