Skip to content

Commit

Permalink
Preferred instances (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
cofob authored Sep 1, 2024
1 parent 28ea5f9 commit bc3ef15
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ bottlenecks and rate-limiting.

- [x] Support for hidden networks (tor, i2p, etc).
- [x] Redirect behaviour can be configured. (for example - you can exclude cloudflare)
- [x] User-preferred instances.
- [x] POST redirects.
- [x] Regex redirects via `/{url}` routes.
- [x] Anonymous and cached redirects via `/@cached/#{path}` routes.
Expand Down
2 changes: 2 additions & 0 deletions fastside-shared/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ pub struct UserConfig {
pub select_method: SelectMethod,
#[serde(default)]
pub ignore_fallback_warning: bool,
#[serde(default)]
pub preferred_instances: Vec<String>,
}

impl UserConfig {
Expand Down
23 changes: 23 additions & 0 deletions fastside-shared/src/serde_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,29 @@ impl StoredData {
}
}

// Check if all URLs have host
{
for service in &self.services {
if let Some(fallback) = &service.fallback {
if fallback.host_str().is_none() {
results.add_warning(format!(
"Service {} has fallback URL without host",
service.name
));
}
}

for instance in &service.instances {
if instance.url.host_str().is_none() {
results.add_warning(format!(
"Service {} has instance URL without host",
service.name
));
}
}
}
}

results
}
}
1 change: 1 addition & 0 deletions fastside/src/routes/redirect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ async fn cached_redirect(
crawled_service,
&user_config.required_tags,
&user_config.forbidden_tags,
&user_config.preferred_instances,
)
.ok_or(RedirectError::from(SearchError::NoInstancesFound))?;
if user_config.select_method == SelectMethod::LowPing {
Expand Down
21 changes: 21 additions & 0 deletions fastside/src/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ pub fn get_redirect_instances<'a>(
crawled_service: &'a CrawledService,
required_tags: &[String],
forbidden_tags: &[String],
preferred_instances: &[String],
) -> Option<Vec<&'a CrawledInstance>> {
let alive_instances = crawled_service.get_alive_instances();
let instances = alive_instances
Expand All @@ -183,6 +184,25 @@ pub fn get_redirect_instances<'a>(
if instances.is_empty() {
return None;
}
let instances = if preferred_instances.is_empty() {
instances
} else {
// Filter out instances that are not in the preferred list.
let filtered_preferred_instances: Vec<_> = instances
.iter()
.filter(|i| {
let host = i.url.host_str().unwrap_or("");
preferred_instances.iter().any(|p| host == p)
})
.cloned()
.collect();
// If there are no preferred instances, return all instances.
if filtered_preferred_instances.is_empty() {
instances
} else {
filtered_preferred_instances
}
};
Some(instances)
}

Expand All @@ -197,6 +217,7 @@ pub fn get_redirect_instance(
crawled_service,
&user_config.required_tags,
&user_config.forbidden_tags,
&user_config.preferred_instances,
);
match &instances {
None => match &service.fallback {
Expand Down
44 changes: 43 additions & 1 deletion fastside/templates/configure.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ <h3>Ignore fallback warning</h3>
<input type="checkbox" id="ignore-fallback-warning" value="true">
</div>

<div>
<h3>Preferred instances</h3>
<input type="text" id="preferred-instance-input" placeholder="Add preferred instance">
<button onclick="addPreferred()">Add</button>
<ul id="preferred-instances-list"></ul>
</div>

<div>
<h3>Generated config</h3>
<textarea id="generated-json" readonly cols="80" rows="10"></textarea>
Expand All @@ -44,6 +51,7 @@ <h3>Generated config</h3>
required: [],
forbidden: []
};
let preferred = [];
let ignoreFallbackWarning = false;

document.addEventListener('DOMContentLoaded', () => {
Expand All @@ -57,9 +65,11 @@ <h3>Generated config</h3>
tags.required = decodedConfig.required_tags || [];
tags.forbidden = decodedConfig.forbidden_tags || [];
const selectorMethod = decodedConfig.select_method || 'Random';
preferred = decodedConfig.preferred_instances || [];

renderTags('required');
renderTags('forbidden');
renderPreferred();
if (selectorMethod) {
document.querySelector('input[name="selector-method"]:checked').checked = false;
document.querySelector(`input[name="selector-method"][value="${selectorMethod}"]`).checked = true;
Expand Down Expand Up @@ -101,13 +111,45 @@ <h3>Generated config</h3>
});
}

function addPreferred() {
const input = document.getElementById('preferred-instance-input');
const instance = input.value.trim();
if (instance && !preferred.includes(instance)) {
preferred.push(instance);
input.value = '';
renderPreferred();
generateJSON();
}
}

function removePreferred(index) {
preferred.splice(index, 1);
renderPreferred();
generateJSON();
}

function renderPreferred() {
const list = document.getElementById('preferred-instances-list');
list.innerHTML = '';
preferred.forEach((instance, index) => {
const li = document.createElement('li');
li.textContent = instance;
const removeButton = document.createElement('button');
removeButton.textContent = 'Remove';
removeButton.onclick = () => removePreferred(index);
li.appendChild(removeButton);
list.appendChild(li);
});
}

function generateJSON() {
const selectorMethod = document.querySelector('input[name="selector-method"]:checked')?.value || '';
const json = JSON.stringify({
required_tags: tags.required,
forbidden_tags: tags.forbidden,
select_method: selectorMethod,
ignore_fallback_warning: document.getElementById('ignore-fallback-warning').checked
ignore_fallback_warning: document.getElementById('ignore-fallback-warning').checked,
preferred_instances: preferred
});
const encoded = btoa(json);
document.getElementById('generated-json').value = `/configure/save?${encoded}`;
Expand Down

0 comments on commit bc3ef15

Please sign in to comment.