Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
304a25a
chore(bump): version of the crate
tkr-sh May 13, 2024
5b94c53
fix(README): proxy_port is a u16 not &str
tkr-sh May 13, 2024
1aa1d39
Update tokio-rustls dependency
kpcyrd Jul 1, 2024
62dd1f8
Make DangerousAcceptAllVerifier wrap a CryptoProvider
kpcyrd Jul 2, 2024
30cb2fd
Do not separate mode flags with spaces when stringifying MODE commands
zetafunction Sep 24, 2024
6767278
Merge pull request #263 from kpcyrd/rustls
aatxe Nov 6, 2024
9c9e8b2
Merge pull request #262 from tkr-sh/develop
aatxe Nov 6, 2024
3f2737c
Fix gating of tokio feature
kpcyrd Nov 8, 2024
4308605
make encoding optional
stevefan1999-personal Dec 10, 2024
111ed0b
Update README examples
sneakycrow Jan 11, 2025
a2979df
Re-add Config::load comment
sneakycrow Jan 11, 2025
e9f0999
Merge pull request #269 from sneakycrow/patch-1
aatxe Jan 19, 2025
e0f6703
Update name in README.md
aatxe Jan 19, 2025
61f43f1
Merge pull request #268 from stevefan1999-personal/develop
aatxe Jan 19, 2025
070b93a
Add native-certs support
kpcyrd Jan 24, 2025
2135612
Replace serde_derive with serde/derive
kpcyrd Jan 24, 2025
9aee9b8
Merge pull request #271 from kpcyrd/serde-derive
aatxe Jan 25, 2025
10d1147
Merge pull request #267 from kpcyrd/tokio-dep
aatxe Jan 25, 2025
8474385
Merge pull request #270 from kpcyrd/native-certs
aatxe Jan 25, 2025
c5fee75
Merge pull request #264 from zetafunction/develop
aatxe Feb 3, 2025
b04602d
cargo.toml edits for new release
aatxe Mar 24, 2025
d6b80f4
bump msrv to 1.80
aatxe Mar 24, 2025
fb6ace2
updated ci job for msrv
aatxe Mar 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
strategy:
fail-fast: false
matrix:
rust: ["1.71", stable]
rust: ["1.80", stable]
steps:
- uses: actions/checkout@v3
- uses: dtolnay/rust-toolchain@master
Expand Down
55 changes: 36 additions & 19 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[package]
name = "irc"
version = "1.0.0"
authors = ["Aaron Weiss <aweiss@hey.com>"]
version = "1.1.0"
authors = ["Ariel Weiss <aweiss@hey.com>"]
edition = "2018"
rust-version = "1.71"
rust-version = "1.80"
description = "the irc crate – usable, async IRC for Rust"
documentation = "https://docs.rs/irc/"
readme = "README.md"
Expand All @@ -20,31 +20,42 @@ is-it-maintained-open-issues = { repository = "aatxe/irc" }


[workspace]
members = [ "./", "irc-proto/" ]
members = ["./", "irc-proto/"]


[features]
default = ["ctcp", "tls-native", "channel-lists", "toml_config"]
default = ["ctcp", "tls-native", "channel-lists", "toml_config", "encoding"]
ctcp = []
channel-lists = []

json_config = ["serde", "serde/derive", "serde_derive", "serde_json"]
toml_config = ["serde", "serde/derive", "serde_derive", "toml"]
yaml_config = ["serde", "serde/derive", "serde_derive", "serde_yaml"]
json_config = ["serde", "serde_json"]
toml_config = ["serde", "toml"]
yaml_config = ["serde", "serde_yaml"]
# Temporary transitionary features
json = ["json_config"]
yaml = ["yaml_config"]

proxy = ["tokio-socks"]

tls-native = ["native-tls", "tokio-native-tls"]
tls-rust = ["tokio-rustls", "webpki-roots", "rustls-pemfile"]

tls-rust = [
"rustls-native-certs",
"rustls-pemfile",
"tokio-rustls",
"webpki-roots",
]
encoding = ["dep:encoding", "irc-proto/encoding"]

[dependencies]
chrono = { version = "0.4.24", default-features = false, features = ["clock", "std"] }
encoding = "0.2.33"
futures-util = { version = "0.3.30", default-features = false, features = ["alloc", "sink"] }
chrono = { version = "0.4.24", default-features = false, features = [
"clock",
"std",
] }
encoding = { version = "0.2.33", optional = true }
futures-util = { version = "0.3.30", default-features = false, features = [
"alloc",
"sink",
] }
irc-proto = { version = "1.0.0", path = "irc-proto" }
log = "0.4.21"
parking_lot = "0.12.1"
Expand All @@ -55,8 +66,7 @@ tokio-stream = "0.1.12"
tokio-util = { version = "0.7.7", features = ["codec"] }

# Feature - Config
serde = { version = "1.0.160", optional = true }
serde_derive = { version = "1.0.160", optional = true }
serde = { version = "1.0.160", features = ["derive"], optional = true }
serde_json = { version = "1.0.95", optional = true }
serde_yaml = { version = "0.9.21", optional = true }
toml = { version = "0.7.3", optional = true }
Expand All @@ -66,10 +76,11 @@ tokio-socks = { version = "0.5.1", optional = true }

# Feature - TLS
native-tls = { version = "0.2.11", optional = true }
tokio-rustls = { version = "0.24.0", features = ["dangerous_configuration"], optional = true }
rustls-pemfile = { version = "1.0.2", optional = true }
tokio-native-tls = { version = "0.3.1", optional = true }
webpki-roots = { version = "0.23.0", optional = true }
rustls-native-certs = { version = "0.8", optional = true }
rustls-pemfile = { version = "2", optional = true }
tokio-rustls = { version = "0.26.0", optional = true }
webpki-roots = { version = "0.26.0", optional = true }


[dev-dependencies]
Expand All @@ -78,7 +89,13 @@ args = "2.2.0"
env_logger = "0.11.0"
futures = "0.3.30"
getopts = "0.2.21"
tokio = { version = "1.27.0", features = ["rt", "rt-multi-thread", "macros", "net", "time"] }
tokio = { version = "1.27.0", features = [
"rt",
"rt-multi-thread",
"macros",
"net",
"time",
] }


[[example]]
Expand Down
31 changes: 18 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Making your own project? [Submit a pull request](https://github.com/aatxe/irc/pu

## Getting Started

To start using the irc crate with cargo, you can add `irc = "0.15"` to your dependencies in
To start using the irc crate with cargo, you can add `irc = "1.0.0"` to your dependencies in or you can use the comman `cargo add irc`.
your Cargo.toml file. The high-level API can be found in [`irc::client::prelude`][irc-prelude].
You'll find a number of examples to help you get started in `examples/`, throughout the
documentation, and below.
Expand All @@ -52,20 +52,19 @@ documentation, and below.

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

```rust,no_run,edition2018
use irc::client::prelude::*;
```rust,no_run,edition2021
use futures::prelude::*;
use irc::client::prelude::*;

#[tokio::main]
async fn main() -> Result<(), failure::Error> {
async fn main() -> Result<(), anyhow::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()?;

Expand All @@ -80,19 +79,25 @@ async fn main() -> Result<(), failure::Error> {
```

Example Cargo.toml file:
```rust,no_run,edition2018
```rust,no_run,edition2021
[package]
name = "example"
version = "0.1.0"
edition = "2018"
edition = "2021"

# 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"
anyhow = "1.0"
futures = "0.3"
irc = "1.0.0"
tokio = { version = "1.0", features = [
"rt",
"rt-multi-thread",
"macros",
"net",
"time",
] }
```

## Configuring IRC Clients
Expand Down Expand Up @@ -122,7 +127,7 @@ port = 6697
password = ""
proxy_type = "None"
proxy_server = "127.0.0.1"
proxy_port = "1080"
proxy_port = 1080
proxy_username = ""
proxy_password = ""
use_tls = true
Expand Down Expand Up @@ -162,7 +167,7 @@ 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][awe]) and Peter Atashian ([@retep998][bun]), as well as the broader Rust
Ariel Weiss ([@aatxe][awe]) and Peter Atashian ([@retep998][bun]), 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
Expand Down
9 changes: 5 additions & 4 deletions irc-proto/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "irc-proto"
version = "1.0.0"
authors = ["Aaron Weiss <aweiss@hey.com>"]
version = "1.1.0"
authors = ["Ariel Weiss <aweiss@hey.com>"]
edition = "2018"
rust-version = "1.60"
description = "The IRC protocol distilled."
Expand All @@ -15,10 +15,11 @@ categories = ["network-programming"]
travis-ci = { repository = "aatxe/irc" }

[features]
default = ["bytes", "tokio", "tokio-util"]
default = ["tokio"]
tokio = ["bytes", "dep:tokio", "tokio-util"]

[dependencies]
encoding = "0.2.33"
encoding = { version = "0.2.33", optional = true }
thiserror = "1.0.40"

bytes = { version = "1.4.0", optional = true }
Expand Down
26 changes: 13 additions & 13 deletions irc-proto/src/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,15 +227,13 @@ impl<'a> From<&'a Command> for String {
Command::NICK(ref n) => stringify("NICK", &[n]),
Command::USER(ref u, ref m, ref r) => stringify("USER", &[u, m, "*", r]),
Command::OPER(ref u, ref p) => stringify("OPER", &[u, p]),
Command::UserMODE(ref u, ref m) => format!(
"MODE {}{}",
u,
m.iter().fold(String::new(), |mut acc, mode| {
acc.push(' ');
acc.push_str(&mode.to_string());
Command::UserMODE(ref u, ref m) => {
// User modes never have arguments.
m.iter().fold(format!("MODE {u} "), |mut acc, m| {
acc.push_str(&m.flag());
acc
})
),
}
Command::SERVICE(ref nick, ref r0, ref dist, ref typ, ref r1, ref info) => {
stringify("SERVICE", &[nick, r0, dist, typ, r1, info])
}
Expand All @@ -248,15 +246,17 @@ impl<'a> From<&'a Command> for String {
Command::JOIN(ref c, None, None) => stringify("JOIN", &[c]),
Command::PART(ref c, Some(ref m)) => stringify("PART", &[c, m]),
Command::PART(ref c, None) => stringify("PART", &[c]),
Command::ChannelMODE(ref u, ref m) => format!(
"MODE {}{}",
u,
m.iter().fold(String::new(), |mut acc, mode| {
Command::ChannelMODE(ref c, ref m) => {
let cmd = m.iter().fold(format!("MODE {c} "), |mut acc, m| {
acc.push_str(&m.flag());
acc
});
m.iter().filter_map(|m| m.arg()).fold(cmd, |mut acc, arg| {
acc.push(' ');
acc.push_str(&mode.to_string());
acc.push_str(arg);
acc
})
),
}
Command::TOPIC(ref c, Some(ref t)) => stringify("TOPIC", &[c, t]),
Command::TOPIC(ref c, None) => stringify("TOPIC", &[c]),
Command::NAMES(Some(ref c), Some(ref t)) => stringify("NAMES", &[c, t]),
Expand Down
92 changes: 59 additions & 33 deletions irc-proto/src/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,37 @@
use std::io;

use bytes::BytesMut;
#[cfg(feature = "encoding")]
use encoding::label::encoding_from_whatwg_label;
#[cfg(feature = "encoding")]
use encoding::{DecoderTrap, EncoderTrap, EncodingRef};
use tokio_util::codec::{Decoder, Encoder};

use crate::error;

/// A line-based codec parameterized by an encoding.
pub struct LineCodec {
#[cfg(feature = "encoding")]
encoding: EncodingRef,
next_index: usize,
}

impl LineCodec {
/// Creates a new instance of LineCodec from the specified encoding.
pub fn new(label: &str) -> error::Result<LineCodec> {
encoding_from_whatwg_label(label)
.map(|enc| LineCodec {
encoding: enc,
next_index: 0,
})
.ok_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
&format!("Attempted to use unknown codec {}.", label)[..],
)
.into()
})
Ok(LineCodec {
#[cfg(feature = "encoding")]
encoding: match encoding_from_whatwg_label(label) {
Some(x) => x,
None => {
return Err(error::ProtocolError::Io(io::Error::new(
io::ErrorKind::InvalidInput,
&format!("Attempted to use unknown codec {}.", label)[..],
)));
}
},
next_index: 0,
})
}
}

Expand All @@ -45,14 +49,29 @@ impl Decoder for LineCodec {
// Set the search start index back to 0 since we found a newline.
self.next_index = 0;

// Decode the line using the codec's encoding.
match self.encoding.decode(line.as_ref(), DecoderTrap::Replace) {
Ok(data) => Ok(Some(data)),
Err(data) => Err(io::Error::new(
io::ErrorKind::InvalidInput,
&format!("Failed to decode {} as {}.", data, self.encoding.name())[..],
)
.into()),
#[cfg(feature = "encoding")]
{
// Decode the line using the codec's encoding.
match self.encoding.decode(line.as_ref(), DecoderTrap::Replace) {
Ok(data) => Ok(Some(data)),
Err(data) => Err(io::Error::new(
io::ErrorKind::InvalidInput,
&format!("Failed to decode {} as {}.", data, self.encoding.name())[..],
)
.into()),
}
}

#[cfg(not(feature = "encoding"))]
{
match String::from_utf8(line.to_vec()) {
Ok(data) => Ok(Some(data)),
Err(data) => Err(io::Error::new(
io::ErrorKind::InvalidInput,
&format!("Failed to decode {} as UTF-8.", data)[..],
)
.into()),
}
}
} else {
// Set the search start index to the current length since we know that none of the
Expand All @@ -67,20 +86,27 @@ impl Encoder<String> for LineCodec {
type Error = error::ProtocolError;

fn encode(&mut self, msg: String, dst: &mut BytesMut) -> error::Result<()> {
// Encode the message using the codec's encoding.
let data: error::Result<Vec<u8>> = self
.encoding
.encode(&msg, EncoderTrap::Replace)
.map_err(|data| {
io::Error::new(
io::ErrorKind::InvalidInput,
&format!("Failed to encode {} as {}.", data, self.encoding.name())[..],
)
.into()
});
#[cfg(feature = "encoding")]
{
// Encode the message using the codec's encoding.
let data: error::Result<Vec<u8>> = self
.encoding
.encode(&msg, EncoderTrap::Replace)
.map_err(|data| {
io::Error::new(
io::ErrorKind::InvalidInput,
&format!("Failed to encode {} as {}.", data, self.encoding.name())[..],
)
.into()
});
// Write the encoded message to the output buffer.
dst.extend(&data?);
}

// Write the encoded message to the output buffer.
dst.extend(&data?);
#[cfg(not(feature = "encoding"))]
{
dst.extend(msg.into_bytes());
}

Ok(())
}
Expand Down
Loading