Repository navigation
Improve booking server and Firebase integration #189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
aa90065
7fb200f
4420e2b
7476ee0
57885ee
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -24,6 +24,9 @@ import androidx.a2ui.model.protocol.A2uiClientEventMessage | |
| import androidx.a2ui.model.protocol.A2uiComponentPayload | ||
| import androidx.a2ui.model.protocol.A2uiCreateSurfaceMessage | ||
| import androidx.a2ui.model.protocol.A2uiUpdateComponentsMessage | ||
| import androidx.compose.runtime.getValue | ||
| import androidx.compose.runtime.mutableStateOf | ||
| import androidx.compose.runtime.setValue | ||
| import androidx.lifecycle.SavedStateHandle | ||
| import androidx.lifecycle.ViewModel | ||
| import androidx.lifecycle.viewModelScope | ||
|
|
@@ -75,8 +78,32 @@ class BookingAssistantViewModel @Inject constructor( | |
| private var activeStreamJob: Job? = null | ||
| private var streamIdleJob: Job? = null | ||
|
|
||
| // Set to true when testing against local server (http://localhost:8000) | ||
| val useLocalServer: Boolean = false | ||
| enum class BackendEndpoint { | ||
| LOCAL, | ||
| PARALLEL_STAGING, | ||
| PRODUCTION, | ||
| } | ||
|
|
||
| /** | ||
| * Active backend endpoint. Defaults to [BackendEndpoint.PARALLEL_STAGING] to connect to the | ||
| * side-by-side /v2 Cloud Run service without impacting production. | ||
| */ | ||
| var backendEndpoint by mutableStateOf(BackendEndpoint.PARALLEL_STAGING) | ||
|
|
||
| // Backwards compatibility property | ||
| var useLocalServer: Boolean | ||
| get() = backendEndpoint == BackendEndpoint.LOCAL | ||
| set(value) { | ||
| backendEndpoint = if (value) BackendEndpoint.LOCAL else BackendEndpoint.PARALLEL_STAGING | ||
| } | ||
|
|
||
| val baseUrl: String | ||
| get() = | ||
| when (backendEndpoint) { | ||
| BackendEndpoint.LOCAL -> "http://localhost:8000" | ||
| BackendEndpoint.PARALLEL_STAGING -> "https://jetset-gateway-38wzy18y.uc.gateway.dev/v2" | ||
| BackendEndpoint.PRODUCTION -> "https://jetset-gateway-38wzy18y.uc.gateway.dev" | ||
| } | ||
|
|
||
| private val client = OkHttpClient.Builder().readTimeout(0, TimeUnit.MILLISECONDS).build() | ||
|
|
||
|
|
@@ -310,9 +337,9 @@ class BookingAssistantViewModel @Inject constructor( | |
| } | ||
| } | ||
|
|
||
| log("Starting connectToStream with sId: $sId, useLocalServer: $useLocalServer") | ||
| log("Starting connectToStream with sId: $sId, backendEndpoint: $backendEndpoint") | ||
|
|
||
| if (useLocalServer) { | ||
| if (backendEndpoint == BackendEndpoint.LOCAL) { | ||
| streamToken = "local_dev_token" | ||
| streamUrl = "http://localhost:8000/run_sse" | ||
| } else { | ||
|
|
@@ -323,7 +350,7 @@ class BookingAssistantViewModel @Inject constructor( | |
| return | ||
| } | ||
|
|
||
| val gatewayUrl = "https://jetset-gateway-38wzy18y.uc.gateway.dev/stream?auth_only=true" | ||
| val gatewayUrl = "$baseUrl/stream?auth_only=true" | ||
| val tokenRequest = Request.Builder() | ||
| .url(gatewayUrl) | ||
| .addHeader("Authorization", "Bearer $fbToken") | ||
|
|
@@ -656,7 +683,6 @@ class BookingAssistantViewModel @Inject constructor( | |
| } | ||
|
|
||
| val token = getFirebaseAuthToken() | ||
| val baseUrl = if (useLocalServer) "http://localhost:8000" else "https://jetset-gateway-38wzy18y.uc.gateway.dev" | ||
| val encodedSessionId = URLEncoder.encode(sId, "UTF-8") | ||
| val encodedAgentId = URLEncoder.encode(agentId, "UTF-8") | ||
| val request = Request.Builder() | ||
|
|
@@ -680,7 +706,13 @@ class BookingAssistantViewModel @Inject constructor( | |
|
|
||
| private suspend fun getFirebaseAuthToken(): String { | ||
| log("getFirebaseAuthToken: getting FirebaseAuth instance") | ||
| val auth = FirebaseAuth.getInstance() | ||
| val auth = try { | ||
| FirebaseAuth.getInstance() | ||
| } catch (e: Exception) { | ||
| log("FirebaseAuth.getInstance failed: ${e.message}") | ||
| Log.e("BookingAssistant", "FirebaseAuth.getInstance failed", e) | ||
| return "" | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we return an empty token here? should it return the exception?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Basically we choose to catch the exception here instead of at the caller site so that we can run the app even when firebase is not initialized and at least test the other features. Not the best user experience as the firebase features would not work, but that's not our demo scenario anyway. |
||
| } | ||
| var user = auth.currentUser | ||
| log("getFirebaseAuthToken: current user is ${user?.uid ?: "null"}") | ||
| if (user == null) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| __pycache__ | ||
| *.pyc | ||
| *.pyo | ||
| *.pyd | ||
| .Python | ||
| env/ | ||
| venv/ | ||
| booking/.adk |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import sys | ||
| from typing import Any | ||
|
|
||
|
|
||
| def __getattr__(name: str) -> Any: | ||
| if name == "root_agent": | ||
| if "main" in sys.modules: | ||
| return sys.modules["main"].ItineraryOrchestratorAgent() | ||
| import main | ||
|
|
||
| return main.ItineraryOrchestratorAgent() | ||
| raise AttributeError(f"module '{__name__}' has no attribute '{name}'") |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| from __future__ import annotations | ||
|
|
||
| import sys | ||
| from typing import Any | ||
|
|
||
|
|
||
| def __getattr__(name: str) -> Any: | ||
| if name == "root_agent": | ||
| if "main" in sys.modules: | ||
| return sys.modules["main"].ItineraryOrchestratorAgent() | ||
| import main | ||
|
|
||
| return main.ItineraryOrchestratorAgent() | ||
| raise AttributeError(f"module '{__name__}' has no attribute '{name}'") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If initialization fails how the app should work? Do we need to exit here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nah the rest of the features will still work so no need to fully cancel. We should just make sure not to crash