Skip to content

Commit c420a4f

Browse files
JSMonkbashor
andauthored
* Move ktor.client.cio to backend, since it's needed only there * Update ktor and multiplatform-markdown-renderer to versions supporting wasm-js target Version for ktor plugin and backend part was kept as is. * Add web targets to shared module * Enable wasm and js targets of Compose Multiplatform * Add actual implementations for web part * Introduce expect-actuals for Dispatchers.IO due to lack of it in web parts of kotlinx-coroutines * Add expect-actual annotation FloatRange which is missed in web part of Compose * Mention Web in the app description and rename the file * Remove unused Dispatchers.App * Remove unused zoomFraction and FloatRange * fixup! Introduce expect-actuals for Dispatchers.IO due to lack of it in web parts of kotlinx-coroutines * Rebase with a fixed Menu icon * fixup! Remove unused Dispatchers.App * Rename Dispatchers.IO_MP to Dispatchers.App * Setup GitHub pages + running Wasm on the modern browsers and JS on the rest + fix other platforms * fixup!: use another task to build github pages * fixup!: use the right module name inside the sources path * add explicit github link * fix ktor versions for backend * fix backend CORS * Add images proxy * Prettify images, map, and GitHub link * Use dev version until Monday to fix problem with resources * Fix scrolling issue + add offline mode * Fix image on abount conf screen * Move GitHub icon --------- Co-authored-by: Zalim Bashorov <[email protected]>
1 parent 81d40a5 commit c420a4f

File tree

58 files changed

+3843
-97
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3843
-97
lines changed

.github/workflows/ci.yml

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: Publish Application on GitHub Pages
2+
on: [push, pull_request]
3+
jobs:
4+
# Build job
5+
build:
6+
name: Build Kotlin/Wasm
7+
runs-on: ubuntu-latest
8+
steps:
9+
- name: Set up JDK
10+
uses: actions/setup-java@v2
11+
with:
12+
distribution: 'adopt'
13+
java-version: '17'
14+
15+
- name: Checkout code
16+
uses: actions/checkout@v3
17+
18+
- name: Run Gradle Tasks
19+
run: ./gradlew buildWebApp
20+
21+
- name: Fix permissions
22+
run: |
23+
chmod -v -R +rX "shared/build/webApp/" | while read line; do
24+
echo "::warning title=Invalid file permissions automatically fixed::$line"
25+
done
26+
27+
- name: Upload Pages artifact
28+
uses: actions/upload-pages-artifact@v3
29+
with:
30+
path: shared/build/webApp/
31+
32+
deploy:
33+
# Add a dependency to the build job
34+
needs: build
35+
36+
# Grant GITHUB_TOKEN the permissions required to make a Pages deployment
37+
permissions:
38+
pages: write # to deploy to Pages
39+
id-token: write # to verify the deployment originates from an appropriate source
40+
41+
# Deploy to the github-pages environment
42+
environment:
43+
name: github-pages
44+
url: ${{ steps.deployment.outputs.page_url }}
45+
46+
# Specify runner + deployment step
47+
runs-on: ubuntu-latest
48+
steps:
49+
- name: Deploy to GitHub Pages
50+
id: deployment
51+
uses: actions/deploy-pages@v4

backend/src/main/kotlin/org/jetbrains/kotlinconf/backend/Api.kt

+19-6
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,25 @@ import org.jetbrains.kotlinconf.*
1111
import org.jetbrains.kotlinconf.Votes
1212
import java.time.*
1313

14-
internal fun Routing.api(
14+
internal fun Route.api(
1515
store: Store,
1616
sessionizeUrl: String,
17+
imagesUrl: String,
1718
adminSecret: String
1819
) {
1920
apiUsers(store)
2021
sessions()
2122
apiVote(store, adminSecret)
2223
apiSynchronize(sessionizeUrl, adminSecret)
2324
apiTime(adminSecret)
25+
apiSessionizeImagesProxy(imagesUrl)
2426
}
2527

2628
/*
2729
POST http://localhost:8080/sign
2830
1238476512873162837
2931
*/
30-
private fun Routing.apiUsers(database: Store) {
32+
private fun Route.apiUsers(database: Store) {
3133
post("sign") {
3234
val userUUID = call.receive<String>()
3335
val timestamp = LocalDateTime.now(Clock.systemUTC())
@@ -42,7 +44,7 @@ GET http://localhost:8080/vote
4244
Accept: application/json
4345
Authorization: Bearer 1238476512873162837
4446
*/
45-
private fun Routing.apiVote(
47+
private fun Route.apiVote(
4648
database: Store,
4749
adminSecret: String
4850
) {
@@ -113,7 +115,7 @@ GET http://localhost:8080/conference
113115
Accept: application/json
114116
Authorization: Bearer 1238476512873162837
115117
*/
116-
private fun Routing.sessions() {
118+
private fun Route.sessions() {
117119
get("conference") {
118120
call.respond(getSessionizeData())
119121
}
@@ -125,7 +127,7 @@ private fun Routing.sessions() {
125127
*
126128
* POST http://localhost:8080/time/1589568000000
127129
*/
128-
private fun Routing.apiTime(adminSecret: String) {
130+
private fun Route.apiTime(adminSecret: String) {
129131
get("time") {
130132
call.respond(now())
131133
}
@@ -147,7 +149,7 @@ private fun Routing.apiTime(adminSecret: String) {
147149
/*
148150
POST http://localhost:8080/sessionizeSync
149151
*/
150-
private fun Routing.apiSynchronize(
152+
private fun Route.apiSynchronize(
151153
sessionizeUrl: String,
152154
adminSecret: String
153155
) {
@@ -159,6 +161,17 @@ private fun Routing.apiSynchronize(
159161
}
160162
}
161163

164+
/*
165+
GET http://localhost:8080/sessionize/image/{imageId}
166+
Authorization: Bearer 1238476512873162837
167+
*/
168+
private fun Route.apiSessionizeImagesProxy(imagesUrl: String) {
169+
get("sessionize/image/{imageId}") {
170+
call.respond(fetchSessionizeImage(imagesUrl, call.parameters["imageId"] ?: error("No imageId")))
171+
}
172+
}
173+
174+
162175
private fun ApplicationCall.validateSecret(adminSecret: String) {
163176
val principal = principal<KotlinConfPrincipal>()
164177
if (principal?.token != adminSecret) {

backend/src/main/kotlin/org/jetbrains/kotlinconf/backend/Main.kt

+13-9
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import io.ktor.server.plugins.contentnegotiation.*
1414
import io.ktor.server.plugins.cors.routing.*
1515
import io.ktor.server.plugins.defaultheaders.*
1616
import io.ktor.server.plugins.forwardedheaders.*
17-
import io.ktor.server.plugins.partialcontent.*
1817
import io.ktor.server.plugins.statuspages.*
1918
import io.ktor.server.plugins.swagger.*
2019
import io.ktor.server.request.*
@@ -31,6 +30,7 @@ fun Application.conferenceBackend() {
3130
val mode = serviceConfig.property("environment").getString()
3231
log.info("Environment: $mode")
3332
val sessionizeConfig = config.config("sessionize")
33+
val imagesUrl = sessionizeConfig.property("imagesUrl").getString()
3434
val sessionizeUrl = sessionizeConfig.property("url").getString()
3535
val sessionizeInterval = sessionizeConfig.property("interval").getString().toLong()
3636
val adminSecret = serviceConfig.property("secret").getString()
@@ -68,15 +68,19 @@ fun Application.conferenceBackend() {
6868
}
6969
}
7070

71-
install(ContentNegotiation) {
72-
json()
73-
}
74-
75-
install(CORS) {
76-
anyHost()
71+
install(CORS){
7772
allowHeader(HttpHeaders.Authorization)
73+
allowHeader(HttpHeaders.CacheControl)
7874
allowCredentials = true
79-
listOf(HttpMethod.Put, HttpMethod.Delete, HttpMethod.Options).forEach { allowMethod(it) }
75+
allowNonSimpleContentTypes = true
76+
listOf(HttpMethod.Put, HttpMethod.Get, HttpMethod.Post, HttpMethod.Delete, HttpMethod.Options).forEach {
77+
allowMethod(it)
78+
}
79+
anyHost()
80+
}
81+
82+
install(ContentNegotiation) {
83+
json()
8084
}
8185

8286
val database = Store(this)
@@ -89,7 +93,7 @@ fun Application.conferenceBackend() {
8993
files("static")
9094
}
9195

92-
api(database, sessionizeUrl, adminSecret)
96+
api(database, sessionizeUrl, imagesUrl, adminSecret)
9397

9498
get("/healthz") {
9599
call.respond(HttpStatusCode.OK)

backend/src/main/kotlin/org/jetbrains/kotlinconf/backend/Sessionize.kt

+7
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,13 @@ suspend fun synchronizeWithSessionize(
4343
.toConference()
4444
}
4545

46+
suspend fun fetchSessionizeImage(
47+
imagesUrl: String,
48+
imageId: String
49+
): ByteArray {
50+
return client.get("$imagesUrl/$imageId").body<ByteArray>()
51+
}
52+
4653
fun getSessionizeData(): Conference = conference ?: throw ServiceUnavailable()
4754

4855
fun SessionizeData.toConference(): Conference {

backend/src/main/resources/application.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ ktor:
99

1010
sessionize:
1111
url: "https://sessionize.com/api/v2/cdftbl11/view/All"
12+
imagesUrl: "https://sessionize.com/image/"
1213
interval: 60
1314

1415
database:

build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ plugins {
66
alias(libs.plugins.kotlinMultiplatform) apply false
77
alias(libs.plugins.kotlinSerialization) apply false
88
alias(libs.plugins.kotlinJvm) apply false
9-
}
9+
}

gradle.properties

+5
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,9 @@ development=true
1515
kotlin.mpp.stability.nowarn=true
1616
kotlin.mpp.enableCInteropCommonization=true
1717
kotlin.mpp.androidSourceSetLayoutVersion=2
18+
19+
# Compose Multiplatform
1820
compose.resources.always.generate.accessors=true
21+
org.jetbrains.compose.experimental.wasm.enabled=true
22+
# fallback for old browsers
23+
org.jetbrains.compose.experimental.jscanvas.enabled=true

gradle/libs.versions.toml

+9-5
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ androidx-preference = "1.2.1"
1313
kotlin = "1.9.23"
1414

1515
compose-android = "1.6.4"
16-
compose-multiplatform = "1.6.2"
16+
compose-multiplatform = "1.6.10-dev1640"
1717

1818
exposed = "0.47.0"
1919
h2 = "2.2.220"
@@ -22,10 +22,11 @@ image-loader = "1.7.8"
2222
junit = "4.13.2"
2323
kotlinx-serialization-json = "1.6.3"
2424
kotlinx-datetime = "0.6.0-RC.2"
25-
ktor = "2.3.10"
25+
ktor-plugin = "3.0.0-beta-1-eap-58"
26+
ktor = "3.0.0-beta-2-eap-932"
2627
android-svg="1.4"
2728
logbackClassic = "1.4.14"
28-
markdown = "0.13.0"
29+
markdown = "0.14.0"
2930
material3 = "1.6.0"
3031
postgresql = "42.6.0"
3132
androidx-navigation = "2.7.0-alpha04"
@@ -61,9 +62,12 @@ multiplatform-markdown-renderer-m3 = { module = "com.mikepenz:multiplatform-mark
6162

6263
# ktor
6364
ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }
65+
ktor-client-js = { module = "io.ktor:ktor-client-js", version.ref = "ktor" }
66+
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
67+
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
68+
ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }
6469
ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
6570
ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
66-
ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
6771
ktor-utils = { module = "io.ktor:ktor-utils", version.ref = "ktor" }
6872
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization-json" }
6973

@@ -82,5 +86,5 @@ jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-multip
8286
kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
8387
kotlinSerialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
8488
kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
85-
ktor = { id = "io.ktor.plugin", version.ref = "ktor" }
89+
ktor = { id = "io.ktor.plugin", version.ref = "ktor-plugin" }
8690

0 commit comments

Comments
 (0)