diff --git a/packages/frontend/apps/android/App/app/build.gradle b/packages/frontend/apps/android/App/app/build.gradle index 5c1fca8b10..fbedd6c449 100644 --- a/packages/frontend/apps/android/App/app/build.gradle +++ b/packages/frontend/apps/android/App/app/build.gradle @@ -53,14 +53,10 @@ android { } flavorDimensions = ['chanel'] productFlavors { - stable { - buildConfigField 'String', 'BASE_URL', '"https://app.affine.pro"' - resValue 'string', 'host', '"app.affine.pro"' - } - canary { - buildConfigField 'String', 'BASE_URL', '"https://affine.fail"' - resValue 'string', 'host', '"affine.fail"' - } + stable + beta + internal + canary } compileOptions { diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/AffineApp.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/AffineApp.kt index 56a9e8763f..4aa7ec3716 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/AffineApp.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/AffineApp.kt @@ -3,9 +3,6 @@ package app.affine.pro import android.annotation.SuppressLint import android.app.Application import android.content.Context -import app.affine.pro.service.CookieStore -import app.affine.pro.utils.dataStore -import app.affine.pro.utils.get import app.affine.pro.utils.logger.AffineDebugTree import app.affine.pro.utils.logger.CrashlyticsTree import app.affine.pro.utils.logger.FileTree @@ -13,11 +10,6 @@ import com.google.firebase.crashlytics.ktx.crashlytics import com.google.firebase.crashlytics.setCustomKeys import com.google.firebase.ktx.Firebase import dagger.hilt.android.HiltAndroidApp -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.MainScope -import kotlinx.coroutines.launch -import okhttp3.Cookie -import okhttp3.HttpUrl.Companion.toHttpUrl import timber.log.Timber @HiltAndroidApp @@ -39,28 +31,6 @@ class AffineApp : Application() { Firebase.crashlytics.setCustomKeys { key("affine_version", CapacitorConfig.getAffineVersion()) } - // init cookies from local - MainScope().launch(Dispatchers.IO) { - val sessionCookieStr = applicationContext.dataStore.get(CookieStore.AFFINE_SESSION) - val userIdCookieStr = applicationContext.dataStore.get(CookieStore.AFFINE_USER_ID) - if (sessionCookieStr.isEmpty() || userIdCookieStr.isEmpty()) { - Timber.i("[init] user has not signed in yet.") - return@launch - } - Timber.i("[init] user already signed in.") - try { - val cookies = listOf( - Cookie.parse(BuildConfig.BASE_URL.toHttpUrl(), sessionCookieStr) - ?: error("Parse session cookie fail:[ cookie = $sessionCookieStr ]"), - Cookie.parse(BuildConfig.BASE_URL.toHttpUrl(), userIdCookieStr) - ?: error("Parse user id cookie fail:[ cookie = $userIdCookieStr ]"), - ) - CookieStore.saveCookies(BuildConfig.BASE_URL.toHttpUrl().host, cookies) - FileTree.get()?.checkAndUploadOldLogs() - } catch (e: Exception) { - Timber.w(e, "[init] load persistent cookies fail.") - } - } } override fun onTerminate() { diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/AuthInitializer.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/AuthInitializer.kt new file mode 100644 index 0000000000..2d042269e8 --- /dev/null +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/AuthInitializer.kt @@ -0,0 +1,52 @@ +package app.affine.pro + +import android.webkit.WebView +import app.affine.pro.service.CookieStore +import app.affine.pro.utils.dataStore +import app.affine.pro.utils.get +import app.affine.pro.utils.getCurrentServerBaseUrl +import app.affine.pro.utils.logger.FileTree +import com.getcapacitor.Bridge +import com.getcapacitor.WebViewListener +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.MainScope +import kotlinx.coroutines.launch +import okhttp3.Cookie +import okhttp3.HttpUrl.Companion.toHttpUrl +import timber.log.Timber + +object AuthInitializer { + + fun initialize(bridge: Bridge) { + bridge.addWebViewListener(object : WebViewListener() { + override fun onPageLoaded(webView: WebView?) { + bridge.removeWebViewListener(this) + MainScope().launch(Dispatchers.IO) { + try { + val server = bridge.getCurrentServerBaseUrl().toHttpUrl() + val sessionCookieStr = AffineApp.context().dataStore + .get(server.host + CookieStore.AFFINE_SESSION) + val userIdCookieStr = AffineApp.context().dataStore + .get(server.host + CookieStore.AFFINE_USER_ID) + if (sessionCookieStr.isEmpty() || userIdCookieStr.isEmpty()) { + Timber.i("[init] user has not signed in yet.") + return@launch + } + Timber.i("[init] user already signed in.") + val cookies = listOf( + Cookie.parse(server, sessionCookieStr) + ?: error("Parse session cookie fail:[ cookie = $sessionCookieStr ]"), + Cookie.parse(server, userIdCookieStr) + ?: error("Parse user id cookie fail:[ cookie = $userIdCookieStr ]"), + ) + CookieStore.saveCookies(server.host, cookies) + FileTree.get()?.checkAndUploadOldLogs(server) + } catch (e: Exception) { + Timber.w(e, "[init] load persistent cookies fail.") + } + } + } + }) + } + +} \ No newline at end of file diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/MainActivity.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/MainActivity.kt index 4f9590adfb..3f25829c89 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/MainActivity.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/MainActivity.kt @@ -13,7 +13,9 @@ import app.affine.pro.plugin.AffineThemePlugin import app.affine.pro.plugin.AuthPlugin import app.affine.pro.plugin.HashCashPlugin import app.affine.pro.plugin.NbStorePlugin -import app.affine.pro.repo.WebRepo +import app.affine.pro.service.GraphQLService +import app.affine.pro.service.SSEService +import app.affine.pro.service.WebService import app.affine.pro.utils.dp import com.getcapacitor.BridgeActivity import com.google.android.material.floatingactionbutton.FloatingActionButton @@ -27,7 +29,13 @@ class MainActivity : BridgeActivity(), AIButtonPlugin.Callback, AffineThemePlugi View.OnClickListener { @Inject - lateinit var webRepo: WebRepo + lateinit var webService: WebService + + @Inject + lateinit var sseService: SSEService + + @Inject + lateinit var graphQLService: GraphQLService init { registerPlugins( @@ -56,6 +64,11 @@ class MainActivity : BridgeActivity(), AIButtonPlugin.Callback, AffineThemePlugi } } + override fun load() { + super.load() + AuthInitializer.initialize(bridge) + } + override fun present() { lifecycleScope.launch { fab.show() @@ -85,7 +98,9 @@ class MainActivity : BridgeActivity(), AIButtonPlugin.Callback, AffineThemePlugi override fun onClick(v: View) { lifecycleScope.launch { - webRepo.init(bridge) + webService.update(bridge) + sseService.updateServer(bridge) + graphQLService.updateServer(bridge) AIActivity.open(this@MainActivity) } } diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/ai/chat/ChatViewModel.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/ai/chat/ChatViewModel.kt index cca5cb07b9..f790e200e0 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/ai/chat/ChatViewModel.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/ai/chat/ChatViewModel.kt @@ -2,9 +2,9 @@ package app.affine.pro.ai.chat import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope -import app.affine.pro.repo.GraphQLRepo -import app.affine.pro.repo.SSERepo -import app.affine.pro.repo.WebRepo +import app.affine.pro.service.GraphQLService +import app.affine.pro.service.SSEService +import app.affine.pro.service.WebService import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.MutableStateFlow @@ -18,9 +18,9 @@ import javax.inject.Inject @HiltViewModel class ChatViewModel @Inject constructor( - private val webRepo: WebRepo, - private val graphQLRepo: GraphQLRepo, - private val sseRepo: SSERepo, + private val webService: WebService, + private val graphQLService: GraphQLService, + private val sseService: SSEService, ) : ViewModel() { private lateinit var sessionId: String @@ -32,17 +32,17 @@ class ChatViewModel @Inject constructor( init { viewModelScope.launch { - sessionId = graphQLRepo.createCopilotSession( - workspaceId = webRepo.workspaceId(), - docId = webRepo.docId(), + sessionId = graphQLService.createCopilotSession( + workspaceId = webService.workspaceId(), + docId = webService.docId(), ).getOrElse { Timber.w(it, "Create session failed") return@launch } Timber.i("Create session success:[ sessionId = $sessionId].") - val historyMessages = graphQLRepo.getCopilotHistories( - workspaceId = webRepo.workspaceId(), - docId = webRepo.docId(), + val historyMessages = graphQLService.getCopilotHistories( + workspaceId = webService.workspaceId(), + docId = webService.docId(), sessionId = sessionId, ).getOrDefault(emptyList()).map { ChatMessage.from(it) @@ -55,12 +55,12 @@ class ChatViewModel @Inject constructor( fun sendMessage(message: String) { val sendMessage = suspend { - graphQLRepo.createCopilotMessage( + graphQLService.createCopilotMessage( sessionId = sessionId, message = message, ).onSuccess { messageId -> Timber.i("send message: $messageId") - sseRepo.messageStream(sessionId, messageId) + sseService.messageStream(sessionId, messageId) .onEach { Timber.d("On sse message: ${it.getOrNull()}") } @@ -70,9 +70,9 @@ class ChatViewModel @Inject constructor( } viewModelScope.launch { if (!this@ChatViewModel::sessionId.isInitialized) { - graphQLRepo.getCopilotSession( - workspaceId = webRepo.workspaceId(), - docId = webRepo.docId(), + graphQLService.getCopilotSession( + workspaceId = webService.workspaceId(), + docId = webService.docId(), ).onSuccess { id -> sessionId = id Timber.i("Create session: $id") diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/plugin/AuthPlugin.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/plugin/AuthPlugin.kt index 6d978ef098..7becc0b556 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/plugin/AuthPlugin.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/plugin/AuthPlugin.kt @@ -11,6 +11,7 @@ import com.getcapacitor.PluginMethod import com.getcapacitor.annotation.CapacitorPlugin import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi +import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody @@ -144,7 +145,7 @@ class AuthPlugin : Plugin() { call.reject(response.body.string()) return@launch } - CookieStore.getCookie(endpoint, CookieStore.AFFINE_SESSION)?.let { + CookieStore.getCookie(endpoint.toHttpUrl(), CookieStore.AFFINE_SESSION)?.let { Timber.i("$method sign in success.") Timber.d("Update session [$it]") call.resolve(JSObject().put("token", it)) diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/repo/WebRepo.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/repo/WebRepo.kt deleted file mode 100644 index 97f4da1ffa..0000000000 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/repo/WebRepo.kt +++ /dev/null @@ -1,35 +0,0 @@ -package app.affine.pro.repo - -import com.getcapacitor.Bridge -import javax.inject.Inject -import javax.inject.Singleton -import kotlin.coroutines.resume -import kotlin.coroutines.suspendCoroutine - -@Singleton -class WebRepo @Inject constructor() { - - suspend fun init(bridge: Bridge) { - _workspaceId = eval(bridge, "window.getCurrentWorkspaceId()") - _docId = eval(bridge, "window.getCurrentDocId()") - _docContentInMD = eval(bridge, "window.getCurrentDocContentInMarkdown()") - } - - private suspend fun eval(bridge: Bridge, js: String): String { - return suspendCoroutine { continuation -> - bridge.eval(js) { result -> - continuation.resume(result) - } - } - } - - private lateinit var _workspaceId: String - private lateinit var _docId: String - private lateinit var _docContentInMD: String - - fun workspaceId() = _workspaceId - - fun docId() = _docId - - fun docContentInMD() = _docContentInMD -} \ No newline at end of file diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/GraphQLClient.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/GraphQLClient.kt deleted file mode 100644 index 3bbffa0b62..0000000000 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/GraphQLClient.kt +++ /dev/null @@ -1,43 +0,0 @@ -package app.affine.pro.service - -import app.affine.pro.BuildConfig -import com.apollographql.apollo.ApolloClient -import com.apollographql.apollo.api.Mutation -import com.apollographql.apollo.api.Query -import com.apollographql.apollo.api.Subscription -import com.apollographql.apollo.network.okHttpClient -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import javax.inject.Inject -import javax.inject.Singleton - -@Singleton -class GraphQLClient @Inject constructor() { - - private val _client: ApolloClient by lazy { - ApolloClient.Builder().serverUrl("${BuildConfig.BASE_URL}/graphql") - .okHttpClient(OkHttp.client) - .build() - } - - suspend fun query(query: Query) = withContext(Dispatchers.IO) { - runCatching { - withContext(Dispatchers.IO) { - _client.query(query).execute().dataOrThrow() - } - } - } - - suspend fun mutation(mutation: Mutation) = withContext(Dispatchers.IO) { - runCatching { - _client.mutation(mutation).execute().dataOrThrow() - } - } - - suspend fun subscription(subscription: Subscription) = - withContext(Dispatchers.IO) { - runCatching { - _client.subscription(subscription).execute().dataOrThrow() - } - } -} \ No newline at end of file diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/repo/GraphQLRepo.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/GraphQLService.kt similarity index 50% rename from packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/repo/GraphQLRepo.kt rename to packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/GraphQLService.kt index 588774770d..7cbf7b3cca 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/repo/GraphQLRepo.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/GraphQLService.kt @@ -1,23 +1,29 @@ -package app.affine.pro.repo +package app.affine.pro.service import app.affine.pro.Prompt -import app.affine.pro.service.GraphQLClient +import app.affine.pro.utils.getCurrentServerBaseUrl import com.affine.pro.graphql.CreateCopilotMessageMutation import com.affine.pro.graphql.CreateCopilotSessionMutation import com.affine.pro.graphql.GetCopilotHistoriesQuery import com.affine.pro.graphql.GetCopilotSessionsQuery import com.affine.pro.graphql.type.CreateChatMessageInput import com.affine.pro.graphql.type.CreateChatSessionInput +import com.apollographql.apollo.ApolloClient +import com.apollographql.apollo.api.Mutation import com.apollographql.apollo.api.Optional +import com.apollographql.apollo.api.Query +import com.apollographql.apollo.api.Subscription +import com.apollographql.apollo.network.okHttpClient +import com.getcapacitor.Bridge +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext import javax.inject.Inject import javax.inject.Singleton @Singleton -class GraphQLRepo @Inject constructor( - private val client: GraphQLClient -) { +class GraphQLService @Inject constructor() { - suspend fun getCopilotSession(workspaceId: String, docId: String) = client.query( + suspend fun getCopilotSession(workspaceId: String, docId: String) = query( GetCopilotSessionsQuery( workspaceId = workspaceId, docId = Optional.present(docId) @@ -30,7 +36,7 @@ class GraphQLRepo @Inject constructor( workspaceId: String, docId: String, prompt: Prompt = Prompt.ChatWithAFFiNEAI - ) = client.mutation( + ) = mutation( CreateCopilotSessionMutation( CreateChatSessionInput( docId = docId, @@ -46,7 +52,7 @@ class GraphQLRepo @Inject constructor( workspaceId: String, docId: String, sessionId: String, - ) = client.query( + ) = query( GetCopilotHistoriesQuery( workspaceId = workspaceId, docId = Optional.present(docId), @@ -60,15 +66,49 @@ class GraphQLRepo @Inject constructor( suspend fun createCopilotMessage( sessionId: String, message: String, - ) = client.mutation(CreateCopilotMessageMutation( - CreateChatMessageInput( - sessionId = sessionId, - content = Optional.present(message) + ) = mutation( + CreateCopilotMessageMutation( + CreateChatMessageInput( + sessionId = sessionId, + content = Optional.present(message) + ) ) - )).mapCatching { data -> + ).mapCatching { data -> data.createCopilotMessage } + suspend fun updateServer(bridge: Bridge) { + val server = bridge.getCurrentServerBaseUrl() + if (this::_client.isInitialized && _client.newBuilder().httpServerUrl == server) return + _client = ApolloClient.Builder().serverUrl("$server/graphql") + .okHttpClient(OkHttp.client) + .build() + } + + private lateinit var _client: ApolloClient + + private suspend fun query(query: Query) = withContext(Dispatchers.IO) { + runCatching { + withContext(Dispatchers.IO) { + _client.query(query).execute().dataOrThrow() + } + } + } + + private suspend fun mutation(mutation: Mutation) = + withContext(Dispatchers.IO) { + runCatching { + _client.mutation(mutation).execute().dataOrThrow() + } + } + + private suspend fun subscription(subscription: Subscription) = + withContext(Dispatchers.IO) { + runCatching { + _client.subscription(subscription).execute().dataOrThrow() + } + } + companion object { private const val ERROR_NULL_SESSION_ID = "null session id." } diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/OkHttp.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/OkHttp.kt index 14c4d91207..fad34f8b49 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/OkHttp.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/OkHttp.kt @@ -1,6 +1,5 @@ package app.affine.pro.service -import androidx.core.net.toUri import app.affine.pro.AffineApp import app.affine.pro.utils.dataStore import app.affine.pro.utils.set @@ -53,11 +52,11 @@ object CookieStore { _cookies[host] = cookies MainScope().launch(Dispatchers.IO) { cookies.find { it.name == AFFINE_SESSION }?.let { - AffineApp.context().dataStore.set(AFFINE_SESSION, it.toString()) + AffineApp.context().dataStore.set(host + AFFINE_SESSION, it.toString()) } cookies.find { it.name == AFFINE_USER_ID }?.let { Timber.d("Update user id [${it.value}]") - AffineApp.context().dataStore.set(AFFINE_USER_ID, it.toString()) + AffineApp.context().dataStore.set(host + AFFINE_USER_ID, it.toString()) Firebase.crashlytics.setUserId(it.value) } } @@ -65,8 +64,8 @@ object CookieStore { fun getCookies(host: String) = _cookies[host] ?: emptyList() - fun getCookie(url: String, name: String) = url.toUri().host - ?.let { _cookies[it] } + fun getCookie(url: HttpUrl, name: String) = url.host + .let { _cookies[it] } ?.find { cookie -> cookie.name == name } ?.value } \ No newline at end of file diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/repo/SSERepo.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/SSEService.kt similarity index 82% rename from packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/repo/SSERepo.kt rename to packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/SSEService.kt index d41df7c052..e629f9bb9a 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/repo/SSERepo.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/SSEService.kt @@ -1,7 +1,7 @@ -package app.affine.pro.repo +package app.affine.pro.service -import app.affine.pro.BuildConfig -import app.affine.pro.service.OkHttp +import app.affine.pro.utils.getCurrentServerBaseUrl +import com.getcapacitor.Bridge import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.channels.trySendBlocking @@ -17,10 +17,16 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class SSERepo @Inject constructor() { +class SSEService @Inject constructor() { + + private lateinit var _server: String + + suspend fun updateServer(bridge: Bridge) { + _server = bridge.getCurrentServerBaseUrl() + } fun messageStream(sessionId: String, messageId: String) = - "${BuildConfig.BASE_URL}/api/copilot/chat/$sessionId/stream?messageId=$messageId".eventSource() + "$_server/api/copilot/chat/$sessionId/stream?messageId=$messageId".eventSource() data class Event(val id: String?, val type: String?, val data: String) diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/WebService.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/WebService.kt new file mode 100644 index 0000000000..ed6b50b4c3 --- /dev/null +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/WebService.kt @@ -0,0 +1,28 @@ +package app.affine.pro.service + +import app.affine.pro.utils.getCurrentDocContentInMarkdown +import app.affine.pro.utils.getCurrentDocId +import app.affine.pro.utils.getCurrentWorkspaceId +import com.getcapacitor.Bridge +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class WebService @Inject constructor() { + + suspend fun update(bridge: Bridge) { + _workspaceId = bridge.getCurrentWorkspaceId() + _docId = bridge.getCurrentDocId() + _docContentInMD = bridge.getCurrentDocContentInMarkdown() + } + + private lateinit var _workspaceId: String + private lateinit var _docId: String + private lateinit var _docContentInMD: String + + fun workspaceId() = _workspaceId + + fun docId() = _docId + + fun docContentInMD() = _docContentInMD +} \ No newline at end of file diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/interceptor/CookieInterceptor.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/interceptor/CookieInterceptor.kt deleted file mode 100644 index 8f557a63e0..0000000000 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/service/interceptor/CookieInterceptor.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.affine.pro.service.interceptor - -import android.webkit.CookieManager -import app.affine.pro.BuildConfig -import com.apollographql.apollo.api.http.HttpRequest -import com.apollographql.apollo.network.http.HttpInterceptor -import com.apollographql.apollo.network.http.HttpInterceptorChain - -object CookieInterceptor : HttpInterceptor { - override suspend fun intercept( - request: HttpRequest, - chain: HttpInterceptorChain - ) = chain.proceed( - request.newBuilder().addHeader( - "Cookie", CookieManager.getInstance().getCookie(BuildConfig.BASE_URL) - ).build() - ) -} \ No newline at end of file diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/utils/DataStore.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/utils/DataStore.kt index ba49521ac2..3f3ed1ce0e 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/utils/DataStore.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/utils/DataStore.kt @@ -19,12 +19,4 @@ suspend fun DataStore.set(key: String, value: String) { suspend fun DataStore.get(key: String) = data.map { it[stringPreferencesKey(key)] ?: "" -}.first() - -suspend fun DataStore.clear(vararg keys: String) { - edit { prefs -> - keys.forEach { key -> - prefs[stringPreferencesKey(key)] = "" - } - } -} \ No newline at end of file +}.first() \ No newline at end of file diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/utils/WebExt.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/utils/WebExt.kt new file mode 100644 index 0000000000..0286edf7ad --- /dev/null +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/utils/WebExt.kt @@ -0,0 +1,30 @@ +package app.affine.pro.utils + +import com.getcapacitor.Bridge +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine + +suspend fun Bridge.getCurrentServerBaseUrl() = eval("window.getCurrentServerBaseUrl()").strict() + +suspend fun Bridge.getCurrentWorkspaceId() = eval("window.getCurrentWorkspaceId()").strict() + +suspend fun Bridge.getCurrentDocId() = eval("window.getCurrentDocId()").strict() + +suspend fun Bridge.getCurrentDocContentInMarkdown() = + eval("window.getCurrentDocContentInMarkdown()").strict() + +private suspend fun Bridge.eval(js: String): String { + return suspendCoroutine { continuation -> + eval(js) { result -> + continuation.resume(result) + } + } +} + +private fun String.strict() = let { + if (startsWith("\"") && endsWith("\"")) { + substring(1, lastIndex) + } else { + this + } +} \ No newline at end of file diff --git a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/utils/logger/FileTree.kt b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/utils/logger/FileTree.kt index 5e124ce933..bcd0c54d7b 100644 --- a/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/utils/logger/FileTree.kt +++ b/packages/frontend/apps/android/App/app/src/main/java/app/affine/pro/utils/logger/FileTree.kt @@ -12,6 +12,7 @@ import kotlinx.coroutines.MainScope import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withContext +import okhttp3.HttpUrl import timber.log.Timber import java.io.File import java.io.FileOutputStream @@ -41,19 +42,19 @@ class FileTree(context: Context) : Timber.Tree() { } } - suspend fun checkAndUploadOldLogs() { + suspend fun checkAndUploadOldLogs(server: HttpUrl) { val today = dateFormat.format(Date()) logDirectory.listFiles()?.forEach { file -> val fileName = file.name if (fileName.endsWith(".log") && !fileName.startsWith(today)) { - uploadLogToFirebase(file) + uploadLogToFirebase(server, file) } } } - private suspend fun uploadLogToFirebase(file: File) = + private suspend fun uploadLogToFirebase(server: HttpUrl, file: File) = suspendCancellableCoroutine { continuation -> - val user = CookieStore.getCookie(BuildConfig.BASE_URL, CookieStore.AFFINE_USER_ID) + val user = CookieStore.getCookie(server, CookieStore.AFFINE_USER_ID) ?: return@suspendCancellableCoroutine val storageRef = Firebase.storage.reference val logFileRef = storageRef.child("android_log/$user/${file.name}")