1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use anyhow::Result;
use clap::{App, Arg, ArgMatches};
use libworterbuch::{
codec::{Err, KeyValuePair, PState, State},
client::config::Config,
};
pub fn print_pstate(msg: &PState, json: bool) {
if json {
match serde_json::to_string(msg) {
Ok(json) => println!("{json}"),
Err(e) => {
eprintln!("Error converting message to json: {e}");
}
}
} else {
for KeyValuePair { key, value } in &msg.key_value_pairs {
println!("{key}={value}");
}
}
}
pub fn print_state(msg: &State, json: bool) {
if json {
match serde_json::to_string(msg) {
Ok(json) => println!("{json}"),
Err(e) => {
eprintln!("Error converting message to json: {e}");
}
}
} else {
if let Some(KeyValuePair { key, value }) = &msg.key_value {
println!("{}={}", key, value);
} else {
eprintln!("No result.");
}
}
}
pub fn print_err(msg: &Err, json: bool) {
if json {
match serde_json::to_string(msg) {
Ok(json) => println!("{json}"),
Err(e) => {
eprintln!("Error converting message to json: {e}");
}
}
} else {
eprintln!("server error {}: {}", msg.error_code, msg.metadata);
}
}
pub fn app<'help>(
name: &'help str,
about: &'help str,
include_json: bool,
args: Vec<Arg<'help>>,
) -> Result<(ArgMatches, String, String, u16, bool)> {
let config = Config::new()?;
let mut app = App::new(name)
.version(env!("CARGO_PKG_VERSION"))
.author(env!("CARGO_PKG_AUTHORS"))
.about(about);
for arg in default_args(include_json).iter().chain(args.iter()) {
app = app.arg(arg)
}
let matches = app.get_matches();
let default_proto = config.proto;
let default_host_addr = config.host_addr;
let default_port = config.port;
let proto = default_proto;
let host_addr = matches
.get_one::<String>("ADDR")
.map(ToOwned::to_owned)
.unwrap_or(default_host_addr);
let port = matches
.get_one::<u16>("PORT")
.map(ToOwned::to_owned)
.unwrap_or(default_port);
let json = if include_json {matches.is_present("JSON")} else {false};
Ok((matches, proto, host_addr, port, json))
}
fn default_args<'help>(include_json: bool) -> Vec<Arg<'help>> {
let mut args = vec![
Arg::with_name("ADDR")
.short('a')
.long("addr")
.help("The address of the Wörterbuch server. When omitted, the value of the env var WORTERBUCH_HOST_ADDRESS will be used. If that is not set, 127.0.0.1 will be used.")
.takes_value(true)
.required(false),
Arg::with_name("PORT")
.short('p')
.long("port")
.help("The port of the Wörterbuch server. When omitted, the value of the env var WORTERBUCH_PORT will be used. If that is not set, 4242 will be used.")
.takes_value(true)
.required(false),
];
if include_json {
args.push(
Arg::with_name("JSON")
.short('j')
.long("json")
.help("Output data in JSON format instead of '[key]=[value]' pairs.")
.takes_value(false)
.required(false)
);
}
args
}