Rebrand to Galaxy, major improvements to Bedrock support, still needs some TLC though
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::AppId;
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct ChannelConfig {
|
||||
/// The application ID for this channel.
|
||||
pub app_id: AppId,
|
||||
|
||||
/// The name of the file to which logs should be written.
|
||||
pub logfile_name: Cow<'static, str>,
|
||||
|
||||
/// Configuration for talking to Warp's servers.
|
||||
pub server_config: WarpServerConfig,
|
||||
/// Configuration for Oz/ambient agents.
|
||||
pub oz_config: OzConfig,
|
||||
/// Configuration for telemetry sending, or [`None`] if telemetry should be
|
||||
/// disabled for this build.
|
||||
pub telemetry_config: Option<TelemetryConfig>,
|
||||
/// Configuration for autoupdate functionality.
|
||||
pub autoupdate_config: Option<AutoupdateConfig>,
|
||||
/// Configuration for crash reporting.
|
||||
pub crash_reporting_config: Option<CrashReportingConfig>,
|
||||
/// Configuration for statically-bundled MCP OAuth credentials.
|
||||
pub mcp_static_config: Option<McpStaticConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct WarpServerConfig {
|
||||
/// The root URL for the standard server pool.
|
||||
pub server_root_url: Cow<'static, str>,
|
||||
/// The URL for the RTC server, which serves real-time updates for Warp Drive objects.
|
||||
pub rtc_server_url: Cow<'static, str>,
|
||||
/// The URL for the session sharing server, or [`None`] if session sharing is not
|
||||
/// supported.
|
||||
pub session_sharing_server_url: Option<Cow<'static, str>>,
|
||||
/// The API key to use when making requests to Firebase Authentication endpoints.
|
||||
pub firebase_auth_api_key: Cow<'static, str>,
|
||||
}
|
||||
|
||||
impl WarpServerConfig {
|
||||
pub fn production() -> Self {
|
||||
Self {
|
||||
server_root_url: "".into(),
|
||||
rtc_server_url: "".into(),
|
||||
session_sharing_server_url: None,
|
||||
firebase_auth_api_key: "".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct OzConfig {
|
||||
/// Root URL for the Oz (ambient agent management) dashboard.
|
||||
pub oz_root_url: Cow<'static, str>,
|
||||
|
||||
/// URL to use as the audience when issuing workload identity tokens. If [`None`], falls back
|
||||
/// to [`WarpServerConfig::server_root_url`]. This exists so the audience is not overridden
|
||||
/// when a custom server root URL is provided (e.g. an ngrok URL for local development).
|
||||
pub workload_audience_url: Option<Cow<'static, str>>,
|
||||
}
|
||||
|
||||
impl OzConfig {
|
||||
pub fn production() -> Self {
|
||||
Self {
|
||||
oz_root_url: "".into(),
|
||||
workload_audience_url: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct TelemetryConfig {
|
||||
/// The name of the file in which not-yet-sent telemetry events will be stored.
|
||||
pub telemetry_file_name: Cow<'static, str>,
|
||||
/// Configuration for Rudderstack, for reporting telemetry events.
|
||||
pub rudderstack_config: Option<RudderStackConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
pub struct RudderStackConfig {
|
||||
pub write_key: Cow<'static, str>,
|
||||
pub root_url: Cow<'static, str>,
|
||||
pub ugc_write_key: Cow<'static, str>,
|
||||
}
|
||||
|
||||
impl RudderStackConfig {
|
||||
pub fn non_ugc_destination(&self) -> RudderStackDestination {
|
||||
RudderStackDestination {
|
||||
root_url: self.root_url.clone(),
|
||||
write_key: self.write_key.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ugc_destination(&self) -> RudderStackDestination {
|
||||
RudderStackDestination {
|
||||
root_url: self.root_url.clone(),
|
||||
write_key: self.ugc_write_key.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RudderStackDestination {
|
||||
pub root_url: Cow<'static, str>,
|
||||
pub write_key: Cow<'static, str>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct AutoupdateConfig {
|
||||
/// The base URL for fetching autoupdate versions and updated release bundles.
|
||||
pub releases_base_url: Cow<'static, str>,
|
||||
/// Whether or not to display menu items relating to autoupdate.
|
||||
pub show_autoupdate_menu_items: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct CrashReportingConfig {
|
||||
/// The URL/DSN for sending error logs and crash reports to Sentry.
|
||||
pub sentry_url: Cow<'static, str>,
|
||||
}
|
||||
|
||||
/// Configuration for statically-bundled MCP OAuth credentials.
|
||||
///
|
||||
/// These are credentials for OAuth providers where dynamic client registration
|
||||
/// is not supported and we instead ship pre-registered client IDs and secrets.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct McpStaticConfig {
|
||||
/// Per-provider OAuth credentials.
|
||||
pub providers: Vec<McpOAuthProviderConfig>,
|
||||
}
|
||||
|
||||
/// A single OAuth provider's credentials for MCP authentication.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct McpOAuthProviderConfig {
|
||||
/// The issuer URL of the OAuth provider (e.g. `https://github.com/login/oauth`).
|
||||
pub issuer: Cow<'static, str>,
|
||||
/// The OAuth client ID registered for this channel.
|
||||
pub client_id: Cow<'static, str>,
|
||||
/// The OAuth client secret registered for this channel.
|
||||
pub client_secret: Cow<'static, str>,
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
mod config;
|
||||
mod state;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
pub use config::*;
|
||||
pub use state::*;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Channel {
|
||||
/// The official/first-party stable release.
|
||||
Stable,
|
||||
/// The official/first-party feature preview release.
|
||||
Preview,
|
||||
|
||||
/// The internal-only nightly build.
|
||||
Dev,
|
||||
/// The internal-only HEAD build.
|
||||
Local,
|
||||
|
||||
/// The open-source build of Warp.
|
||||
Oss,
|
||||
|
||||
/// The integration test build.
|
||||
Integration,
|
||||
}
|
||||
|
||||
impl Channel {
|
||||
/// Whether or not this channel is for internal use only
|
||||
pub fn is_dogfood(&self) -> bool {
|
||||
match self {
|
||||
Channel::Dev | Channel::Local => true,
|
||||
Channel::Stable | Channel::Preview | Channel::Integration | Channel::Oss => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether this channel honors the `--server-root-url` / `--ws-server-url` /
|
||||
/// `--session-sharing-server-url` flags (and their `WARP_*` env-var equivalents).
|
||||
///
|
||||
/// Release channels (`Stable`, `Preview`, `Oss`) ignore these overrides so shipped
|
||||
/// builds can't be redirected away from their baked-in server URLs. Internal-only channels
|
||||
/// (`Dev`, `Local`, `Integration`) continue to honor them for local development and testing.
|
||||
pub fn allows_server_url_overrides(&self) -> bool {
|
||||
match self {
|
||||
Channel::Dev | Channel::Local | Channel::Integration => true,
|
||||
Channel::Stable | Channel::Preview | Channel::Oss => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the CLI command name corresponding to this channel.
|
||||
pub fn cli_command_name(&self) -> &'static str {
|
||||
match self {
|
||||
Channel::Stable => "galaxy-ai",
|
||||
Channel::Dev => "galaxy-ai-dev",
|
||||
Channel::Preview => "galaxy-ai-preview",
|
||||
Channel::Local => "galaxy-ai-local",
|
||||
Channel::Integration => "galaxy-ai-integration",
|
||||
Channel::Oss => "galaxy-ai-oss",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Channel {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
Channel::Stable => "stable",
|
||||
Channel::Preview => "preview",
|
||||
Channel::Dev => "dev",
|
||||
Channel::Integration => "integration",
|
||||
Channel::Local => "local",
|
||||
Channel::Oss => "warp-oss",
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
use lazy_static::lazy_static;
|
||||
use parking_lot::Mutex;
|
||||
use std::{borrow::Cow, collections::HashSet};
|
||||
use url::{Origin, ParseError, Url};
|
||||
|
||||
use crate::AppId;
|
||||
use crate::{
|
||||
channel::config::{
|
||||
ChannelConfig, McpOAuthProviderConfig, OzConfig, RudderStackDestination, WarpServerConfig,
|
||||
},
|
||||
features::FeatureFlag,
|
||||
};
|
||||
|
||||
use super::Channel;
|
||||
|
||||
lazy_static! {
|
||||
static ref CHANNEL_STATE: Mutex<ChannelState> = Mutex::new(ChannelState::init());
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-util")]
|
||||
lazy_static! {
|
||||
static ref MOCK_SERVER: mockito::ServerGuard = mockito::Server::new();
|
||||
static ref MOCK_SERVER_URL: String = MOCK_SERVER.url();
|
||||
static ref APP_VERSION: Mutex<Option<&'static str>> = Mutex::new(None);
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ChannelState {
|
||||
channel: Channel,
|
||||
|
||||
/// The set of additional features to enable (on top of default-enabled ones).
|
||||
additional_features: HashSet<FeatureFlag>,
|
||||
|
||||
config: ChannelConfig,
|
||||
}
|
||||
|
||||
impl ChannelState {
|
||||
pub fn init() -> Self {
|
||||
let channel = Channel::Oss;
|
||||
let app_id = AppId::new("dev", "warp", "WarpOss");
|
||||
Self {
|
||||
channel,
|
||||
additional_features: Default::default(),
|
||||
config: ChannelConfig {
|
||||
app_id,
|
||||
logfile_name: "".into(),
|
||||
server_config: WarpServerConfig::production(),
|
||||
oz_config: OzConfig::production(),
|
||||
telemetry_config: None,
|
||||
autoupdate_config: None,
|
||||
crash_reporting_config: None,
|
||||
mcp_static_config: None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(channel: Channel, mut config: ChannelConfig) -> Self {
|
||||
if let Some(app_id) = app_id_from_bundle() {
|
||||
config.app_id = app_id;
|
||||
}
|
||||
Self {
|
||||
channel,
|
||||
additional_features: Default::default(),
|
||||
config,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_additional_features(mut self, overrides: &[FeatureFlag]) -> Self {
|
||||
self.additional_features.extend(overrides);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set(state: ChannelState) {
|
||||
*CHANNEL_STATE.lock() = state;
|
||||
}
|
||||
|
||||
pub fn is_release_bundle() -> bool {
|
||||
cfg!(feature = "release_bundle")
|
||||
}
|
||||
|
||||
pub fn enable_debug_features() -> bool {
|
||||
cfg!(debug_assertions) || matches!(Self::channel(), Channel::Local | Channel::Dev)
|
||||
}
|
||||
|
||||
pub fn override_server_root_url(url: impl Into<Cow<'static, str>>) -> Result<(), ParseError> {
|
||||
let url = url.into();
|
||||
Url::parse(&url)?;
|
||||
CHANNEL_STATE.lock().config.server_config.server_root_url = url;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn override_ws_server_url(url: impl Into<Cow<'static, str>>) -> Result<(), ParseError> {
|
||||
let url = url.into();
|
||||
Url::parse(&url)?;
|
||||
CHANNEL_STATE.lock().config.server_config.rtc_server_url = url;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn override_session_sharing_server_url(
|
||||
url: impl Into<Cow<'static, str>>,
|
||||
) -> Result<(), ParseError> {
|
||||
let url = url.into();
|
||||
Url::parse(&url)?;
|
||||
CHANNEL_STATE
|
||||
.lock()
|
||||
.config
|
||||
.server_config
|
||||
.session_sharing_server_url = Some(url);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn uses_staging_server() -> bool {
|
||||
let Ok(url) = Url::parse(Self::server_root_url().as_ref()) else {
|
||||
return false;
|
||||
};
|
||||
url.host_str() == Some("staging.warp.dev")
|
||||
}
|
||||
|
||||
/// Returns the canonical identifier for the application.
|
||||
///
|
||||
/// This should not be used for namespacing persisted data - such use cases
|
||||
/// should make use of [`Self::data_domain`] instead.
|
||||
pub fn app_id() -> AppId {
|
||||
CHANNEL_STATE.lock().config.app_id.clone()
|
||||
}
|
||||
|
||||
/// Returns a profile name for isolating user data. This should be used to
|
||||
/// sandbox how user data is stored.
|
||||
///
|
||||
/// This is a debugging tool for isolating development instances of Warp, and is not
|
||||
/// supported in release builds.
|
||||
pub fn data_profile() -> Option<String> {
|
||||
if cfg!(debug_assertions) {
|
||||
std::env::var("WARP_DATA_PROFILE").ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a value that should be used for namespacing persisted data.
|
||||
///
|
||||
/// In release builds, this is identical to the app ID; in debug builds,
|
||||
/// it optionally includes a suffix derived from the `WARP_DATA_PROFILE`
|
||||
/// environment variable.
|
||||
pub fn data_domain() -> String {
|
||||
match Self::data_profile() {
|
||||
Some(profile) => format!("{}-{profile}", Self::app_id()),
|
||||
None => Self::app_id().to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the data domain if overridden from the default, otherwise None.
|
||||
pub fn data_domain_if_not_default() -> Option<String> {
|
||||
Self::data_profile().map(|_| Self::data_domain())
|
||||
}
|
||||
|
||||
pub fn additional_features() -> HashSet<FeatureFlag> {
|
||||
CHANNEL_STATE
|
||||
.lock()
|
||||
.additional_features
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn debug_str() -> String {
|
||||
format!("{:?}", *CHANNEL_STATE.lock())
|
||||
}
|
||||
|
||||
pub fn logfile_name() -> Cow<'static, str> {
|
||||
CHANNEL_STATE.lock().config.logfile_name.clone()
|
||||
}
|
||||
|
||||
pub fn telemetry_file_name() -> Cow<'static, str> {
|
||||
CHANNEL_STATE
|
||||
.lock()
|
||||
.config
|
||||
.telemetry_config
|
||||
.as_ref()
|
||||
.map(|tc| tc.telemetry_file_name.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Returns whether this build has a telemetry config and can therefore ship
|
||||
/// telemetry events. Builds like OpenWarp intentionally ship with
|
||||
/// `telemetry_config: None`, in which case UI that controls telemetry
|
||||
/// should be hidden since the toggle has no effect.
|
||||
pub fn is_telemetry_available() -> bool {
|
||||
CHANNEL_STATE.lock().config.telemetry_config.is_some()
|
||||
}
|
||||
|
||||
/// Returns whether this build has a crash reporting config and can therefore
|
||||
/// ship crash reports. Builds like OpenWarp intentionally ship with
|
||||
/// `crash_reporting_config: None`, in which case UI that controls crash
|
||||
/// reporting should be hidden since the toggle has no effect.
|
||||
pub fn is_crash_reporting_available() -> bool {
|
||||
CHANNEL_STATE.lock().config.crash_reporting_config.is_some()
|
||||
}
|
||||
|
||||
pub fn releases_base_url() -> Cow<'static, str> {
|
||||
CHANNEL_STATE
|
||||
.lock()
|
||||
.config
|
||||
.autoupdate_config
|
||||
.as_ref()
|
||||
.map(|ac| ac.releases_base_url.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn firebase_api_key() -> Cow<'static, str> {
|
||||
CHANNEL_STATE
|
||||
.lock()
|
||||
.config
|
||||
.server_config
|
||||
.firebase_auth_api_key
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn ws_server_url() -> Cow<'static, str> {
|
||||
CHANNEL_STATE
|
||||
.lock()
|
||||
.config
|
||||
.server_config
|
||||
.rtc_server_url
|
||||
.clone()
|
||||
}
|
||||
|
||||
/// Returns the HTTP(S) root URL for the RTC server. Used for HTTP endpoints
|
||||
/// served by warp-server-rtc (e.g. the agent event SSE stream).
|
||||
///
|
||||
/// Derived from [`ws_server_url`] by rewriting the scheme (`wss`→`https`,
|
||||
/// `ws`→`http`) and stripping the path. Falls back to [`server_root_url`]
|
||||
/// when the WS URL cannot be parsed or uses an unexpected scheme — this
|
||||
/// keeps override paths (e.g. `WARP_WS_SERVER_URL=...`) working without a
|
||||
/// separate override for the HTTP variant.
|
||||
pub fn rtc_http_url() -> Cow<'static, str> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "test-util")] {
|
||||
Cow::Owned(MOCK_SERVER_URL.clone())
|
||||
} else {
|
||||
match derive_http_origin_from_ws_url(&Self::ws_server_url()) {
|
||||
Some(origin) => Cow::Owned(origin),
|
||||
None => Self::server_root_url(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn session_sharing_server_url() -> Option<Cow<'static, str>> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "test-util")] {
|
||||
Some(Cow::Borrowed("fake_session_sharing_url"))
|
||||
} else {
|
||||
CHANNEL_STATE.lock().config.server_config.session_sharing_server_url.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn oz_root_url() -> Cow<'static, str> {
|
||||
CHANNEL_STATE.lock().config.oz_config.oz_root_url.clone()
|
||||
}
|
||||
|
||||
pub fn server_root_url() -> Cow<'static, str> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(feature = "test-util")] {
|
||||
Cow::Owned(MOCK_SERVER_URL.clone())
|
||||
} else {
|
||||
CHANNEL_STATE.lock().config.server_config.server_root_url.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn workload_audience_url() -> Cow<'static, str> {
|
||||
let state = CHANNEL_STATE.lock();
|
||||
match &state.config.oz_config.workload_audience_url {
|
||||
Some(url) => url.clone(),
|
||||
None => {
|
||||
drop(state);
|
||||
Self::server_root_url()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the origin url, with scheme, domain, and ports (if any)
|
||||
pub fn server_root_domain() -> Origin {
|
||||
Url::parse(&Self::server_root_url())
|
||||
.unwrap_or_else(|_| Url::parse("http://localhost").unwrap())
|
||||
.origin()
|
||||
}
|
||||
|
||||
/// Returns the rudderstack destination for all events that don't contain user-generated content.
|
||||
pub fn rudderstack_non_ugc_destination() -> RudderStackDestination {
|
||||
let state = CHANNEL_STATE.lock();
|
||||
|
||||
state
|
||||
.config
|
||||
.telemetry_config
|
||||
.as_ref()
|
||||
.and_then(|tc| tc.rudderstack_config.as_ref())
|
||||
.map(|rs| rs.non_ugc_destination())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Returns the rudderstack destination for all events that contain user-generated content.
|
||||
pub fn rudderstack_ugc_destination() -> RudderStackDestination {
|
||||
let state = CHANNEL_STATE.lock();
|
||||
|
||||
state
|
||||
.config
|
||||
.telemetry_config
|
||||
.as_ref()
|
||||
.and_then(|tc| tc.rudderstack_config.as_ref())
|
||||
.map(|rs| rs.ugc_destination())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn channel() -> Channel {
|
||||
CHANNEL_STATE.lock().channel
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-util")]
|
||||
pub fn app_version() -> Option<&'static str> {
|
||||
let version = APP_VERSION.lock();
|
||||
|
||||
version.or_else(|| option_env!("GIT_RELEASE_TAG"))
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-util")]
|
||||
pub fn set_app_version(version: Option<&'static str>) {
|
||||
*APP_VERSION.lock() = version;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "test-util"))]
|
||||
pub fn app_version() -> Option<&'static str> {
|
||||
option_env!("GIT_RELEASE_TAG")
|
||||
}
|
||||
|
||||
pub fn sentry_url() -> Cow<'static, str> {
|
||||
CHANNEL_STATE
|
||||
.lock()
|
||||
.config
|
||||
.crash_reporting_config
|
||||
.as_ref()
|
||||
.map(|crc| crc.sentry_url.clone())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub fn show_autoupdate_menu_items() -> bool {
|
||||
CHANNEL_STATE
|
||||
.lock()
|
||||
.config
|
||||
.autoupdate_config
|
||||
.as_ref()
|
||||
.map(|ac| ac.show_autoupdate_menu_items)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Returns the MCP OAuth provider config matching the given client ID, if any.
|
||||
pub fn mcp_oauth_provider_by_client_id(client_id: &str) -> Option<McpOAuthProviderConfig> {
|
||||
CHANNEL_STATE
|
||||
.lock()
|
||||
.config
|
||||
.mcp_static_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.providers.iter().find(|p| p.client_id == client_id))
|
||||
.cloned()
|
||||
}
|
||||
|
||||
/// Returns the MCP OAuth provider config matching the given issuer URL, if any.
|
||||
pub fn mcp_oauth_provider_by_issuer(issuer: &str) -> Option<McpOAuthProviderConfig> {
|
||||
CHANNEL_STATE
|
||||
.lock()
|
||||
.config
|
||||
.mcp_static_config
|
||||
.as_ref()
|
||||
.and_then(|c| c.providers.iter().find(|p| p.issuer == issuer))
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub fn url_scheme() -> &'static str {
|
||||
match Self::channel() {
|
||||
Channel::Stable => "warp",
|
||||
Channel::Preview => "warppreview",
|
||||
Channel::Dev => "warpdev",
|
||||
// Dummy value--integration tests shouldn't support URL schemes.
|
||||
Channel::Integration => "warpintegration",
|
||||
Channel::Local => "warplocal",
|
||||
Channel::Oss => "warposs",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Derives an HTTP(S) origin URL from a WebSocket URL by rewriting the scheme
|
||||
/// (`wss`→`https`, `ws`→`http`) and stripping the path, query, and fragment.
|
||||
/// Returns [`None`] when the input cannot be parsed as a URL or uses a scheme
|
||||
/// other than `ws` or `wss`.
|
||||
#[cfg(not(feature = "test-util"))]
|
||||
fn derive_http_origin_from_ws_url(ws_url: &str) -> Option<String> {
|
||||
let url = Url::parse(ws_url).ok()?;
|
||||
let http_scheme = match url.scheme() {
|
||||
"wss" => "https",
|
||||
"ws" => "http",
|
||||
_ => return None,
|
||||
};
|
||||
let host = url.host_str()?;
|
||||
let mut origin = format!("{http_scheme}://{host}");
|
||||
if let Some(port) = url.port() {
|
||||
origin.push_str(&format!(":{port}"));
|
||||
}
|
||||
Some(origin)
|
||||
}
|
||||
|
||||
#[cfg(all(test, not(feature = "test-util")))]
|
||||
#[path = "state_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
fn app_id_from_bundle() -> Option<AppId> {
|
||||
// On macOS, attempt to determine the app ID from the containing bundle,
|
||||
// falling back to the channel-keyed "default" ID if we cannot retrieve
|
||||
// bundle information.
|
||||
//
|
||||
// We skip this for tests, as the call to `mainBundle` can take 30+ms,
|
||||
// which is a significant portion of the total test runtime.
|
||||
#[cfg(all(target_os = "macos", not(feature = "test-util")))]
|
||||
#[allow(deprecated)]
|
||||
unsafe {
|
||||
use cocoa::{
|
||||
base::{id, nil},
|
||||
foundation::NSBundle,
|
||||
};
|
||||
use objc::{msg_send, sel, sel_impl};
|
||||
use galaxyui::platform::mac::utils::nsstring_as_str;
|
||||
|
||||
let bundle = id::mainBundle();
|
||||
if bundle != nil {
|
||||
let nsstring: id = msg_send![bundle, bundleIdentifier];
|
||||
if nsstring != nil {
|
||||
let app_id = nsstring_as_str(nsstring)
|
||||
.expect("bundle IDs should always be valid UTF-8 strings");
|
||||
|
||||
if !app_id.is_empty() {
|
||||
return Some(
|
||||
AppId::parse(app_id)
|
||||
.expect("macOS bundle identifier has an unexpected format"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
use super::derive_http_origin_from_ws_url;
|
||||
|
||||
#[test]
|
||||
fn wss_becomes_https_and_strips_path() {
|
||||
let got = derive_http_origin_from_ws_url("wss://rtc.app.warp.dev/graphql/v2");
|
||||
assert_eq!(got.as_deref(), Some("https://rtc.app.warp.dev"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ws_becomes_http_and_preserves_port() {
|
||||
let got = derive_http_origin_from_ws_url("ws://localhost:8080/graphql/v2");
|
||||
assert_eq!(got.as_deref(), Some("http://localhost:8080"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unparseable_input_returns_none() {
|
||||
assert!(derive_http_origin_from_ws_url("not a url").is_none());
|
||||
assert!(derive_http_origin_from_ws_url("https://app.warp.dev").is_none());
|
||||
}
|
||||
Reference in New Issue
Block a user