// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. use std::cell::RefCell; use std::rc::Rc; use std::sync::Arc; use runtimelib::JupyterMessage; use runtimelib::JupyterMessageContent; use runtimelib::KernelIoPubConnection; use runtimelib::StreamContent; use deno_core::error::AnyError; use deno_core::op2; use deno_core::serde_json; use deno_core::OpState; use tokio::sync::mpsc; use tokio::sync::Mutex; deno_core::extension!(deno_jupyter, ops = [ op_jupyter_broadcast, ], options = { sender: mpsc::UnboundedSender, }, middleware = |op| match op.name { "op_print" => op_print(), _ => op, }, state = |state, options| { state.put(options.sender); }, ); #[op2(async)] pub async fn op_jupyter_broadcast( state: Rc>, #[string] message_type: String, #[serde] content: serde_json::Value, #[serde] metadata: serde_json::Value, #[serde] buffers: Vec, ) -> Result<(), AnyError> { let (iopub_connection, last_execution_request) = { let s = state.borrow(); ( s.borrow::>>().clone(), s.borrow::>>>().clone(), ) }; let maybe_last_request = last_execution_request.borrow().clone(); if let Some(last_request) = maybe_last_request { let content = JupyterMessageContent::from_type_and_content( &message_type, content.clone(), ) .map_err(|err| { log::error!( "Error deserializing content from jupyter.broadcast, message_type: {}:\n\n{}\n\n{}", &message_type, content, err ); err })?; let mut jupyter_message = JupyterMessage::new(content, Some(&last_request)); jupyter_message.metadata = metadata; jupyter_message.buffers = buffers.into_iter().map(|b| b.to_vec().into()).collect(); jupyter_message.set_parent(last_request); (iopub_connection.lock().await) .send(jupyter_message) .await?; } Ok(()) } #[op2(fast)] pub fn op_print( state: &mut OpState, #[string] msg: &str, is_err: bool, ) -> Result<(), AnyError> { let sender = state.borrow_mut::>(); if is_err { if let Err(err) = sender.send(StreamContent::stderr(msg.into())) { log::error!("Failed to send stderr message: {}", err); } return Ok(()); } if let Err(err) = sender.send(StreamContent::stdout(msg.into())) { log::error!("Failed to send stdout message: {}", err); } Ok(()) }