1use std::net::TcpStream;
9
10pub use paper_utils::stream::{StreamError, StreamReader};
11
12use crate::{
13 addr::FromPaperAddr,
14 arg::{AsPaperAuthToken, AsPaperKey},
15 command::Command,
16 error::{PaperClientError, PaperClientResult},
17 policy::PaperPolicy,
18 status::Status,
19 value::PaperValue,
20};
21
22const RECONNECT_MAX_ATTEMPTS: u8 = 3;
23
24#[derive(Debug)]
25pub struct PaperClient {
26 addr: String,
27
28 auth_token: Option<String>,
29 reconnect_attempts: u8,
30
31 stream: TcpStream,
32}
33
34impl PaperClient {
35 pub fn new(paper_addr: impl FromPaperAddr) -> PaperClientResult<Self> {
46 let addr = paper_addr.to_addr()?;
47 let stream = init_stream(&addr)?;
48
49 let mut client = PaperClient {
50 addr,
51
52 auth_token: None,
53 reconnect_attempts: 0,
54
55 stream,
56 };
57
58 client.handshake()?;
59
60 Ok(client)
61 }
62
63 pub fn ping(&mut self) -> PaperClientResult<PaperValue> {
77 self.process_value(&Command::Ping)
78 }
79
80 pub fn version(&mut self) -> PaperClientResult<PaperValue> {
94 self.process_value(&Command::Version)
95 }
96
97 pub fn auth(&mut self, token: impl AsPaperAuthToken) -> PaperClientResult<()> {
113 let auth_token = token.as_paper_auth_token();
114
115 let command = Command::Auth(auth_token);
116 let result = self.process(&command);
117
118 self.auth_token = Some(auth_token.to_owned());
119
120 result
121 }
122
123 pub fn get(&mut self, key: impl AsPaperKey) -> PaperClientResult<PaperValue> {
137 let command = Command::Get(key.as_paper_key());
138 self.process_value(&command)
139 }
140
141 pub fn set(
155 &mut self,
156 key: impl AsPaperKey,
157 value: impl TryInto<PaperValue>,
158 ttl: Option<u32>,
159 ) -> PaperClientResult<()> {
160 let value: PaperValue = value
161 .try_into()
162 .map_err(|_| PaperClientError::InvalidValue)?;
163
164 let command = Command::Set(key.as_paper_key(), value, ttl.unwrap_or(0));
165
166 self.process(&command)
167 }
168
169 pub fn del(&mut self, key: impl AsPaperKey) -> PaperClientResult<()> {
183 let command = Command::Del(key.as_paper_key());
184 self.process(&command)
185 }
186
187 pub fn has(&mut self, key: impl AsPaperKey) -> PaperClientResult<bool> {
202 let command = Command::Has(key.as_paper_key());
203 self.process_has(&command)
204 }
205
206 pub fn peek(&mut self, key: impl AsPaperKey) -> PaperClientResult<PaperValue> {
221 let command = Command::Peek(key.as_paper_key());
222 self.process_value(&command)
223 }
224
225 pub fn ttl(&mut self, key: impl AsPaperKey, ttl: Option<u32>) -> PaperClientResult<()> {
239 let command = Command::Ttl(key.as_paper_key(), ttl.unwrap_or(0));
240 self.process(&command)
241 }
242
243 pub fn size(&mut self, key: impl AsPaperKey) -> PaperClientResult<u32> {
257 let command = Command::Size(key.as_paper_key());
258 self.process_size(&command)
259 }
260
261 pub fn wipe(&mut self) -> PaperClientResult<()> {
275 self.process(&Command::Wipe)
276 }
277
278 pub fn resize(&mut self, size: u64) -> PaperClientResult<()> {
292 let command = Command::Resize(size);
293 self.process(&command)
294 }
295
296 pub fn policy(&mut self, policy: PaperPolicy) -> PaperClientResult<()> {
310 let command = Command::Policy(policy);
311 self.process(&command)
312 }
313
314 pub fn status(&mut self) -> PaperClientResult<Status> {
328 self.process_status(&Command::Status)
329 }
330
331 fn process(&mut self, command: &Command<'_>) -> PaperClientResult<()> {
332 match self
333 .send(command)
334 .and_then(|_| self.receive(command))
335 {
336 Ok(response) => {
337 self.reconnect_attempts = 0;
338 Ok(response)
339 },
340
341 Err(PaperClientError::InvalidResponse) => {
342 self.reconnect_attempts += 1;
343 self.reconnect()?;
344 self.process(command)
345 },
346
347 err => err,
348 }
349 }
350
351 fn process_value(&mut self, command: &Command<'_>) -> PaperClientResult<PaperValue> {
352 match self
353 .send(command)
354 .and_then(|_| self.receive_value(command))
355 {
356 Ok(response) => {
357 self.reconnect_attempts = 0;
358 Ok(response)
359 },
360
361 Err(PaperClientError::InvalidResponse) => {
362 self.reconnect_attempts += 1;
363 self.reconnect()?;
364 self.process_value(command)
365 },
366
367 err => err,
368 }
369 }
370
371 fn process_has(&mut self, command: &Command<'_>) -> PaperClientResult<bool> {
372 match self
373 .send(command)
374 .and_then(|_| self.receive_has(command))
375 {
376 Ok(response) => {
377 self.reconnect_attempts = 0;
378 Ok(response)
379 },
380
381 Err(PaperClientError::InvalidResponse) => {
382 self.reconnect_attempts += 1;
383 self.reconnect()?;
384 self.process_has(command)
385 },
386
387 err => err,
388 }
389 }
390
391 fn process_size(&mut self, command: &Command<'_>) -> PaperClientResult<u32> {
392 match self
393 .send(command)
394 .and_then(|_| self.receive_size(command))
395 {
396 Ok(response) => {
397 self.reconnect_attempts = 0;
398 Ok(response)
399 },
400
401 Err(PaperClientError::InvalidResponse) => {
402 self.reconnect_attempts += 1;
403 self.reconnect()?;
404 self.process_size(command)
405 },
406
407 err => err,
408 }
409 }
410
411 fn process_status(&mut self, command: &Command<'_>) -> PaperClientResult<Status> {
412 match self
413 .send(command)
414 .and_then(|_| self.receive_status(command))
415 {
416 Ok(response) => {
417 self.reconnect_attempts = 0;
418 Ok(response)
419 },
420
421 Err(PaperClientError::InvalidResponse) => {
422 self.reconnect_attempts += 1;
423 self.reconnect()?;
424 self.process_status(command)
425 },
426
427 err => err,
428 }
429 }
430
431 fn send(&mut self, command: &Command<'_>) -> PaperClientResult<()> {
432 command
433 .write(&mut self.stream)
434 .map_err(|err| match err {
435 StreamError::InvalidStream => PaperClientError::Disconnected,
436 _ => PaperClientError::InvalidCommand,
437 })
438 }
439
440 fn receive(&mut self, command: &Command<'_>) -> PaperClientResult<()> {
441 command.parse_reader(&mut self.stream)
442 }
443
444 fn receive_value(&mut self, command: &Command<'_>) -> PaperClientResult<PaperValue> {
445 command.parse_buf_reader(&mut self.stream)
446 }
447
448 fn receive_has(&mut self, command: &Command<'_>) -> PaperClientResult<bool> {
449 command.parse_has_reader(&mut self.stream)
450 }
451
452 fn receive_size(&mut self, command: &Command<'_>) -> PaperClientResult<u32> {
453 command.parse_size_reader(&mut self.stream)
454 }
455
456 fn receive_status(&mut self, command: &Command<'_>) -> PaperClientResult<Status> {
457 command.parse_status_reader(&mut self.stream)
458 }
459
460 fn handshake(&mut self) -> PaperClientResult<()> {
461 let mut reader = StreamReader::new(&mut self.stream);
462
463 let is_ok = reader
464 .read_bool()
465 .map_err(|_| PaperClientError::UnreachableServer)?;
466
467 match is_ok {
468 true => Ok(()),
469 false => Err(PaperClientError::from_reader(reader)),
470 }
471 }
472
473 fn reconnect(&mut self) -> PaperClientResult<()> {
474 if self.reconnect_attempts > RECONNECT_MAX_ATTEMPTS {
475 return Err(PaperClientError::Disconnected);
476 }
477
478 self.stream = init_stream(&self.addr)?;
479 self.handshake()?;
480
481 if let Some(token) = self.auth_token.clone() {
482 self.auth(token)?;
483 }
484
485 Ok(())
486 }
487}
488
489fn init_stream(addr: &str) -> PaperClientResult<TcpStream> {
490 let stream = TcpStream::connect(addr).map_err(|_| PaperClientError::UnreachableServer)?;
491
492 if stream.set_nodelay(true).is_err() {
493 return Err(PaperClientError::Internal);
494 }
495
496 Ok(stream)
497}