GithubHelp home page GithubHelp logo

aatxe / irc Goto Github PK

View Code? Open in Web Editor NEW
525.0 11.0 100.0 14.66 MB

the irc crate – usable, async IRC for Rust

License: Mozilla Public License 2.0

Rust 100.00%
irc ircv3 client async protocol thread-safe

irc's Introduction

the irc crate Build Status Crates.io Downloads Docs

"the irc crate" is a thread-safe and async-friendly IRC client library written in Rust. It's compliant with RFC 2812, IRCv3.1, IRCv3.2, and includes some additional, common features from popular IRCds. You can find up-to-date, ready-to-use documentation online on docs.rs.

Built with the irc crate

the irc crate is being used to build new IRC software in Rust. Here are some of our favorite projects:

Making your own project? Submit a pull request to add it!

Getting Started

To start using the irc crate with cargo, you can add irc = "0.15" to your dependencies in your Cargo.toml file. The high-level API can be found in irc::client::prelude. You'll find a number of examples to help you get started in examples/, throughout the documentation, and below.

Using Futures

The release of v0.14 replaced all existing APIs with one based on async/await.

use irc::client::prelude::*;
use futures::prelude::*;

#[tokio::main]
async fn main() -> Result<(), failure::Error> {
    // We can also load the Config at runtime via Config::load("path/to/config.toml")
    let config = Config {
        nickname: Some("the-irc-crate".to_owned()),
        server: Some("chat.freenode.net".to_owned()),
        channels: vec!["#test".to_owned()],
        ..Config::default()
    };

    let mut client = Client::from_config(config).await?;
    client.identify()?;

    let mut stream = client.stream()?;

    while let Some(message) = stream.next().await.transpose()? {
        print!("{}", message);
    }

    Ok(())
}

Example Cargo.toml file:

[package]
name = "example"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
irc = "0.15.0"
tokio = { version = "1.0.0", features = ["rt", "rt-multi-thread", "macros", "net", "time"] }
futures = "0.3.0"
failure = "0.1.8"

Configuring IRC Clients

As seen above, there are two techniques for configuring the irc crate: runtime loading and programmatic configuration. Runtime loading is done via the function Config::load, and is likely sufficient for most IRC bots. Programmatic configuration is convenient for writing tests, but can also be useful when defining your own custom configuration format that can be converted to Config. The primary configuration format is TOML, but if you are so inclined, you can use JSON and/or YAML via the optional json_config and yaml_config features respectively. At the minimum, a configuration requires nickname and server to be defined, and all other fields are optional. You can find detailed explanations of the various fields on docs.rs.

Alternatively, you can look at the example below of a TOML configuration with all the fields:

owners = []
nickname = "user"
nick_password = "password"
alt_nicks = ["user_", "user__"]
username = "user"
realname = "Test User"
server = "chat.freenode.net"
port = 6697
password = ""
proxy_type = "None"
proxy_server = "127.0.0.1"
proxy_port = "1080"
proxy_username = ""
proxy_password = ""
use_tls = true
cert_path = "cert.der"
client_cert_path = "client.der"
client_cert_pass = "password"
encoding = "UTF-8"
channels = ["#rust", "#haskell", "#fake"]
umodes = "+RB-x"
user_info = "I'm a test user for the irc crate."
version = "irc:git:Rust"
source = "https://github.com/aatxe/irc"
ping_time = 180
ping_timeout = 20
burst_window_length = 8
max_messages_in_burst = 15
should_ghost = false
ghost_sequence = []

[channel_keys]
"#fake" = "password"

[options]
note = "anything you want can be in here!"
and = "you can use it to build your own additional configuration options."
key = "value"

You can convert between different configuration formats with convertconf like so:

cargo run --example convertconf -- -i client_config.json -o client_config.toml

Note that the formats are automatically determined based on the selected file extensions. This tool should make it easier for users to migrate their old configurations to TOML.

Contributing

the irc crate is a free, open source library that relies on contributions from its maintainers, Aaron Weiss (@aatxe) and Peter Atashian (@retep998), as well as the broader Rust community. It's licensed under the Mozilla Public License 2.0 whose text can be found in LICENSE.md. To foster an inclusive community around the irc crate, we have adopted a Code of Conduct whose text can be found in CODE_OF_CONDUCT.md. You can find details about how to contribute in CONTRIBUTING.md.

irc's People

Contributors

aatxe avatar agausmann avatar andreasots avatar angelsl avatar bassetts avatar belak avatar brigand avatar doumanash avatar filipegoncalves avatar freaky avatar freddyb avatar jesopo avatar johann150 avatar jokler avatar kroisse avatar ljrk0 avatar martinetd avatar maugier avatar miedzinski avatar ratysz avatar retep998 avatar sbstp avatar simnalamburt avatar sshine avatar steveklabnik avatar theduke avatar themightybuzzard avatar tobbez avatar udoprog avatar yancyribbens avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

irc's Issues

Option to throttle outgoing messages

throttle burst messages to prevent kicks from the server.
config example:

{
  "burst": 4, // throttle after a burst of 4 messages
  "cooldown": 4 // time in seconds after a new burst is allowed
  "throttle": 1 // time in seconds between successive messages
}

Failed to decode configuration file.

Given the source code and config.json as given by the readme, I get the following error:

thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Custom(Custom { kind: InvalidInput, error: StringError("Failed to decode configuration file.") }) }', ../src/libcore/result.rs:746

Here is my Cargo.toml:

[package]
name = "simpleirc"
version = "0.1.0"
authors = ["Filip Szczepański <[email protected]>"]

[dependencies]
irc = "0.10.0"

ERR_KEYNOPERMISSION Typo/Bug

I was just skimming the source and noticed that in response.rs ERR_KEYNOPERMISSION is defined as 779, but the preceding comment describes it with 769.

I'm not sure which is correct, but at least one is probably wrong.

Case insensitive Command/CTCP parsing

RFC 2812 specifies a command to be

command    =  1*letter / 3digit
letter     =  %x41-5A / %x61-7A       ; A-Z / a-z

There is no mention of case sensitivity of commands.

Currently, Command::new and *SubCommand::from_str only accept uppercase commands. IrcServer::handle_ctcp also only accepts uppercase commands.

As far as I know, all IRC servers now accept commands regardless of case, and most clients will respond to CTCP commands regardless of case.

This would be a trivial fix, but we also want to reduce allocations, so ...

Possible solutions

  1. Match on the &strs to_uppercase()ed.

    The problem with this is now you get an additional allocation which will be thrown away immediately (unless it can be optimised away?)

  2. Use eq_ignore_ascii_case

    This disregards Unicode case (although there are no commands that are not purely letters), and will be ugly compared to a simple match.

update openssl version

I have ran into some issues using the irc crate in my project, it seems to use an outdated version of openssl-sys (specifically version 0.7; current version is 0.9.5).

Here is the error message I am getting when using this in conjunction with curl (uses up-to-date version of openssl-sys.

Updating registry https://github.com/rust-lang/crates.io-index
Downloading curl v0.4.2
Downloading curl-sys v0.3.6
Downloading libz-sys v1.0.10
Downloading openssl-sys v0.9.5
Downloading openssl-probe v0.1.0
Downloading metadeps v1.1.1
Downloading error-chain v0.7.2
error: native library openssl is being linked to by more than one version of the same package, but it can only be linked once; try updating or pinning your dependencies to ensure that this package only shows up once

openssl-sys v0.7.17
openssl-sys v0.9.5

shell returned 101

Press ENTER or type command to continue
error: native library openssl is being linked to by more than one version of the same package, but it can only be linked once; try updating or pinning your dependencies to ensure that this package only shows up once

openssl-sys v0.9.5
openssl-sys v0.7.17

shell returned 101

Press ENTER or type command to continue
`

CAP command is not specification-compliant.

The loose specification for the capabilities extension protocol was harder for me to follow than the RFC, and as a result, the CAP command is not specification compliant. Specifically, it doesn't match the server responses for the protocol. These look like so: :server CAP * ACK :multi-prefix.

Access level tracking is inaccurate.

Access level tracking is sometimes inaccurate. Specifically, if a user is given both +v and +o and then is given -o, they're downgraded to a Member. In actuality, they should be kept as voiced in the tracking. The solution to this will involve tracking all the modes in a vector, and defining a method to get the "highest access level" or, in other words, the one with the most authority.

Automatic login to nickserv

Add a way to automatically identify to nickserv and/or provide the password when supplying USER/NICK during the initial connection phase.

Send time limit

Is there something that is throttling sent messages if they are sending to fast, if so, how can I turn it off?

Confusing naming.

When looking at the client code I see irc::client::IrcServer, which confused me at first. I would expect irc::client::IrcClient. Is there a reason for this name? What will the name of the server be? irc::server::IrcClient?

How can I build without SSL support?

I am banging my head against a wall to get cargo to build openssl on Windows and I've had enough. How can I simply build without SSL support?

Failed to parse MODE message

( Edited error to make person and channel names private )

thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Custom(Custom { kind: InvalidInput, error: StringError("Failed to parse message. (Message: :[email protected] MODE #channel +ao ClientTesttest ClientTesttest\r\n)") }) }', ../src/libcore/result.rs:746

It seems to only happen when more than one mode is given in a single message

`Custom` command

It would be great to add Custom (Raw) command to enum Command. Or make possible execute from_message method for custom message:

let message = Message {
    prefix: None,
    command: "CUSTOM_COMMAND".to_string(),
    args: vec!["arg0".to_string()],
    suffix: None,
};
let custom_command = Command::from_message(&message).unwrap();

thx.

Wrappers are not thread-safe.

It shouldn't be terrible to make wrappers thread-safe. It'd be nice to do that because as it stands, you need to make one for every thread, and use an Arc for the initial server.

Config file channel keys

I couldn't find a way to easily autojoin channels that need a channel key. Maybe these chankeys could be read from the config file somehow?

[0.9.0] Warnings Beta(1.4)

Not sure if you already aware of it\or fixed it but here are warnings on current Beta(1.4) for version 0.9.0:

Example:

/home/travis/.cargo/registry/src/github.com-0a35038f75765ae4/irc-0.9.0/src/client/server/mod.rs:26:5: 26:51 warning: the trait `std::io::BufRead` is not implemented for the type `T` [E0277]

/home/travis/.cargo/registry/src/github.com-0a35038f75765ae4/irc-0.9.0/src/client/server/mod.rs:26     fn iter(&'a self) -> ServerIterator<'a, T, U>;

                                                                                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/home/travis/.cargo/registry/src/github.com-0a35038f75765ae4/irc-0.9.0/src/client/server/mod.rs:26:5: 26:51 help: run `rustc --explain E0277` to see a detailed explanation

/home/travis/.cargo/registry/src/github.com-0a35038f75765ae4/irc-0.9.0/src/client/server/mod.rs:26:5: 26:51 note: this warning results from recent bug fixes and clarifications; it will become a HARD ERROR in the next release. See RFC 1214 for details.

/home/travis/.cargo/registry/src/github.com-0a35038f75765ae4/irc-0.9.0/src/client/server/mod.rs:26     fn iter(&'a self) -> ServerIterator<'a, T, U>;

                                                                                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/home/travis/.cargo/registry/src/github.com-0a35038f75765ae4/irc-0.9.0/src/client/server/mod.rs:26:5: 26:51 note: required by `client::server::ServerIterator`

/home/travis/.cargo/registry/src/github.com-0a35038f75765ae4/irc-0.9.0/src/client/server/mod.rs:26:5: 26:51 warning: the trait `core::marker::Send` is not implemented for the type `T` [E0277]

/home/travis/.cargo/registry/src/github.com-0a35038f75765ae4/irc-0.9.0/src/client/server/mod.rs:26     fn iter(&'a self) -> ServerIterator<'a, T, U>;

                                                                                                       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

/home/travis/.cargo/registry/src/github.com-0a35038f75765ae4/irc-0.9.0/src/client/server/mod.rs:26:5: 26:51 help: run `rustc --explain E0277` to see a detailed explanation

/home/travis/.cargo/registry/src/github.com-0a35038f75765ae4/irc-0.9.0/src/client/server/mod.rs:26:5: 26:51 note: `T` cannot be sent between threads safely

/home/travis/.cargo/registry/src/github.com-0a35038f75765ae4/irc-0.9.0/src/client/server/mod.rs:26:5: 26:51 note: this warning results from recent bug fixes and clarifications; it will become a HARD ERROR in the next release. See RFC 1214 for details.

FYI:
https://travis-ci.org/DoumanAsh/vndis-rusty-bot/jobs/84440421

Join new channels on reconnect

This is a feature request.

Currently, only configured channels are joined on reconnect.
One can join new channel by calling send_join(), but the channels are not kept when some error occurs.

The desired scenario looks like the following.

  1. The library connects to the server and initializes some statuses.
  2. A user calls send_join() to join some channels.
  3. Something bad happens. Then reconnect() is called internally.
  4. The library automatically joins the channels that were joined in step 2.

Implement server library.

I've been waiting for IO to settle for a while now, but I think it's in a good position to work on a server component. It should likely be somewhat based on the new std::net design.

extreme CPU usage on OS X

Hello!

I'm trying to write a little bot in IRC, but when I run my really simple bot (it just says "hi" to anything) it takes up a whole core worth of CPU!

Details about my system:

  • platform: OS X 10.10.5
  • rust version: rustc 1.6.0 (c30b771ad 2016-01-19)

Source code for the offending bot: https://github.com/tahnok/ironbot/blob/master/src/main.rs

Has anyone else seen this? Is it just an OS X thing?

can't decode json config

Not sure what is going wrong here, but when I call Config::load() on a totally non-exotic config file, it panics:

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Custom(Custom { kind: InvalidData, error: StringError("stream did not contain valid UTF-8") }) }', ../src/libcore/result.rs:799

File looks like

{
  "nickname": "omnbot",
  "alt_nicks": ["omnbot_", "omnbot__"],
  "use_ssl": false,
  "port": 6667,
  "server": "irc.freenode.net",
  "channels": ["##omnbot_testing"]
}

and file config.json reports ascii, which should decode as utf-8 just fine as far as I know.

Any idea what's up?

Redesign client command support.

We should redesign Command to address a few problems. Firstly, current conversion into a Command results in loss of data (specifically, you lose the message prefix). Secondly, the code to convert messages into commands is a huge mess. Thirdly, the code to convert commands into messages is also a huge mess. This stuff could do with a lot of love. It's hard to maintain as it stands.

For some initial design thoughts, macros might be useful in cleaning up the conversion from messages. The rest of the issues may be improved by the following design (perhaps with better names?):

struct Command {
    message: Message,
    detail: CommandDetail
}

enum CommandDetail<'a> {
    // RFC commands...
    PRIVMSG(&'a str, &'a str)
    // more commands...
}

/cc @filipegoncalves @retep998

Redesign Wrapper as ServerExt.

It'd be a lot nicer, and a lot more idiomatic if we eliminated the need for a Wrapper altogether. This would implicitly solve #5. ServerExt would be included in the prelude, but is something that someone who does not wish to use it could ignore. The change overall would involve renaming Wrapper and making it into a trait that's implemented for all types that implement Server.

Example:

pub trait ServerExt: Server + Sized {
    fn send_privmsg(&self, target: &str, message: &str) {
        self.server.send(PRIVMSG(target.to_owned(), line.to_owned()))
    }

    // more stuff...
}

impl<T: Server> ServerExt for T {}

Bot Crash when encountering special char username

thread '<main>' panicked at 'index 1 and/or 2 inɸdo not lie on character boundary', ../src/libcore/str/mod.rs:1534 is the error I get when joining a channel with someone named ɸ maybe slicing strings with .chars() might help?

Stack overflow

I sometimes get a stack overflow when connecting to the IRC server I'm running on localhost
I've tested it on stable and nightly, debug and release modes

extern crate irc;
use irc::client::prelude::*;

fn main() {
    let server = IrcServer::from_config(Config {
            nickname: Some("meow".to_string()),
            server: Some("localhost".to_string()),
            ..Default::default()
        }).unwrap();
    server.identify().unwrap();
    std::thread::sleep(std::time::Duration::from_secs(30));
}

I had more complete code, similar to the simple example, but I stripped parts away until I had the minimum that I still got a stack overflow running

Outdated documentation

The online documentation does not contain the sasl related functions, since gh_pages was last updated before those were added.

Allocation heavy

Every occurence of String or Vec is an allocation. Especially for sending messages, this seems a bit wasteful! The Cow (clone-on-write) type (and Into<Cow<str>>) can ease this burden, by allowing the flexibility of the user providing either a slice or a String, and the library only cloning it for unique ownership where necessary (if ever). This isn't a very practical concern, admittedly, and is more about good style and creating the best IRC library in existence.

Reconnecting on timeout does not work

I tried playing with ping_time and ping_timeout options, but can't reproduce reconnect even if I suspend the IRC server. It sends more and more pings even thou there are no replies.

extern crate irc;

use std::default::Default;
use irc::client::prelude::*;

fn main() {
    let config = Config {
        nickname: Some(format!("pickles")),
        alt_nicks: Some(vec![format!("bananas"), format!("apples")]),
        server: Some(format!("127.0.0.1")),
        channels: Some(vec![format!("#vana")]),
        ping_time: Some(3),
        ping_timeout: Some(1),
        .. Default::default()
    };
    let server = IrcServer::from_config(config).unwrap();
    server.identify().unwrap();
    for message in server.iter() {
        let message = message.unwrap(); // We'll just panic if there's an error.
        print!("{}", message);
        match message.command {
            Command::PRIVMSG(ref target, ref msg) => if msg.contains("pickles") {
                server.send_privmsg(target, "Hi!").unwrap();
            },
            _ => (),
        }
    }
}

How do I make it actually reconnect?

CTCP Optional Feature

There should be an optional feature to add support for CTCP requests in Commands, and also to auto-process things such as CTCP VERSION, PING, TIME, etc. This is a potentially helpful specification.

encoding in privmsg

Hi,

I'm a newbie in Rust so it might be a stupid question, but,
I just tried to print in my terminal the received Command::privmsgs in a chan and sometimes I get this kind of stuff :
�ACTION blah blah �

my terminal is configured in UTF-8
Am I missing something obvious ?

Proxy support

Hey! Can you tell me how to establish an IRC client connection through a proxy server?

Non-channel PRIVMSG message has wrong name

When receiving a message from a channel, the resulting PRIVMSG command has the channel as the msgtarget parameter. However, when receiving a private message, the msgtarget parameter contains the bot's nick instead of the sender's nick. This makes direct replies impossible.

No defined behavior when nickname is taken.

There should be some sort of defined behavior for when a nickname is taken. This could be adding underscores until it works. It could be building in a list of alternative nicknames, and panicking when the list is exhausted. This could be propagating an IoError and letting the user figure out what action to take. It'll probably be the last one, but discussion could take place here on what this should look like.

Crates.io name being squatted.

The name of this crate (irc) is currently being squatted by @mahkoh. There have been multiple attempts made to contact him, but he has not responded to any of them.

Change `Capability` to trait `AsRef<str>`

pub trait ServerExt<'a, T, U>: Server<'a, T, U> {
...
    /// Sends an IRCv3 capabilities request for the specified extensions.
    fn send_cap_req(&self, extensions: &[Capability]) -> Result<()> where Self: Sized {
...

Propose: Change Capability to trait AsRef<str>.

Because some servers use custom capabilities (for example)

IRCv3 support

Howdy. Do you have plans to implement IRCv3 support? If not, I strongly urge you to, as IRCv3 provides a number of useful extensions to IRC (particularly account-notify, extended-join, and account-msg, for bot authors) that improve the experience for users and developers alike.

RFCs 2810 through 2813 have a lot of content that have nothing to do with real-world IRC, as they're basically what IRCnet thought IRC should be at the time they were published. Nobody else bit, unfortunately, and even IRCnet today has generally moved on. The IRCv3 working group is working on a 'core protocol' based on 3.1 with 3.2's core specifications (IIRC), to be published by the IETF using the same mechanism XMPP did, but I wouldn't wait for that to materialize.

Servers should support automatic reconnection on timeout.

It should be possible to have servers automatically reconnect if the server has not sent them a message after some defined timeout period. This may involve backwards-incompatible configuration changes, if it is to be made optional in that way. It could also be implemented as an optional feature without changes to configuration (instead being determined at compile-time). This would involve adding some sort of reconnection hook and a reconnect method to Connections. For arbitrary connections, it'd default to no reconnection hook, but a reconnection hook could be supplied there as well.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.