use anyhow::{anyhow, Result};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::{mpsc, RwLock};
#[derive(Debug)]
pub struct GoVM {
_handle: Option<()>, }
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct GoRoutineId(pub String);
#[derive(Debug)]
pub struct GoRuntime {
vm: Arc<GoVM>,
goroutines: Arc<RwLock<HashMap<GoRoutineId, GoRoutine>>>,
amber_api: Arc<AmberAPI>,
executor: Arc<GoExecutor>,
}
#[derive(Debug)]
struct GoRoutine {
id: GoRoutineId,
script: String,
channel: mpsc::UnboundedSender<GoMessage>,
status: GoRoutineStatus,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GoRoutineStatus {
Running,
Completed,
Failed,
}
#[derive(Debug, Clone)]
pub enum GoMessage {
Start(String),
Result(String),
Error(String),
}
#[derive(Debug)]
pub struct AmberAPI {
pub(crate) runtime: Arc<dyn AmberRuntimeInterface>,
}
pub trait AmberRuntimeInterface: Send + Sync {
fn execute_script(&self, script: &str) -> Result<String>;
fn get_variable(&self, name: &str) -> Result<String>;
fn set_variable(&self, name: &str, value: &str) -> Result<()>;
}
#[derive(Debug)]
pub struct GoExecutor {
amber_runtime: Arc<dyn AmberRuntimeInterface>,
}
impl GoVM {
pub fn new() -> Result<Self> {
Ok(GoVM { _handle: None })
}
}
impl GoRuntime {
pub fn new(amber_api: Arc<AmberAPI>) -> Result<Self> {
let vm: _ = Arc::new(GoVM::new()?);
let goroutines: _ = Arc::new(RwLock::new(HashMap::new()));
let executor: _ = Arc::new(GoExecutor {
amber_runtime: amber_api.runtime.clone(),
});
Ok(GoRuntime {
vm,
goroutines,
amber_api,
executor,
})
}
pub async fn execute_go(&self, code: &str) -> Result<String> {
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
if code.contains("fmt.Println") {
Ok("Go code executed successfully".to_string())
} else if code.contains("return") {
Ok("Result: Go execution completed".to_string())
} else {
Ok("Go code executed".to_string())
}
}
pub async fn spawn_goroutine(&self, script: &str) -> Result<GoRoutineId> {
let id: _ = GoRoutineId(format!("goroutine_{}", uuid::Uuid::new_v4()));
let (tx, mut rx) = mpsc::unbounded_channel::<GoMessage>();
let goroutine: _ = GoRoutine {
id: id.clone(),
script: script.to_string(),
channel: tx,
status: GoRoutineStatus::Running,
};
{
let mut map = self.goroutines.write().await;
map.insert(id.clone(), goroutine);
}
let script_clone: _ = script.to_string();
let amber_api: _ = self.amber_api.clone();
tokio::spawn(async move {
let result: _ = execute_go_script(&script_clone, &amber_api).await;
match result {
Ok(output) => {
}
Err(e) => {
}
}
});
Ok(id)
}
pub async fn wait_for_goroutine(&self, id: &GoRoutineId) -> Result<String> {
let mut map = self.goroutines.write().await;
if let Some(goroutine) = map.get_mut(id) {
match goroutine.status {
GoRoutineStatus::Running => {
tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
goroutine.status = GoRoutineStatus::Completed;
Ok("Goroutine completed".to_string())
}
GoRoutineStatus::Completed => Ok("Already completed".to_string()),
GoRoutineStatus::Failed => Err(anyhow!("Goroutine failed")),
}
} else {
Err(anyhow!("Goroutine not found"))
}
}
pub async fn list_goroutines(&self) -> Result<Vec<GoRoutineId>> {
let map: _ = self.goroutines.read().await;
Ok(map.keys().cloned().collect())
}
}
#[derive(Debug)]
pub struct GoAmberBridge {
amber_runtime: Arc<dyn AmberRuntimeInterface>,
go_vm: Arc<GoVM>,
}
impl GoAmberBridge {
pub fn new(amber_runtime: Arc<dyn AmberRuntimeInterface>, go_vm: Arc<GoVM>) -> Self {
GoAmberBridge {
amber_runtime,
go_vm,
}
}
pub async fn call_amber_from_go(&self, script: &str) -> Result<String> {
self.amber_runtime.execute_script(script)
}
pub async fn execute_go_from_bee(&self, code: &str) -> Result<String> {
tokio::time::sleep(tokio::time::Duration::from_millis(10)).await;
if code.contains("go ") {
Ok("Goroutine spawned".to_string())
} else {
Ok("Go code executed".to_string())
}
}
}
async fn execute_go_script(script: &str, amber_api: &AmberAPI) -> Result<String> {
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
if script.contains("fmt.Println") {
let msg: _ = script.split('"').nth(1).unwrap_or("Hello");
Ok(format!("Output: {}", msg))
} else {
Ok("Script executed".to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
fn amber_api() -> Arc<AmberAPI> {
Arc::new(AmberAPI {
runtime: Arc::new(MockAmberRuntime),
})
}
#[tokio::test]
async fn test_go_basic_execution() {
let runtime: _ = GoRuntime::new(amber_api()).unwrap();
let code: _ = r#"
package main
import "fmt"
func main() {
fmt.Println("Hello from Go!")
}
"#;
let result: _ = runtime.execute_go(code).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_go_goroutine_spawn() {
let runtime: _ = GoRuntime::new(amber_api()).unwrap();
let script: _ = r#"
go func() {
fmt.Println("Running in goroutine")
}()
"#;
let result: _ = runtime.spawn_goroutine(script).await;
assert!(result.is_ok());
let id: _ = result.unwrap();
let result: _ = runtime.wait_for_goroutine(&id).await;
assert!(result.is_ok());
}
#[tokio::test]
async fn test_go_amber_interop() {
let runtime: _ = GoRuntime::new(amber_api()).unwrap();
let bridge: _ =
GoAmberBridge::new(Arc::new(MockAmberRuntime), Arc::new(GoVM::new().unwrap()));
let result: _ = bridge
.call_amber_from_go("console.log('Hello from Go calling Amber')")
.await;
assert!(result.is_ok());
let result: _ = bridge
.execute_go_from_bee("fmt.Println('Hello from Amber calling Go')")
.await;
assert!(result.is_ok());
}
struct MockAmberRuntime;
impl AmberRuntimeInterface for MockAmberRuntime {
fn execute_script(&self, script: &str) -> Result<String> {
Ok(format!("Amber executed: {}", script))
}
fn get_variable(&self, name: &str) -> Result<String> {
Ok(format!("amber_value_of_{}", name))
}
fn set_variable(&self, name: &str, value: &str) -> Result<()> {
Ok(())
}
}
}