Rust练手项目,写个有趣的小工具定时从一言网获取一段有趣的话并推送通知

Rust练手项目,写个有趣的小工具

继续练习Rust, 写个小工具定时从一言网获取一段有趣的话并提示,如下
图片

练习以下Rust点

  • 并发编程 Mutex, Arc指针使用
  • HTTP请求
  • Windows Gui

代码

Cargo.toml

[package]
name = "funny_word"
edition = "2021"
version.workspace = true
authors.workspace = true
description.workspace = true

[dependencies]
trayicon = "0.2.0"
winapi = { version = "0.3.9", features = [
    "winuser",
    "windef",
    "minwindef",
    "shellapi",
    "libloaderapi",
    "commctrl",
    "basetsd",
] }
win-toast-notify = "0.1.6"
windows = { version = "0.58.0", features = [
    "Win32_Security",
    "Win32_System_Threading",
    "Win32_UI_WindowsAndMessaging",
] }
reqwest = { version = "0.11", features = ["blocking"]  }
[package]
name = "funny_word"
edition = "2021"
version.workspace = true
authors.workspace = true
description.workspace = true

[dependencies]
trayicon = "0.2.0"
winapi = { version = "0.3.9", features = [
    "winuser",
    "windef",
    "minwindef",
    "shellapi",
    "libloaderapi",
    "commctrl",
    "basetsd",
] }
win-toast-notify = "0.1.6"
windows = { version = "0.58.0", features = [
    "Win32_Security",
    "Win32_System_Threading",
    "Win32_UI_WindowsAndMessaging",
] }
reqwest = { version = "0.11", features = ["blocking"]  }

main.rs

#![windows_subsystem = "windows"]
use core::mem::MaybeUninit;
use std::{
    sync::{Arc, Mutex},
    thread::sleep,
    time::Duration,
};
use trayicon::*;
use win_toast_notify::WinToastNotify;
use winapi::um::winuser;

fn main() {
    #[derive(Copy, Clone, Eq, PartialEq, Debug)]
    enum Events {
        RightClickTrayIcon,
        LeftClickTrayIcon,
        OneMinute,
        FiveMinute,
        FifteenMinute,
        HalfHour,
        OneHour,
        Exit,
    }

    let (sender, receiver) = std::sync::mpsc::channel::<Events>();
    let icon_bytes = include_bytes!("rust.ico");

    let mut tray_icon = TrayIconBuilder::new()
        .sender(move |e: &Events| {
            let _ = sender.send(*e);
        })
        .icon(Icon::from_buffer(icon_bytes, None, None).unwrap())
        .tooltip("💪没事喝点鸡汤吧!")
        .on_right_click(Events::RightClickTrayIcon)
        .on_click(Events::LeftClickTrayIcon)
        .menu(
            MenuBuilder::new()
                .separator()
                .submenu(
                    "提醒间隔",
                    MenuBuilder::new()
                        .checkable("1分钟", true, Events::OneMinute)
                        .checkable("5分钟", false, Events::FiveMinute)
                        .checkable("15分钟", false, Events::FifteenMinute)
                        .checkable("半小时", false, Events::HalfHour)
                        .checkable("一小时", false, Events::OneHour),
                )
                .separator()
                .item("退出", Events::Exit),
        )
        .build()
        .unwrap();

    let _interval = Arc::new(Mutex::new(1));
    let interval = _interval.clone();
    std::thread::spawn(move || {
        receiver.iter().for_each(|m| match m {
            Events::RightClickTrayIcon => {
                tray_icon.show_menu().unwrap();
            }
            Events::LeftClickTrayIcon => {
                tray_icon.show_menu().unwrap();
            }
            Events::Exit => {
                std::process::exit(0);
            }
            Events::OneMinute => {
                let mut i = interval.lock().unwrap();
                *i = 1;
                tray_icon
                    .set_menu_item_checkable(Events::OneMinute, true)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::FiveMinute, false)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::FifteenMinute, false)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::HalfHour, false)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::OneHour, false)
                    .unwrap();
            }
            Events::FiveMinute => {
                let mut i = interval.lock().unwrap();
                *i = 5;
                tray_icon
                    .set_menu_item_checkable(Events::OneMinute, false)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::FiveMinute, true)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::FifteenMinute, false)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::HalfHour, false)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::OneHour, false)
                    .unwrap();
            }
            Events::FifteenMinute => {
                let mut i = interval.lock().unwrap();
                *i = 15;
                tray_icon
                    .set_menu_item_checkable(Events::OneMinute, false)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::FiveMinute, false)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::FifteenMinute, true)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::HalfHour, false)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::OneHour, false)
                    .unwrap();
            }
            Events::HalfHour => {
                let mut i = interval.lock().unwrap();
                *i = 30;
                tray_icon
                    .set_menu_item_checkable(Events::OneMinute, false)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::FiveMinute, false)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::FifteenMinute, false)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::HalfHour, true)
                    .unwrap();
                tray_icon
                    .set_menu_item_checkable(Events::OneHour, false)
                    .unwrap();
            }
            Events::OneHour => {
                let mut i = interval.lock().unwrap();
                *i = 60;
                tray_icon.set_menu_item_checkable(Events::OneMinute, false);
                tray_icon.set_menu_item_checkable(Events::FiveMinute, false);
                tray_icon.set_menu_item_checkable(Events::FifteenMinute, false);
                tray_icon.set_menu_item_checkable(Events::HalfHour, false);
                tray_icon.set_menu_item_checkable(Events::OneHour, true);
            }
        })
    });

    std::thread::spawn(move || loop {
        match reqwest::blocking::get("https://v1.hitokoto.cn?&encode=text") {
            Ok(resp) => match resp.text() {
                Ok(text) => {
                    WinToastNotify::new()
                        .set_title("来自一言网")
                        .set_messages(vec![&text])
                        .show()
                        .expect("发送通知失败!");
                }
                Err(e) => {
                    WinToastNotify::new()
                        .set_title("错误")
                        .set_messages(vec![&format!(
                            "HTTP错误 {}",
                            e.status().unwrap_or_default()
                        )])
                        .show()
                        .expect("发送通知失败!");
                }
            },
            Err(e) => {
                WinToastNotify::new()
                    .set_title("获取网站内容失败错误")
                    .set_messages(vec![&format!(
                        "HTTP错误 {}",
                        e.status().unwrap_or_default()
                    )])
                    .show()
                    .expect("发送通知失败!");
            }
        }

        let mut _b = 1;
        {
            // 加个大括号是为了尽快释放lock, 免得睡眠中(60 * (*i))一直占用锁,点击右键菜单无反应
            let interval = _interval.clone();
            let i = interval.lock().unwrap();
            _b = *i;
        }
        sleep(Duration::from_secs(60 * _b));
    });

    loop {
        unsafe {
            let mut msg = MaybeUninit::uninit();
            let bret = winuser::GetMessageA(msg.as_mut_ptr(), 0 as _, 0, 0);
            if bret > 0 {
                winuser::TranslateMessage(msg.as_ptr());
                winuser::DispatchMessageA(msg.as_ptr());
            } else {
                break;
            }
        }
    }
}

rust.ico图标文件放在main.rs目录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值