2023-11-24 03:54:47 +00:00
import ' package:appflowy/core/config/kv.dart ' ;
import ' package:appflowy/core/config/kv_keys.dart ' ;
import ' package:appflowy/env/backend_env.dart ' ;
2023-11-28 02:54:31 +00:00
import ' package:appflowy/env/env.dart ' ;
2023-08-03 00:48:04 +00:00
import ' package:appflowy/startup/startup.dart ' ;
2023-10-02 09:22:22 +00:00
import ' package:appflowy_backend/log.dart ' ;
2023-11-24 03:54:47 +00:00
import ' package:dartz/dartz.dart ' ;
2023-05-21 10:53:59 +00:00
2023-11-24 03:54:47 +00:00
/// Sets the cloud type for the application.
///
/// This method updates the cloud type setting in the key-value storage
/// using the [KeyValueStorage] service. The cloud type is identified
2023-11-28 02:54:31 +00:00
/// by the [AuthenticatorType] enum.
2023-11-24 03:54:47 +00:00
///
/// [ty] - The type of cloud to be set. It must be one of the values from
2023-11-28 02:54:31 +00:00
/// [AuthenticatorType] enum. The corresponding integer value of the enum is stored:
2023-11-24 03:54:47 +00:00
/// - `CloudType.local` is stored as "0".
/// - `CloudType.supabase` is stored as "1".
/// - `CloudType.appflowyCloud` is stored as "2".
2023-11-28 02:54:31 +00:00
Future < void > setAuthenticatorType ( AuthenticatorType ty ) async {
2023-11-24 03:54:47 +00:00
switch ( ty ) {
2023-11-28 02:54:31 +00:00
case AuthenticatorType . local:
2023-11-24 03:54:47 +00:00
getIt < KeyValueStorage > ( ) . set ( KVKeys . kCloudType , 0. toString ( ) ) ;
break ;
2023-11-28 02:54:31 +00:00
case AuthenticatorType . supabase:
2023-11-24 03:54:47 +00:00
getIt < KeyValueStorage > ( ) . set ( KVKeys . kCloudType , 1. toString ( ) ) ;
break ;
2023-11-28 02:54:31 +00:00
case AuthenticatorType . appflowyCloud:
2023-11-24 03:54:47 +00:00
getIt < KeyValueStorage > ( ) . set ( KVKeys . kCloudType , 2. toString ( ) ) ;
break ;
}
}
2023-05-21 10:53:59 +00:00
2023-11-24 03:54:47 +00:00
/// Retrieves the currently set cloud type.
///
/// This method fetches the cloud type setting from the key-value storage
/// using the [KeyValueStorage] service and returns the corresponding
2023-11-28 02:54:31 +00:00
/// [AuthenticatorType] enum value.
2023-11-24 03:54:47 +00:00
///
/// Returns:
2023-11-28 02:54:31 +00:00
/// A Future that resolves to a [AuthenticatorType] enum value representing the
2023-11-24 03:54:47 +00:00
/// currently set cloud type. The default return value is `CloudType.local`
/// if no valid setting is found.
2023-07-05 12:57:09 +00:00
///
2023-11-28 02:54:31 +00:00
Future < AuthenticatorType > getAuthenticatorType ( ) async {
2023-11-24 03:54:47 +00:00
final value = await getIt < KeyValueStorage > ( ) . get ( KVKeys . kCloudType ) ;
2023-11-28 02:54:31 +00:00
return value . fold ( ( ) = > AuthenticatorType . local , ( s ) {
2023-11-24 03:54:47 +00:00
switch ( s ) {
case " 0 " :
2023-11-28 02:54:31 +00:00
return AuthenticatorType . local ;
2023-11-24 03:54:47 +00:00
case " 1 " :
2023-11-28 02:54:31 +00:00
return AuthenticatorType . supabase ;
2023-11-24 03:54:47 +00:00
case " 2 " :
2023-11-28 02:54:31 +00:00
return AuthenticatorType . appflowyCloud ;
2023-11-24 03:54:47 +00:00
default :
2023-11-28 02:54:31 +00:00
return AuthenticatorType . local ;
2023-11-24 03:54:47 +00:00
}
} ) ;
}
2023-07-05 12:57:09 +00:00
2023-11-24 03:54:47 +00:00
/// Determines whether authentication is enabled.
///
/// This getter evaluates if authentication should be enabled based on the
/// current integration mode and cloud type settings.
2023-07-05 12:57:09 +00:00
///
2023-11-24 03:54:47 +00:00
/// Returns:
/// A boolean value indicating whether authentication is enabled. It returns
/// `true` if the application is in release or develop mode, and the cloud type
/// is not set to `CloudType.local`. Additionally, it checks if either the
/// AppFlowy Cloud or Supabase configuration is valid.
/// Returns `false` otherwise.
bool get isAuthEnabled {
2023-12-21 00:12:40 +00:00
final env = getIt < AppFlowyCloudSharedEnv > ( ) ;
if ( env . authenticatorType = = AuthenticatorType . supabase ) {
return env . supabaseConfig . isValid ;
}
2023-11-24 03:54:47 +00:00
2023-12-21 00:12:40 +00:00
if ( env . authenticatorType = = AuthenticatorType . appflowyCloud ) {
return env . appflowyCloudConfig . isValid ;
2023-08-03 00:48:04 +00:00
}
2023-12-21 00:12:40 +00:00
return false ;
2023-08-03 00:48:04 +00:00
}
2023-10-02 09:22:22 +00:00
2023-11-24 03:54:47 +00:00
/// Checks if Supabase is enabled.
///
/// This getter evaluates if Supabase should be enabled based on the
/// current integration mode and cloud type setting.
///
/// Returns:
/// A boolean value indicating whether Supabase is enabled. It returns `true`
/// if the application is in release or develop mode and the current cloud type
/// is `CloudType.supabase`. Otherwise, it returns `false`.
2023-10-07 01:58:44 +00:00
bool get isSupabaseEnabled {
2023-12-21 00:12:40 +00:00
return currentCloudType ( ) = = AuthenticatorType . supabase ;
2023-10-07 01:58:44 +00:00
}
2023-11-24 03:54:47 +00:00
/// Determines if AppFlowy Cloud is enabled.
2023-10-07 01:58:44 +00:00
bool get isAppFlowyCloudEnabled {
2023-12-21 00:12:40 +00:00
return currentCloudType ( ) = = AuthenticatorType . appflowyCloud ;
2023-10-07 01:58:44 +00:00
}
2023-11-28 02:54:31 +00:00
enum AuthenticatorType {
2023-11-24 03:54:47 +00:00
local ,
2023-10-02 09:22:22 +00:00
supabase ,
appflowyCloud ;
2023-11-28 02:54:31 +00:00
bool get isEnabled = > this ! = AuthenticatorType . local ;
2023-11-24 03:54:47 +00:00
int get value {
switch ( this ) {
2023-11-28 02:54:31 +00:00
case AuthenticatorType . local:
2023-11-24 03:54:47 +00:00
return 0 ;
2023-11-28 02:54:31 +00:00
case AuthenticatorType . supabase:
2023-11-24 03:54:47 +00:00
return 1 ;
2023-11-28 02:54:31 +00:00
case AuthenticatorType . appflowyCloud:
2023-11-24 03:54:47 +00:00
return 2 ;
}
}
2023-11-25 09:18:31 +00:00
2023-12-08 13:01:54 +00:00
static AuthenticatorType fromValue ( int value ) {
2023-11-25 09:18:31 +00:00
switch ( value ) {
case 0 :
2023-11-28 02:54:31 +00:00
return AuthenticatorType . local ;
2023-11-25 09:18:31 +00:00
case 1 :
2023-11-28 02:54:31 +00:00
return AuthenticatorType . supabase ;
2023-11-25 09:18:31 +00:00
case 2 :
2023-11-28 02:54:31 +00:00
return AuthenticatorType . appflowyCloud ;
2023-11-25 09:18:31 +00:00
default :
2023-11-28 02:54:31 +00:00
return AuthenticatorType . local ;
2023-11-25 09:18:31 +00:00
}
}
2023-10-02 09:22:22 +00:00
}
2023-11-28 02:54:31 +00:00
AuthenticatorType currentCloudType ( ) {
return getIt < AppFlowyCloudSharedEnv > ( ) . authenticatorType ;
2023-11-24 03:54:47 +00:00
}
2023-10-02 09:22:22 +00:00
2023-11-25 09:18:31 +00:00
Future < void > setAppFlowyCloudUrl ( Option < String > url ) async {
2023-11-24 03:54:47 +00:00
await url . fold (
( ) = > getIt < KeyValueStorage > ( ) . remove ( KVKeys . kAppflowyCloudBaseURL ) ,
( s ) = > getIt < KeyValueStorage > ( ) . set ( KVKeys . kAppflowyCloudBaseURL , s ) ,
) ;
}
/// Use getIt<AppFlowyCloudSharedEnv>() to get the shared environment.
class AppFlowyCloudSharedEnv {
2023-11-28 02:54:31 +00:00
final AuthenticatorType _authenticatorType ;
2023-11-24 03:54:47 +00:00
final AppFlowyCloudConfiguration appflowyCloudConfig ;
final SupabaseConfiguration supabaseConfig ;
AppFlowyCloudSharedEnv ( {
2023-11-28 02:54:31 +00:00
required AuthenticatorType authenticatorType ,
2023-11-24 03:54:47 +00:00
required this . appflowyCloudConfig ,
required this . supabaseConfig ,
2023-11-28 02:54:31 +00:00
} ) : _authenticatorType = authenticatorType ;
AuthenticatorType get authenticatorType = > _authenticatorType ;
static Future < AppFlowyCloudSharedEnv > fromEnv ( ) async {
2023-11-30 21:47:12 +00:00
// If [Env.enableCustomCloud] is true, then use the custom cloud configuration.
2023-11-28 02:54:31 +00:00
if ( Env . enableCustomCloud ) {
// Use the custom cloud configuration.
final cloudType = await getAuthenticatorType ( ) ;
final appflowyCloudConfig = await getAppFlowyCloudConfig ( ) ;
final supabaseCloudConfig = await getSupabaseCloudConfig ( ) ;
return AppFlowyCloudSharedEnv (
authenticatorType: cloudType ,
appflowyCloudConfig: appflowyCloudConfig ,
supabaseConfig: supabaseCloudConfig ,
) ;
} else {
2023-11-30 21:47:12 +00:00
// Using the cloud settings from the .env file.
2023-11-28 02:54:31 +00:00
final appflowyCloudConfig = AppFlowyCloudConfiguration (
base_url: Env . afCloudUrl ,
ws_base_url: await _getAppFlowyCloudWSUrl ( Env . afCloudUrl ) ,
gotrue_url: await _getAppFlowyCloudGotrueUrl ( Env . afCloudUrl ) ,
) ;
return AppFlowyCloudSharedEnv (
authenticatorType: AuthenticatorType . fromValue ( Env . authenticatorType ) ,
appflowyCloudConfig: appflowyCloudConfig ,
supabaseConfig: SupabaseConfiguration . defaultConfig ( ) ,
) ;
}
}
2023-11-24 03:54:47 +00:00
}
2023-11-30 21:47:12 +00:00
Future < AppFlowyCloudConfiguration > configurationFromUri (
Uri baseUri ,
String baseUrl ,
) async {
// When the host is set to 'localhost', the application will utilize the local configuration. This setup assumes that 'localhost' does not employ a reverse proxy, therefore default port settings are used.
if ( baseUri . host = = " localhost " ) {
return AppFlowyCloudConfiguration (
base_url: " $ baseUrl :8000 " ,
ws_base_url: " ws:// ${ baseUri . host } :8000/ws " ,
gotrue_url: " $ baseUrl :9998 " ,
) ;
} else {
return AppFlowyCloudConfiguration (
base_url: baseUrl ,
2023-12-04 22:20:07 +00:00
ws_base_url: await _getAppFlowyCloudWSUrl ( baseUrl ) ,
gotrue_url: await _getAppFlowyCloudGotrueUrl ( baseUrl ) ,
2023-11-30 21:47:12 +00:00
) ;
}
}
2023-11-24 03:54:47 +00:00
Future < AppFlowyCloudConfiguration > getAppFlowyCloudConfig ( ) async {
2023-11-28 02:54:31 +00:00
final baseURL = await getAppFlowyCloudUrl ( ) ;
2023-11-30 21:47:12 +00:00
try {
final uri = Uri . parse ( baseURL ) ;
return await configurationFromUri ( uri , baseURL ) ;
} catch ( e ) {
Log . error ( " Failed to parse AppFlowy Cloud URL: $ e " ) ;
return AppFlowyCloudConfiguration . defaultConfig ( ) ;
}
2023-11-24 03:54:47 +00:00
}
Future < String > getAppFlowyCloudUrl ( ) async {
final result =
await getIt < KeyValueStorage > ( ) . get ( KVKeys . kAppflowyCloudBaseURL ) ;
return result . fold (
( ) = > " " ,
( url ) = > url ,
) ;
}
2023-11-28 02:54:31 +00:00
Future < String > _getAppFlowyCloudWSUrl ( String baseURL ) async {
2023-11-24 03:54:47 +00:00
try {
2023-11-28 02:54:31 +00:00
final uri = Uri . parse ( baseURL ) ;
2023-11-24 03:54:47 +00:00
// Construct the WebSocket URL directly from the parsed URI.
final wsScheme = uri . isScheme ( ' HTTPS ' ) ? ' wss ' : ' ws ' ;
final wsUrl = Uri ( scheme: wsScheme , host: uri . host , path: ' /ws ' ) ;
return wsUrl . toString ( ) ;
} catch ( e ) {
Log . error ( " Failed to get WebSocket URL: $ e " ) ;
return " " ;
2023-10-02 09:22:22 +00:00
}
2023-11-24 03:54:47 +00:00
}
2023-11-28 02:54:31 +00:00
Future < String > _getAppFlowyCloudGotrueUrl ( String baseURL ) async {
return " $ baseURL /gotrue " ;
2023-11-24 03:54:47 +00:00
}
Future < void > setSupbaseServer (
Option < String > url ,
Option < String > anonKey ,
) async {
assert (
( url . isSome ( ) & & anonKey . isSome ( ) ) | | ( url . isNone ( ) & & anonKey . isNone ( ) ) ,
" Either both Supabase URL and anon key must be set, or both should be unset " ,
) ;
await url . fold (
( ) = > getIt < KeyValueStorage > ( ) . remove ( KVKeys . kSupabaseURL ) ,
( s ) = > getIt < KeyValueStorage > ( ) . set ( KVKeys . kSupabaseURL , s ) ,
) ;
await anonKey . fold (
( ) = > getIt < KeyValueStorage > ( ) . remove ( KVKeys . kSupabaseAnonKey ) ,
( s ) = > getIt < KeyValueStorage > ( ) . set ( KVKeys . kSupabaseAnonKey , s ) ,
) ;
}
Future < SupabaseConfiguration > getSupabaseCloudConfig ( ) async {
final url = await _getSupbaseUrl ( ) ;
final anonKey = await _getSupabaseAnonKey ( ) ;
return SupabaseConfiguration (
url: url ,
anon_key: anonKey ,
) ;
}
Future < String > _getSupbaseUrl ( ) async {
final result = await getIt < KeyValueStorage > ( ) . get ( KVKeys . kSupabaseURL ) ;
return result . fold (
( ) = > " " ,
( url ) = > url ,
) ;
}
2023-10-02 09:22:22 +00:00
2023-11-24 03:54:47 +00:00
Future < String > _getSupabaseAnonKey ( ) async {
final result = await getIt < KeyValueStorage > ( ) . get ( KVKeys . kSupabaseAnonKey ) ;
return result . fold (
( ) = > " " ,
( url ) = > url ,
) ;
2023-10-02 09:22:22 +00:00
}