Skip to content

Commit 218dc36

Browse files
authored
Merge pull request #273 from aatxe/develop
Release v1.1.0
2 parents 57d8a68 + fb6ace2 commit 218dc36

File tree

10 files changed

+292
-149
lines changed

10 files changed

+292
-149
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
strategy:
1313
fail-fast: false
1414
matrix:
15-
rust: ["1.71", stable]
15+
rust: ["1.80", stable]
1616
steps:
1717
- uses: actions/checkout@v3
1818
- uses: dtolnay/rust-toolchain@master

Cargo.toml

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
[package]
22
name = "irc"
3-
version = "1.0.0"
4-
authors = ["Aaron Weiss <[email protected]>"]
3+
version = "1.1.0"
4+
authors = ["Ariel Weiss <[email protected]>"]
55
edition = "2018"
6-
rust-version = "1.71"
6+
rust-version = "1.80"
77
description = "the irc crate – usable, async IRC for Rust"
88
documentation = "https://docs.rs/irc/"
99
readme = "README.md"
@@ -20,31 +20,42 @@ is-it-maintained-open-issues = { repository = "aatxe/irc" }
2020

2121

2222
[workspace]
23-
members = [ "./", "irc-proto/" ]
23+
members = ["./", "irc-proto/"]
2424

2525

2626
[features]
27-
default = ["ctcp", "tls-native", "channel-lists", "toml_config"]
27+
default = ["ctcp", "tls-native", "channel-lists", "toml_config", "encoding"]
2828
ctcp = []
2929
channel-lists = []
3030

31-
json_config = ["serde", "serde/derive", "serde_derive", "serde_json"]
32-
toml_config = ["serde", "serde/derive", "serde_derive", "toml"]
33-
yaml_config = ["serde", "serde/derive", "serde_derive", "serde_yaml"]
31+
json_config = ["serde", "serde_json"]
32+
toml_config = ["serde", "toml"]
33+
yaml_config = ["serde", "serde_yaml"]
3434
# Temporary transitionary features
3535
json = ["json_config"]
3636
yaml = ["yaml_config"]
3737

3838
proxy = ["tokio-socks"]
3939

4040
tls-native = ["native-tls", "tokio-native-tls"]
41-
tls-rust = ["tokio-rustls", "webpki-roots", "rustls-pemfile"]
42-
41+
tls-rust = [
42+
"rustls-native-certs",
43+
"rustls-pemfile",
44+
"tokio-rustls",
45+
"webpki-roots",
46+
]
47+
encoding = ["dep:encoding", "irc-proto/encoding"]
4348

4449
[dependencies]
45-
chrono = { version = "0.4.24", default-features = false, features = ["clock", "std"] }
46-
encoding = "0.2.33"
47-
futures-util = { version = "0.3.30", default-features = false, features = ["alloc", "sink"] }
50+
chrono = { version = "0.4.24", default-features = false, features = [
51+
"clock",
52+
"std",
53+
] }
54+
encoding = { version = "0.2.33", optional = true }
55+
futures-util = { version = "0.3.30", default-features = false, features = [
56+
"alloc",
57+
"sink",
58+
] }
4859
irc-proto = { version = "1.0.0", path = "irc-proto" }
4960
log = "0.4.21"
5061
parking_lot = "0.12.1"
@@ -55,8 +66,7 @@ tokio-stream = "0.1.12"
5566
tokio-util = { version = "0.7.7", features = ["codec"] }
5667

5768
# Feature - Config
58-
serde = { version = "1.0.160", optional = true }
59-
serde_derive = { version = "1.0.160", optional = true }
69+
serde = { version = "1.0.160", features = ["derive"], optional = true }
6070
serde_json = { version = "1.0.95", optional = true }
6171
serde_yaml = { version = "0.9.21", optional = true }
6272
toml = { version = "0.7.3", optional = true }
@@ -66,10 +76,11 @@ tokio-socks = { version = "0.5.1", optional = true }
6676

6777
# Feature - TLS
6878
native-tls = { version = "0.2.11", optional = true }
69-
tokio-rustls = { version = "0.24.0", features = ["dangerous_configuration"], optional = true }
70-
rustls-pemfile = { version = "1.0.2", optional = true }
7179
tokio-native-tls = { version = "0.3.1", optional = true }
72-
webpki-roots = { version = "0.23.0", optional = true }
80+
rustls-native-certs = { version = "0.8", optional = true }
81+
rustls-pemfile = { version = "2", optional = true }
82+
tokio-rustls = { version = "0.26.0", optional = true }
83+
webpki-roots = { version = "0.26.0", optional = true }
7384

7485

7586
[dev-dependencies]
@@ -78,7 +89,13 @@ args = "2.2.0"
7889
env_logger = "0.11.0"
7990
futures = "0.3.30"
8091
getopts = "0.2.21"
81-
tokio = { version = "1.27.0", features = ["rt", "rt-multi-thread", "macros", "net", "time"] }
92+
tokio = { version = "1.27.0", features = [
93+
"rt",
94+
"rt-multi-thread",
95+
"macros",
96+
"net",
97+
"time",
98+
] }
8299

83100

84101
[[example]]

README.md

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Making your own project? [Submit a pull request](https://github.com/aatxe/irc/pu
4141

4242
## Getting Started
4343

44-
To start using the irc crate with cargo, you can add `irc = "0.15"` to your dependencies in
44+
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`.
4545
your Cargo.toml file. The high-level API can be found in [`irc::client::prelude`][irc-prelude].
4646
You'll find a number of examples to help you get started in `examples/`, throughout the
4747
documentation, and below.
@@ -52,20 +52,19 @@ documentation, and below.
5252

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

55-
```rust,no_run,edition2018
56-
use irc::client::prelude::*;
55+
```rust,no_run,edition2021
5756
use futures::prelude::*;
57+
use irc::client::prelude::*;
5858
5959
#[tokio::main]
60-
async fn main() -> Result<(), failure::Error> {
60+
async fn main() -> Result<(), anyhow::Error> {
6161
// We can also load the Config at runtime via Config::load("path/to/config.toml")
6262
let config = Config {
6363
nickname: Some("the-irc-crate".to_owned()),
6464
server: Some("chat.freenode.net".to_owned()),
6565
channels: vec!["#test".to_owned()],
6666
..Config::default()
6767
};
68-
6968
let mut client = Client::from_config(config).await?;
7069
client.identify()?;
7170
@@ -80,19 +79,25 @@ async fn main() -> Result<(), failure::Error> {
8079
```
8180

8281
Example Cargo.toml file:
83-
```rust,no_run,edition2018
82+
```rust,no_run,edition2021
8483
[package]
8584
name = "example"
8685
version = "0.1.0"
87-
edition = "2018"
86+
edition = "2021"
8887
8988
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
9089
9190
[dependencies]
92-
irc = "0.15.0"
93-
tokio = { version = "1.0.0", features = ["rt", "rt-multi-thread", "macros", "net", "time"] }
94-
futures = "0.3.0"
95-
failure = "0.1.8"
91+
anyhow = "1.0"
92+
futures = "0.3"
93+
irc = "1.0.0"
94+
tokio = { version = "1.0", features = [
95+
"rt",
96+
"rt-multi-thread",
97+
"macros",
98+
"net",
99+
"time",
100+
] }
96101
```
97102

98103
## Configuring IRC Clients
@@ -122,7 +127,7 @@ port = 6697
122127
password = ""
123128
proxy_type = "None"
124129
proxy_server = "127.0.0.1"
125-
proxy_port = "1080"
130+
proxy_port = 1080
126131
proxy_username = ""
127132
proxy_password = ""
128133
use_tls = true
@@ -162,7 +167,7 @@ tool should make it easier for users to migrate their old configurations to TOML
162167

163168
## Contributing
164169
the irc crate is a free, open source library that relies on contributions from its maintainers,
165-
Aaron Weiss ([@aatxe][awe]) and Peter Atashian ([@retep998][bun]), as well as the broader Rust
170+
Ariel Weiss ([@aatxe][awe]) and Peter Atashian ([@retep998][bun]), as well as the broader Rust
166171
community. It's licensed under the Mozilla Public License 2.0 whose text can be found in
167172
`LICENSE.md`. To foster an inclusive community around the irc crate, we have adopted a Code of
168173
Conduct whose text can be found in `CODE_OF_CONDUCT.md`. You can find details about how to

irc-proto/Cargo.toml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "irc-proto"
3-
version = "1.0.0"
4-
authors = ["Aaron Weiss <[email protected]>"]
3+
version = "1.1.0"
4+
authors = ["Ariel Weiss <[email protected]>"]
55
edition = "2018"
66
rust-version = "1.60"
77
description = "The IRC protocol distilled."
@@ -15,10 +15,11 @@ categories = ["network-programming"]
1515
travis-ci = { repository = "aatxe/irc" }
1616

1717
[features]
18-
default = ["bytes", "tokio", "tokio-util"]
18+
default = ["tokio"]
19+
tokio = ["bytes", "dep:tokio", "tokio-util"]
1920

2021
[dependencies]
21-
encoding = "0.2.33"
22+
encoding = { version = "0.2.33", optional = true }
2223
thiserror = "1.0.40"
2324

2425
bytes = { version = "1.4.0", optional = true }

irc-proto/src/command.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -227,15 +227,13 @@ impl<'a> From<&'a Command> for String {
227227
Command::NICK(ref n) => stringify("NICK", &[n]),
228228
Command::USER(ref u, ref m, ref r) => stringify("USER", &[u, m, "*", r]),
229229
Command::OPER(ref u, ref p) => stringify("OPER", &[u, p]),
230-
Command::UserMODE(ref u, ref m) => format!(
231-
"MODE {}{}",
232-
u,
233-
m.iter().fold(String::new(), |mut acc, mode| {
234-
acc.push(' ');
235-
acc.push_str(&mode.to_string());
230+
Command::UserMODE(ref u, ref m) => {
231+
// User modes never have arguments.
232+
m.iter().fold(format!("MODE {u} "), |mut acc, m| {
233+
acc.push_str(&m.flag());
236234
acc
237235
})
238-
),
236+
}
239237
Command::SERVICE(ref nick, ref r0, ref dist, ref typ, ref r1, ref info) => {
240238
stringify("SERVICE", &[nick, r0, dist, typ, r1, info])
241239
}
@@ -248,15 +246,17 @@ impl<'a> From<&'a Command> for String {
248246
Command::JOIN(ref c, None, None) => stringify("JOIN", &[c]),
249247
Command::PART(ref c, Some(ref m)) => stringify("PART", &[c, m]),
250248
Command::PART(ref c, None) => stringify("PART", &[c]),
251-
Command::ChannelMODE(ref u, ref m) => format!(
252-
"MODE {}{}",
253-
u,
254-
m.iter().fold(String::new(), |mut acc, mode| {
249+
Command::ChannelMODE(ref c, ref m) => {
250+
let cmd = m.iter().fold(format!("MODE {c} "), |mut acc, m| {
251+
acc.push_str(&m.flag());
252+
acc
253+
});
254+
m.iter().filter_map(|m| m.arg()).fold(cmd, |mut acc, arg| {
255255
acc.push(' ');
256-
acc.push_str(&mode.to_string());
256+
acc.push_str(arg);
257257
acc
258258
})
259-
),
259+
}
260260
Command::TOPIC(ref c, Some(ref t)) => stringify("TOPIC", &[c, t]),
261261
Command::TOPIC(ref c, None) => stringify("TOPIC", &[c]),
262262
Command::NAMES(Some(ref c), Some(ref t)) => stringify("NAMES", &[c, t]),

irc-proto/src/line.rs

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,37 @@
33
use std::io;
44

55
use bytes::BytesMut;
6+
#[cfg(feature = "encoding")]
67
use encoding::label::encoding_from_whatwg_label;
8+
#[cfg(feature = "encoding")]
79
use encoding::{DecoderTrap, EncoderTrap, EncodingRef};
810
use tokio_util::codec::{Decoder, Encoder};
911

1012
use crate::error;
1113

1214
/// A line-based codec parameterized by an encoding.
1315
pub struct LineCodec {
16+
#[cfg(feature = "encoding")]
1417
encoding: EncodingRef,
1518
next_index: usize,
1619
}
1720

1821
impl LineCodec {
1922
/// Creates a new instance of LineCodec from the specified encoding.
2023
pub fn new(label: &str) -> error::Result<LineCodec> {
21-
encoding_from_whatwg_label(label)
22-
.map(|enc| LineCodec {
23-
encoding: enc,
24-
next_index: 0,
25-
})
26-
.ok_or_else(|| {
27-
io::Error::new(
28-
io::ErrorKind::InvalidInput,
29-
&format!("Attempted to use unknown codec {}.", label)[..],
30-
)
31-
.into()
32-
})
24+
Ok(LineCodec {
25+
#[cfg(feature = "encoding")]
26+
encoding: match encoding_from_whatwg_label(label) {
27+
Some(x) => x,
28+
None => {
29+
return Err(error::ProtocolError::Io(io::Error::new(
30+
io::ErrorKind::InvalidInput,
31+
&format!("Attempted to use unknown codec {}.", label)[..],
32+
)));
33+
}
34+
},
35+
next_index: 0,
36+
})
3337
}
3438
}
3539

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

48-
// Decode the line using the codec's encoding.
49-
match self.encoding.decode(line.as_ref(), DecoderTrap::Replace) {
50-
Ok(data) => Ok(Some(data)),
51-
Err(data) => Err(io::Error::new(
52-
io::ErrorKind::InvalidInput,
53-
&format!("Failed to decode {} as {}.", data, self.encoding.name())[..],
54-
)
55-
.into()),
52+
#[cfg(feature = "encoding")]
53+
{
54+
// Decode the line using the codec's encoding.
55+
match self.encoding.decode(line.as_ref(), DecoderTrap::Replace) {
56+
Ok(data) => Ok(Some(data)),
57+
Err(data) => Err(io::Error::new(
58+
io::ErrorKind::InvalidInput,
59+
&format!("Failed to decode {} as {}.", data, self.encoding.name())[..],
60+
)
61+
.into()),
62+
}
63+
}
64+
65+
#[cfg(not(feature = "encoding"))]
66+
{
67+
match String::from_utf8(line.to_vec()) {
68+
Ok(data) => Ok(Some(data)),
69+
Err(data) => Err(io::Error::new(
70+
io::ErrorKind::InvalidInput,
71+
&format!("Failed to decode {} as UTF-8.", data)[..],
72+
)
73+
.into()),
74+
}
5675
}
5776
} else {
5877
// Set the search start index to the current length since we know that none of the
@@ -67,20 +86,27 @@ impl Encoder<String> for LineCodec {
6786
type Error = error::ProtocolError;
6887

6988
fn encode(&mut self, msg: String, dst: &mut BytesMut) -> error::Result<()> {
70-
// Encode the message using the codec's encoding.
71-
let data: error::Result<Vec<u8>> = self
72-
.encoding
73-
.encode(&msg, EncoderTrap::Replace)
74-
.map_err(|data| {
75-
io::Error::new(
76-
io::ErrorKind::InvalidInput,
77-
&format!("Failed to encode {} as {}.", data, self.encoding.name())[..],
78-
)
79-
.into()
80-
});
89+
#[cfg(feature = "encoding")]
90+
{
91+
// Encode the message using the codec's encoding.
92+
let data: error::Result<Vec<u8>> = self
93+
.encoding
94+
.encode(&msg, EncoderTrap::Replace)
95+
.map_err(|data| {
96+
io::Error::new(
97+
io::ErrorKind::InvalidInput,
98+
&format!("Failed to encode {} as {}.", data, self.encoding.name())[..],
99+
)
100+
.into()
101+
});
102+
// Write the encoded message to the output buffer.
103+
dst.extend(&data?);
104+
}
81105

82-
// Write the encoded message to the output buffer.
83-
dst.extend(&data?);
106+
#[cfg(not(feature = "encoding"))]
107+
{
108+
dst.extend(msg.into_bytes());
109+
}
84110

85111
Ok(())
86112
}

0 commit comments

Comments
 (0)