https://kotlinlang.org logo
Docs
Join the conversationJoin Slack
Channels
100daysofcode
100daysofkotlin
100daysofkotlin-2021
advent-of-code
aem
ai
alexa
algeria
algolialibraries
amsterdam
android
android-architecture
android-databinding
android-studio
androidgithubprojects
androidthings
androidx
androidx-xprocessing
anime
anko
announcements
apollo-kotlin
appintro
arabic
argentina
arkenv
arksemdevteam
armenia
arrow
arrow-contributors
arrow-meta
ass
atlanta
atm17
atrium
austin
australia
austria
awesome-kotlin
ballast
bangladesh
barcelona
bayarea
bazel
beepiz-libraries
belgium
berlin
big-data
books
boston
brazil
brikk
budapest
build
build-tools
bulgaria
bydgoszcz
cambodia
canada
carrat
carrat-dev
carrat-feed
chicago
chile
china
chucker
cincinnati-user-group
cli
clikt
cloudfoundry
cn
cobalt
code-coverage
codeforces
codemash-precompiler
codereview
codingame
codingconventions
coimbatore
collaborations
colombia
colorado
communities
competitive-programming
competitivecoding
compiler
compose
compose-android
compose-desktop
compose-hiring
compose-ios
compose-mp
compose-ui-showcase
compose-wear
compose-web
connect-audit-events
corda
cork
coroutines
couchbase
coursera
croatia
cryptography
cscenter-course-2016
cucumber-bdd
cyprus
czech
dagger
data2viz
databinding
datascience
dckotlin
debugging
decompose
decouple
denmark
deprecated
detekt
detekt-hint
dev-core
dfw
docs-revamped
dokka
domain-driven-design
doodle
dsl
dublin
dutch
eap
eclipse
ecuador
edinburgh
education
effective-kotlin
effectivekotlin
emacs
embedded-kotlin
estatik
event21-community-content
events
exposed
failgood
fb-internal-demo
feed
firebase
flow
fluid-libraries
forkhandles
forum
fosdem
fp-in-kotlin
framework-elide
freenode
french
fritz2
fuchsia
functional
funktionale
gamedev
ge-kotlin
general-advice
georgia
geospatial
german-lang
getting-started
github-workflows-kt
glance
godot-kotlin
google-io
gradle
graphic
graphkool
graphql
graphql-kotlin
graviton-browser
greece
grpc
gsoc
gui
hackathons
hacktoberfest
hamburg
hamkrest
helios
helsinki
hexagon
hibernate
hikari-cp
hire-me
hiring
hongkong
hoplite
http4k
hungary
hyderabad
image-processing
india
indonesia
inkremental
intellij
intellij-plugins
intellij-tricks
internships
introduce-yourself
io
ios
iran
israel
istanbulcoders
italian
jackson-kotlin
jadx
japanese
jasync-sql
java-to-kotlin-refactoring
javadevelopers
javafx
javalin
javascript
jdbi
jhipster-kotlin
jobsworldwide
jpa
jshdq
juul-libraries
jvm-ir-backend-feedback
jxadapter
k2-early-adopters
kaal
kafka
kakao
kalasim
kapt
karachi
karg
karlsruhe
kash_shell
kaskade
kbuild
kdbc
kgen-doc-tools
kgraphql
kinta
klaxon
klock
kloudformation
kmdc
kmm-español
kmongo
knbt
knote
koalaql
koans
kobalt
kobweb
kodein
kodex
kohesive
koin
koin-dev
komapper
kondor-json
kong
kontent
kontributors
korau
korean
korge
korim
korio
korlibs
korte
kotest
kotest-contributors
kotless
kotlick
kotlin-asia
kotlin-beam
kotlin-by-example
kotlin-csv
kotlin-data-storage
kotlin-foundation
kotlin-fuel
kotlin-in-action
kotlin-inject
kotlin-latam
kotlin-logging
kotlin-multiplatform-contest
kotlin-mumbai
kotlin-native
kotlin-pakistan
kotlin-plugin
kotlin-pune
kotlin-roadmap
kotlin-samples
kotlin-sap
kotlin-serbia
kotlin-spark
kotlin-szeged
kotlin-website
kotlinacademy
kotlinbot
kotlinconf
kotlindl
kotlinforbeginners
kotlingforbeginners
kotlinlondon
kotlinmad
kotlinprogrammers
kotlinsu
kotlintest
kotlintest-devs
kotlintlv
kotlinultimatechallenge
kotlinx-datetime
kotlinx-files
kotlinx-html
kotrix
kotson
kovenant
kprompt
kraph
krawler
kroto-plus
ksp
ktcc
ktfmt
ktlint
ktor
ktp
kubed
kug-leads
kug-torino
kvision
kweb
lambdaworld_cadiz
lanark
language-evolution
language-proposals
latvia
leakcanary
leedskotlinusergroup
lets-have-fun
libgdx
libkgd
library-development
linkeddata
lithuania
london
losangeles
lottie
love
lychee
macedonia
machinelearningbawas
madrid
malaysia
mathematics
meetkotlin
memes
meta
metro-detroit
mexico
miami
micronaut
minnesota
minutest
mirror
mockk
moko
moldova
monsterpuzzle
montreal
moonbean
morocco
motionlayout
mpapt
mu
multiplatform
mumbai
munich
mvikotlin
mvrx
myndocs-oauth2-server
naming
navigation-architecture-component
nepal
new-mexico
new-zealand
newname
nigeria
nodejs
norway
npm-publish
nyc
oceania
ohio-kotlin-users
oldenburg
oolong
opensource
orbit-mvi
osgi
otpisani
package-search
pakistan
panamá
pattern-matching
pbandk
pdx
peru
philippines
phoenix
pinoy
pocketgitclient
polish
popkorn
portugal
practical-functional-programming
proguard
prozis-android-backup
pyhsikal
python
python-contributors
quasar
random
re
react
reaktive
realm
realworldkotlin
reductor
reduks
redux
redux-kotlin
refactoring-to-kotlin
reflect
refreshversions
reports
result
rethink
revolver
rhein-main
rocksdb
romania
room
rpi-pico
rsocket
russian
russian_feed
russian-kotlinasfirst
rx
rxjava
san-diego
science
scotland
scrcast
scrimage
script
scripting
seattle
serialization
server
sg-user-group
singapore
skia-wasm-interop-temp
skrape-it
slovak
snake
sofl-user-group
southafrica
spacemacs
spain
spanish
speaking
spek
spin
splitties
spotify-mobius
spring
spring-security
squarelibraries
stackoverflow
stacks
stayhungrystayfoolish
stdlib
stlouis
strife-discord-lib
strikt
students
stuttgart
sudan
swagger-gradle-codegen
swarm
sweden
swing
swiss-user-group
switzerland
talking-kotlin
tallinn
tampa
teamcity
tegal
tempe
tensorflow
terminal
test
testing
testtestest
texas
tgbotapi
thailand
tornadofx
touchlab-tools
training
tricity-kotlin-user-group
trójmiasto
truth
tunisia
turkey
turkiye
twitter-feed
uae
udacityindia
uk
ukrainian
uniflow
unkonf
uruguay
utah
uuid
vancouver
vankotlin
vertx
videos
vienna
vietnam
vim
vkug
vuejs
web-mpp
webassembly
webrtc
wimix_sentry
wwdc
zircon
Powered by Linen
ktor
  • p

    Phil Richardson

    04/10/2022, 11:40 AM
    Should 2.0 docs be the default at this stage?
    ☝️ 1
    r
    a
    • 3
    • 2
  • c

    ct

    04/10/2022, 3:57 PM
    Hey there. I’m trying to get my head around Ktor2 by creating a simple REST endpoint to manage things called ‘agents’.
    @Serializable
    data class Agent(val id: Int, val hostname: String, val port: Int)
    I’m struggling with handling POST:
    @Serializable
    @Resource("/api/agents")
    data class AgentsRoute(val sort: String? = "id") {
        @Serializable
        @Resource("{id}")
        data class Id(val parent: AgentsRoute = AgentsRoute(), val id: Int)
    }
    
    fun Application.agentRoutes() {
        val agentService = AgentService() // Talks to the database
    
        routing {
            get<AgentsRoute> {
                call.respond(agentService.getAll())
            }
            get<AgentsRoute.Id> { request ->
                val agent = agentService.get(request.id) ?: call.respond(
                    HttpStatusCode.NotFound, "Agent not found"
                )
                call.respond(agent)
            }
            post<AgentsRoute> {
                val agent = call.receive<Agent>() // This blows up!
                // TODO
            }
            delete<AgentsRoute.Id> { request ->
                agentService.get(request.id) ?: call.respond(
                    HttpStatusCode.NotFound, "Agent not found"
                )
                call.respond(agentService.delete(request.id))
            }
        }
    }
    I’m having a problem with the
    POST
    when I post some data to create a new agent:
    {
      "hostname": "192.168.1.1",
      "port": 1012
    }
    Here’s the exception:
    2022-04-10 16:51:06.740 [eventLoopGroupProxy-4-1] ERROR Application - Unhandled: POST - /api/agents/
    kotlinx.serialization.MissingFieldException: Field 'id' is required for type with serial name 'com.sonalake.snmpsim.model.Agent', but it was missing
            at kotlinx.serialization.internal.PluginExceptionsKt.throwMissingFieldException(PluginExceptions.kt:20)
    I understand why it’s happening - the JSON doesn’t contain an id property - but, as I want to create a new agent I don’t want to have to provide one. I had a look at the Ktor 2.0.0 resource-routing code snippet, but it didn’t go further than receiving the request. Any suggests on the idiomatic Ktor 2 way of doing this? Thank you 🙇
    s
    j
    • 3
    • 8
  • n

    Nick Halase

    04/10/2022, 5:33 PM
    Why do I often see ktor apps with the routing module using
    install(Routing)
    and others just declare routing directly? Is the install for the routing module really optional?
    s
    • 2
    • 1
  • h

    hfhbd

    04/11/2022, 4:01 AM
    Ktor 2.0: Should you apply @KtorDsl to a custom plugin? To the variable
    @KtorDsl val myPlugin = createRouteScopedPlugin("myPlugin, ::Config) {}
    AND to
    @KtorDsl class Config
    too?
    a
    r
    • 3
    • 7
  • h

    hhariri

    04/11/2022, 1:35 PM
    📣 Ktor 2.0.0 is now available 📣 https://blog.jetbrains.com/ktor/2022/04/11/ktor-2-0-released/
    🎉 6
    🚀 20
    👏🏼 3
    :thank-you: 7
    👏 6
    :kotlin-intensifies: 41
    :ktor: 10
    ❤️ 4
    o
    d
    +2
    • 5
    • 4
  • v

    Vivek Modi

    04/11/2022, 3:41 PM
    Hey I want to understand, what is the use of this
    ContentNegotiation
    in ktor in client side? Can someone guide me.
    a
    m
    • 3
    • 4
  • d

    dodalovic

    04/11/2022, 6:36 PM
    Is koin still incompatible with ktor 2? If so - is there some alternative?
    n
    r
    d
    • 4
    • 6
  • h

    hawklike

    04/11/2022, 7:35 PM
    TL;DR Is there a way how to react to the unauthorized response by the Authentication feature, i.e. do something before (automatically) returning the 401 response? Hi, I have deployed my Ktor app to Heroku. When I make a POST request that uploads a file (via multipart/form-data) while the user is not authorized (token has expired), I got the 401 response as intended on my localhost. I use JWT and the Authentication feature. However, the app on Heroku responds with 503 Server Request Interrupted. It only happens when the token is invalid and the 401 should be returned. What I have found so far is that the socket is connected, some data was sent as part of a response, but then the socket was destroyed without completing the response. My question is, is there a way how to react to the unauthorized response by the Authentication feature, i.e. do something before (automatically) returning the 401 response? In my case catching an exception?
    n
    • 2
    • 2
  • b

    ByteZ

    04/11/2022, 9:11 PM
    Is there no way to access the pipeline context within the new
    on
    functions in plugins? Do I simply not have to call
    finish
    and
    proceed
    anymore? Will ktor automatically detect that the request has already received a response and not pass it further down the pipeline?
    a
    • 2
    • 2
  • l

    Landry Norris

    04/11/2022, 9:24 PM
    Just updated to 2.0.0 and switched back to the CIO engine on all platforms. I immediately start seeing this error on Android.
    Domain specific configurations require that hostname aware checkServerTrusted(X509Certificate[], String, String) is used
    The SO answers I found say this function should not be used in this way. Is there a way to configure the CIO engine to avoid this method?
    e
    • 2
    • 3
  • j

    Jan

    04/12/2022, 7:36 AM
    Does ktor 2.0 now support native websocket clients?
    o
    t
    • 3
    • 6
  • s

    sindrenm

    04/12/2022, 10:24 AM
    Hi! Client question: Is `HttpResponseValidator`'s
    handleResponseException
    supposed to also catch `io.ktor.client.call.NoTransformationFoundException`s? Cause it just seems to fall through in my case. I can see it catching other non-HTTP exceptions such as `kotlinx.serialization.MissingFieldException`s, for instance, and of course `io.ktor.client.features.ClientRequestException`s and `io.ktor.client.features.ServerResponseException`s. I'm on Ktor v1.6.7 on Android using the
    CIO
    engine.
    a
    • 2
    • 7
  • j

    Júlio Santos

    04/12/2022, 5:00 PM
    Is anyone having trouble downloading the lib
    com.github.nielsfalk:ktor-swagger:pom:v0.7.0
    ? I have this error
    Could not find artifact com.github.nielsfalk:ktor-swagger:pom:v0.7.0 in maven-central (<https://repo1.maven.org/maven2>)
    ! I believe it may have changed repositories, I’ve been searching and haven’t found anything about a possible change
    a
    • 2
    • 2
  • p

    PHaroZ

    04/12/2022, 5:13 PM
    Hi, I use the ktor client (v1.6.7, jvm platform) with
    HttpTimeout
    feature ; I try to figure out were I can catch the
    HttpRequestTimeoutException
    thrown but I don't find any clean and generic solution. Here is my config :
    val engine = TODO("CIO.create() or MockEngine")
    val ktorBaseClient = HttpClient(engine) {
      install(HttpTimeout)
    }
    val ktorClient = ktorBaseClient.config {
    		HttpResponseValidator {
    			handleResponseException { t ->
    				when (t) {
    // -----> next line works with MockEngine but not with CIO.create()
    					is HttpRequestTimeoutException -> throw MyCustomException()
    					else -> throw t
    				}
    			}
    			validateResponse { response ->
    // it doesn't seem do by the right place to catch HttpRequestTimeoutException
    				...
                }
            }
    }
    
    ktorClient.get("some_uri") {
      timeout { requestTimeoutMillis = 1.seconds.inWholeMilliseconds }
    }
    Note that to simulate a timeout via the MockEngine I do something like
    MockEngine {
    			delay(2.seconds.inWholeMilliseconds)
    			throw IllegalStateException("should never be called")
    		}
    and it works, it throws a
    MyCustomException
    ; but this is not the case in production code, with the CIO engine. Does someone have any advice or example ? thx for your help.
    a
    • 2
    • 4
  • j

    Jim

    04/12/2022, 6:26 PM
    I've got a fun one on kotlin 1.6.20 and ktor 2.0.0 -
    java.lang.IllegalStateException: FATAL ERROR: Could not find "io.ktor:ktor-http-cio"
    - has anyone seen anything like this lately? Searching the slack I found an error in #apollo-kotlin but didn't get anywhere with that thread
    • 1
    • 1
  • v

    Vivek Modi

    04/13/2022, 11:00 AM
    Hey what is d/w Android and OkHttp in HttpClient in ktor?
    a
    g
    a
    • 4
    • 13
  • s

    sindrenm

    04/13/2022, 11:09 AM
    Judging by the https://ktor.io/docs/default-request.html docs, I would think I was supposed to be in the scope of an
    HttpRequestBuilder
    when configuring
    DefaultRequest
    , but I'm instead in the scope of a
    DefaultRequestBuilder
    . AFAICT, they don't share the same structure. Previously, in ktor-client v1.6.7, I was able to access
    body
    inside of this builder scope, but no more. Docs:
    val client = HttpClient(CIO) {
        defaultRequest {
            // this: HttpRequestBuilder
        }
    }
    Actual (ktor-client-core-jvm-2.0.0.jar):
    public class DefaultRequest private constructor(private val block: DefaultRequestBuilder.() -> Unit) {
    
        public companion object Plugin : HttpClientPlugin<DefaultRequestBuilder, DefaultRequest> {
            // ...
        }
    
        // ...
    }
    
    // Hence:
    
    defaultRequest {
        // this: io.ktor.client.plugins.DefaultRequest.DefaultRequestBuilder
    }
    Is this by design? Are the docs wrong here?
    h
    a
    • 3
    • 11
  • r

    Robert Jaros

    04/13/2022, 1:25 PM
    After upgrading Ktor to 2.0.0, I see this error in IntelliJ only (no error when building from gradle):
    Cannot access class 'kotlinx.serialization.json.Json'. Check your module classpath for missing or conflicting dependencies
    when I try to use content negotiation:
    install(ContentNegotiation) {
            json(json)
        }
    I checked the dependencies but I can't see any obvious conflicts.
    s
    a
    • 3
    • 23
  • d

    d.medina

    04/13/2022, 1:30 PM
    im having an issue with single page application if i try to have it live any place but the root i get an error
    routing() {
            singlePageApplication {
                applicationRoute = "/admin"
                useResources = true
                filesPath = "admin_app"
                }
    }
    when i try to set a route i get this
    Admin_Dash_Compose.js:1          Failed to load resource: the server responded with a status of 404 (Not Found)
    so i need to change my folder path to match or something? i tryed a few things but they didnt work out for me so far
    a
    • 2
    • 4
  • d

    Denis A

    04/13/2022, 4:43 PM
    Hi everyone, i need help with migration to 2.0.0 version. Now i have a crash in app start on IOS version 12.4.
    dyld: Symbol not found: _OBJC_CLASS_$_NSURLSessionWebSocketMessage
      Referenced from: /Users/my name/Library/Developer/CoreSimulator/Devices/0B611991-66BF-4BE7-9534-628D49250D1E/data/Containers/Bundle/Application/E6ED3D75-FBF2-427E-8B82-F6E9E0B09D33/App.app/Frameworks/shared.framework/shared
      Expected in: /Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/Foundation.framework/Foundation
     in /Users/my user/Library/Developer/CoreSimulator/Devices/0B611991-66BF-4BE7-9534-628D49250D1E/data/Containers/Bundle/Application/E6ED3D75-FBF2-427E-8B82-F6E9E0B09D33/App.app/Frameworks/shared.framework/shared
    dyld: launch, loading dependent libraries
    DYLD_FRAMEWORK_PATH=/Users/denis.alexandrov/Library/Developer/Xcode/DerivedData/App-dljtddjulmigkpgpribvzgwhjcds/Build/Products/Debug-iphonesimulator
    DYLD_FALLBACK_LIBRARY_PATH=/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime/Contents/Resources/RuntimeRoot/usr/lib
    DYLD_ROOT_PATH=/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime/Contents/Resources/RuntimeRoot
    DYLD_FALLBACK_FRAMEWORK_PATH=/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks
    DYLD_INSERT_LIBRARIES=/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime/Contents/Resources/RuntimeRoot/usr/lib/libBacktraceRecording.dylib:/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime/Contents/Resources/RuntimeRoot/usr/lib/libMainThreadChecker.dylib:/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 12.4.simruntime/Contents/Resources/RuntimeRoot/Developer/Library
    (lldb)
    👀 1
    🙌 1
    e
    • 2
    • 3
  • a

    Anton Afanasev

    04/13/2022, 4:55 PM
    Hi. Trying to set timeout on KMM, For test purposes set a pretty small value and expect to receive a timeout exception. On Android I am capable to receive an error, but on iOS my request execute as usual. What am I missing?
    internal fun defaultHttpClient(): HttpClient = HttpClient {
        install(HttpTimeout) {
            connectTimeoutMillis = 10
            requestTimeoutMillis = 10
        }
    }
    ktor 1.6.4
    a
    • 2
    • 8
  • a

    Android75

    04/13/2022, 5:06 PM
    I don’t know if i put a link.. but.. https://kotlinlang.slack.com/archives/C0B8M7BUY/p1649824367818059
    a
    • 2
    • 2
  • e

    Evan

    04/13/2022, 11:38 PM
    What is the minimum supported iOS version for ktor
    2.0.0
    ? Ktor
    2.0.0-beta-1
    works on iOS 12, but
    2.0.0
    does not, it crashes with
    dyld: Symbol not found: _OBJC_CLASS_$_NSURLSessionWebSocketMessage
    I’ve tried both the Darwin engine and CIO.
    j
    d
    b
    • 4
    • 6
  • n

    napperley

    04/14/2022, 12:53 AM
    What is the current status on Ktor supporting the Linux ARM targets? There hasn't been any news on this from the Kotlin/Ktor team since 14 May 2021 ( https://github.com/Kotlin/kotlinx.coroutines/issues/855#issuecomment-840552347 ).
    a
    • 2
    • 1
  • a

    André Martins

    04/14/2022, 9:07 AM
    Hello, I’m using ktor client (v1.6.8) and got this exception
    java.io.EOFException: Failed to parse HTTP response: unexpected EOF
    Can’t seem to understand further what happened but from my understanding it seems like it tried to parse the response payload but there wasn’t any.
    a
    • 2
    • 5
  • g

    Giuliopime

    04/14/2022, 9:36 AM
    Why is ktor not able to parse the res to a data class? I have the contentNegotiation plugin installed
    client = HttpClient(CIO) {
                install(ContentNegotiation) {
                    jackson()
                }
            }
    g
    • 2
    • 5
  • g

    gnu

    04/14/2022, 12:39 PM
    Hi! I am currently migrating a project from Ktor-1.6.8/Kotlin-1.6.10 to Ktor-2.0.0/Kotlin-1.6.20 and something has changed with the ClassLoader-behavior: I cannot cast a received object from the (Apache-ActiveMQ-Artemis-)message-queue to the corresponding DTO anymore. In Ktor-1.6.8 an "OverridingClassLoader" was being used while in Ktor-2.0.0 it is "ClassLoader@AppClassLoader". How can I fix this to get rid of the ClassCastException?
    e
    • 2
    • 4
  • n

    Nathan Kleinschmidt

    04/14/2022, 3:04 PM
    Which is the recommended library for hashing passwords in Kotlin/Ktor? E.g. bcrypt does not appear to have an official Kotlin library.
    n
    r
    h
    • 4
    • 7
  • j

    James Ward

    04/14/2022, 8:14 PM
    I'm trying to use ktor 2.0 for a native app and getting an error:
    Uncaught Kotlin exception: kotlin.native.IncorrectDereferenceException: Trying to access top level value not marked as @ThreadLocal or @SharedImmutable from non-main thread
        at kfun:kotlin.Throwable#<init>(kotlin.String?){} (0x43c461)
        at kfun:kotlin.Exception#<init>(kotlin.String?){} (0x435e6d)
        at kfun:kotlin.RuntimeException#<init>(kotlin.String?){} (0x43600d)
        at kfun:kotlin.native.IncorrectDereferenceException#<init>(kotlin.String){} (0x46606d)
        at ThrowIncorrectDereferenceException (0x483fbe)
        at CheckGlobalsAccessible (0x603112)
        at kfun:io.ktor.client.engine.curl.<get-curlApi>#internal (0x8b15c7)
    Seems like this has come up in the past: https://github.com/ktorio/ktor/issues/1559 https://github.com/ktorio/ktor/pull/2193 Think I should file a new issue? Is there a known workaround?
    m
    • 2
    • 2
  • s

    Srki Rakic

    04/14/2022, 9:59 PM
    Hi 👋 . I there a way to expose micrometer/prometheus
    GET /metrics
    endpoint on a different port?
    a
    • 2
    • 2
Powered by Linen
Title
s

Srki Rakic

04/14/2022, 9:59 PM
Hi 👋 . I there a way to expose micrometer/prometheus
GET /metrics
endpoint on a different port?
a

Andreas Scheja

04/14/2022, 10:14 PM
you could always just launch two `embeddedServer`s, one listening on your traffic port and the other just serving the metrics endpoint on a different port.
s

Srki Rakic

04/14/2022, 10:28 PM
Cool. Thank you.
View count: 9