Implement Nexus integration #54
3 changed files with 81 additions and 9 deletions
|
@ -27,12 +27,25 @@ pub(crate) async fn import_mod(state: ActionState, info: FileInfo) -> Result<Mod
|
||||||
.wrap_err_with(|| format!("Failed to read file {}", info.path.display()))?;
|
.wrap_err_with(|| format!("Failed to read file {}", info.path.display()))?;
|
||||||
let data = Cursor::new(data);
|
let data = Cursor::new(data);
|
||||||
|
|
||||||
let nexus = info
|
let nexus = if let Some((_, id, _, _)) = info
|
||||||
.path
|
.path
|
||||||
.file_name()
|
.file_name()
|
||||||
.and_then(|s| s.to_str())
|
.and_then(|s| s.to_str())
|
||||||
.and_then(NexusApi::parse_file_name)
|
.and_then(NexusApi::parse_file_name)
|
||||||
.map(|(_, id, version, _)| NexusInfo { id, version });
|
{
|
||||||
|
if !state.nexus_api_key.is_empty() {
|
||||||
|
let api = NexusApi::new(state.nexus_api_key.to_string())?;
|
||||||
|
let mod_info = api
|
||||||
|
.mods_id(id)
|
||||||
|
.await
|
||||||
|
.wrap_err_with(|| format!("Failed to query mod {} from Nexus", id))?;
|
||||||
|
Some(NexusInfo::from(mod_info))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let mut archive = ZipArchive::new(data).wrap_err("Failed to open ZIP archive")?;
|
let mut archive = ZipArchive::new(data).wrap_err("Failed to open ZIP archive")?;
|
||||||
|
|
||||||
|
@ -375,13 +388,8 @@ async fn check_mod_update(info: Arc<ModInfo>, api: Arc<NexusApi>) -> Result<Opti
|
||||||
.await
|
.await
|
||||||
.wrap_err_with(|| format!("Failed to query mod {} from Nexus", nexus.id))?;
|
.wrap_err_with(|| format!("Failed to query mod {} from Nexus", nexus.id))?;
|
||||||
|
|
||||||
let updated_nexus = NexusInfo {
|
|
||||||
id: nexus.id,
|
|
||||||
version: updated_info.version,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut info = Arc::unwrap_or_clone(info);
|
let mut info = Arc::unwrap_or_clone(info);
|
||||||
info.nexus = Some(updated_nexus);
|
info.nexus = Some(NexusInfo::from(updated_info));
|
||||||
|
|
||||||
Ok(Some(info))
|
Ok(Some(info))
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::sync::Arc;
|
||||||
use druid::im::{HashMap, Vector};
|
use druid::im::{HashMap, Vector};
|
||||||
use druid::{Data, ImageBuf, Lens, WindowHandle, WindowId};
|
use druid::{Data, ImageBuf, Lens, WindowHandle, WindowId};
|
||||||
use dtmt_shared::ModConfig;
|
use dtmt_shared::ModConfig;
|
||||||
|
use nexusmods::Mod as NexusMod;
|
||||||
|
|
||||||
use super::SelectedModLens;
|
use super::SelectedModLens;
|
||||||
|
|
||||||
|
@ -72,6 +73,21 @@ impl From<dtmt_shared::ModDependency> for ModDependency {
|
||||||
pub(crate) struct NexusInfo {
|
pub(crate) struct NexusInfo {
|
||||||
pub id: u64,
|
pub id: u64,
|
||||||
pub version: String,
|
pub version: String,
|
||||||
|
pub author: String,
|
||||||
|
pub summary: String,
|
||||||
|
pub description: Arc<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<NexusMod> for NexusInfo {
|
||||||
|
fn from(value: NexusMod) -> Self {
|
||||||
|
Self {
|
||||||
|
id: value.mod_id,
|
||||||
|
version: value.version,
|
||||||
|
author: value.author,
|
||||||
|
summary: value.summary,
|
||||||
|
description: Arc::new(value.description),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Data, Debug, Lens)]
|
#[derive(Clone, Data, Debug, Lens)]
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||||
use druid::im::Vector;
|
use druid::im::Vector;
|
||||||
use druid::{Data, Lens};
|
use druid::{Data, Lens};
|
||||||
|
|
||||||
use super::{ModInfo, State};
|
use super::{ModInfo, NexusInfo, State};
|
||||||
|
|
||||||
pub(crate) struct SelectedModLens;
|
pub(crate) struct SelectedModLens;
|
||||||
|
|
||||||
|
@ -73,3 +73,51 @@ impl<T: Data> Lens<Vector<T>, Vector<(usize, T)>> for IndexedVectorLens {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A Lens that first checks a key in a mod's `NexusInfo`, then falls back to
|
||||||
|
/// the regular one.
|
||||||
|
pub(crate) struct NexusInfoLens<T, L, R>
|
||||||
|
where
|
||||||
|
L: Lens<NexusInfo, T>,
|
||||||
|
R: Lens<ModInfo, T>,
|
||||||
|
{
|
||||||
|
value: L,
|
||||||
|
fallback: R,
|
||||||
|
_marker: std::marker::PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Data, L, R> NexusInfoLens<T, L, R>
|
||||||
|
where
|
||||||
|
L: Lens<NexusInfo, T>,
|
||||||
|
R: Lens<ModInfo, T>,
|
||||||
|
{
|
||||||
|
pub fn new(value: L, fallback: R) -> Self {
|
||||||
|
Self {
|
||||||
|
value,
|
||||||
|
fallback,
|
||||||
|
_marker: std::marker::PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Data, L, R> Lens<ModInfo, T> for NexusInfoLens<T, L, R>
|
||||||
|
where
|
||||||
|
L: Lens<NexusInfo, T>,
|
||||||
|
R: Lens<ModInfo, T>,
|
||||||
|
{
|
||||||
|
fn with<V, F: FnOnce(&T) -> V>(&self, data: &ModInfo, f: F) -> V {
|
||||||
|
if let Some(nexus) = &data.nexus {
|
||||||
|
self.value.with(nexus, f)
|
||||||
|
} else {
|
||||||
|
self.fallback.with(data, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with_mut<V, F: FnOnce(&mut T) -> V>(&self, data: &mut ModInfo, f: F) -> V {
|
||||||
|
if let Some(nexus) = &mut data.nexus {
|
||||||
|
self.value.with_mut(nexus, f)
|
||||||
|
} else {
|
||||||
|
self.fallback.with_mut(data, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue