package oppen.tva.io import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import java.io.* import java.net.URI import java.security.SecureRandom import javax.net.ssl.* const val GEMINI_SCHEME = "gemini" class GeminiDatasource: Datasource{ override fun request(uri: URI, onUpdate: (state: TvaState) -> Unit) { //Any inputted uri starting with a colon is an app-specific command, eg. :prefs :settings if(uri.toString().startsWith(":")){ onUpdate(TvaState.AppQuery(uri)) return } when (uri.scheme) { GEMINI_SCHEME -> { //Indicate app should show progress indicator onUpdate(TvaState.Requesting(uri)) GlobalScope.launch { geminiRequest(uri, onUpdate) } } else -> onUpdate(TvaState.NotGeminiRequest(uri)) } } /** * * This was largely copied from https://framagit.org/waweic/gemini-client/-/blob/master/app/src/main/java/rocks/ism/decentral/geminiclient/GeminiConnection.kt * */ private fun geminiRequest(uri: URI, onUpdate: (state: TvaState) -> Unit){ val port = if(uri.port == -1) 1965 else uri.port val sslContext = SSLContext.getInstance("TLSv1.2") 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() // OUT >>>>>>>>>>>>>>>>>>>>>>>>>> val outputStreamWriter = OutputStreamWriter(socket.outputStream) val bufferedWriter = BufferedWriter(outputStreamWriter) val outWriter = PrintWriter(bufferedWriter) outWriter.print(uri.toString() + "\r\n") outWriter.flush() if (outWriter.checkError()) { onUpdate(TvaState.GeminiPrintWriterError) outWriter.close() return } // IN <<<<<<<<<<<<<<<<<<<<<<<<<<< val lines = mutableListOf() socket.inputStream.reader().use { inputStreamReader -> BufferedReader(inputStreamReader).use { reader -> lines.addAll(reader.readLines()) } } val header = lines.firstOrNull() ?: "" lines.removeAt(0) println("Tva: header: $header") lines.forEach { println("Tva: line: $it") } println("Tva: ends -----------------") outputStreamWriter.close() bufferedWriter.close() outWriter.close() onUpdate(TvaState.GeminiResponse(uri, header, lines)) } }