yewstack / yew

Rust / Wasm framework for creating reliable and efficient web applications
https://yew.rs
Apache License 2.0
30.5k stars 1.42k forks source link

Error: cannot find a provider for current agent #3698

Open FantasyPvP opened 1 month ago

FantasyPvP commented 1 month ago

Problem when trying to make a reactor agent i get the above error message after the code compiled successfully

Steps To Reproduce Steps to reproduce the behavior: All code and full error message attached below

Expected behavior the code runs after compiling with no runtime errors

Screenshots image

Environment:

Questionnaire

use std::{borrow::Cow, sync::Arc};

use futures::{lock::Mutex, SinkExt, StreamExt};

use reqwasm::websocket::{futures::WebSocket, Message};
use serde::{Deserialize, Serialize};
use wasm_bindgen_futures::spawn_local;
use yew::{function_component, hook, html, use_effect_with, use_node_ref, use_state, use_state_eq, BaseComponent, Callback, Event, Html, Properties};
use yew_agent::{oneshot::OneshotProvider, prelude::use_oneshot_runner, reactor::{reactor, use_reactor_bridge, ReactorEvent, ReactorScope}};

use crate::components::{navbar::Navbar, button::Button};

#[derive(Properties, PartialEq, Default)]
pub struct ChatProps {
    messages: Vec<PublicMessage>
}

#[function_component(Chat)]
pub fn chat(props: &ChatProps) -> Html {

    let messages = Arc::new(use_state_eq(|| props.messages.clone() ));
    let messages_reactor = messages.clone();

    let reactor = use_reactor_bridge(move |output: ReactorEvent<ChatReactor>| match output {
        ReactorEvent::Output(msg) => {
            let mut msg_list: Vec<PublicMessage> = messages_reactor.to_vec();
            msg_list.push(msg);
            messages_reactor.set(msg_list);
        }
        _ => {}
    });

    let submit = Callback::from(move |_| {

        let _ = reactor.send(String::new());
    });

    html! {
        <>
            <Navbar user_id={ None }/>
            <div class="messenger-page-container">
                <div class="messenger-main-section" id="messages">
                    { 
                        messages.clone().iter().map(|m| {
                            html! {
                                <div class="message-container" id={ m.message_id.to_string() }>
                                <img class="message-avatar" src={ format!("/userassets/avatar/{}.png", m.user_id)}/> 
                                <div class="message-outer">
                                    <div class="message-inner">
                                        <div class="message-header">
                                            <div class="message-username">{ m.display_name.clone() }</div>
                                            <div class="message-date"> { m.created_at } </div>
                                        </div>
                                        <div class="message-body">{ m.content.clone() }</div>    
                                    </div>
                                </div>
                            </div>
                            }
                        }).collect::<Html>()
                    }
                </div>
                <div class="messenger-end-marker">{ "Already At Newest Messages" }</div>
            </div>
            <div class="messenger-entry-container" style="width: 100%; position: absolute; bottom: 0px; align-items: center; display: flex; flex-direction: column">
                <div class="messenger-main-section">
                    <div class="ui-horizontal-menu">
                        <img src="/static/icons/messenger.svg" style="padding: 0px 10px"/>
                        <input style="width: 100%;" class="ui-input" id="inputField" type="text" placeholder="Send Message"/>
                        <button class="ui-button" id="enterButton" onclick={ submit }>
                            <img src="/static/icons/return.svg"/>
                        </button>
                    </div>
                </div>        
            </div>
        </>
    }
}

#[reactor(ChatReactor)]
pub async fn chat_reactor(mut scope: ReactorScope<String, PublicMessage>) {
    let arcscope_rx = Arc::new(Mutex::new(scope));
    let arcscope_tx = Arc::clone(&arcscope_rx);
    let ws = WebSocket::open("ws://localhost:8000/messenger/connect/1").unwrap();
    let (mut ws_sender, mut ws_receiver) = ws.split();

    spawn_local(async move {
        while let Some(msg) = ws_receiver.next().await {
            match msg {
                Ok(Message::Text(data)) => {
                    log::debug!("{}", data);

                    let message: PublicMessage = serde_json::from_str(&data).unwrap();
                    arcscope_tx.lock().await.send(message).await.unwrap();

                }
                Ok(Message::Bytes(b)) => {
                    if let Ok(data) = String::from_utf8(b) {
                        log::debug!("{}", data);

                        let message: PublicMessage = serde_json::from_str(&data).unwrap();
                        arcscope_tx.lock().await.send(message).await.unwrap();
                    }
                },
                Err(e) => {
                    log::error!("{}", e);
                }
            }
        }
    });

    spawn_local(async move {
        while let Some(msg) = arcscope_rx.lock().await.next().await {
            if let Err(e) = ws_sender.send(Message::Text(serde_json::to_string(&msg).unwrap())).await {
                log::error!("{}", e);
            }
        }
        log::debug!("Websocket connection closed");
    });
}

#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct PublicMessage {
    pub message_id: i32,
    pub user_id: i32,
    pub display_name: String,
    pub created_at: i64,
    pub content: String,
}
FantasyPvP commented 1 month ago

just to add to this. the exact point where the error seems to occur is when i create a reactor using the use_reactor_bridge method. removing all the logic from my actual reactor and simply setting a catch all case that does nothing

  let reactor = use_reactor_bridge(move |output: ReactorEvent<ChatReactor>| match output {
        _ => {}
    });

#[reactor(ChatReactor)]
pub async fn chat_reactor(mut scope: ReactorScope<String, PublicMessage>) {}

the above code still results in the same error