gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libeufin] branch master updated (35c2cb9 -> 4424785)


From: gnunet
Subject: [libeufin] branch master updated (35c2cb9 -> 4424785)
Date: Mon, 11 Oct 2021 09:51:00 +0200

This is an automated email from the git hooks/post-receive script.

ms pushed a change to branch master
in repository libeufin.

    from 35c2cb9  syntax
     new 569904a  log conf
     new b2423b3  Logging and sending HTTP chunks via library's handlers.
     new 0a01af8  renaming
     new afacf8c  Ask env for base URL.
     new 4424785  ignore trial-and-error test

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../tech/libeufin/nexus/server/NexusServer.kt      |  10 +-
 nexus/src/main/resources/logback.xml               |   1 +
 .../src/main/kotlin/tech/libeufin/sandbox/Main.kt  |  41 ++++----
 util/src/main/kotlin/Config.kt                     |   6 +-
 util/src/main/kotlin/UnixDomainSocket.kt           | 110 ++++++++++++---------
 util/src/test/kotlin/DomainSocketTest.kt           |  14 ++-
 .../main => util/src/test}/resources/logback.xml   |   6 +-
 7 files changed, 107 insertions(+), 81 deletions(-)
 copy {sandbox/src/main => util/src/test}/resources/logback.xml (79%)

diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt 
b/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt
index 5fb37ea..a9a2e64 100644
--- a/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt
+++ b/nexus/src/main/kotlin/tech/libeufin/nexus/server/NexusServer.kt
@@ -54,6 +54,12 @@ import tech.libeufin.util.*
 import java.net.BindException
 import java.net.URLEncoder
 import kotlin.system.exitProcess
+import java.net.URL
+
+private val baseUrl = URL(
+    getValueFromEnv("LIBEUFIN_NEXUS_BASE_URL") ?: throw Exception(
+        "env LIBEUFIN_NEXUS_BASE_URL is not defined")
+)
 
 /**
  * Return facade state depending on the type.
@@ -895,7 +901,7 @@ val nexusApp: Application.() -> Unit = {
                     type = f.type,
                     baseUrl = call.url {
                         parameters.clear()
-                        encodedPath = ""
+                        encodedPath = baseUrl.path
                         pathComponents("facades", f.facadeName, f.type)
                         encodedPath += "/"
                     },
@@ -922,7 +928,7 @@ val nexusApp: Application.() -> Unit = {
                             type = it.type,
                             baseUrl = call.url {
                                 parameters.clear()
-                                encodedPath = ""
+                                encodedPath = baseUrl.path
                                 pathComponents("facades", it.facadeName, 
it.type)
                                 encodedPath += "/"
                             },
diff --git a/nexus/src/main/resources/logback.xml 
b/nexus/src/main/resources/logback.xml
index 54df1d0..d4e1605 100644
--- a/nexus/src/main/resources/logback.xml
+++ b/nexus/src/main/resources/logback.xml
@@ -14,6 +14,7 @@
     <logger name="io.netty" level="WARN"/>
     <logger name="ktor" level="WARN"/>
     <logger name="Exposed" level="WARN"/>
+    <logger name="tech.libeufin.util" level="DEBUG"/>
 
     <root level="WARN">
         <appender-ref ref="STDERR"/>
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt 
b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
index 9411577..d0e8f7e 100644
--- a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
+++ b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -63,16 +63,12 @@ import com.github.ajalt.clikt.parameters.options.*
 import com.github.ajalt.clikt.parameters.types.int
 import execThrowableOrTerminate
 import io.ktor.application.ApplicationCall
-import io.ktor.application.ApplicationCallPipeline
 import io.ktor.application.call
 import io.ktor.application.install
-import io.ktor.features.CallLogging
-import io.ktor.features.ContentNegotiation
 import org.jetbrains.exposed.sql.statements.api.ExposedBlob
 import com.fasterxml.jackson.core.util.DefaultIndenter
 import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
 import com.fasterxml.jackson.module.kotlin.KotlinModule
-import com.fasterxml.jackson.databind.SerializationFeature
 import 
org.jetbrains.exposed.sql.transactions.experimental.newSuspendedTransaction
 import io.ktor.features.StatusPages
 import io.ktor.response.respond
@@ -84,19 +80,23 @@ import io.ktor.routing.*
 import io.ktor.server.netty.*
 import io.ktor.util.date.*
 import io.ktor.application.*
+import io.ktor.util.*
 import kotlinx.coroutines.newSingleThreadContext
 import startServer
 import tech.libeufin.util.*
 import validatePlainAmount
 import java.net.BindException
-import java.util.*
+import java.net.URL
 import kotlin.system.exitProcess
 
 private val logger: Logger = LoggerFactory.getLogger("tech.libeufin.sandbox")
-private val hostName: String? = getValueFromEnv("LIBEUFIN_SANDBOX_HOSTNAME")
 private val currencyEnv: String? = getValueFromEnv("LIBEUFIN_SANDBOX_CURRENCY")
 private val envName: String? = getValueFromEnv("TALER_ENV_NAME")
 const val SANDBOX_DB_ENV_VAR_NAME = "LIBEUFIN_SANDBOX_DB_CONNECTION"
+private val baseUrl = URL(
+    getValueFromEnv("LIBEUFIN_SANDBOX_BASE_URL") ?: throw Exception(
+        "env LIBEUFIN_SANDBOX_BASE_URL is not defined")
+)
 
 data class SandboxError(
     val statusCode: HttpStatusCode,
@@ -889,24 +889,20 @@ val sandboxApp: Application.() -> Unit = {
          */
         get("/taler") {
             requireSuperuser(call.request)
-            SandboxAssert(
-                hostName != null,
-                "Own hostname not found.  Logs should have warned"
-            )
             SandboxAssert(
                 currencyEnv != null,
                 "Currency not found.  Logs should have warned"
             )
             // check that the three canonical accounts exist
             val wo = transaction {
-                val exchange = tech.libeufin.sandbox.BankAccountEntity.find {
-                    tech.libeufin.sandbox.BankAccountsTable.label eq 
"sandbox-account-exchange"
+                val exchange = BankAccountEntity.find {
+                    BankAccountsTable.label eq "sandbox-account-exchange"
                 }.firstOrNull()
-                val customer = tech.libeufin.sandbox.BankAccountEntity.find {
-                    tech.libeufin.sandbox.BankAccountsTable.label eq 
"sandbox-account-customer"
+                val customer = BankAccountEntity.find {
+                    BankAccountsTable.label eq "sandbox-account-customer"
                 }.firstOrNull()
-                val merchant = tech.libeufin.sandbox.BankAccountEntity.find {
-                    tech.libeufin.sandbox.BankAccountsTable.label eq 
"sandbox-account-merchant"
+                val merchant = BankAccountEntity.find {
+                    BankAccountsTable.label eq "sandbox-account-merchant"
                 }.firstOrNull()
 
                 SandboxAssert(exchange != null, "exchange has no bank account")
@@ -914,15 +910,22 @@ val sandboxApp: Application.() -> Unit = {
                 SandboxAssert(merchant != null, "merchant has no bank account")
 
                 // At this point, the three actors exist and a new withdraw 
operation can be created.
-                tech.libeufin.sandbox.TalerWithdrawalEntity.new {
+                TalerWithdrawalEntity.new {
                     // wopid is autogenerated, and momentarily the only column
-
                 }
             }
             /**
              * Future versions will include the QR code in this response.
              */
-            call.respondText("taler://withdraw/${hostName}/api/${wo.wopid}")
+            val ret = call.url {
+                protocol = URLProtocol(
+                    "taler".plus(if (baseUrl.protocol.lowercase() == "http") 
"+http" else ""),
+                    -1
+                )
+                pathComponents(baseUrl.path, "api", wo.wopid.toString())
+                encodedPath += "/"
+            }
+            call.respondText(ret)
             return@get
         }
         get("/api/config") {
diff --git a/util/src/main/kotlin/Config.kt b/util/src/main/kotlin/Config.kt
index bda57ea..8a9aa43 100644
--- a/util/src/main/kotlin/Config.kt
+++ b/util/src/main/kotlin/Config.kt
@@ -51,12 +51,12 @@ fun setLogLevel(logLevel: String?) {
 }
 
 fun getValueFromEnv(varName: String): String? {
-    val hostName = System.getenv(varName)
-    if (hostName.isNullOrBlank() or hostName.isNullOrEmpty()) {
+    val ret = System.getenv(varName)
+    if (ret.isNullOrBlank() or ret.isNullOrEmpty()) {
         println("WARNING, $varName was not found in the environment. Will stay 
unknown")
         return null
     }
-    return hostName
+    return ret
 }
 
 fun getDbConnFromEnv(varName: String): String {
diff --git a/util/src/main/kotlin/UnixDomainSocket.kt 
b/util/src/main/kotlin/UnixDomainSocket.kt
index b2713f2..448f1d5 100644
--- a/util/src/main/kotlin/UnixDomainSocket.kt
+++ b/util/src/main/kotlin/UnixDomainSocket.kt
@@ -1,75 +1,75 @@
 import io.ktor.application.*
 import io.ktor.client.statement.*
 import io.ktor.http.*
+import io.ktor.http.HttpHeaders
 import io.ktor.http.HttpMethod
 import io.ktor.server.engine.*
 import io.ktor.server.testing.*
+import io.ktor.utils.io.pool.*
 import io.netty.bootstrap.ServerBootstrap
+import io.netty.buffer.ByteBuf
 import io.netty.buffer.ByteBufInputStream
 import io.netty.buffer.Unpooled
+import io.netty.buffer.UnpooledDirectByteBuf
 import io.netty.channel.*
 import io.netty.channel.epoll.EpollEventLoopGroup
 import io.netty.channel.epoll.EpollServerDomainSocketChannel
 import io.netty.channel.unix.DomainSocketAddress
+import io.netty.handler.codec.LengthFieldPrepender
 import io.netty.handler.codec.http.*
 import io.netty.handler.codec.http.DefaultHttpResponse
+import io.netty.handler.codec.http.HttpMessage
+import io.netty.handler.logging.LogLevel
+import io.netty.handler.logging.LoggingHandler
+import io.netty.handler.stream.ChunkedInput
+import io.netty.handler.stream.ChunkedStream
+import io.netty.handler.stream.ChunkedWriteHandler
 import io.netty.util.AttributeKey
+import io.netty.util.ReferenceCountUtil
+import org.slf4j.LoggerFactory
+import java.io.ByteArrayInputStream
+import java.io.InputStream
+import java.nio.charset.Charset
 
 fun startServer(unixSocketPath: String, app: Application.() -> Unit) {
-
     val boss = EpollEventLoopGroup()
     val worker = EpollEventLoopGroup()
-    val serverBootstrap = ServerBootstrap()
-    serverBootstrap.group(boss, worker).channel(
-        EpollServerDomainSocketChannel::class.java
-    ).childHandler(LibeufinHttpInit(app))
-
-    val socketPath = DomainSocketAddress(unixSocketPath)
-    serverBootstrap.bind(socketPath).sync().channel().closeFuture().sync()
+    try {
+        val serverBootstrap = ServerBootstrap()
+        serverBootstrap.group(boss, worker).channel(
+            EpollServerDomainSocketChannel::class.java
+        ).childHandler(LibeufinHttpInit(app))
+        val socketPath = DomainSocketAddress(unixSocketPath)
+        logger.debug("Listening on $unixSocketPath ..")
+        serverBootstrap.bind(socketPath).sync().channel().closeFuture().sync()
+    } finally {
+        boss.shutdownGracefully()
+        worker.shutdownGracefully()
+    }
 }
 
-private val ktorApplicationKey = AttributeKey.newInstance<Application.() -> 
Unit>("KtorApplicationCall")
-
-class LibeufinHttpInit(private val app: Application.() -> Unit) : 
ChannelInitializer<Channel>() {
+class LibeufinHttpInit(
+    private val app: Application.() -> Unit
+) : ChannelInitializer<Channel>() {
     override fun initChannel(ch: Channel) {
-        val libeufinHandler = LibeufinHttpHandler()
         ch.pipeline(
-        ).addLast(
-            HttpServerCodec()
-        ).addLast(
-            HttpObjectAggregator(Int.MAX_VALUE)
-        ).addLast(
-            libeufinHandler
-        )
-        val libeufinCtx: ChannelHandlerContext = 
ch.pipeline().context(libeufinHandler)
-        libeufinCtx.attr(ktorApplicationKey).set(app)
+        ).addLast(LoggingHandler("tech.libeufin.util")
+        ).addLast(HttpServerCodec() // in- and out- bound
+        ).addLast(HttpObjectAggregator(Int.MAX_VALUE) // only in- bound
+        ).addLast(ChunkedWriteHandler()
+        ).addLast(LibeufinHttpHandler(app)) // in- bound, and triggers out- 
bound.
     }
 }
 
-class LibeufinHttpHandler : SimpleChannelInboundHandler<FullHttpRequest>() {
-
+class LibeufinHttpHandler(
+    private val app: Application.() -> Unit
+) : SimpleChannelInboundHandler<FullHttpRequest>() {
     @OptIn(EngineAPI::class)
-    override fun channelRead0(ctx: ChannelHandlerContext?, msg: 
FullHttpRequest) {
-        val app = ctx?.attr(ktorApplicationKey)?.get()
-        if (app == null) throw UtilError(
-            HttpStatusCode.InternalServerError,
-            "custom libEufin Unix-domain-socket+HTTP handler lost its Web app",
-            null
-        )
-        /**
-         * Below is only a echo of what euFin gets from the network.  All
-         * the checks should then occur at the Web app + Ktor level.  Hence,
-         * a HTTP call of GET with a non-empty body is not to be blocked / 
warned
-         * at this level.
-         *
-         * The only exception is the HTTP version value in the response, as the
-         * response returned by the Web app does not set it.  Therefore, this
-         * proxy echoes back the HTTP version that was read in the request.
-         */
+    override fun channelRead0(ctx: ChannelHandlerContext, msg: 
FullHttpRequest) {
         withTestApplication(app) {
             val httpVersion = msg.protocolVersion()
-            // Proxying the request with Ktor API.
-            val call = handleRequest(closeRequest = false) {
+            // Proxying the request to Ktor API.
+            val call = handleRequest {
                 msg.headers().forEach { addHeader(it.key, it.value) }
                 method = HttpMethod(msg.method().name())
                 uri = msg.uri()
@@ -81,17 +81,29 @@ class LibeufinHttpHandler : 
SimpleChannelInboundHandler<FullHttpRequest>() {
                 "app proxied via Unix domain socket did not include a response 
status code",
                 ec = null // FIXME: to be defined.
             )
-            // Responding with Netty API.
-            val response = DefaultFullHttpResponse(
+            // Responding to Netty API.
+            val response = DefaultHttpResponse(
                 httpVersion,
-                HttpResponseStatus.valueOf(statusCode),
-                Unpooled.wrappedBuffer(call.response.byteContent ?: 
ByteArray(0))
+                HttpResponseStatus.valueOf(statusCode)
             )
+            var chunked = false
             call.response.headers.allValues().forEach { s, list ->
-                response.headers().set(s, list.joinToString()) // 
joinToString() separates with ", " by default.
+                if (s == HttpHeaders.TransferEncoding && 
list.contains("chunked"))
+                    chunked = true
+                response.headers().set(s, list.joinToString())
+            }
+            ctx.writeAndFlush(response)
+            if (chunked) {
+                ctx.writeAndFlush(
+                    HttpChunkedInput(
+                        ChunkedStream(
+                            ByteArrayInputStream(call.response.byteContent)
+                        )
+                    )
+                )
+            } else {
+                
ctx.writeAndFlush(Unpooled.wrappedBuffer(call.response.byteContent))
             }
-            ctx.write(response)
-            ctx.flush()
         }
     }
 }
\ No newline at end of file
diff --git a/util/src/test/kotlin/DomainSocketTest.kt 
b/util/src/test/kotlin/DomainSocketTest.kt
index d6e5c18..73e2cdd 100644
--- a/util/src/test/kotlin/DomainSocketTest.kt
+++ b/util/src/test/kotlin/DomainSocketTest.kt
@@ -1,3 +1,8 @@
+import com.fasterxml.jackson.core.util.DefaultIndenter
+import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
+import com.fasterxml.jackson.databind.DeserializationFeature
+import com.fasterxml.jackson.databind.SerializationFeature
+import com.fasterxml.jackson.module.kotlin.KotlinModule
 import io.ktor.application.*
 import io.ktor.features.*
 import io.ktor.http.*
@@ -6,22 +11,21 @@ import io.ktor.routing.*
 import org.junit.Test
 import io.ktor.jackson.jackson
 import io.ktor.request.*
+import org.junit.Assert
+import org.junit.Ignore
 
 class DomainSocketTest {
-    // @Test
+    @Test @Ignore
     fun bind() {
         startServer("/tmp/java.sock") {
             install(ContentNegotiation) { jackson() }
             routing {
-                // responds with a empty JSON object.
                 get("/") {
                     this.call.respond(object {})
                     return@get
                 }
-                // echoes what it read in the request.
                 post("/") {
-                    val body = this.call.receiveText()
-                    this.call.respondText(body)
+                    this.call.respond(object {})
                     return@post
                 }
             }
diff --git a/sandbox/src/main/resources/logback.xml 
b/util/src/test/resources/logback.xml
similarity index 79%
copy from sandbox/src/main/resources/logback.xml
copy to util/src/test/resources/logback.xml
index d761ec6..4e7740a 100644
--- a/sandbox/src/main/resources/logback.xml
+++ b/util/src/test/resources/logback.xml
@@ -1,12 +1,12 @@
 <configuration>
     <appender name="STDERR" class="ch.qos.logback.core.ConsoleAppender">
-       <target>System.err</target>
+        <target>System.err</target>
         <encoder>
             <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - 
%msg%n</pattern>
         </encoder>
     </appender>
 
-    <logger name="tech.libeufin.sandbox" level="DEBUG"  additivity="false">
+    <logger name="tech.libeufin.util" level="DEBUG"  additivity="false">
         <appender-ref ref="STDERR" />
     </logger>
 
@@ -18,4 +18,4 @@
         <appender-ref ref="STDERR" />
     </root>
 
-</configuration>
+</configuration>
\ No newline at end of file

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]