use super::{
Data, SchedulerClusterConfigBlockList, SchedulerClusterConfigDownloadBlockList,
SchedulerClusterConfigUploadBlockList,
};
use dragonfly_client_config::dfdaemon::Config;
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(Debug, Clone)]
pub struct DownloadBlockListCheckParams {
pub url: Option<String>,
pub application: Option<String>,
pub tag: Option<String>,
pub priority: Option<i32>,
}
#[derive(Debug, Clone)]
pub struct UploadBlockListCheckParams {
pub url: Option<String>,
pub application: Option<String>,
pub tag: Option<String>,
}
pub struct BlockList {
config: Arc<Config>,
data: Arc<RwLock<Data>>,
}
impl BlockList {
pub fn new(config: Arc<Config>, data: Arc<RwLock<Data>>) -> Self {
Self { config, data }
}
async fn with_block_list<F, R>(&self, f: F) -> Option<R>
where
F: FnOnce(&SchedulerClusterConfigBlockList) -> Option<R>,
{
let data = self.data.read().await;
let config = if self.config.seed_peer.enable {
data.seed_client_config
.as_ref()
.and_then(|config| config.block_list.as_ref())
} else {
data.client_config
.as_ref()
.and_then(|config| config.block_list.as_ref())
};
config.and_then(f)
}
pub async fn is_task_download_blocked(&self, params: &DownloadBlockListCheckParams) -> bool {
self.with_block_list(|block_list| {
let block_list = block_list.task.as_ref()?.download.as_ref()?;
Some(Self::is_download_blocked(block_list, params))
})
.await
.unwrap_or(false)
}
pub async fn is_persistent_task_download_blocked(
&self,
params: &DownloadBlockListCheckParams,
) -> bool {
self.with_block_list(|block_list| {
let block_list = block_list.persistent_task.as_ref()?.download.as_ref()?;
Some(Self::is_download_blocked(block_list, params))
})
.await
.unwrap_or(false)
}
pub async fn is_persistent_task_upload_blocked(
&self,
params: &UploadBlockListCheckParams,
) -> bool {
self.with_block_list(|block_list| {
let block_list = block_list.persistent_task.as_ref()?.upload.as_ref()?;
Some(Self::is_upload_blocked(block_list, params))
})
.await
.unwrap_or(false)
}
pub async fn is_persistent_cache_task_download_blocked(
&self,
params: &DownloadBlockListCheckParams,
) -> bool {
self.with_block_list(|block_list| {
let block_list = block_list
.persistent_cache_task
.as_ref()?
.download
.as_ref()?;
Some(Self::is_download_blocked(block_list, params))
})
.await
.unwrap_or(false)
}
pub async fn is_persistent_cache_task_upload_blocked(
&self,
params: &UploadBlockListCheckParams,
) -> bool {
self.with_block_list(|block_list| {
let block_list = block_list.persistent_cache_task.as_ref()?.upload.as_ref()?;
Some(Self::is_upload_blocked(block_list, params))
})
.await
.unwrap_or(false)
}
fn is_download_blocked(
block_list: &SchedulerClusterConfigDownloadBlockList,
params: &DownloadBlockListCheckParams,
) -> bool {
if let Some(url) = ¶ms.url {
if block_list
.urls
.iter()
.any(|blocked_url| blocked_url.is_match(url))
{
return true;
}
}
if let (Some(application), Some(blocked_applications)) =
(¶ms.application, &block_list.applications)
{
if blocked_applications.contains(application) {
return true;
}
}
if let (Some(tag), Some(blocked_tags)) = (¶ms.tag, &block_list.tags) {
if blocked_tags.contains(tag) {
return true;
}
}
if let (Some(priority), Some(blocked_priorities)) =
(¶ms.priority, &block_list.priorities)
{
if blocked_priorities.contains(priority) {
return true;
}
}
false
}
fn is_upload_blocked(
block_list: &SchedulerClusterConfigUploadBlockList,
params: &UploadBlockListCheckParams,
) -> bool {
if let Some(url) = ¶ms.url {
if block_list
.urls
.iter()
.any(|blocked_url| blocked_url.is_match(url))
{
return true;
}
}
if let (Some(application), Some(blocked_applications)) =
(¶ms.application, &block_list.applications)
{
if blocked_applications.contains(application) {
return true;
}
}
if let (Some(tag), Some(blocked_tags)) = (¶ms.tag, &block_list.tags) {
if blocked_tags.contains(tag) {
return true;
}
}
false
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dynconfig::{
SchedulerClusterClientConfig, SchedulerClusterConfigTaskBlockList,
SchedulerClusterSeedClientConfig,
};
use dragonfly_client_config::dfdaemon::SeedPeer;
use regex::Regex;
#[test]
fn is_download_blocked_matches_url_application_tag_or_priority() {
let test_cases = vec![
(
SchedulerClusterConfigDownloadBlockList {
applications: Some(vec!["blocked-app".to_string()]),
..Default::default()
},
None,
Some("blocked-app"),
None,
None,
true,
),
(
SchedulerClusterConfigDownloadBlockList {
applications: Some(vec!["blocked-app".to_string()]),
..Default::default()
},
None,
Some("allowed-app"),
None,
None,
false,
),
(
SchedulerClusterConfigDownloadBlockList {
applications: Some(vec!["blocked-app".to_string()]),
..Default::default()
},
None,
None,
None,
None,
false,
),
(
SchedulerClusterConfigDownloadBlockList {
urls: vec![
Regex::new(r".*\.blocked\.com.*").unwrap(),
Regex::new(r"^https://forbidden\.").unwrap(),
],
..Default::default()
},
Some("https://example.blocked.com/file"),
None,
None,
None,
true,
),
(
SchedulerClusterConfigDownloadBlockList {
urls: vec![
Regex::new(r".*\.blocked\.com.*").unwrap(),
Regex::new(r"^https://forbidden\.").unwrap(),
],
..Default::default()
},
Some("https://forbidden.example.com/file"),
None,
None,
None,
true,
),
(
SchedulerClusterConfigDownloadBlockList {
urls: vec![
Regex::new(r".*\.blocked\.com.*").unwrap(),
Regex::new(r"^https://forbidden\.").unwrap(),
],
..Default::default()
},
Some("https://allowed.com/file"),
None,
None,
None,
false,
),
(
SchedulerClusterConfigDownloadBlockList {
urls: vec![
Regex::new(r".*\.blocked\.com.*").unwrap(),
Regex::new(r"^https://forbidden\.").unwrap(),
],
..Default::default()
},
None,
None,
None,
None,
false,
),
(
SchedulerClusterConfigDownloadBlockList {
tags: Some(vec!["blocked-tag".to_string()]),
..Default::default()
},
None,
None,
Some("blocked-tag"),
None,
true,
),
(
SchedulerClusterConfigDownloadBlockList {
tags: Some(vec!["blocked-tag".to_string()]),
..Default::default()
},
None,
None,
Some("allowed-tag"),
None,
false,
),
(
SchedulerClusterConfigDownloadBlockList {
priorities: Some(vec![0]),
..Default::default()
},
None,
None,
None,
Some(0),
true,
),
(
SchedulerClusterConfigDownloadBlockList {
priorities: Some(vec![0]),
..Default::default()
},
None,
None,
None,
Some(5),
false,
),
(
SchedulerClusterConfigDownloadBlockList::default(),
Some("https://any.url.com"),
Some("any-app"),
Some("any-tag"),
Some(1),
false,
),
(
SchedulerClusterConfigDownloadBlockList {
applications: Some(vec!["blocked-app".to_string()]),
urls: vec![Regex::new(r"^https://forbidden\.").unwrap()],
tags: Some(vec!["blocked-tag".to_string()]),
priorities: Some(vec![0]),
},
Some("https://allowed.com/file"),
Some("allowed-app"),
Some("allowed-tag"),
Some(0),
true,
),
];
for (block_list, url, application, tag, priority, expected) in test_cases {
let params = DownloadBlockListCheckParams {
url: url.map(str::to_string),
application: application.map(str::to_string),
tag: tag.map(str::to_string),
priority,
};
assert_eq!(
BlockList::is_download_blocked(&block_list, ¶ms),
expected
);
}
}
#[test]
fn is_upload_blocked_matches_url_application_or_tag() {
let test_cases = vec![
(
SchedulerClusterConfigUploadBlockList {
applications: Some(vec!["blocked-app".to_string()]),
..Default::default()
},
None,
Some("blocked-app"),
None,
true,
),
(
SchedulerClusterConfigUploadBlockList {
applications: Some(vec!["blocked-app".to_string()]),
..Default::default()
},
None,
Some("allowed-app"),
None,
false,
),
(
SchedulerClusterConfigUploadBlockList {
urls: vec![Regex::new(r".*blocked.*").unwrap()],
..Default::default()
},
Some("https://blocked.com/upload"),
None,
None,
true,
),
(
SchedulerClusterConfigUploadBlockList {
urls: vec![Regex::new(r".*blocked.*").unwrap()],
..Default::default()
},
Some("https://allowed.com/upload"),
None,
None,
false,
),
(
SchedulerClusterConfigUploadBlockList {
tags: Some(vec!["blocked-tag".to_string()]),
..Default::default()
},
None,
None,
Some("blocked-tag"),
true,
),
(
SchedulerClusterConfigUploadBlockList {
tags: Some(vec!["blocked-tag".to_string()]),
..Default::default()
},
None,
None,
Some("allowed-tag"),
false,
),
(
SchedulerClusterConfigUploadBlockList::default(),
Some("https://any.url.com"),
Some("any-app"),
Some("any-tag"),
false,
),
(
SchedulerClusterConfigUploadBlockList {
applications: Some(vec!["blocked-app".to_string()]),
urls: vec![Regex::new(r".*blocked.*").unwrap()],
tags: Some(vec!["blocked-tag".to_string()]),
},
Some("https://allowed.com/upload"),
Some("allowed-app"),
Some("blocked-tag"),
true,
),
];
for (block_list, url, application, tag, expected) in test_cases {
let params = UploadBlockListCheckParams {
url: url.map(str::to_string),
application: application.map(str::to_string),
tag: tag.map(str::to_string),
};
assert_eq!(BlockList::is_upload_blocked(&block_list, ¶ms), expected);
}
}
#[tokio::test]
async fn is_task_download_blocked_reads_client_or_seed_client_config() {
let task_block_list = SchedulerClusterConfigBlockList {
task: Some(SchedulerClusterConfigTaskBlockList {
download: Some(SchedulerClusterConfigDownloadBlockList {
applications: Some(vec!["blocked-app".to_string()]),
..Default::default()
}),
}),
..Default::default()
};
let params = DownloadBlockListCheckParams {
url: None,
application: Some("blocked-app".to_string()),
tag: None,
priority: None,
};
let test_cases = vec![
(
false,
Some(SchedulerClusterClientConfig {
block_list: Some(task_block_list.clone()),
}),
None,
true,
),
(
true,
Some(SchedulerClusterClientConfig {
block_list: Some(task_block_list.clone()),
}),
None,
false,
),
(
true,
None,
Some(SchedulerClusterSeedClientConfig {
block_list: Some(task_block_list.clone()),
}),
true,
),
(
false,
None,
Some(SchedulerClusterSeedClientConfig {
block_list: Some(task_block_list.clone()),
}),
false,
),
(
false,
Some(SchedulerClusterClientConfig { block_list: None }),
None,
false,
),
(false, None, None, false),
];
for (seed_peer_enabled, client_config, seed_client_config, expected) in test_cases {
let config = Config {
seed_peer: SeedPeer {
enable: seed_peer_enabled,
..Default::default()
},
..Default::default()
};
let data = Data {
client_config: client_config.clone(),
seed_client_config: seed_client_config.clone(),
..Default::default()
};
let block_list = BlockList::new(Arc::new(config), Arc::new(RwLock::new(data)));
assert_eq!(block_list.is_task_download_blocked(¶ms).await, expected);
}
}
}