1 use std
::collections
::HashMap
;
2 use std
::path
::PathBuf
;
3 use std
::time
::SystemTime
;
7 use anyhow
::{bail, Error, format_err}
;
9 use handlebars
::Handlebars
;
12 use proxmox
::api
::{ApiMethod, Router, RpcEnvironmentType}
;
14 pub struct ApiConfig
{
16 router
: &'
static Router
,
17 aliases
: HashMap
<String
, PathBuf
>,
18 env_type
: RpcEnvironmentType
,
19 templates
: RwLock
<Handlebars
<'
static>>,
20 template_files
: RwLock
<HashMap
<String
, (SystemTime
, PathBuf
)>>,
25 pub fn new
<B
: Into
<PathBuf
>>(basedir
: B
, router
: &'
static Router
, env_type
: RpcEnvironmentType
) -> Result
<Self, Error
> {
27 basedir
: basedir
.into(),
29 aliases
: HashMap
::new(),
31 templates
: RwLock
::new(Handlebars
::new()),
32 template_files
: RwLock
::new(HashMap
::new()),
40 uri_param
: &mut HashMap
<String
, String
>,
41 ) -> Option
<&'
static ApiMethod
> {
43 self.router
.find_method(components
, method
, uri_param
)
46 pub fn find_alias(&self, components
: &[&str]) -> PathBuf
{
48 let mut prefix
= String
::new();
49 let mut filename
= self.basedir
.clone();
50 let comp_len
= components
.len();
52 prefix
.push_str(components
[0]);
53 if let Some(subdir
) = self.aliases
.get(&prefix
) {
54 filename
.push(subdir
);
55 for i
in 1..comp_len { filename.push(components[i]) }
57 for i
in 0..comp_len { filename.push(components[i]) }
63 pub fn add_alias
<S
, P
>(&mut self, alias
: S
, path
: P
)
64 where S
: Into
<String
>,
67 self.aliases
.insert(alias
.into(), path
.into());
70 pub fn env_type(&self) -> RpcEnvironmentType
{
74 pub fn register_template
<P
>(&self, name
: &str, path
: P
) -> Result
<(), Error
>
78 if self.template_files
.read().unwrap().contains_key(name
) {
79 bail
!("template already registered");
82 let path
: PathBuf
= path
.into();
83 let metadata
= metadata(&path
)?
;
84 let mtime
= metadata
.modified()?
;
86 self.templates
.write().unwrap().register_template_file(name
, &path
)?
;
87 self.template_files
.write().unwrap().insert(name
.to_string(), (mtime
, path
));
92 /// Checks if the template was modified since the last rendering
93 /// if yes, it loads a the new version of the template
94 pub fn render_template
<T
>(&self, name
: &str, data
: &T
) -> Result
<String
, Error
>
101 let template_files
= self.template_files
.read().unwrap();
102 let (old_mtime
, old_path
) = template_files
.get(name
).ok_or_else(|| format_err
!("template not found"))?
;
104 mtime
= metadata(old_path
)?
.modified()?
;
105 if mtime
<= *old_mtime
{
106 return self.templates
.read().unwrap().render(name
, data
).map_err(|err
| format_err
!("{}", err
));
108 path
= old_path
.to_path_buf();
112 let mut template_files
= self.template_files
.write().unwrap();
113 let mut templates
= self.templates
.write().unwrap();
115 templates
.register_template_file(name
, &path
)?
;
116 template_files
.insert(name
.to_string(), (mtime
, path
));
118 templates
.render(name
, data
).map_err(|err
| format_err
!("{}", err
))