nreplops_tool/conn_expr/
resolution.rs1use std::{fs, io, path, thread, time};
17
18use crate::error::Error;
19
20use super::conn_expr::ConnectionExpr;
21
22#[derive(Debug)]
23pub enum ConnectionExprSource {
24 Direct(ConnectionExpr),
26 PortFile {
28 path: Option<path::PathBuf>,
30 wait_for: Option<time::Duration>,
32 },
33}
34
35impl From<ConnectionExpr> for ConnectionExprSource {
36 fn from(e: ConnectionExpr) -> Self {
37 ConnectionExprSource::Direct(e)
38 }
39}
40
41impl From<&ConnectionExpr> for ConnectionExprSource {
42 fn from(e: &ConnectionExpr) -> Self {
43 e.clone().into()
44 }
45}
46
47impl ConnectionExprSource {
48 pub fn resolve_expr(&self) -> Result<ConnectionExpr, Error> {
49 const THROTTLING_DELAY: time::Duration = time::Duration::from_millis(50);
50 match self {
51 ConnectionExprSource::Direct(e) => Ok(e.clone()),
52 ConnectionExprSource::PortFile {
53 path,
54 wait_for: None,
55 } => try_load_from_port_file(path.as_ref()),
56 ConnectionExprSource::PortFile {
57 path,
58 wait_for: Some(duration),
59 } => {
60 let deadline = time::SystemTime::now() + *duration;
61 loop {
62 match try_load_from_port_file(path.as_ref()) {
63 Ok(r) => return Ok(r),
64 Err(e) => match e {
65 Error::NotSpecified | Error::NotFound(_) => {
66 if time::SystemTime::now() >= deadline {
67 return Err(Error::PortFileTimeout);
68 }
69 }
70 _ => return Err(e),
71 },
72 }
73 thread::sleep(THROTTLING_DELAY);
74 }
75 }
76 }
77 }
78}
79
80fn try_load_from_port_file(
81 given: Option<impl AsRef<path::Path>>,
82) -> Result<ConnectionExpr, Error> {
83 if let Some(f) = given {
84 load_from_port_file(f)
85 } else if let Some(ref f) = find_port_file().map_err(|_| Error::Unknown)? {
86 load_from_port_file(f)
87 } else {
88 Err(Error::NotSpecified)
89 }
90}
91
92fn find_port_file() -> io::Result<Option<path::PathBuf>> {
93 let current_dir = path::PathBuf::from(".").canonicalize()?;
94 for dir in current_dir.ancestors() {
95 let mut path = path::PathBuf::from(dir);
96 path.push(".nrepl-port");
97 if path.is_file() {
98 return Ok(Some(path));
99 }
100 }
101 Ok(None)
102}
103
104fn load_from_port_file(
105 path: impl AsRef<path::Path>,
106) -> Result<ConnectionExpr, Error> {
107 let path = path.as_ref();
108 fs::read_to_string(path)
109 .map_err(|e| {
110 if e.kind() == io::ErrorKind::NotFound {
111 Error::NotFound(path.to_string_lossy().into())
112 } else {
113 Error::CannotReadFile(path.to_string_lossy().into())
114 }
115 })?
116 .trim()
117 .parse()
118 .map_err(|_| Error::CannotParsePortFile(path.to_string_lossy().into()))
119}