Ray Rahke
05/16/2024, 1:44 PM<http://0.0.0.0:8080>
. But on javascript frontend websocket clients expect the url to begin with wss://
. How can I change ktor to use wss?Rob Elliot
05/16/2024, 1:46 PMwss://
is secure, have you tried using ws://
?
My recollection is that a ws://
will start with an http://
request and seek to upgrade the protocol to ws
, and wss://
will do the same with https://
Ray Rahke
05/16/2024, 1:49 PMRay Rahke
05/16/2024, 1:50 PMconst websocket = new WebSocket('<http://0.0.0.0:8080/ws>');
Ray Rahke
05/16/2024, 1:50 PMfun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
install(CORS) {
anyHost()
}
Ray Rahke
05/16/2024, 1:50 PMFirefox can't establish a connection to the server at <ws://0.0.0.0:8080/ws>.
Gleb Minaev
05/16/2024, 1:52 PMwebSocket("/ws")
, you get requests at <ws://localhost:8080/ws>
. See more in docs: https://ktor.io/docs/server-websockets.html#api-overviewRay Rahke
05/16/2024, 1:54 PMpackage com.example.plugins
import com.example.Connection
import io.ktor.server.application.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
import io.ktor.server.websocket.*
import io.ktor.websocket.*
import java.time.Duration
fun Application.configureSockets() {
install(WebSockets) {
pingPeriod = Duration.ofSeconds(15)
timeout = Duration.ofSeconds(15)
maxFrameSize = Long.MAX_VALUE
masking = false
}
routing {
val connections = mutableListOf<Connection>()
webSocket("/ws") {
println("Adding user!")
val thisConnection = Connection(this, "user-1")
connections += thisConnection
try {
send("You are connected! There are ${connections.count()} users here.")
for (frame in incoming) {
frame as? Frame.Text ?: continue
val receivedText = frame.readText()
val textWithUsername = "[${thisConnection.username}]: $receivedText"
connections.forEach {
it.session.send(textWithUsername)
}
}
} catch (e: Exception) {
println(e.localizedMessage)
} finally {
println("Removing $thisConnection!")
connections -= thisConnection
}
}
}
}
Ray Rahke
05/16/2024, 1:55 PMpackage com.example
import com.example.plugins.*
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.plugins.cors.CORS
import io.ktor.server.plugins.cors.routing.*
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
install(CORS) {
anyHost()
}
}.start(wait = true)
}
fun Application.module() {
configureSockets()
configureRouting()
}
Ray Rahke
05/16/2024, 1:56 PM[DefaultDispatcher-worker-2] INFO ktor.application - Responding at <http://0.0.0.0:8080>
Ray Rahke
05/16/2024, 2:00 PMfun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
install(CORS) {
anyHost()
}
}.start(wait = true)
}
to
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module)
.start(wait = true)
}
not sure how I am supposed to install CORS but it apparently is not caring about cors anymore either.Gleb Minaev
05/16/2024, 2:04 PManyHost()
(am I correct that it contains routings above?) inside install(CORS) { ... }
, but put it right after it. I'll check it right now.
P.S. Sorry, I did not find declaration of module
.Gleb Minaev
05/16/2024, 2:12 PMmodule
function in embeddedServer
? I don't see in the first listing of your last message, but it is explicitly applied with Application::module
in the second listing.Ray Rahke
05/16/2024, 2:13 PMRay Rahke
05/16/2024, 2:13 PMRay Rahke
05/16/2024, 2:14 PMGleb Minaev
05/16/2024, 2:14 PMmodule
function, configureSockets
won't be applied as well. Becausse configureSockets
is placed only in module
.Ray Rahke
05/16/2024, 2:15 PMRay Rahke
05/16/2024, 2:16 PMhfhbd
05/16/2024, 2:37 PMfun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0") {
install(CORS) {
anyHost()
}
module()
}.start(wait = true)
}
Joffrey
05/16/2024, 3:16 PMmodule
argument.
Here is some background to clarify how you should understand that you need Philip's approach.
First, there is a lot of useful information about function types, lambdas, and function references in the docs.
If you check the docs of embeddedServer, you'll notice that its last parameter (module
) is a function of type Application.() -> Unit
. This means it's a function that has a receiver of type Application
, no parameters, and return type Unit
(meaning it doesn't return anything useful).
Instances of functions can be "created" in several ways. One of them is to use a lambda expression with the code directly within braces ({ a, b -> a + b }
), another is using a function reference (::functionName
, SomeType::methodName
, ...), and there are other ways too.
In your case, you can pass the module
parameter of embeddedServer
as a lambda or with a function reference. When a lambda argument is the last argument of a function call, it can be passed outside the parenthese of the function call. This is why all of these are the same thing:
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module) // reference
.start(wait = true)
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = { module() }) // lambda
.start(wait = true)
}
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0") { module() } // lambda outside parens
.start(wait = true)
}
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0") { // lambda outside parens, but with new lines
module()
}.start(wait = true)
}
Since the module()
function is defined (by you) as an extension on Application
, you can use it directly in the lambda because embeddedServer
declares that the function you pass will get an Application
instance as a receiver.
If you use a lambda, you can call module()
but you can also write any code there, including calling other functions that can work with a receiver of type Application
, such as install()
.Joffrey
05/16/2024, 3:30 PMinstall()
and you start from the first form, you should first swith to the last form, and then you can add install()
next to the call to module()
. Another option is to keep the function reference to Application::module
, but add the call install()
directly inside `module()`:
fun main() {
embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module)
.start(wait = true)
}
fun Application.module() {
install(CORS) {
...
}
configureSockets()
configureRouting()
}