Skip to main content

wowlab_engine/cli/
resolver.rs

1use wowlab_engine_ports::DynDataResolver;
2use wowlab_fs::{
3    directory::{self, EntryKind},
4    path::{Path, PathBuf},
5};
6
7use super::CliError;
8
9pub(super) struct ResolverHandle {
10    pub resolver: Box<DynDataResolver<'static>>,
11    pub source: String,
12}
13
14pub(super) fn create(workspace_root: &Path) -> Result<ResolverHandle, CliError> {
15    #[cfg(feature = "supabase")]
16    {
17        if std::env::var("SUPABASE_URL").is_ok() {
18            let patch = std::env::var("WOWLAB_PATCH")
19                .unwrap_or_else(|_| wowlab_types::constants::DEFAULT_WOW_PATCH.to_string());
20
21            match create_supabase(&patch) {
22                Ok(resolver) => {
23                    return Ok(ResolverHandle {
24                        resolver: DynDataResolver::new_box(resolver),
25                        source: "supabase".to_string(),
26                    });
27                }
28                Err(e) => {
29                    tracing::warn!(error = %e, "Supabase initialization failed; using local data");
30                }
31            }
32        }
33    }
34
35    let data_dir = local_data_dir(workspace_root)?;
36    let source = format!("local ({data_dir})");
37
38    Ok(ResolverHandle {
39        resolver: DynDataResolver::new_box(wowlab_engine_adapter_data::LocalCsvResolver::new(
40            data_dir,
41        )),
42        source,
43    })
44}
45
46#[cfg(feature = "supabase")]
47fn create_supabase(patch: &str) -> Result<wowlab_engine_adapter_data::SupabaseResolver, CliError> {
48    let client = wowlab_supabase::SupabaseClient::from_env()?;
49    let cache_dir = wowlab_common::config_dir(
50        "WOWLAB",
51        wowlab_common::ProjectIdentity {
52            qualifier: "gg",
53            organization: "wowlab",
54            application: "wowlab-engine",
55        },
56    )
57    .map(|directory| directory.join("game-data"))
58    .ok_or_else(|| {
59        CliError::resolver(
60            "game-data cache directory is unavailable; set WOWLAB_CONFIG_DIR".to_string(),
61        )
62    })?;
63    let cache = wowlab_engine_adapter_data::GameDataCache::new(client, patch, cache_dir)?;
64
65    Ok(wowlab_engine_adapter_data::SupabaseResolver::new(cache))
66}
67
68fn local_data_dir(workspace_root: &Path) -> Result<PathBuf, CliError> {
69    let data_dir = match std::env::var("WOWLAB_DATA_DIR") {
70        Ok(dir) => PathBuf::from(dir),
71        Err(_) => default_data_dir(workspace_root).ok_or_else(|| {
72            CliError::resolver(
73                "could not derive the default game-data directory from the repo root. \
74                 Set WOWLAB_DATA_DIR to a local game-data directory"
75                    .to_string(),
76            )
77        })?,
78    };
79
80    if !directory::inspect(&data_dir)?.is_some_and(|entry| entry.kind() == EntryKind::Directory) {
81        return Err(CliError::resolver(format!(
82            "game-data directory '{data_dir}' does not exist. \
83             Set WOWLAB_DATA_DIR to a valid local game-data directory"
84        )));
85    }
86
87    Ok(data_dir)
88}
89
90fn default_data_dir(workspace_root: &Path) -> Option<PathBuf> {
91    workspace_root.parent().map(|root| root.join("wowlab-data"))
92}