Initial commit.
This commit is contained in:
commit
ad978e8007
22
.github/workflows/rust.yml
vendored
Normal file
22
.github/workflows/rust.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
name: Rust
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
18
.gitignore
vendored
Normal file
18
.gitignore
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
## ------------------------------------------------------------------------------------------------
|
||||
# Files created by development tools
|
||||
/.idea/
|
||||
*.iml
|
||||
**/*.rs~
|
||||
**/*.md~
|
||||
|
||||
## ------------------------------------------------------------------------------------------------
|
||||
# Files created by cargo (build, fmt, make, etc.)
|
||||
/.cargo
|
||||
/target
|
||||
/docs
|
||||
Cargo.lock
|
||||
**/*.rs.bk
|
||||
|
||||
## ------------------------------------------------------------------------------------------------
|
||||
# Files required for CI integration (Travis)
|
||||
/ci
|
12
.idea/luxafor.iml
Normal file
12
.idea/luxafor.iml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/luxafor.iml" filepath="$PROJECT_DIR$/.idea/luxafor.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
31
Cargo.toml
Normal file
31
Cargo.toml
Normal file
@ -0,0 +1,31 @@
|
||||
[package]
|
||||
name = "luxafor"
|
||||
description = "Library, and CLI, for Luxafor lights via webhooks."
|
||||
version = "0.1.0"
|
||||
authors = ["Simon Johnston <johnstonskj@gmail.com>"]
|
||||
edition = "2018"
|
||||
license = "MIT"
|
||||
readme = "README.md"
|
||||
publish = true
|
||||
default-run = "lux"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
targets = ["x86_64-unknown-linux-gnu"]
|
||||
all-features = true
|
||||
|
||||
[features]
|
||||
command-line = ["pretty_env_logger", "structopt"]
|
||||
|
||||
[[bin]]
|
||||
name = "lux"
|
||||
path = "src/bin/main.rs"
|
||||
required-features = ["command-line"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.4.11"
|
||||
error-chain = "0.12.2"
|
||||
reqwest = { version = "0.10", features = ["blocking", "json"] }
|
||||
|
||||
#[feature-dependencies]
|
||||
structopt = { version = "0.3.14", optional = true }
|
||||
pretty_env_logger = { version = "0.4.0", optional = true }
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 Simon Johnston
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
47
README.md
Normal file
47
README.md
Normal file
@ -0,0 +1,47 @@
|
||||
#Crate luxafor
|
||||
|
||||
Library, and CLI, for [Luxafor](https://luxafor.com/products/) lights via webhooks.
|
||||
|
||||

|
||||

|
||||
[](https://crates.io/crates/atelier_core)
|
||||
[](https://docs.rs/atelier_core)
|
||||

|
||||
[](https://github.com/johnstonskj/luxafor/stargazers)
|
||||
|
||||
This has been tested with the USB connected [flag](https://luxafor.com/flag-usb-busylight-availability-indicator/)
|
||||
as well as the [Bluetooth](https://luxafor.com/bluetooth-busy-light-availability-indicator/) lights.
|
||||
|
||||
# Examples
|
||||
|
||||
The following shows the command line tool setting the color to red.
|
||||
|
||||
```bash
|
||||
❯ lux solid red -d 2a0f2c73b72
|
||||
```
|
||||
|
||||
The following shows the command line tool setting the color to a blinking green.
|
||||
|
||||
```bash
|
||||
❯ lux blink green -d 2a0f2c73b72
|
||||
```
|
||||
|
||||
The following shows the command line tool turning the light off.
|
||||
|
||||
```bash
|
||||
❯ lux -vvv off -d 2a0f2c73b72
|
||||
INFO luxafor > Setting the color of device '2a0f2c73b72e' to 000000
|
||||
INFO luxafor > call successful
|
||||
```
|
||||
|
||||
|
||||
## Changes
|
||||
|
||||
**Version 0.1.0**
|
||||
|
||||
* Initial commit, supports flag and bluetooth lights.
|
||||
|
||||
|
||||
## TODO
|
||||
|
||||
TBD
|
81
src/bin/main.rs
Normal file
81
src/bin/main.rs
Normal file
@ -0,0 +1,81 @@
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use luxafor::{set_pattern, set_solid_color, turn_off, DeviceID, Pattern, SolidColor};
|
||||
use std::error::Error;
|
||||
use structopt::StructOpt;
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
#[structopt(name = "lux", about = "CLI for Luxafor lights")]
|
||||
pub(crate) struct CommandLine {
|
||||
/// The level of logging to perform; from off to trace
|
||||
#[structopt(long, short = "v", parse(from_occurrences))]
|
||||
verbose: i8,
|
||||
|
||||
#[structopt(subcommand)]
|
||||
cmd: SubCommand,
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
pub(crate) enum SubCommand {
|
||||
/// Set the light to a to a solid color
|
||||
Solid {
|
||||
/// The device identifier
|
||||
#[structopt(long, short)]
|
||||
device: DeviceID,
|
||||
|
||||
/// The color to set
|
||||
#[structopt(name = "COLOR")]
|
||||
color: SolidColor,
|
||||
},
|
||||
/// Set the light to a to a blinking color
|
||||
Blink {
|
||||
/// The device identifier
|
||||
#[structopt(long, short)]
|
||||
device: DeviceID,
|
||||
|
||||
/// The color to set
|
||||
#[structopt(name = "COLOR")]
|
||||
color: SolidColor,
|
||||
},
|
||||
/// Set the light to a to a pre-defined pattern
|
||||
Pattern {
|
||||
/// The device identifier
|
||||
#[structopt(long, short)]
|
||||
device: DeviceID,
|
||||
|
||||
/// The pattern to set
|
||||
#[structopt(long, short)]
|
||||
pattern: Pattern,
|
||||
},
|
||||
/// Turn the light off
|
||||
Off {
|
||||
/// The device identifier
|
||||
#[structopt(long, short)]
|
||||
device: DeviceID,
|
||||
},
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let args = CommandLine::from_args();
|
||||
|
||||
pretty_env_logger::formatted_builder()
|
||||
.filter_level(match args.verbose {
|
||||
0 => log::LevelFilter::Off,
|
||||
1 => log::LevelFilter::Error,
|
||||
2 => log::LevelFilter::Warn,
|
||||
3 => log::LevelFilter::Info,
|
||||
4 => log::LevelFilter::Debug,
|
||||
_ => log::LevelFilter::Trace,
|
||||
})
|
||||
.init();
|
||||
|
||||
match args.cmd {
|
||||
SubCommand::Solid { device, color } => set_solid_color(device, color, false),
|
||||
SubCommand::Blink { device, color } => set_solid_color(device, color, true),
|
||||
SubCommand::Pattern { device, pattern } => set_pattern(device, pattern),
|
||||
SubCommand::Off { device } => turn_off(device),
|
||||
}?;
|
||||
|
||||
Ok(())
|
||||
}
|
376
src/lib.rs
Normal file
376
src/lib.rs
Normal file
@ -0,0 +1,376 @@
|
||||
/*!
|
||||
Library, and CLI, for [Luxafor](https://luxafor.com/products/) lights via webhooks. This has been
|
||||
tested with the USB connected [flag](https://luxafor.com/flag-usb-busylight-availability-indicator/)
|
||||
as well as the [Bluetooth](https://luxafor.com/bluetooth-busy-light-availability-indicator/) lights.
|
||||
|
||||
# Examples
|
||||
|
||||
The following shows the command line tool setting the color to red.
|
||||
|
||||
```bash
|
||||
❯ lux solid red -d 2a0f2c73b72
|
||||
```
|
||||
|
||||
The following shows the command line tool setting the color to a blinking green.
|
||||
|
||||
```bash
|
||||
❯ lux blink green -d 2a0f2c73b72
|
||||
```
|
||||
|
||||
The following shows the command line tool turning the light off.
|
||||
|
||||
```bash
|
||||
❯ lux -vvv off -d 2a0f2c73b72
|
||||
INFO luxafor > Setting the color of device '2a0f2c73b72e' to 000000
|
||||
INFO luxafor > call successful
|
||||
```
|
||||
|
||||
*/
|
||||
|
||||
#![warn(
|
||||
// ---------- Stylistic
|
||||
future_incompatible,
|
||||
nonstandard_style,
|
||||
rust_2018_idioms,
|
||||
trivial_casts,
|
||||
trivial_numeric_casts,
|
||||
// ---------- Public
|
||||
missing_debug_implementations,
|
||||
//missing_docs,
|
||||
unreachable_pub,
|
||||
// ---------- Unsafe
|
||||
unsafe_code,
|
||||
// ---------- Unused
|
||||
unused_extern_crates,
|
||||
unused_import_braces,
|
||||
unused_qualifications,
|
||||
unused_results,
|
||||
)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate error_chain;
|
||||
|
||||
#[macro_use]
|
||||
extern crate log;
|
||||
|
||||
use reqwest::blocking::Client;
|
||||
use std::fmt::{Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Public Types
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// This wraps a simple string and ensures it only contains valid characters.
|
||||
///
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DeviceID(String);
|
||||
|
||||
///
|
||||
/// A color that the light can be set to.
|
||||
///
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum SolidColor {
|
||||
/// A preset color
|
||||
Red,
|
||||
/// A preset color
|
||||
Green,
|
||||
/// A preset color
|
||||
Yellow,
|
||||
/// A preset color
|
||||
Blue,
|
||||
/// A preset color
|
||||
White,
|
||||
/// A preset color
|
||||
Cyan,
|
||||
/// A preset color
|
||||
Magenta,
|
||||
/// A custom color using standard RGB values
|
||||
Custom { red: u8, green: u8, blue: u8 },
|
||||
}
|
||||
|
||||
///
|
||||
/// A pattern the light can be set to show.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Pattern {
|
||||
/// A preset pattern
|
||||
Police,
|
||||
/// A preset pattern
|
||||
TrafficLights,
|
||||
/// A preset pattern
|
||||
Random(u8),
|
||||
/// A preset pattern (accepted on Windows only)
|
||||
Rainbow,
|
||||
/// A preset pattern (accepted on Windows only)
|
||||
Sea,
|
||||
/// A preset pattern (accepted on Windows only)
|
||||
WhiteWave,
|
||||
/// A preset pattern (accepted on Windows only)
|
||||
Synthetic,
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Private Types
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
const API_V1: &str = "https://api.luxafor.com/webhook/v1/actions";
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Public Functions
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
///
|
||||
/// Turn the light off.
|
||||
///
|
||||
pub fn turn_off(device: DeviceID) -> error::Result<()> {
|
||||
set_solid_color(
|
||||
device,
|
||||
SolidColor::Custom {
|
||||
red: 00,
|
||||
green: 00,
|
||||
blue: 00,
|
||||
},
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
///
|
||||
/// Set the color, and blink status, of the light.
|
||||
///
|
||||
pub fn set_solid_color(device: DeviceID, color: SolidColor, blink: bool) -> error::Result<()> {
|
||||
info!("Setting the color of device '{}' to {}", device, color);
|
||||
|
||||
let body = if let SolidColor::Custom {
|
||||
red: _,
|
||||
green: _,
|
||||
blue: _,
|
||||
} = color
|
||||
{
|
||||
r#"{
|
||||
"userId": "DID",
|
||||
"actionFields":{
|
||||
"color": "custom",
|
||||
"custom_color": "COLOR"
|
||||
}
|
||||
}"#
|
||||
.replace("DID", &device.to_string())
|
||||
.replace("COLOR", &color.to_string())
|
||||
} else {
|
||||
r#"{
|
||||
"userId": "DID",
|
||||
"actionFields":{
|
||||
"color": "COLOR"
|
||||
}
|
||||
}"#
|
||||
.replace("DID", &device.to_string())
|
||||
.replace("COLOR", &color.to_string())
|
||||
};
|
||||
|
||||
let url = &format!("{}/{}", API_V1, if blink { "blink" } else { "solid_color" });
|
||||
|
||||
send_request(url, body)
|
||||
}
|
||||
|
||||
///
|
||||
/// Set the pattern displayed by the light.
|
||||
///
|
||||
pub fn set_pattern(device: DeviceID, pattern: Pattern) -> error::Result<()> {
|
||||
info!("Setting the pattern of device '{}' to {}", device, pattern);
|
||||
|
||||
let body = r#"{
|
||||
"userId": "DID",
|
||||
"actionFields":{
|
||||
"pattern": "PATTERN"
|
||||
}
|
||||
}"#
|
||||
.replace("DID", &device.to_string())
|
||||
.replace("PATTERN", &pattern.to_string());
|
||||
|
||||
let url = &format!("{}/{}", API_V1, "pattern");
|
||||
|
||||
send_request(url, body)
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Implementations
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
impl Display for DeviceID {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for DeviceID {
|
||||
type Err = error::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
if !s.is_empty() && s.chars().all(|c| c.is_ascii_hexdigit()) {
|
||||
Ok(Self(s.to_string()))
|
||||
} else {
|
||||
Err(error::ErrorKind::InvalidDeviceID.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
impl Display for SolidColor {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
fn to_hex(v: &u8) -> String {
|
||||
format!("{:#04x}", v)[2..].to_string()
|
||||
}
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
SolidColor::Red => "red".to_string(),
|
||||
SolidColor::Green => "green".to_string(),
|
||||
SolidColor::Yellow => "yellow".to_string(),
|
||||
SolidColor::Blue => "blue".to_string(),
|
||||
SolidColor::White => "white".to_string(),
|
||||
SolidColor::Cyan => "cyan".to_string(),
|
||||
SolidColor::Magenta => "magenta".to_string(),
|
||||
SolidColor::Custom { red, green, blue } =>
|
||||
format!("{}{}{}", to_hex(red), to_hex(green), to_hex(blue)),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for SolidColor {
|
||||
type Err = error::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.to_lowercase();
|
||||
match s.as_str() {
|
||||
"red" => Ok(SolidColor::Red),
|
||||
"green" => Ok(SolidColor::Green),
|
||||
"yellow" => Ok(SolidColor::Yellow),
|
||||
"blue" => Ok(SolidColor::Blue),
|
||||
"white" => Ok(SolidColor::White),
|
||||
"cyan" => Ok(SolidColor::Cyan),
|
||||
"magenta" => Ok(SolidColor::Magenta),
|
||||
_ => {
|
||||
if s.len() == 6 && s.chars().all(|c| c.is_ascii_hexdigit()) {
|
||||
Ok(SolidColor::Custom {
|
||||
red: u8::from_str_radix(&s[0..1], 16)?,
|
||||
green: u8::from_str_radix(&s[2..3], 16)?,
|
||||
blue: u8::from_str_radix(&s[4..5], 16)?,
|
||||
})
|
||||
} else {
|
||||
Err(error::ErrorKind::InvalidColor.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
impl Display for Pattern {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
Pattern::Police => "police".to_string(),
|
||||
Pattern::TrafficLights => "traffic lights".to_string(),
|
||||
Pattern::Random(n) => format!("random {}", n),
|
||||
Pattern::Rainbow => "rainbow".to_string(),
|
||||
Pattern::Sea => "sea".to_string(),
|
||||
Pattern::WhiteWave => "white wave".to_string(),
|
||||
Pattern::Synthetic => "synthetic".to_string(),
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Pattern {
|
||||
type Err = error::Error;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.to_lowercase();
|
||||
match s.as_str() {
|
||||
"police" => Ok(Pattern::Police),
|
||||
"traffic lights" => Ok(Pattern::TrafficLights),
|
||||
"random 1" => Ok(Pattern::Random(1)),
|
||||
"random 2" => Ok(Pattern::Random(2)),
|
||||
"random 3" => Ok(Pattern::Random(3)),
|
||||
"random 4" => Ok(Pattern::Random(4)),
|
||||
"random 5" => Ok(Pattern::Random(5)),
|
||||
"sea" => Ok(Pattern::Sea),
|
||||
"white wave" => Ok(Pattern::WhiteWave),
|
||||
"synthetic" => Ok(Pattern::Synthetic),
|
||||
_ => Err(error::ErrorKind::InvalidPattern.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Private Functions
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
fn send_request(api: &str, body: String) -> error::Result<()> {
|
||||
debug!("Sending to: {}", api);
|
||||
debug!("Sending data: {:?}", body);
|
||||
|
||||
let client = Client::new();
|
||||
let result = client
|
||||
.post(api)
|
||||
.header("Content-Type", "application/json")
|
||||
.body(body)
|
||||
.send()?;
|
||||
|
||||
if result.status().is_success() {
|
||||
info!("call successful");
|
||||
Ok(())
|
||||
} else {
|
||||
let status_code = result.status().as_u16();
|
||||
error!("call failed");
|
||||
error!("{:?}", result.text());
|
||||
Err(error::ErrorKind::UnexpectedError(status_code).into())
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Modules
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
mod error {
|
||||
error_chain! {
|
||||
errors {
|
||||
#[doc("The color value supplied was not recognized")]
|
||||
InvalidColor {
|
||||
description("The color value supplied was not recognized")
|
||||
display("The color value supplied was not recognized")
|
||||
}
|
||||
#[doc("The pattern value supplied was not recognized")]
|
||||
InvalidPattern {
|
||||
description("The pattern value supplied was not recognized")
|
||||
display("The pattern value supplied was not recognized")
|
||||
}
|
||||
#[doc("The provided device ID was incorrectly formatted")]
|
||||
InvalidDeviceID {
|
||||
description("The provided device ID was incorrectly formatted")
|
||||
display("The provided device ID was incorrectly formatted")
|
||||
}
|
||||
#[doc("The server indicated an invalid request")]
|
||||
InvalidRequest {
|
||||
description("The server indicated an invalid request")
|
||||
display("The server indicated an invalid request")
|
||||
}
|
||||
#[doc("An unexpected HTTP error was returned")]
|
||||
UnexpectedError(sc: u16) {
|
||||
description("An unexpected HTTP error was returned")
|
||||
display("An unexpected HTTP error was returned: {}", sc)
|
||||
}
|
||||
}
|
||||
foreign_links {
|
||||
CustomFmt(::std::num::ParseIntError);
|
||||
Request(::reqwest::Error);
|
||||
Fmt(::std::fmt::Error);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user