Fix:Android app crash when switching server while player open #1336

- Wrap requests in try/catch to prevent app crash for bad requests
This commit is contained in:
advplyr 2024-11-03 14:53:35 -06:00
parent 102fd1f1a1
commit d902417959
5 changed files with 51 additions and 25 deletions

View file

@ -887,16 +887,18 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
fun closePlayback(calledOnError:Boolean? = false) { fun closePlayback(calledOnError:Boolean? = false) {
Log.d(tag, "closePlayback") Log.d(tag, "closePlayback")
val config = DeviceManager.serverConnectionConfig
val isLocal = mediaProgressSyncer.currentIsLocal val isLocal = mediaProgressSyncer.currentIsLocal
val currentSessionId = mediaProgressSyncer.currentSessionId val currentSessionId = mediaProgressSyncer.currentSessionId
if (mediaProgressSyncer.listeningTimerRunning) { if (mediaProgressSyncer.listeningTimerRunning) {
Log.i(tag, "About to close playback so stopping media progress syncer first") Log.i(tag, "About to close playback so stopping media progress syncer first")
mediaProgressSyncer.stop(calledOnError == false) { // If closing on error then do not sync progress (causes exception) mediaProgressSyncer.stop(calledOnError == false) { // If closing on error then do not sync progress (causes exception)
Log.d(tag, "Media Progress syncer stopped") Log.d(tag, "Media Progress syncer stopped")
// If not local session then close on server // If not local session then close on server
if (!isLocal && currentSessionId != "") { if (!isLocal && currentSessionId != "") {
apiHandler.closePlaybackSession(currentSessionId) { apiHandler.closePlaybackSession(currentSessionId, config) {
Log.d(tag, "Closed playback session $currentSessionId") Log.d(tag, "Closed playback session $currentSessionId")
} }
} }
@ -904,7 +906,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
} else { } else {
// If not local session then close on server // If not local session then close on server
if (!isLocal && currentSessionId != "") { if (!isLocal && currentSessionId != "") {
apiHandler.closePlaybackSession(currentSessionId) { apiHandler.closePlaybackSession(currentSessionId, config) {
Log.d(tag, "Closed playback session $currentSessionId") Log.d(tag, "Closed playback session $currentSessionId")
} }
} }

View file

@ -44,10 +44,17 @@ class ApiHandler(var ctx:Context) {
val address = config?.address ?: DeviceManager.serverAddress val address = config?.address ?: DeviceManager.serverAddress
val token = config?.token ?: DeviceManager.token val token = config?.token ?: DeviceManager.token
val request = Request.Builder() try {
.url("${address}$endpoint").addHeader("Authorization", "Bearer $token") val request = Request.Builder()
.build() .url("${address}$endpoint").addHeader("Authorization", "Bearer $token")
makeRequest(request, httpClient, cb) .build()
makeRequest(request, httpClient, cb)
} catch(e: Exception) {
e.printStackTrace()
val jsobj = JSObject()
jsobj.put("error", "Request failed: ${e.message}")
cb(jsobj)
}
} }
private fun postRequest(endpoint:String, payload: JSObject?, config:ServerConnectionConfig?, cb: (JSObject) -> Unit) { private fun postRequest(endpoint:String, payload: JSObject?, config:ServerConnectionConfig?, cb: (JSObject) -> Unit) {
@ -57,23 +64,38 @@ class ApiHandler(var ctx:Context) {
val requestBody = payload?.toString()?.toRequestBody(mediaType) ?: EMPTY_REQUEST val requestBody = payload?.toString()?.toRequestBody(mediaType) ?: EMPTY_REQUEST
val requestUrl = "${address}$endpoint" val requestUrl = "${address}$endpoint"
Log.d(tag, "postRequest to $requestUrl") Log.d(tag, "postRequest to $requestUrl")
val request = Request.Builder().post(requestBody) try {
.url(requestUrl).addHeader("Authorization", "Bearer ${token}") val request = Request.Builder().post(requestBody)
.build() .url(requestUrl).addHeader("Authorization", "Bearer ${token}")
makeRequest(request, null, cb) .build()
makeRequest(request, null, cb)
} catch(e: Exception) {
e.printStackTrace()
val jsobj = JSObject()
jsobj.put("error", "Request failed: ${e.message}")
cb(jsobj)
}
} }
private fun patchRequest(endpoint:String, payload: JSObject, cb: (JSObject) -> Unit) { private fun patchRequest(endpoint:String, payload: JSObject, cb: (JSObject) -> Unit) {
val mediaType = "application/json; charset=utf-8".toMediaType() val mediaType = "application/json; charset=utf-8".toMediaType()
val requestBody = payload.toString().toRequestBody(mediaType) val requestBody = payload.toString().toRequestBody(mediaType)
val request = Request.Builder().patch(requestBody) try {
.url("${DeviceManager.serverAddress}$endpoint").addHeader("Authorization", "Bearer ${DeviceManager.token}") val request = Request.Builder().patch(requestBody)
.build() .url("${DeviceManager.serverAddress}$endpoint").addHeader("Authorization", "Bearer ${DeviceManager.token}")
makeRequest(request, null, cb) .build()
makeRequest(request, null, cb)
} catch(e: Exception) {
e.printStackTrace()
val jsobj = JSObject()
jsobj.put("error", "Request failed: ${e.message}")
cb(jsobj)
}
} }
private fun makeRequest(request:Request, httpClient:OkHttpClient?, cb: (JSObject) -> Unit) { private fun makeRequest(request:Request, httpClient:OkHttpClient?, cb: (JSObject) -> Unit) {
val client = httpClient ?: defaultClient val client = httpClient ?: defaultClient
client.newCall(request).enqueue(object : Callback { client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) { override fun onFailure(call: Call, e: IOException) {
Log.d(tag, "FAILURE TO CONNECT") Log.d(tag, "FAILURE TO CONNECT")
@ -297,9 +319,9 @@ class ApiHandler(var ctx:Context) {
} }
} }
fun closePlaybackSession(playbackSessionId:String, cb: (Boolean) -> Unit) { fun closePlaybackSession(playbackSessionId:String, config:ServerConnectionConfig?, cb: (Boolean) -> Unit) {
Log.d(tag, "closePlaybackSession: playbackSessionId=$playbackSessionId") Log.d(tag, "closePlaybackSession: playbackSessionId=$playbackSessionId")
postRequest("/api/session/$playbackSessionId/close", null, null) { postRequest("/api/session/$playbackSessionId/close", null, config) {
cb(true) cb(true)
} }
} }

View file

@ -171,6 +171,10 @@ export default {
}, },
async logout() { async logout() {
if (this.user) { if (this.user) {
if (this.$store.getters['getIsPlayerOpen']) {
this.$eventBus.$emit('close-stream')
}
await this.$nativeHttp.post('/logout').catch((error) => { await this.$nativeHttp.post('/logout').catch((error) => {
console.error('Failed to logout', error) console.error('Failed to logout', error)
}) })

View file

@ -143,8 +143,6 @@ export default {
this.comicHasMetadata = false this.comicHasMetadata = false
this.registerListeners() this.registerListeners()
this.hideToolbar() this.hideToolbar()
console.log('showReader for ebookFile', JSON.stringify(this.ebookFile))
} else { } else {
this.unregisterListeners() this.unregisterListeners()
this.$showHideStatusBar(true) this.$showHideStatusBar(true)
@ -435,7 +433,9 @@ export default {
await VolumeButtons.watchVolume(options, this.volumePressed) await VolumeButtons.watchVolume(options, this.volumePressed)
} }
} else if (isWatching.value) { } else if (isWatching.value) {
await VolumeButtons.clearWatch() await VolumeButtons.clearWatch().catch((error) => {
console.error('Failed to clear volume watch', error)
})
} }
this.isInittingWatchVolume = false this.isInittingWatchVolume = false
@ -450,7 +450,9 @@ export default {
this.$eventBus.$on('close-ebook', this.closeEvt) this.$eventBus.$on('close-ebook', this.closeEvt)
document.body.removeEventListener('touchstart', this.touchstart) document.body.removeEventListener('touchstart', this.touchstart)
document.body.removeEventListener('touchend', this.touchend) document.body.removeEventListener('touchend', this.touchend)
VolumeButtons.clearWatch() VolumeButtons.clearWatch().catch((error) => {
console.error('Failed to clear volume watch', error)
})
}, },
volumePressed(e) { volumePressed(e) {
if (this.ereaderSettings.navigateWithVolume == 'enabled') { if (this.ereaderSettings.navigateWithVolume == 'enabled') {

View file

@ -177,10 +177,6 @@ export default {
} }
} }
}, },
userLoggedOut() {
// Only cancels stream if streamining not playing downloaded
this.$eventBus.$emit('close-stream')
},
socketConnectionFailed(err) { socketConnectionFailed(err) {
this.$toast.error('Socket connection error: ' + err.message) this.$toast.error('Socket connection error: ' + err.message)
}, },