Files
mize/marts/src/discord/mod.rs
2026-09-16 21:32:53 +00:00

168 lines
5.8 KiB
Rust

pub use mize::*;
// ========== WASM-specific imports (Obsidian plugin) ==========
#[cfg(feature = "target-obsidian")]
use wasm_bindgen::prelude::*;
#[cfg(feature = "target-obsidian")]
use js_sys;
#[cfg(feature = "target-obsidian")]
use web_sys;
#[cfg(feature = "target-obsidian")]
use crate::obsidian::{ObsidianPart, MartsCommand};
// ========== Native-specific imports (OS daemon) ==========
#[cfg(feature = "target-os")]
use serenity::{
async_trait as serenity_async_trait,
client::{Client, Context, EventHandler},
model::{
channel::Message,
gateway::Ready,
id::ChannelId,
},
prelude::GatewayIntents,
};
#[cfg(feature = "target-os")]
use mize::async_trait;
#[derive(Clone)]
#[mize_part]
pub struct DiscordPart {
pub mize: Mize,
// Native: serenity client
#[cfg(feature = "target-os")]
pub client: Option<Client>,
}
impl DiscordPart {
// ========== WASM (Obsidian plugin) methods ==========
/// Read a file from the Obsidian vault using the Obsidian API
#[cfg(feature = "target-obsidian")]
pub fn read_obsidian_file(&self, path: &str) -> MizeResult<String> {
// TODO: Implement using js_sys to call Obsidian's vault.read() or similar
// Example approach:
use wasm_bindgen::JsCast;
use js_sys::Reflect;
let obsidian_part = self.mize.get_part_native::<ObsidianPart>("obsidian")?;
let plugin = &obsidian_part.plugin();
let app = Reflect::get(plugin, &"app".into())?;
let vault = Reflect::get(&app, &"vault".into())?;
let content = Reflect::call(&vault, &"read".into(), &path.into())?;
content.as_string().ok_or_else(|| mize_err!("Failed to read file"))
}
/// Send content to Discord channel using Discord REST API
#[cfg(feature = "target-obsidian")]
pub fn send_to_discord_rest(&self, content: String, channel_id: u64) -> MizeResult<()> {
// TODO: Implement using web_sys to call Discord REST API
// 1. Get token: mize.get_config("discord.token")
// 2. POST to https://discord.com/api/v10/channels/{channel_id}/messages
// 3. Headers: Authorization: Bot <token>, Content-Type: application/json
// 4. Body: {"content": content}
Ok(())
}
// ========== Native (OS daemon) methods ==========
/// Start the serenity Discord bot
#[cfg(feature = "target-os")]
pub async fn start_serenity_bot(&mut self, mize: &mut Mize) -> MizeResult<()> {
let token = mize.get_config("discord.token")?.value_string()?;
// Define event handler
struct Handler;
#[serenity_async_trait]
impl EventHandler for Handler {
async fn ready(&self, _: Context, ready: Ready) {
println!("Discord bot logged in as {}", ready.user.name);
}
// TODO: Add message handler for receiving commands from plugin
// This is where you'll implement communication with the Obsidian plugin
// Example:
// async fn message(&self, ctx: Context, msg: Message) {
// if msg.content.starts_with("!send") {
// // Parse command and send file to channel
// }
// }
}
let mut client = Client::builder(&token, GatewayIntents::non_privileged())
.event_handler(Handler)
.await?;
// Spawn the client in a tokio task
tokio::spawn({
let client_clone = client.clone();
async move {
if let Err(why) = client_clone.start().await {
eprintln!("Discord client error: {:?}", why);
}
}
});
self.client = Some(client);
Ok(())
}
}
impl MizePart for DiscordPart {
fn init(&mut self, mize: &mut Mize) -> MizeResult<()> {
// WASM: Add command to Obsidian
#[cfg(feature = "target-obsidian")]
{
let obsidian_part = mize.get_part_native::<ObsidianPart>("obsidian")?;
let callback = {
let mize_clone = mize.clone();
move |mize_inner: Mize| -> MizeResult<()> {
// Get configuration values
let file_path = mize_inner.get_config("sc2.shared_daily_journal_file")?
.value_string()?;
let channel_id_str = mize_inner.get_config("sc2.shared_daily_journal_channel")?
.value_string()?;
let channel_id = channel_id_str.parse::<u64>()?;
// Get DiscordPart and send the file
let mut mize_mut = mize_inner;
let discord_part = mize_mut.get_part_native::<DiscordPart>("discord")?;
let content = discord_part.read_obsidian_file(&file_path)?;
// TODO: COMMUNICATION WITH DAEMON GOES HERE
// For now, we send directly using REST API.
// Replace this with your plugin-to-daemon messaging logic.
discord_part.send_to_discord_rest(content, channel_id)?;
Ok(())
}
};
obsidian_part.add_command(MartsCommand {
id: "send_to_discord".to_string(),
name: "Send to Discord".to_string(),
callback: Box::new(callback),
})?;
}
Ok(())
}
// Native: Override async_init to start serenity bot
#[cfg(feature = "target-os")]
async fn async_init(&mut self, mize: &mut Mize) -> MizeResult<()> {
self.start_serenity_bot(mize).await
}
}
impl MizePartCreate for DiscordPart {}
pub fn part_discord(mize: &mut Mize) -> MizeResult<()> {
mize.register_part(Box::new(DiscordPart {
mize: mize.clone(),
#[cfg(feature = "target-os")]
client: None,
}))
}