Skip to content

Commit

Permalink
Merge pull request #594 from hexagonkt/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
jaguililla committed Jan 6, 2023
2 parents 8bcf792 + 4b1eb96 commit 217445d
Show file tree
Hide file tree
Showing 35 changed files with 251 additions and 73 deletions.
2 changes: 1 addition & 1 deletion .github/actions/image_magick/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ runs:
sudo apt-get install librsvg2-bin
mkdir -p ~/.local/bin
export MAGICK="https://download.imagemagick.org/ImageMagick/download/binaries/magick"
[[ ! -f ~/.local/bin/magick ]] && sudo curl "$MAGICK" -o ~/.local/bin/magick
[[ ! -f ~/.local/bin/magick ]] && sudo curl "$MAGICK" -Lo ~/.local/bin/magick
sudo chmod +x ~/.local/bin/magick
magick --version
11 changes: 0 additions & 11 deletions .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,6 @@ on:
- pull_request

jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Check Out
uses: actions/checkout@v3
- name: Build Project
uses: ./.github/actions/gradle
- name: Check Build
run: ls -AlF core/build

sample_keystores:
name: Sample Keystores
runs-on: ubuntu-latest
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package com.hexagonkt.core.logging

import com.hexagonkt.core.logging.jul.JulLoggingAdapter
import kotlin.reflect.KClass

/**
* Manages Logs using [JulLoggingAdapter]
* Manages Logs using [PrintLoggingAdapter]
*/
object LoggingManager {
var useColor: Boolean = true
var adapter: LoggingPort = JulLoggingAdapter()
var adapter: LoggingPort = PrintLoggingAdapter()
var defaultLoggerName: String = "com.hexagonkt.core.logging"
set(value) {
require(value.isNotEmpty()) { "Default logger name cannot be empty string" }
Expand Down
14 changes: 14 additions & 0 deletions core/src/main/kotlin/com/hexagonkt/core/logging/PrintLogger.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.hexagonkt.core.logging

import com.hexagonkt.core.toText

data class PrintLogger(val name: String) : LoggerPort {

override fun <E : Throwable> log(level: LoggingLevel, exception: E, message: (E) -> Any?) {
println("$level - ${message(exception)}:\n${exception.toText()}")
}

override fun log(level: LoggingLevel, message: () -> Any?) {
println("$level - ${message()}")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.hexagonkt.core.logging

import com.hexagonkt.core.logging.LoggingLevel.INFO
import com.hexagonkt.core.require

class PrintLoggingAdapter(defaultLevel: LoggingLevel = INFO) : LoggingPort {

private val loggerLevels: MutableMap<String, LoggingLevel> = mutableMapOf("" to defaultLevel)

override fun createLogger(name: String): LoggerPort =
PrintLogger(name)

override fun setLoggerLevel(name: String, level: LoggingLevel) {
loggerLevels[name] = level
}

override fun isLoggerLevelEnabled(name: String, level: LoggingLevel): Boolean =
findLoggingLevel(name).ordinal <= level.ordinal

private fun findLoggingLevel(name: String): LoggingLevel {
var path = name

do {
val loggingLevel = loggerLevels[path]
if (loggingLevel != null)
return loggingLevel

path = path.substringBeforeLast('.')
}
while (path.contains('.'))

return loggerLevels.require("")
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.hexagonkt.core.logging

import com.hexagonkt.core.logging.LoggingLevel.*
import com.hexagonkt.core.logging.jul.JulLoggingAdapter
import io.mockk.every
import io.mockk.mockk
import org.junit.jupiter.api.Test
import java.lang.IllegalStateException
import kotlin.IllegalStateException
import kotlin.reflect.KClass
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
Expand All @@ -17,14 +16,16 @@ internal class LoggingManagerTest {
// TODO Repeat this test on other logging adapters
@Test fun `Loggers are enabled and disabled at runtime`() {

LoggingManager.adapter = JulLoggingAdapter()
LoggingManager.adapter = PrintLoggingAdapter()
val allLevels = LoggingLevel.values()

val ch = Logger("com.hx")
val chc = Logger("com.hx.core")
val chl = Logger("com.hx.logging")

LoggingManager.setLoggerLevel("com.hx", TRACE)
assertTrue(Logger("z").isLoggerLevelEnabled(INFO))
assertFalse(Logger("z").isLoggerLevelEnabled(DEBUG))
assertTrue(
allLevels.all {
ch.isLoggerLevelEnabled(it)
Expand Down
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ org.gradle.warning.mode=all
org.gradle.console=plain

# Gradle
version=2.3.1
version=2.4.0
group=com.hexagonkt
description=The atoms of your platform

Expand Down Expand Up @@ -42,7 +42,7 @@ mockkVersion=1.13.3
junitVersion=5.9.1
gatlingVersion=3.9.0
jmhVersion=1.36
mkdocsMaterialVersion=8.5.11
mkdocsMaterialVersion=9.0.2
mermaidDokkaVersion=0.4.2
nativeToolsVersion=0.9.19

Expand Down
1 change: 1 addition & 0 deletions gradle/kotlin.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ tasks.withType(Test) { testTask ->
testTask.useJUnitPlatform()
testTask.systemProperties(project.getProperties().findAll { it.value instanceof String })
testTask.systemProperty("file.encoding", "utf-8")
testTask.jvmArgs('--enable-preview')

testTask.testLogging {
if (logger.isInfoEnabled())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.hexagonkt.http.model.ws.WsCloseStatus
import com.hexagonkt.http.model.ws.WsSession
import java.io.Closeable
import java.net.URL
import java.util.concurrent.Flow.Publisher

/**
* Client to use other REST services.
Expand Down Expand Up @@ -59,6 +60,9 @@ class HttpClient(
fun send(request: HttpClientRequest): HttpClientResponse =
adapter.send(request)

fun sse(path: String): Publisher<ServerEvent> =
adapter.sse(path)

fun ws(
path: String,
onConnect: WsSession.() -> Unit = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package com.hexagonkt.http.client

import com.hexagonkt.http.client.model.HttpClientRequest
import com.hexagonkt.http.client.model.HttpClientResponse
import com.hexagonkt.http.model.ServerEvent
import com.hexagonkt.http.model.ws.WsCloseStatus
import com.hexagonkt.http.model.ws.WsSession
import java.util.concurrent.Flow.Publisher

interface HttpClientPort {

Expand All @@ -15,6 +17,8 @@ interface HttpClientPort {

fun send(request: HttpClientRequest): HttpClientResponse

fun sse(path: String): Publisher<ServerEvent>

fun ws(
path: String,
onConnect: WsSession.() -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package com.hexagonkt.http.client
import com.hexagonkt.http.client.model.HttpClientRequest
import com.hexagonkt.http.client.model.HttpClientResponse
import com.hexagonkt.http.model.Header
import com.hexagonkt.http.model.ServerEvent
import com.hexagonkt.http.model.ws.WsCloseStatus
import com.hexagonkt.http.model.ws.WsSession
import java.util.concurrent.Flow.Publisher

object VoidAdapter : HttpClientPort {
var started: Boolean = false
Expand All @@ -27,6 +29,9 @@ object VoidAdapter : HttpClientPort {
contentType = request.contentType,
)

override fun sse(path: String): Publisher<ServerEvent> =
error("Unsupported operation")

override fun ws(
path: String,
onConnect: WsSession.() -> Unit,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ import com.hexagonkt.http.client.HttpClientPort
import com.hexagonkt.http.client.HttpClientSettings
import com.hexagonkt.http.client.model.HttpClientRequest
import com.hexagonkt.http.client.model.HttpClientResponse
import com.hexagonkt.http.model.Cookie
import com.hexagonkt.http.model.Header
import com.hexagonkt.http.model.Headers
import com.hexagonkt.http.model.HttpStatus
import com.hexagonkt.http.model.*
import com.hexagonkt.http.model.ws.WsCloseStatus
import com.hexagonkt.http.model.ws.WsSession
import com.hexagonkt.http.parseContentType
Expand All @@ -29,9 +26,12 @@ import org.eclipse.jetty.http.HttpFields.EMPTY
import org.eclipse.jetty.http.HttpMethod
import org.eclipse.jetty.io.ClientConnector
import org.eclipse.jetty.websocket.client.WebSocketClient
import java.lang.StringBuilder
import java.net.CookieStore
import java.net.URI
import java.util.concurrent.ExecutionException
import java.util.concurrent.Flow.Publisher
import java.util.concurrent.SubmissionPublisher
import org.eclipse.jetty.client.HttpClient as JettyHttpClient
import org.eclipse.jetty.util.ssl.SslContextFactory.Client as ClientSslContextFactory

Expand Down Expand Up @@ -107,6 +107,35 @@ class JettyClientAdapter : HttpClientPort {
return JettyClientWsSession(uri, session)
}

override fun sse(path: String): Publisher<ServerEvent> {
check(started) { "HTTP client *MUST BE STARTED* before sending requests" }

val clientPublisher = SubmissionPublisher<ServerEvent>()

createJettyRequest(httpClient, jettyClient, HttpClientRequest(path = path))
.onResponseBegin {
if (it.status !in 200 until 300)
error("Invalid response: ${it.status}")
}
.onResponseContent { _, content ->
val sb = StringBuilder()
while (content.hasRemaining())
sb.append(Char(content.get().toInt()))

val evt = sb
.trim()
.lines()
.map { it.split(":") }
.associate { it.first().trim().lowercase() to it.last().trim() }
.let { ServerEvent(it["event"], it["data"], it["id"], it["retry"]?.toLong()) }

clientPublisher.submit(evt)
}
.send {}

return clientPublisher
}

private fun convertJettyResponse(
adapterHttpClient: HttpClient, adapterJettyClient: JettyHttpClient, response: Response
): HttpClientResponse {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,20 +179,22 @@ data class HttpServer(

val hostnameValue = "$BLUE$hostname$RESET"
val cpuCountValue = "$BLUE$cpuCount$RESET"
val jvmMemoryValue = "$BLUE${initialMemory()}$RESET"

val javaVersionValue = "$BOLD${BLUE}Java $version$RESET [$BLUE$name$RESET]"

val localeValue = "$BLUE$localeCode$RESET"
val timezoneValue = "$BLUE$timezone$RESET"
val charsetValue = "$BLUE$charset$RESET"

val bootTimeValue = "$BOLD$MAGENTA${uptime()} s$RESET"
val startUpTimeValue = "$BOLD$MAGENTA$startUpTime ms$RESET"
val usedMemoryValue = "$BOLD$MAGENTA${usedMemory()} KB$RESET"
val bindingValue = "$BLUE$UNDERLINE$binding$RESET"

val information = """
val information = if (settings.vmInformation) {
val jvmMemoryValue = "$BLUE${initialMemory()}$RESET"
val bootTimeValue = "$BOLD$MAGENTA${uptime()} s$RESET"
val usedMemoryValue = "$BOLD$MAGENTA${usedMemory()} KB$RESET"

"""
Server Adapter: $serverAdapterValue ($protocols)
Supported Features: $features
Expand All @@ -205,9 +207,26 @@ data class HttpServer(
⏱️ Started in $bootTimeValue (server: $startUpTimeValue) using $usedMemoryValue
🚀 Served at $bindingValue${if (protocol == HTTP2) " (HTTP/2)" else "" }
""".trimIndent()
"""
}
else {
"""
Server Adapter: $serverAdapterValue ($protocols)
Supported Features: $features
Configuration Options: $options
🖥️️ Running in '$hostnameValue' with $cpuCountValue CPUs
🛠 Using $javaVersionValue
🌍 Locale: $localeValue Timezone: $timezoneValue Charset: $charsetValue
⏱️ Started in $startUpTimeValue (excluding VM)
🚀 Served at $bindingValue${if (protocol == HTTP2) " (HTTP/2)" else "" }
"""
}

val banner = (settings.banner?.let { "$it\n" } ?: banner) + information
val banner = (settings.banner?.let { "$it\n" } ?: banner) + information.trimIndent()
return banner.prependIndent()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import java.net.InetAddress
* @property sslSettings SSL settings info for configuring the server.
* @property banner Server banner message.
* @property zip Option to compress server responses.
* @property vmInformation If true, show JVM information on start banner. If enabled, it forces
* the `java.management` module to be included.
*/
data class HttpServerSettings(
val bindAddress: InetAddress = InetAddress.getLoopbackAddress(),
Expand All @@ -24,4 +26,5 @@ data class HttpServerSettings(
val sslSettings: SslSettings? = null,
val banner: String? = null,
val zip: Boolean = false,
val vmInformation: Boolean = false,
)
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,23 @@ internal class HttpServerTest {
banner = bannerPrefix,
)

val server = serve(VoidAdapter, serverSettings) {}
val createdBanner = server.createBanner(System.currentTimeMillis())
server.stop()

assertEquals(bannerPrefix, createdBanner.lines()[0].trimIndent())
assertContains(createdBanner, "✅HTTP" )
assertContains(createdBanner, "HTTPS")
assertFalse(createdBanner.contains("ZIP"))
assertFalse(createdBanner.contains("✅HTTPS"))
val banners = listOf(
serve(VoidAdapter, serverSettings) {},
serve(VoidAdapter, serverSettings.copy(vmInformation = true)) {}
)
.map {
it.createBanner(System.currentTimeMillis())
}
.map {
assertEquals(bannerPrefix, it.lines()[0].trimIndent())
assertContains(it, "✅HTTP" )
assertContains(it, "HTTPS")
assertFalse(it.contains("ZIP"))
assertFalse(it.contains("✅HTTPS"))
it
}
assertContains(banners.first(), "(excluding VM)")
assertFalse(banners.last().contains("(excluding VM)"))
}

@Test fun `Banner creation with enabled features and custom options`() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ class JettyServletAdapter(

override fun startUp(server: HttpServer) {
val settings = server.settings
val threadPool = QueuedThreadPool(maxThreads, minThreads)
if (useVirtualThreads)
threadPool.virtualThreadsExecutor = VirtualThreads.getDefaultVirtualThreadsExecutor()
val threadPool =
if (useVirtualThreads) VirtualThreadPool()
else QueuedThreadPool(maxThreads, minThreads)
val serverInstance = JettyServer(threadPool)
jettyServer = serverInstance

Expand Down

0 comments on commit 217445d

Please sign in to comment.