168 lines
5.8 KiB
Rust
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,
|
|
}))
|
|
}
|