Skip to content
This repository was archived by the owner on Mar 26, 2024. It is now read-only.

Commit 1b08e11

Browse files
committed
Add status endpoint
1 parent 0a68d1e commit 1b08e11

File tree

6 files changed

+107
-22
lines changed

6 files changed

+107
-22
lines changed

projector-common/src/commonMain/kotlin/org/jetbrains/projector/common/protocol/handshake/Constant.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,5 @@ val commonVersionList = listOf(
6161
1980644253,
6262
1328208692,
6363
-1867356666,
64+
-1218764012,
6465
)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2019-2022 JetBrains s.r.o.
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
25+
package org.jetbrains.projector.common.protocol.toClient
26+
27+
import kotlinx.serialization.Serializable
28+
import kotlinx.serialization.json.Json
29+
30+
@Serializable
31+
data class Status(
32+
val mainWindowsCount: Int,
33+
val lastUserActionTimeStampMs: Long,
34+
)
35+
36+
private val json = Json.Default
37+
private val serializer = Status.serializer()
38+
39+
fun Status.toJson(): String = json.encodeToString(serializer, this)
40+
41+
fun String.toStatus(): Status = json.decodeFromString(serializer, this)

projector-common/src/commonMain/kotlin/org/jetbrains/projector/common/protocol/toServer/ClientEvent.kt

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,12 @@ enum class KeyModifier {
5656
@Serializable
5757
sealed class ClientEvent
5858

59+
@Serializable
60+
sealed class ClientUserEvent : ClientEvent()
61+
62+
@Serializable
63+
sealed class ClientNonUserEvent : ClientEvent()
64+
5965
@Serializable
6066
data class ClientMouseEvent(
6167
/** From connection opening. */
@@ -67,7 +73,7 @@ data class ClientMouseEvent(
6773
val clickCount: Int,
6874
val modifiers: Set<MouseModifier>,
6975
val mouseEventType: MouseEventType,
70-
) : ClientEvent() {
76+
) : ClientUserEvent() {
7177

7278
enum class MouseEventType {
7379
MOVE,
@@ -91,7 +97,7 @@ data class ClientWheelEvent(
9197
val y: Int,
9298
val deltaX: Double,
9399
val deltaY: Double,
94-
) : ClientEvent() {
100+
) : ClientUserEvent() {
95101

96102
enum class ScrollingMode {
97103
PIXEL,
@@ -109,7 +115,7 @@ data class ClientKeyEvent(
109115
val location: KeyLocation,
110116
val modifiers: Set<KeyModifier>,
111117
val keyEventType: KeyEventType,
112-
) : ClientEvent() {
118+
) : ClientUserEvent() {
113119

114120
enum class KeyEventType {
115121
DOWN,
@@ -130,7 +136,7 @@ data class ClientKeyPressEvent(
130136
val timeStamp: Int,
131137
val char: Char,
132138
val modifiers: Set<KeyModifier>,
133-
) : ClientEvent()
139+
) : ClientUserEvent()
134140

135141
@Serializable
136142
data class ClientRawKeyEvent(
@@ -141,7 +147,7 @@ data class ClientRawKeyEvent(
141147
val modifiers: Int,
142148
val location: Int,
143149
val keyEventType: RawKeyEventType,
144-
) : ClientEvent() {
150+
) : ClientUserEvent() {
145151

146152
enum class RawKeyEventType {
147153
DOWN,
@@ -151,38 +157,38 @@ data class ClientRawKeyEvent(
151157
}
152158

153159
@Serializable
154-
data class ClientResizeEvent(val size: CommonIntSize) : ClientEvent()
160+
data class ClientResizeEvent(val size: CommonIntSize) : ClientUserEvent()
155161

156162
@Serializable
157-
data class ClientRequestImageDataEvent(val imageId: ImageId) : ClientEvent()
163+
data class ClientRequestImageDataEvent(val imageId: ImageId) : ClientNonUserEvent()
158164

159165
@Serializable
160166
data class ClientClipboardEvent(
161167
val stringContent: String, // TODO: support more types
162-
) : ClientEvent()
168+
) : ClientNonUserEvent()
163169

164170
@Serializable
165171
data class ClientRequestPingEvent(
166172
/** From connection opening. */
167173
val clientTimeStamp: Int,
168-
) : ClientEvent()
174+
) : ClientNonUserEvent()
169175

170176
@Serializable
171177
data class ClientSetKeymapEvent(
172178
val keymap: UserKeymap,
173-
) : ClientEvent()
179+
) : ClientUserEvent()
174180

175181
@Serializable
176182
data class ClientOpenLinkEvent(
177183
val link: String,
178-
) : ClientEvent()
184+
) : ClientUserEvent()
179185

180186
@Serializable
181187
data class ClientWindowMoveEvent(
182188
val windowId: Int,
183189
val deltaX: Int,
184190
val deltaY: Int,
185-
) : ClientEvent()
191+
) : ClientUserEvent()
186192

187193
// If delta is negative, we resizing to the left top
188194
@Serializable
@@ -191,38 +197,38 @@ data class ClientWindowResizeEvent(
191197
val deltaX: Int,
192198
val deltaY: Int,
193199
val direction: ResizeDirection,
194-
) : ClientEvent()
200+
) : ClientUserEvent()
195201

196202
@Serializable
197203
data class ClientWindowSetBoundsEvent(
198204
val windowId: Int,
199-
val bounds: CommonIntRectangle
200-
) : ClientEvent()
205+
val bounds: CommonIntRectangle,
206+
) : ClientUserEvent()
201207

202208
@Serializable
203209
data class ClientDisplaySetChangeEvent(
204-
val newDisplays: List<DisplayDescription>
205-
) : ClientEvent()
210+
val newDisplays: List<DisplayDescription>,
211+
) : ClientUserEvent()
206212

207213
@Serializable
208214
data class ClientWindowCloseEvent(
209215
val windowId: Int,
210-
) : ClientEvent()
216+
) : ClientUserEvent()
211217

212218
@Serializable
213219
data class ClientWindowInterestEvent(
214220
val windowId: Int,
215-
val isInterested: Boolean
216-
): ClientEvent()
221+
val isInterested: Boolean,
222+
) : ClientNonUserEvent()
217223

218224
@Suppress("unused") //used in client-web/org.jetbrains.projector.client.web.window.WindowManager and at server side
219225
@Serializable
220226
data class ClientWindowsActivationEvent(
221227
val windowIds: List<Int>,
222-
) : ClientEvent()
228+
) : ClientUserEvent()
223229

224230
@Suppress("unused") //used in client-web/org.jetbrains.projector.client.web.window.WindowManager and at server side
225231
@Serializable
226232
data class ClientWindowsDeactivationEvent(
227233
val windowIds: List<Int>,
228-
) : ClientEvent()
234+
) : ClientUserEvent()

projector-server-core/src/intTest/kotlin/org/jetbrains/projector/intTest/headless/ProjectorHttpWsServerTest.kt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import kotlinx.coroutines.runBlocking
3737
import org.java_websocket.WebSocket
3838
import org.jetbrains.projector.common.protocol.toClient.MainWindow
3939
import org.jetbrains.projector.common.protocol.toClient.toMainWindowList
40+
import org.jetbrains.projector.common.protocol.toClient.toStatus
4041
import org.jetbrains.projector.server.core.websocket.HttpWsServer
4142
import java.io.File
4243
import java.nio.ByteBuffer
@@ -75,6 +76,8 @@ class ProjectorHttpWsServerTest {
7576
pngBase64Icon = "png base 64",
7677
)
7778
)
79+
80+
override fun getLastUserActionTimeStampMs(): Long = 123
7881
}
7982
}
8083

@@ -143,6 +146,20 @@ class ProjectorHttpWsServerTest {
143146
server.stop()
144147
}
145148

149+
@Test
150+
fun testStatus() {
151+
val server = createServer().also { it.start() }
152+
val client = HttpClient()
153+
154+
val response = runBlocking { client.get<String>(prj("/status")) }.toStatus()
155+
156+
assertEquals(1, response.mainWindowsCount)
157+
assertEquals(123, response.lastUserActionTimeStampMs)
158+
159+
client.close()
160+
server.stop()
161+
}
162+
146163
@Test
147164
fun testFiles() {
148165
val server = createServer().also { it.start() }

projector-server-core/src/main/kotlin/org/jetbrains/projector/server/core/websocket/HttpWsServer.kt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import org.java_websocket.handshake.*
3535
import org.java_websocket.server.WebSocketServer
3636
import org.java_websocket.util.Charsetfunctions
3737
import org.jetbrains.projector.common.protocol.toClient.MainWindow
38+
import org.jetbrains.projector.common.protocol.toClient.Status
3839
import org.jetbrains.projector.common.protocol.toClient.toJson
3940
import org.jetbrains.projector.server.core.ClientWrapper
4041
import org.jetbrains.projector.server.core.util.getWildcardHostAddress
@@ -60,6 +61,7 @@ public abstract class HttpWsServer(host: InetAddress, port: Int) : HttpWsTranspo
6061
public constructor(port: Int) : this(getWildcardHostAddress(), port)
6162

6263
public abstract fun getMainWindows(): List<MainWindow>
64+
public abstract fun getLastUserActionTimeStampMs(): Long
6365

6466
public fun onGetRequest(path: String): GetRequestResult {
6567
val pathWithoutParams = path.substringBefore('?').substringBefore('#')
@@ -75,6 +77,22 @@ public abstract class HttpWsServer(host: InetAddress, port: Int) : HttpWsTranspo
7577
)
7678
}
7779

80+
if (pathWithoutParams == "/status") {
81+
val mainWindows = getMainWindows()
82+
val lastUserActionTimeStampMs = getLastUserActionTimeStampMs()
83+
val status = Status(
84+
mainWindowsCount = mainWindows.size,
85+
lastUserActionTimeStampMs = lastUserActionTimeStampMs,
86+
)
87+
val json = status.toJson().toByteArray()
88+
return GetRequestResult(
89+
statusCode = 200,
90+
statusText = "OK",
91+
contentType = "text/json",
92+
content = json,
93+
)
94+
}
95+
7896
val resourceFileName = getResourceName(pathWithoutParams)
7997
val resourceBytes = getResource(resourceFileName)
8098

projector-server-core/src/main/kotlin/org/jetbrains/projector/server/core/websocket/HttpWsServerBuilder.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ import java.nio.ByteBuffer
3333
public class HttpWsServerBuilder(private val host: InetAddress, private val port: Int): WsTransportBuilder() {
3434

3535
public lateinit var getMainWindows: () -> List<MainWindow>
36+
public lateinit var getLastUserActionTimeStampMs: () -> Long
3637

3738
override fun build(): HttpWsServer {
3839
val wsServer = object : HttpWsServer(host, port) {
3940
override fun getMainWindows(): List<MainWindow> = this@HttpWsServerBuilder.getMainWindows()
41+
override fun getLastUserActionTimeStampMs() = this@HttpWsServerBuilder.getLastUserActionTimeStampMs()
4042
override fun onError(connection: WebSocket?, e: Exception) = this@HttpWsServerBuilder.onError(connection, e)
4143
override fun onWsOpen(connection: WebSocket) = this@HttpWsServerBuilder.onWsOpen(connection)
4244
override fun onWsClose(connection: WebSocket) = this@HttpWsServerBuilder.onWsClose(connection)

0 commit comments

Comments
 (0)