#irc #hex-chat #api-bindings

hexavalent

使用 Rust 编写 HexChat 插件

10 个版本

0.3.0 2024年3月24日
0.2.1 2022年1月31日
0.1.7 2021年10月21日
0.1.6 2021年1月16日
0.1.2 2020年3月22日

#10 in #irc

MIT 许可协议

245KB
4K SLoC

Rust 3.5K SLoC // 0.1% comments C 654 SLoC // 0.0% comments JavaScript 134 SLoC Shell 8 SLoC

hexavalent

使用 Rust 编写 HexChat 插件。

阅读 文档 或查看示例目录以开始。

为什么叫这个名字?

"Hex" 来自 HexChat,当然。"六价" 因为 CrO3 的外观与 Fe2O3 类似。

...并且六价铬处理起来不安全,就像 HexChat 的 API 一样。


lib.rs:

使用 Rust 编写 HexChat 插件。

创建你的插件

  • 使用 crate-type = "cdylib" 创建一个库 crate。
  • 定义一个类型,例如 struct MyPlugin,以保存插件需要的任何状态。
  • MyPlugin 实现 Plugin 特性。
  • 使用类型 MyPlugin、其名称、描述和版本调用 export_plugin

在 Windows 上,建议将 -C target-feature=+crt-static 添加到你的 RUSTFLAGS,例如在 <project root>/.cargo/config 中。这确保你的 DLL 不会动态导入 MSVCRT。

示例

以下是将 HexChat 的 示例 "auto-op" 插件移植过来。它将自动将加入的所有人设为 OP(所以如果你在一个真实频道里,不要尝试这个!),并且可以通过 /autooptoggle 切换开启和关闭。

use std::cell::Cell;
use hexavalent::{Plugin, PluginHandle, export_plugin};
use hexavalent::event::print::Join;
use hexavalent::hook::{Eat, Priority};
use hexavalent::str::HexStr;

struct AutoOpPlugin {
    enabled: Cell<bool>,
}

impl Default for AutoOpPlugin {
    fn default() -> Self {
        Self {
            enabled: Cell::new(true),
        }
    }
}

impl AutoOpPlugin {
    fn autooptoggle_cb(&self, ph: PluginHandle<'_, Self>, _words: &[&HexStr]) -> Eat {
        if !self.enabled.get() {
            self.enabled.set(true);
            ph.print("Auto-Oping now enabled!");
        } else {
            self.enabled.set(false);
            ph.print("Auto-Oping now disabled!");
        }
        // eat this command so HexChat and other plugins can't process it
        Eat::All
    }

    fn join_cb(&self, ph: PluginHandle<'_, Self>, args: [&HexStr; 4]) -> Eat {
        let [nick, _channel, _host, _account] = args;
        if self.enabled.get() {
            // op ANYONE who joins
            ph.command(format!("OP {}", nick));
        }
        // don't eat this event, HexChat needs to see it
        Eat::None
    }
}

impl Plugin for AutoOpPlugin {
    fn init(&self, ph: PluginHandle<'_, Self>) {
        ph.hook_command(
            "AutoOpToggle",
            "Usage: AUTOOPTOGGLE, turns OFF/ON Auto-Oping",
            Priority::Normal,
            Self::autooptoggle_cb,
        );
        ph.hook_print(Join, Priority::Normal, Self::join_cb);

        ph.print("AutoOpPlugin loaded successfully!");
    }

    fn deinit(&self, ph: PluginHandle<'_, Self>) {
        ph.print("Unloading AutoOpPlugin...");
    }
}

export_plugin!(AutoOpPlugin, "AutoOp", "Auto-Ops anyone who joins", "0.1");

安全性

通常情况下,该库依赖于HexChat在单个线程中调用插件。如果不是这种情况,该库无法提供任何保证。(尽管并未明确指出这是真实的,但HexChat的插件文档并未提及同步,示例插件也没有涉及。在实际情况中也似乎如此。)

在调试模式(具体来说,当 debug_assertions 被启用)时,每次调用插件时都会检查当前线程ID,这有助于检测异常行为。

依赖项

~1MB
~17K SLoC