Skip to content

Commit 5c085d9

Browse files
committed
✨ (plugin): 增加插件事件,替换ws实现
1 parent 3fdae1d commit 5c085d9

File tree

5 files changed

+184
-27
lines changed

5 files changed

+184
-27
lines changed

build.gradle.kts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ repositories {
1717
}
1818

1919
dependencies {
20-
implementation("org.java-websocket:Java-WebSocket:1.5.6")
2120
implementation("com.squareup.okhttp3:okhttp:4.12.0")
2221
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
2322
}

src/main/kotlin/irony/pycharm/qsseditor/QSSClient.kt

Lines changed: 128 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,64 +8,168 @@
88
* Site: https://pyqt.site , https://pyqt5.com
99
*/
1010

11-
package irony.pycharm.qsseditor
11+
@file:Suppress("ktlint:standard:no-wildcard-imports")
1212

13+
package irony.pycharm.qsseditor
1314
import com.intellij.openapi.diagnostic.logger
14-
import org.java_websocket.client.WebSocketClient
15-
import org.java_websocket.handshake.ServerHandshake
16-
import java.net.URI
15+
import kotlinx.serialization.json.*
16+
import okhttp3.OkHttpClient
17+
import okhttp3.Request
18+
import okhttp3.WebSocket
19+
import okhttp3.WebSocketListener
20+
import java.util.concurrent.TimeUnit
1721

1822
private val Log = logger<QSSClient>()
1923

20-
class QSSClient(serverUri: URI?) : WebSocketClient(serverUri) {
21-
override fun onOpen(handshakedata: ServerHandshake?) {
24+
interface MessageListener {
25+
fun onParams(array: JsonArray)
26+
}
27+
28+
class KeywordsListener : MessageListener {
29+
override fun onParams(array: JsonArray) {
30+
Log.info("onParams: $array")
31+
}
32+
}
33+
34+
class QSSClient : WebSocketListener() {
35+
init {
36+
listener["addKeywords"] = KeywordsListener()
37+
}
38+
39+
override fun onOpen(
40+
webSocket: okhttp3.WebSocket,
41+
response: okhttp3.Response,
42+
) {
2243
Log.debug("onOpen")
2344
}
2445

25-
override fun onMessage(message: String?) {
26-
Log.debug("onMessage: $message")
46+
override fun onMessage(
47+
webSocket: okhttp3.WebSocket,
48+
text: String,
49+
) {
50+
Log.debug("onMessage: $text")
51+
if (text.isNotEmpty()) {
52+
val json = Json.parseToJsonElement(text).jsonObject
53+
if (json.getValue(
54+
"jsonrpc",
55+
).jsonPrimitive.contentOrNull != "2.0" || json.getValue("method").jsonPrimitive.contentOrNull == null
56+
) {
57+
Log.warn("onMessage: jsonrpc or method is null")
58+
return
59+
}
60+
61+
// 处理对应消息
62+
val method = json.getValue("method").jsonPrimitive.contentOrNull
63+
listener[method]?.onParams(json.getValue("params").jsonArray)
64+
}
2765
}
2866

29-
override fun onClose(
67+
override fun onClosing(
68+
webSocket: okhttp3.WebSocket,
3069
code: Int,
31-
reason: String?,
32-
remote: Boolean,
70+
reason: String,
3371
) {
34-
Log.debug("onClose: code=$code, remote=$remote, reason=$reason")
72+
Log.debug("onClosing")
73+
if (done) {
74+
return
75+
}
76+
Thread.sleep(5000)
77+
reconnect(webSocket.request().url.host, webSocket.request().url.port)
3578
}
3679

37-
override fun onError(e: Exception?) {
38-
Log.error("onError", e)
80+
override fun onFailure(
81+
webSocket: okhttp3.WebSocket,
82+
t: Throwable,
83+
response: okhttp3.Response?,
84+
) {
85+
Log.warn("onFailure, ${t.message}")
86+
if (done) {
87+
Log.info("client require shutdown")
88+
return
89+
}
90+
Thread.sleep(5000)
91+
reconnect(webSocket.request().url.host, webSocket.request().url.port)
3992
}
4093

4194
companion object {
42-
private var client: QSSClient? = null
95+
private var host: String = ""
96+
private var port: Int = 0
97+
private var done: Boolean = false
98+
private var self: QSSClient? = null
99+
private var client: OkHttpClient? = null
100+
private var socket: WebSocket? = null
101+
private var listener: HashMap<String, MessageListener> = HashMap()
43102

44103
fun connect(
45104
host: String,
46105
port: Int,
47106
) {
107+
if (host == this.host && port == this.port) {
108+
if (socket != null || self != null) {
109+
return
110+
}
111+
}
112+
113+
this.host = host
114+
this.port = port
115+
48116
disconnect()
117+
118+
if (self == null) {
119+
self = QSSClient()
120+
}
49121
if (client == null) {
122+
client = OkHttpClient.Builder().pingInterval(5, TimeUnit.SECONDS).connectTimeout(30, TimeUnit.SECONDS).build()
123+
}
124+
125+
if (socket == null) {
50126
Log.debug("connect to node: ws://$host:$port")
51-
client = QSSClient(URI("ws://$host:$port"))
52-
client!!.connect()
127+
socket = client!!.newWebSocket(Request.Builder().url("ws://$host:$port").build(), self!!)
53128
}
54129
}
55130

56-
fun reconnect() {
131+
fun reconnect(
132+
host: String,
133+
port: Int,
134+
) {
57135
Log.debug("do reconnect")
58-
client?.reconnect()
136+
socket = client!!.newWebSocket(Request.Builder().url("ws://$host:$port").build(), self!!)
59137
}
60138

61-
fun disconnect() {
139+
private fun disconnect() {
62140
Log.debug("do disconnect")
63-
client?.close()
64-
client = null
141+
socket?.cancel()
142+
socket?.close(1001, "client disconnect")
143+
socket = null
144+
}
145+
146+
fun shutdown() {
147+
Log.info("do shutdown")
148+
done = true
149+
disconnect()
150+
}
151+
152+
private fun buildMessage(
153+
method: String,
154+
message: List<String>,
155+
): String {
156+
return buildJsonObject {
157+
put("jsonrpc", "2.0")
158+
put("method", method)
159+
putJsonArray("params") {
160+
for (s in message) {
161+
add(s)
162+
}
163+
}
164+
}.toString()
165+
}
166+
167+
fun applyStyle(message: List<String>) {
168+
socket!!.send(buildMessage("setStyleSheet", message))
65169
}
66170

67-
fun send(message: String) {
68-
client?.send(message)
171+
fun selectWidget(message: List<String>) {
172+
socket!!.send(buildMessage("selectWidget", message))
69173
}
70174
}
71175
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright (c) 2024. Irony All Rights Reserved.
3+
* Project: QSSEditor
4+
* File: QSSDynamic.kt
5+
* Date: 2024/5/25 上午11:59
6+
* Author: Irony
7+
* Email: 892768447@qq.com
8+
* Site: https://pyqt.site , https://pyqt5.com
9+
*/
10+
11+
package irony.pycharm.qsseditor
12+
13+
import com.intellij.ide.plugins.DynamicPluginListener
14+
import com.intellij.ide.plugins.IdeaPluginDescriptor
15+
import com.intellij.openapi.diagnostic.logger
16+
17+
private val Log = logger<QSSDynamic>()
18+
19+
class QSSDynamic : DynamicPluginListener {
20+
override fun beforePluginLoaded(pluginDescriptor: IdeaPluginDescriptor) {
21+
Log.info("beforePluginLoaded")
22+
}
23+
24+
override fun beforePluginUnload(
25+
pluginDescriptor: IdeaPluginDescriptor,
26+
isUpdate: Boolean,
27+
) {
28+
Log.info("beforePluginUnload")
29+
QSSClient.shutdown()
30+
}
31+
32+
override fun checkUnloadPlugin(pluginDescriptor: IdeaPluginDescriptor) {
33+
Log.info("checkUnloadPlugin")
34+
QSSClient.shutdown()
35+
}
36+
37+
override fun pluginLoaded(pluginDescriptor: IdeaPluginDescriptor) {
38+
Log.info("pluginLoaded")
39+
}
40+
41+
override fun pluginUnloaded(
42+
pluginDescriptor: IdeaPluginDescriptor,
43+
isUpdate: Boolean,
44+
) {
45+
Log.info("pluginUnloaded, isUpdate: $isUpdate")
46+
QSSClient.shutdown()
47+
}
48+
}

src/main/kotlin/irony/pycharm/qsseditor/QSSStartup.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ private val Log = logger<QSSStartup>()
1919
internal class QSSStartup : StartupActivity {
2020
override fun runActivity(project: Project) {
2121
// 启动客户端连接
22-
Log.debug("project[${project.name}] opened")
22+
Log.info("project[${project.name}] opened")
2323
QSSClient.connect(QSSState.instance.host, QSSState.instance.port)
2424
}
2525
}

src/main/resources/META-INF/plugin.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<name>QSSEditor</name>
99

1010
<!-- A displayed Vendor name or Organization ID displayed on the Plugins Page. -->
11-
<vendor email="892768447@qq.com" url="https://github.com/PyQt5">PyQt5</vendor>
11+
<vendor email="892768447@qq.com" url="https://github.com/PyQt5">Irony</vendor>
1212

1313
<!-- Description of the plugin displayed on the Plugin Page and IDE Plugin Manager.
1414
Simple HTML elements (text formatting, paragraphs, and lists) can be added inside of <![CDATA[ ]]> tag.
@@ -35,6 +35,12 @@
3535
id="irony.pycharm.qsseditor.QSSConfig"
3636
displayName="QSS Editor"/>
3737
</extensions>
38+
39+
<applicationListeners>
40+
<listener class="irony.pycharm.qsseditor.QSSDynamic"
41+
topic="com.intellij.ide.plugins.DynamicPluginListener"/>
42+
</applicationListeners>
43+
3844
<actions resource-bundle="messages.QSSBundle">
3945
<action id="apply" class="irony.pycharm.qsseditor.QSSAction" text="Apply Style">
4046
<add-to-group group-id="EditorPopupMenu" anchor="first"/>

0 commit comments

Comments
 (0)