more error handling

This commit is contained in:
Öppen 2020-08-18 20:02:16 +01:00
parent 372fb876a3
commit 861d3a8619
3 changed files with 61 additions and 21 deletions

View File

@ -3,6 +3,7 @@ package oppen.tva.io
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.*
import java.net.ConnectException
import java.net.URI
import java.security.SecureRandom
import javax.net.ssl.*
@ -84,10 +85,20 @@ class GeminiDatasource: Datasource{
sslContext.init(null, DummyTrustManager.get(), SecureRandom())
val factory: SSLSocketFactory = sslContext.socketFactory
val socket: SSLSocket = factory.createSocket(uri.host, port) as SSLSocket
socket.enabledProtocols = arrayOf("TLSv1.2")
socket.startHandshake()
var socket: SSLSocket? = null
try {
socket = factory.createSocket(uri.host, port) as SSLSocket
socket.enabledProtocols = arrayOf("TLSv1.2")
socket.startHandshake()
}catch(ce: ConnectException){
onUpdate(TvaState.ResponseError(GeminiResponse.Header(-1, ce.message ?: ce.toString())))
return
}catch(she: SSLHandshakeException){
onUpdate(TvaState.ResponseError(GeminiResponse.Header(-1, she.message ?: she.toString())))
return
}
// OUT >>>>>>>>>>>>>>>>>>>>>>>>>>
val outputStreamWriter = OutputStreamWriter(socket.outputStream)
@ -128,26 +139,26 @@ class GeminiDatasource: Datasource{
}
}
private fun getGemtext(socket: SSLSocket, uri: URI, header: GeminiResponse.Header, onUpdate: (state: TvaState) -> Unit){
private fun getGemtext(socket: SSLSocket?, uri: URI, header: GeminiResponse.Header, onUpdate: (state: TvaState) -> Unit){
val lines = mutableListOf<String>()
socket.inputStream.reader().use { inputStreamReader ->
socket?.inputStream?.reader().use { inputStreamReader ->
BufferedReader(inputStreamReader).use { reader ->
lines.addAll(reader.readLines())
}
}
socket.close()
socket?.close()
val processed = GemtextHelper.findCodeBlocks(lines)
RuntimeCache.put(uri, header, processed)
onUpdate(TvaState.ResponseGemtext(uri, header, processed))
}
private fun getString(socket: SSLSocket, uri: URI, header: GeminiResponse.Header, onUpdate: (state: TvaState) -> Unit){
val content = socket.inputStream.bufferedReader().use { reader -> reader.readText() }
private fun getString(socket: SSLSocket?, uri: URI, header: GeminiResponse.Header, onUpdate: (state: TvaState) -> Unit){
val content = socket?.inputStream?.bufferedReader().use { reader -> reader?.readText() }
socket.close()
socket?.close()
}
}

View File

@ -11,22 +11,42 @@ object GeminiResponse {
const val UNKNOWN = -1
fun parseHeader(header: String): Header{
val segments = header.trim().split(" ")
val meta = if(segments.size > 1){
segments[1]
var meta = ""
if(header.startsWith("2")){
val segments = header.trim().split(" ")
meta = when {
segments.size > 1 -> segments[1]
else -> "text/gemini; charset=utf-8"
}
}else{
"text/gemini; charset=utf-8"
meta = when {
header.contains(" ") -> header.substring(meta.indexOf(" ") + 1)
else -> header
}
}
return when {
segments.first().startsWith("1") -> Header(INPUT, meta)
segments.first().startsWith("2") -> Header(SUCCESS, meta)
segments.first().startsWith("3") -> Header(REDIRECT, meta)
segments.first().startsWith("4") -> Header(TEMPORARY_FAILURE, meta)
segments.first().startsWith("5") -> Header(PERMANENT_FAILURE, meta)
segments.first().startsWith("6") -> Header(CLIENT_CERTIFICATE_REQUIRED, meta)
header.startsWith("1") -> Header(INPUT, meta)
header.startsWith("2") -> Header(SUCCESS, meta)
header.startsWith("3") -> Header(REDIRECT, meta)
header.startsWith("4") -> Header(TEMPORARY_FAILURE, meta)
header.startsWith("5") -> Header(PERMANENT_FAILURE, meta)
header.startsWith("6") -> Header(CLIENT_CERTIFICATE_REQUIRED, meta)
else -> Header(UNKNOWN, meta)
}
}
fun getCodeString(code: Int): String{
return when(code){
1 -> "Input"
2 -> "Success"
3 -> "Redirect"
4 -> "Temporary Failure"
5 -> "Permanent Failure"
6 -> "Client Certificate Required"
else -> "Unknown: $code"
}
}
class Header(val code: Int, val meta: String)
}

View File

@ -8,12 +8,14 @@ import android.net.Uri
import android.os.Bundle
import android.view.inputmethod.EditorInfo
import androidx.activity.viewModels
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.snackbar.Snackbar
import oppen.tva.R
import oppen.tva.databinding.ActivityTvaBinding
import oppen.tva.io.GeminiResponse
import oppen.tva.io.TvaState
import oppen.tva.io.history.CacheInterface
import oppen.tva.ui.overflow.OverflowPopup
@ -56,7 +58,7 @@ class TvaActivity : AppCompatActivity() {
is TvaState.AppQuery -> runOnUiThread{ showAlert("App backdoor/query not implemented yet") }
is TvaState.Requesting -> loadingView(true)
is TvaState.NotGeminiRequest -> externalProtocol(state)
is TvaState.ResponseError -> showAlert("${state.header.code}: ${state.header.meta}")
is TvaState.ResponseError -> showAlert("${GeminiResponse.getCodeString(state.header.code)}: ${state.header.meta}")
is TvaState.ResponseGemtext -> renderGemtext(state)
is TvaState.ResponseText -> runOnUiThread{ showAlert("Plain text display not implemented") }
is TvaState.TabChange -> binding.tabCount.text = "${state.count}"
@ -124,7 +126,14 @@ class TvaActivity : AppCompatActivity() {
private fun showAlert(message: String) = runOnUiThread{
loadingView(false)
Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show()
if(message.length > 40){
AlertDialog.Builder(this)
.setMessage(message)
.show()
}else {
Snackbar.make(binding.root, message, Snackbar.LENGTH_SHORT).show()
}
}
private fun externalProtocol(state: TvaState.NotGeminiRequest) = runOnUiThread {