feat(sync): 云同步指向专用端口 apic.openless.top:9443 并补充服务端交接文档
- MarketplaceConfig 新增 cloud_sync_base_url:production 用同一市场主机的独立端口 9443,new() 默认同源以兼容本机假服务合同测试 - cloud_sync 改用 cloud_sync_url 生成 /me/sync 请求地址 - 新增生产同步地址合同测试(主机一致、端口 9443、HTTPS) - docs:cloud-sync.md 更新地址说明;新增 cloud-sync-server-handoff.md 交接文档(请求行为、状态码映射、验收清单)
This commit is contained in:
1 parent
00914cebc5
commit
110f1f631f
7 files changed
+153
-5
No files matched your search
@@ -154,7 +154,7 @@ impl CloudSyncService {
|
||||
body: Option<Vec<u8>>,
|
||||
token: &SecretValue,
|
||||
) -> Result<CloudSyncSnapshot, BackendError> {
|
||||
let url = self.marketplace.public_url("me/sync")?;
|
||||
let url = self.marketplace.cloud_sync_url("me/sync")?;
|
||||
let loopback = url.host_str().is_some_and(|host| {
|
||||
host == "localhost"
|
||||
|| host
|
||||
|
||||
@@ -267,7 +267,9 @@ pub use local_asr_service::{
|
||||
LocalAsrRuntimeLease, ModelPrepareProgressSink, ModelRuntimeAdapter, NativeModelState,
|
||||
StorageRebind,
|
||||
};
|
||||
pub use marketplace::{MarketplaceConfig, MARKETPLACE_BASE_URL, MARKETPLACE_GITHUB_TOKEN_ACCOUNT};
|
||||
pub use marketplace::{
|
||||
MarketplaceConfig, CLOUD_SYNC_BASE_URL, MARKETPLACE_BASE_URL, MARKETPLACE_GITHUB_TOKEN_ACCOUNT,
|
||||
};
|
||||
pub use model_store::{
|
||||
extract_archive_safely, merge_hf_tree_pages, merge_hf_tree_pages_with_base, model_mirror_base,
|
||||
parse_hf_tree_page, validate_model_path, validate_model_url, DownloadProgressSink,
|
||||
|
||||
@@ -20,10 +20,14 @@ use crate::{PreferencesStore, StylePack, StylePackStore};
|
||||
|
||||
pub const MARKETPLACE_GITHUB_TOKEN_ACCOUNT: &str = "github.oauth_token";
|
||||
pub const MARKETPLACE_BASE_URL: &str = "https://apic.openless.top";
|
||||
/// Cloud sync shares the marketplace host but runs on its own listener port;
|
||||
/// the sync service owner deploys TLS on this port.
|
||||
pub const CLOUD_SYNC_BASE_URL: &str = "https://apic.openless.top:9443";
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct MarketplaceConfig {
|
||||
pub base_url: reqwest::Url,
|
||||
pub cloud_sync_base_url: reqwest::Url,
|
||||
pub github_client_id: String,
|
||||
pub github_device_code_url: reqwest::Url,
|
||||
pub github_access_token_url: reqwest::Url,
|
||||
@@ -31,7 +35,17 @@ pub struct MarketplaceConfig {
|
||||
}
|
||||
|
||||
impl MarketplaceConfig {
|
||||
/// The cloud sync endpoint defaults to the given base URL so contract tests
|
||||
/// can point both services at one local mock; production pairs the
|
||||
/// marketplace host with the dedicated [`CLOUD_SYNC_BASE_URL`].
|
||||
pub fn new(base_url: impl AsRef<str>) -> Result<Self, BackendError> {
|
||||
Self::with_cloud_sync_base_url(base_url, None)
|
||||
}
|
||||
|
||||
pub fn with_cloud_sync_base_url(
|
||||
base_url: impl AsRef<str>,
|
||||
cloud_sync_base_url: Option<&str>,
|
||||
) -> Result<Self, BackendError> {
|
||||
let parse = |value: &str, name: &str| {
|
||||
reqwest::Url::parse(value).map_err(|_| {
|
||||
BackendError::new(
|
||||
@@ -46,6 +60,10 @@ impl MarketplaceConfig {
|
||||
.unwrap_or_else(|| "Ov23liyv3nEucG7oMHNE".into());
|
||||
Ok(Self {
|
||||
base_url: parse(base_url.as_ref(), "marketplace")?,
|
||||
cloud_sync_base_url: match cloud_sync_base_url {
|
||||
Some(value) => parse(value, "cloud sync")?,
|
||||
None => parse(base_url.as_ref(), "marketplace")?,
|
||||
},
|
||||
github_client_id,
|
||||
github_device_code_url: parse(
|
||||
"https://github.com/login/device/code",
|
||||
@@ -60,7 +78,8 @@ impl MarketplaceConfig {
|
||||
}
|
||||
|
||||
pub fn production() -> Self {
|
||||
Self::new(MARKETPLACE_BASE_URL).expect("built-in Marketplace URLs are valid")
|
||||
Self::with_cloud_sync_base_url(MARKETPLACE_BASE_URL, Some(CLOUD_SYNC_BASE_URL))
|
||||
.expect("built-in Marketplace URLs are valid")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +283,15 @@ impl MarketplaceService {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn cloud_sync_url(&self, path: &str) -> Result<reqwest::Url, BackendError> {
|
||||
self.config.cloud_sync_base_url.join(path).map_err(|_| {
|
||||
BackendError::new(
|
||||
BackendErrorCode::InvalidArgument,
|
||||
"invalid cloud sync request URL",
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
async fn send_with_retry<F>(&self, make: F) -> Result<reqwest::Response, BackendError>
|
||||
where
|
||||
F: Fn() -> reqwest::RequestBuilder,
|
||||
|
||||
@@ -456,3 +456,26 @@ async fn unsupported_server_auth_failures_and_logout_do_not_invent_success() {
|
||||
);
|
||||
assert_eq!(server.state.lock().unwrap().requests.len(), count);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn production_cloud_sync_targets_the_dedicated_port_on_the_marketplace_host() {
|
||||
let config = MarketplaceConfig::production();
|
||||
assert_eq!(
|
||||
config.cloud_sync_base_url,
|
||||
reqwest::Url::parse(openless_core::CLOUD_SYNC_BASE_URL).unwrap()
|
||||
);
|
||||
assert_eq!(
|
||||
config.cloud_sync_base_url.host_str(),
|
||||
config.base_url.host_str(),
|
||||
"cloud sync must stay on the marketplace host"
|
||||
);
|
||||
assert_eq!(config.cloud_sync_base_url.port(), Some(9443));
|
||||
assert_eq!(
|
||||
config.cloud_sync_base_url.scheme(),
|
||||
"https",
|
||||
"the production sync endpoint must be HTTPS"
|
||||
);
|
||||
// Contract tests point both services at one local mock through `new`.
|
||||
let local = MarketplaceConfig::new("http://127.0.0.1:8080/").unwrap();
|
||||
assert_eq!(local.cloud_sync_base_url.as_str(), "http://127.0.0.1:8080/");
|
||||
}
|
||||
Reference in new issue
Block a user