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()
}