diff --git a/.cursor/rules/connection-management.mdc b/.cursor/rules/connection-management.mdc
index b93c988..6cae9f9 100644
--- a/.cursor/rules/connection-management.mdc
+++ b/.cursor/rules/connection-management.mdc
@@ -3,3 +3,42 @@ description:
globs:
alwaysApply: false
---
+# 连接管理机制
+
+## 连接状态流转
+连接状态在 [WKConnection.java](mdc:wkim/src/main/java/com/xinbida/wukongim/message/WKConnection.java) 中管理,遵循以下规则:
+
+### 有效的状态转换
+- 失败状态 -> 连接中/成功
+- 连接中 -> 成功/失败/无网络
+- 成功 -> 同步消息/被踢/失败
+- 同步消息 -> 成功/失败
+- 无网络 -> 连接中/失败
+
+### 关键同步点
+所有状态转换都需要通过 `connectionLock` 同步锁保护:
+```java
+synchronized (connectionLock) {
+ // 状态转换操作
+}
+```
+
+## 重连机制
+重连策略采用指数退避算法:
+- 基础延迟:1秒
+- 最大延迟:32秒
+- 最大重试次数:5次
+
+## 连接关闭处理
+连接关闭流程:
+1. 使用 `isClosing` 原子变量防止重复关闭
+2. 设置连接标记防止重连
+3. 清理连接资源
+4. 触发超时强制关闭
+
+## 异常处理
+主要在 [ConnectionClient.java](mdc:wkim/src/main/java/com/xinbida/wukongim/message/ConnectionClient.java) 中处理:
+- 连接异常
+- 连接超时
+- 心跳超时
+- 空闲超时
diff --git a/.cursor/rules/message-handling.mdc b/.cursor/rules/message-handling.mdc
index b93c988..fdf526c 100644
--- a/.cursor/rules/message-handling.mdc
+++ b/.cursor/rules/message-handling.mdc
@@ -3,3 +3,36 @@ description:
globs:
alwaysApply: false
---
+# 消息处理机制
+
+## 消息发送流程
+在 [WKConnection.java](mdc:wkim/src/main/java/com/xinbida/wukongim/message/WKConnection.java) 中实现:
+
+### 发送前检查
+- 检查连接状态
+- 验证消息完整性
+- 处理附件(图片、视频等)
+
+### 消息队列管理
+使用 `sendingMsgHashMap` 管理发送中的消息:
+- 消息重发机制
+- 发送超时处理
+- 发送状态追踪
+
+### 消息同步
+两种同步模式:
+- WRITE模式:完整消息同步
+- READ模式:仅同步会话列表
+
+## 消息接收处理
+主要在 ConnectionClient 的 onData 方法中处理:
+- 消息解析
+- 重复消息过滤
+- 消息排序
+- 存储和回调
+
+## 特殊消息处理
+- 心跳消息(ping/pong)
+- 连接确认消息
+- 踢下线消息
+- 同步完成消息
diff --git a/.cursor/rules/project-structure.mdc b/.cursor/rules/project-structure.mdc
index b93c988..7d09bbf 100644
--- a/.cursor/rules/project-structure.mdc
+++ b/.cursor/rules/project-structure.mdc
@@ -3,3 +3,38 @@ description:
globs:
alwaysApply: false
---
+# WuKongIM Android SDK 项目结构
+
+WuKongIM Android SDK 是一个即时通讯SDK,主要包含以下核心组件:
+
+## 核心连接管理
+主要连接管理类在 [WKConnection.java](mdc:wkim/src/main/java/com/xinbida/wukongim/message/WKConnection.java) 中实现,负责:
+- Socket连接的建立和维护
+- 消息的发送和接收
+- 重连机制
+- 心跳管理
+
+## 连接状态处理
+连接状态定义在 [WKConnectStatus.java](mdc:wkim/src/main/java/com/xinbida/wukongim/message/type/WKConnectStatus.java) 中,包括:
+- 连接成功(1)
+- 连接失败(0)
+- 被踢下线(2)
+- 同步消息中(3)
+- 连接中(4)
+- 无网络(5)
+- 同步完成(6)
+
+## 客户端连接处理
+[ConnectionClient.java](mdc:wkim/src/main/java/com/xinbida/wukongim/message/ConnectionClient.java) 处理具体的连接事件:
+- 连接建立回调
+- 数据接收
+- 连接断开处理
+- 超时处理
+- 异常处理
+
+## 应用配置
+[WKIMApplication.java](mdc:wkim/src/main/java/com/xinbida/wukongim/WKIMApplication.java) 管理SDK全局配置:
+- 协议版本
+- 同步消息模式
+- 网络状态
+- 数据库配置
diff --git a/.gitignore b/.gitignore
index 17f5d55..8cfc606 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,5 +13,4 @@
.externalNativeBuild
.cxx
local.properties
-/repository
.cursor
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar
new file mode 100644
index 0000000..fd79d8c
Binary files /dev/null and b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar differ
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar.md5 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar.md5
new file mode 100644
index 0000000..5fc2a75
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar.md5
@@ -0,0 +1 @@
+2a8fa0fa06d069610eed09005b343994
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar.sha1 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar.sha1
new file mode 100644
index 0000000..3ddd0fe
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar.sha1
@@ -0,0 +1 @@
+34a3a10b015c40e16a76fe75cb974d675a9cbda6
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar.sha256 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar.sha256
new file mode 100644
index 0000000..17791cf
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar.sha256
@@ -0,0 +1 @@
+eb0a4ee07731a3ef38f606b2978d16169a6f6388e3f33fa3a10c82f3b0c17bb0
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar.sha512 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar.sha512
new file mode 100644
index 0000000..004aade
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7-sources.jar.sha512
@@ -0,0 +1 @@
+d1a0aa32976653fa04696f6d42edbe8152b59fdaf0135350cdefa14d571212571e85412c8f026a46e43069aadad3603358b63e262635a3716c948dab7b056750
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar
new file mode 100644
index 0000000..51aeca4
Binary files /dev/null and b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar differ
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar.md5 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar.md5
new file mode 100644
index 0000000..ed5e3de
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar.md5
@@ -0,0 +1 @@
+195544eb25003c80879e6390c389f4b5
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar.sha1 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar.sha1
new file mode 100644
index 0000000..7b8d373
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar.sha1
@@ -0,0 +1 @@
+d7a3b759fd22ae6bb0cc7710e87c9f01b197afd8
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar.sha256 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar.sha256
new file mode 100644
index 0000000..a7a524d
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar.sha256
@@ -0,0 +1 @@
+2731b93ebd3aa8f457aa1dd2ac9634de1fb4641facabbc6683bc2b8575076c28
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar.sha512 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar.sha512
new file mode 100644
index 0000000..d48c18e
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.aar.sha512
@@ -0,0 +1 @@
+67d5a21983e722346be407c14a7d0dab5de051789cf7764dfaacd686e770e75a9f8377b49af1e5570e29d6a7ae38fedaec5af4c6b17f631116d665570b92fc5d
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module
new file mode 100644
index 0000000..e4a6251
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module
@@ -0,0 +1,140 @@
+{
+ "formatVersion": "1.1",
+ "component": {
+ "group": "com.xinbida.wukongim",
+ "module": "WKIMLib_local",
+ "version": "1.0.7",
+ "attributes": {
+ "org.gradle.status": "release"
+ }
+ },
+ "createdBy": {
+ "gradle": {
+ "version": "8.9"
+ }
+ },
+ "variants": [
+ {
+ "name": "releaseApiElements-published",
+ "attributes": {
+ "org.gradle.category": "library",
+ "org.gradle.usage": "java-api",
+ "org.jetbrains.kotlin.platform.type": "androidJvm"
+ },
+ "files": [
+ {
+ "name": "WKIMLib_local-1.0.7.aar",
+ "url": "WKIMLib_local-1.0.7.aar",
+ "size": 619369,
+ "sha512": "67d5a21983e722346be407c14a7d0dab5de051789cf7764dfaacd686e770e75a9f8377b49af1e5570e29d6a7ae38fedaec5af4c6b17f631116d665570b92fc5d",
+ "sha256": "2731b93ebd3aa8f457aa1dd2ac9634de1fb4641facabbc6683bc2b8575076c28",
+ "sha1": "d7a3b759fd22ae6bb0cc7710e87c9f01b197afd8",
+ "md5": "195544eb25003c80879e6390c389f4b5"
+ }
+ ]
+ },
+ {
+ "name": "releaseRuntimeElements-published",
+ "attributes": {
+ "org.gradle.category": "library",
+ "org.gradle.usage": "java-runtime",
+ "org.jetbrains.kotlin.platform.type": "androidJvm"
+ },
+ "dependencies": [
+ {
+ "group": "org.jetbrains.kotlin",
+ "module": "kotlin-bom",
+ "version": {
+ "requires": "1.9.22"
+ },
+ "attributes": {
+ "org.gradle.category": "platform"
+ },
+ "endorseStrictVersions": true
+ },
+ {
+ "group": "org.jetbrains.kotlin",
+ "module": "kotlin-stdlib",
+ "version": {
+ "requires": "1.9.22"
+ }
+ },
+ {
+ "group": "org.jetbrains.kotlin",
+ "module": "kotlin-stdlib-jdk8",
+ "version": {
+ "requires": "1.9.22"
+ }
+ },
+ {
+ "group": "com.android.support",
+ "module": "multidex",
+ "version": {
+ "requires": "1.0.3"
+ }
+ },
+ {
+ "group": "net.zetetic",
+ "module": "android-database-sqlcipher",
+ "version": {
+ "requires": "4.5.4"
+ }
+ },
+ {
+ "group": "androidx.sqlite",
+ "module": "sqlite-ktx",
+ "version": {
+ "requires": "2.5.0"
+ }
+ },
+ {
+ "group": "org.whispersystems",
+ "module": "curve25519-android",
+ "version": {
+ "requires": "0.5.0"
+ }
+ },
+ {
+ "group": "org.whispersystems",
+ "module": "signal-protocol-android",
+ "version": {
+ "requires": "2.8.1"
+ }
+ }
+ ],
+ "files": [
+ {
+ "name": "WKIMLib_local-1.0.7.aar",
+ "url": "WKIMLib_local-1.0.7.aar",
+ "size": 619369,
+ "sha512": "67d5a21983e722346be407c14a7d0dab5de051789cf7764dfaacd686e770e75a9f8377b49af1e5570e29d6a7ae38fedaec5af4c6b17f631116d665570b92fc5d",
+ "sha256": "2731b93ebd3aa8f457aa1dd2ac9634de1fb4641facabbc6683bc2b8575076c28",
+ "sha1": "d7a3b759fd22ae6bb0cc7710e87c9f01b197afd8",
+ "md5": "195544eb25003c80879e6390c389f4b5"
+ }
+ ]
+ },
+ {
+ "name": "releaseSourcesElements-published",
+ "attributes": {
+ "org.gradle.category": "documentation",
+ "org.gradle.dependency.bundling": "external",
+ "org.gradle.docstype": "sources",
+ "org.gradle.libraryelements": "jar",
+ "org.gradle.usage": "java-runtime",
+ "org.jetbrains.kotlin.platform.type": "androidJvm"
+ },
+ "files": [
+ {
+ "name": "WKIMLib_local-1.0.7-sources.jar",
+ "url": "WKIMLib_local-1.0.7-sources.jar",
+ "size": 328517,
+ "sha512": "d1a0aa32976653fa04696f6d42edbe8152b59fdaf0135350cdefa14d571212571e85412c8f026a46e43069aadad3603358b63e262635a3716c948dab7b056750",
+ "sha256": "eb0a4ee07731a3ef38f606b2978d16169a6f6388e3f33fa3a10c82f3b0c17bb0",
+ "sha1": "34a3a10b015c40e16a76fe75cb974d675a9cbda6",
+ "md5": "2a8fa0fa06d069610eed09005b343994"
+ }
+ ]
+ }
+ ]
+}
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module.md5 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module.md5
new file mode 100644
index 0000000..e5e50ee
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module.md5
@@ -0,0 +1 @@
+18f875f433f4b46c3a8f82d2102b4efd
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module.sha1 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module.sha1
new file mode 100644
index 0000000..7202ad1
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module.sha1
@@ -0,0 +1 @@
+5e3e6e61712a9bee911ec2191da0faef05f93430
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module.sha256 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module.sha256
new file mode 100644
index 0000000..c4bcd55
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module.sha256
@@ -0,0 +1 @@
+b5c54156b3a952972c75cfed1f5dd52419426a975df9a863efa8eb36f1feae12
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module.sha512 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module.sha512
new file mode 100644
index 0000000..34b6a94
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.module.sha512
@@ -0,0 +1 @@
+0b3a1ba410c00e2566f0052b66121737164e4edc5defe64fd2aa7fd6e02ba05ccd9b2e0e13b603911d53a34ec9c10ee51fcd4c05719e19440c5da726484b45e3
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom
new file mode 100644
index 0000000..0aa9dc0
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+ 4.0.0
+ com.xinbida.wukongim
+ WKIMLib_local
+ 1.0.7
+ aar
+ WKIMLib
+ WuKong IM Android Library
+
+
+ The Apache License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-bom
+ 1.9.22
+ pom
+ import
+
+
+
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ 1.9.22
+ runtime
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib-jdk8
+ 1.9.22
+ runtime
+
+
+ com.android.support
+ multidex
+ 1.0.3
+ runtime
+
+
+ net.zetetic
+ android-database-sqlcipher
+ 4.5.4
+ runtime
+
+
+ androidx.sqlite
+ sqlite-ktx
+ 2.5.0
+ runtime
+
+
+ org.whispersystems
+ curve25519-android
+ 0.5.0
+ runtime
+
+
+ org.whispersystems
+ signal-protocol-android
+ 2.8.1
+ runtime
+
+
+
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom.md5 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom.md5
new file mode 100644
index 0000000..1a86f75
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom.md5
@@ -0,0 +1 @@
+ddc59ca3508344a630f0330f9c75801e
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom.sha1 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom.sha1
new file mode 100644
index 0000000..e1d94c7
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom.sha1
@@ -0,0 +1 @@
+b351753e161fb1fde554f02adc966908b5d835b6
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom.sha256 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom.sha256
new file mode 100644
index 0000000..2751ebc
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom.sha256
@@ -0,0 +1 @@
+67367cbfa088cc2f2c57a66720e040865b70aa718b6f9487eeae174688b311f4
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom.sha512 b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom.sha512
new file mode 100644
index 0000000..266e71f
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/1.0.7/WKIMLib_local-1.0.7.pom.sha512
@@ -0,0 +1 @@
+0ca8950dcf1398e81df06fb2c44015e10dac0d0ccc4d8db4e1e5eda302ee79c2727460d576f855c31bf8db5e669cdbb5d32897dce308009d069bc9e6d85126d9
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml b/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml
new file mode 100644
index 0000000..ab3c9b6
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml
@@ -0,0 +1,13 @@
+
+
+ com.xinbida.wukongim
+ WKIMLib_local
+
+ 1.0.7
+ 1.0.7
+
+ 1.0.7
+
+ 20250524090841
+
+
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml.md5 b/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml.md5
new file mode 100644
index 0000000..da8846e
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml.md5
@@ -0,0 +1 @@
+2867162497a0539e3e3b0a1716f9feaa
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml.sha1 b/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml.sha1
new file mode 100644
index 0000000..a28480b
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml.sha1
@@ -0,0 +1 @@
+e431ad1afdad3aff298476f1949e6dcb73bf52d2
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml.sha256 b/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml.sha256
new file mode 100644
index 0000000..17d5c72
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml.sha256
@@ -0,0 +1 @@
+aa7f10d602787f0faf2fc1a55c04fd089c55313b1d22c30cf1aa24c24ab9a216
\ No newline at end of file
diff --git a/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml.sha512 b/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml.sha512
new file mode 100644
index 0000000..6214cc3
--- /dev/null
+++ b/repository/com/xinbida/wukongim/WKIMLib_local/maven-metadata.xml.sha512
@@ -0,0 +1 @@
+3c7de45f238ee5d29b5c331b4c90ef396a87cc7a36550eeba7aa475e86f77da8d20e3373d177d46845e8e8d26c1ec106d2855ee1298c0763788a2583325b638f
\ No newline at end of file
diff --git a/wkim/src/main/java/com/xinbida/wukongim/message/MessageHandler.java b/wkim/src/main/java/com/xinbida/wukongim/message/MessageHandler.java
index 60d7f29..6a2daa3 100644
--- a/wkim/src/main/java/com/xinbida/wukongim/message/MessageHandler.java
+++ b/wkim/src/main/java/com/xinbida/wukongim/message/MessageHandler.java
@@ -40,6 +40,8 @@ import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.TimeUnit;
/**
* 5/21/21 11:25 AM
@@ -102,20 +104,42 @@ public class MessageHandler {
private volatile List receivedMsgList;
private final Object receivedMsgListLock = new Object();
- private final Object cacheLock = new Object();
+ private final ReentrantLock cacheLock = new ReentrantLock(true); // 使用公平锁
+ private static final long LOCK_TIMEOUT = 2000; // 2秒超时
private byte[] cacheData = null;
private int available_len;
public void clearCacheData() {
- synchronized (cacheLock) {
- cacheData = null;
- available_len = 0;
+ boolean locked = false;
+ try {
+ // 尝试获取锁,最多等待3秒
+ locked = cacheLock.tryLock(LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
+ if (locked) {
+ cacheData = null;
+ available_len = 0;
+ } else {
+ WKLoggerUtils.getInstance().e(TAG, "获取锁超时,clearCacheData失败");
+ }
+ } catch (InterruptedException e) {
+ WKLoggerUtils.getInstance().e(TAG, "clearCacheData等待锁被中断: " + e.getMessage());
+ Thread.currentThread().interrupt();
+ } finally {
+ if (locked) {
+ cacheLock.unlock();
+ }
}
}
synchronized void handlerOnlineBytes(INonBlockingConnection iNonBlockingConnection) {
- synchronized (cacheLock) {
+ boolean locked = false;
+ try {
+ locked = cacheLock.tryLock(LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
+ if (!locked) {
+ WKLoggerUtils.getInstance().e(TAG, "获取锁超时,handlerOnlineBytes失败");
+ return;
+ }
+
try {
// 获取可用数据长度
available_len = iNonBlockingConnection.available();
@@ -160,12 +184,26 @@ public class MessageHandler {
WKLoggerUtils.getInstance().e(TAG, "onData 中发生意外错误: " + e.getMessage());
clearCacheData();
}
+ } catch (InterruptedException e) {
+ WKLoggerUtils.getInstance().e(TAG, "handlerOnlineBytes等待锁被中断: " + e.getMessage());
+ Thread.currentThread().interrupt();
+ } finally {
+ if (locked) {
+ cacheLock.unlock();
+ }
}
}
synchronized void cutBytes(byte[] available_bytes,
IReceivedMsgListener mIReceivedMsgListener) {
- synchronized (cacheLock) {
+ boolean locked = false;
+ try {
+ locked = cacheLock.tryLock(LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
+ if (!locked) {
+ WKLoggerUtils.getInstance().e(TAG, "获取锁超时,cutBytes失败");
+ return;
+ }
+
if (cacheData == null || cacheData.length == 0) cacheData = available_bytes;
else {
//如果上次还存在未解析完的消息将新数据追加到缓存数据中
@@ -265,6 +303,13 @@ public class MessageHandler {
}
}
saveReceiveMsg();
+ } catch (InterruptedException e) {
+ WKLoggerUtils.getInstance().e(TAG, "cutBytes等待锁被中断: " + e.getMessage());
+ Thread.currentThread().interrupt();
+ } finally {
+ if (locked) {
+ cacheLock.unlock();
+ }
}
}
diff --git a/wkim/src/main/java/com/xinbida/wukongim/message/WKConnection.java b/wkim/src/main/java/com/xinbida/wukongim/message/WKConnection.java
index 817b2c3..82bce41 100644
--- a/wkim/src/main/java/com/xinbida/wukongim/message/WKConnection.java
+++ b/wkim/src/main/java/com/xinbida/wukongim/message/WKConnection.java
@@ -60,6 +60,7 @@ import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.locks.ReentrantLock;
/**
* 5/21/21 10:51 AM
@@ -146,9 +147,9 @@ public class WKConnection {
}
};
- // 添加一个专门用于同步connection访问的锁对象
- public final Object connectionLock = new Object();
-
+ // 替换原有的 Object 锁
+ public final ReentrantLock connectionLock = new ReentrantLock(true); // 使用公平锁
+ private static final long LOCK_TIMEOUT = 3000; // 3秒超时
private final Handler mainHandler = new Handler(Looper.getMainLooper());
private static final long CONNECTION_CLOSE_TIMEOUT = 5000; // 5 seconds timeout
@@ -548,15 +549,20 @@ public class WKConnection {
//处理登录消息状态
private void handleLoginStatus(short status) {
- WKLoggerUtils.getInstance().e(TAG, "Connection state transition: " + connectStatus + " -> " + status);
-
- synchronized (connectionLock) {
+ boolean locked = false;
+ try {
+ locked = tryLockWithTimeout();
+ if (!locked) {
+ WKLoggerUtils.getInstance().e(TAG, "获取锁超时,handleLoginStatus失败");
+ return;
+ }
+
+ WKLoggerUtils.getInstance().e(TAG, "Connection state transition: " + connectStatus + " -> " + status);
String reason = WKConnectReason.ConnectSuccess;
if (status == WKConnectStatus.kicked) {
reason = WKConnectReason.ReasonAuthFail;
}
- // Validate state transition
if (!isValidStateTransition(connectStatus, status)) {
WKLoggerUtils.getInstance().e(TAG, "Invalid state transition attempted: " + connectStatus + " -> " + status);
return;
@@ -566,22 +572,22 @@ public class WKConnection {
WKIM.getInstance().getConnectionManager().setConnectionStatus(status, reason);
if (status == WKConnectStatus.success) {
- // Reset reconnection counters since we have a successful connection
connCount = 0;
isReConnecting = false;
-
- // Set to syncing state
connectStatus = WKConnectStatus.syncMsg;
WKIM.getInstance().getConnectionManager().setConnectionStatus(WKConnectStatus.syncMsg, WKConnectReason.SyncMsg);
-
- // Start timers and heartbeat before syncing
startAll();
- // Handle message syncing based on mode
if (WKIMApplication.getInstance().getSyncMsgMode() == WKSyncMsgMode.WRITE) {
WKIM.getInstance().getMsgManager().setSyncOfflineMsg((isEnd, list) -> {
if (isEnd) {
- synchronized (connectionLock) {
+ boolean innerLocked = false;
+ try {
+ innerLocked = tryLockWithTimeout();
+ if (!innerLocked) {
+ WKLoggerUtils.getInstance().e(TAG, "获取锁超时,setSyncOfflineMsg回调处理失败");
+ return;
+ }
if (connection != null && !isClosing.get()) {
connectStatus = WKConnectStatus.success;
MessageHandler.getInstance().saveReceiveMsg();
@@ -590,12 +596,22 @@ public class WKConnection {
resendMsg();
WKIM.getInstance().getConnectionManager().setConnectionStatus(WKConnectStatus.success, WKConnectReason.ConnectSuccess);
}
+ } finally {
+ if (innerLocked) {
+ connectionLock.unlock();
+ }
}
}
});
} else {
WKIM.getInstance().getConversationManager().setSyncConversationListener(syncChat -> {
- synchronized (connectionLock) {
+ boolean innerLocked = false;
+ try {
+ innerLocked = tryLockWithTimeout();
+ if (!innerLocked) {
+ WKLoggerUtils.getInstance().e(TAG, "获取锁超时,setSyncConversationListener回调处理失败");
+ return;
+ }
if (connection != null && !isClosing.get()) {
connectStatus = WKConnectStatus.success;
WKIMApplication.getInstance().isCanConnect = true;
@@ -603,6 +619,10 @@ public class WKConnection {
resendMsg();
WKIM.getInstance().getConnectionManager().setConnectionStatus(WKConnectStatus.success, WKConnectReason.ConnectSuccess);
}
+ } finally {
+ if (innerLocked) {
+ connectionLock.unlock();
+ }
}
});
}
@@ -612,13 +632,16 @@ public class WKConnection {
WKIMApplication.getInstance().isCanConnect = false;
stopAll();
} else {
- // Only attempt reconnection if we're allowed to connect
if (WKIMApplication.getInstance().isCanConnect) {
reconnection();
}
WKLoggerUtils.getInstance().e(TAG, "Login status: " + status);
stopAll();
}
+ } finally {
+ if (locked) {
+ connectionLock.unlock();
+ }
}
}
@@ -655,36 +678,46 @@ public class WKConnection {
public void sendMessage(WKBaseMsg mBaseMsg) {
if (mBaseMsg == null) {
- WKLoggerUtils.getInstance().w(TAG ,"sendMessage called with null mBaseMsg.");
+ WKLoggerUtils.getInstance().w(TAG, "sendMessage called with null mBaseMsg.");
return;
}
- if (mBaseMsg.packetType != WKMsgType.CONNECT) {
- if (connectStatus == WKConnectStatus.syncMsg) {
- WKLoggerUtils.getInstance().i(TAG ," sendMessage: In syncMsg status, message not sent: " + mBaseMsg.packetType);
+
+ boolean locked = false;
+ try {
+ locked = tryLockWithTimeout();
+ if (!locked) {
+ WKLoggerUtils.getInstance().e(TAG, "获取锁超时,sendMessage失败");
return;
}
- if (connectStatus != WKConnectStatus.success) {
- WKLoggerUtils.getInstance().w(TAG , " sendMessage: Not in success status (is " + connectStatus + "), attempting reconnection for: " + mBaseMsg.packetType);
+
+ if (mBaseMsg.packetType != WKMsgType.CONNECT) {
+ if (connectStatus == WKConnectStatus.syncMsg) {
+ WKLoggerUtils.getInstance().i(TAG, " sendMessage: In syncMsg status, message not sent: " + mBaseMsg.packetType);
+ return;
+ }
+ if (connectStatus != WKConnectStatus.success) {
+ WKLoggerUtils.getInstance().w(TAG, " sendMessage: Not in success status (is " + connectStatus + "), attempting reconnection for: " + mBaseMsg.packetType);
+ reconnection();
+ return;
+ }
+ }
+
+ INonBlockingConnection currentConnection = this.connection;
+ if (currentConnection == null || !currentConnection.isOpen()) {
+ WKLoggerUtils.getInstance().w(TAG, " sendMessage: Connection is null or not open, attempting reconnection for: " + mBaseMsg.packetType);
reconnection();
return;
}
- }
- INonBlockingConnection currentConnection;
- synchronized (connectionLock) {
- currentConnection = this.connection;
- }
-
- if (currentConnection == null || !currentConnection.isOpen()) {
- WKLoggerUtils.getInstance().w(TAG ," sendMessage: Connection is null or not open, attempting reconnection for: " + mBaseMsg.packetType);
- reconnection();
- return;
- }
- // Pass the local reference to MessageHandler
- int status = MessageHandler.getInstance().sendMessage(currentConnection, mBaseMsg);
- if (status == 0) {
- WKLoggerUtils.getInstance().e(TAG, "发消息失败 (status 0 from MessageHandler), attempting reconnection for: " + mBaseMsg.packetType);
- reconnection();
+ int status = MessageHandler.getInstance().sendMessage(currentConnection, mBaseMsg);
+ if (status == 0) {
+ WKLoggerUtils.getInstance().e(TAG, "发消息失败 (status 0 from MessageHandler), attempting reconnection for: " + mBaseMsg.packetType);
+ reconnection();
+ }
+ } finally {
+ if (locked) {
+ connectionLock.unlock();
+ }
}
}
private void removeSendingMsg() {
@@ -846,8 +879,18 @@ public class WKConnection {
}
public boolean connectionIsNull() {
- synchronized (connectionLock) {
+ boolean locked = false;
+ try {
+ locked = tryLockWithTimeout();
+ if (!locked) {
+ WKLoggerUtils.getInstance().e(TAG, "获取锁超时,connectionIsNull检查失败");
+ return true; // 保守起见,如果获取锁失败就认为连接为空
+ }
return connection == null || !connection.isOpen();
+ } finally {
+ if (locked) {
+ connectionLock.unlock();
+ }
}
}
@@ -883,7 +926,14 @@ public class WKConnection {
}
public void stopAll() {
- synchronized (connectionLock) {
+ boolean locked = false;
+ try {
+ locked = tryLockWithTimeout();
+ if (!locked) {
+ WKLoggerUtils.getInstance().e(TAG, "获取锁超时,stopAll失败");
+ return;
+ }
+
// 先设置连接状态为失败
WKIM.getInstance().getConnectionManager().setConnectionStatus(WKConnectStatus.fail, "");
// 清理连接相关资源
@@ -912,6 +962,7 @@ public class WKConnection {
connAckTime = 0;
lastMsgTime = 0;
connCount = 0;
+
// 清空发送消息队列
if (sendingMsgHashMap != null) {
sendingMsgHashMap.clear();
@@ -923,28 +974,38 @@ public class WKConnection {
shutdownExecutor();
System.gc();
+ } finally {
+ if (locked) {
+ connectionLock.unlock();
+ }
}
}
private void closeConnect() {
final INonBlockingConnection connectionToCloseActual;
- // 如果已经在关闭过程中,直接返回
if (!isClosing.compareAndSet(false, true)) {
- WKLoggerUtils.getInstance().i(TAG , " Close operation already in progress");
+ WKLoggerUtils.getInstance().i(TAG, " Close operation already in progress");
return;
}
- synchronized (connectionLock) {
+ boolean locked = false;
+ try {
+ locked = tryLockWithTimeout();
+ if (!locked) {
+ WKLoggerUtils.getInstance().e(TAG, "获取锁超时,closeConnect失败");
+ isClosing.set(false);
+ return;
+ }
+
if (connection == null) {
isClosing.set(false);
- WKLoggerUtils.getInstance().i(TAG , " closeConnect called but connection is already null.");
+ WKLoggerUtils.getInstance().i(TAG, " closeConnect called but connection is already null.");
return;
}
connectionToCloseActual = connection;
String connId = connectionToCloseActual.getId();
- // Mark connection for closure to prevent reconnection attempts
try {
connectionToCloseActual.setAttachment("closing_" + System.currentTimeMillis() + "_" + connId);
} catch (Exception e) {
@@ -953,7 +1014,11 @@ public class WKConnection {
connection = null;
connectionClient = null;
- WKLoggerUtils.getInstance().i(TAG , " Connection object nulled, preparing for async close of: " + connId);
+ WKLoggerUtils.getInstance().i(TAG, " Connection object nulled, preparing for async close of: " + connId);
+ } finally {
+ if (locked) {
+ connectionLock.unlock();
+ }
}
// Create a timeout handler to force close after timeout
@@ -961,7 +1026,7 @@ public class WKConnection {
try {
if (connectionToCloseActual.isOpen()) {
String connId = connectionToCloseActual.getId();
- WKLoggerUtils.getInstance().w(TAG , " Connection close timeout reached for: " + connId);
+ WKLoggerUtils.getInstance().w(TAG, " Connection close timeout reached for: " + connId);
connectionToCloseActual.close();
}
} catch (Exception e) {
@@ -979,13 +1044,13 @@ public class WKConnection {
try {
if (connectionToCloseActual.isOpen()) {
String connId = connectionToCloseActual.getId();
- WKLoggerUtils.getInstance().i(TAG , " Attempting to close connection: " + connId);
+ WKLoggerUtils.getInstance().i(TAG, " Attempting to close connection: " + connId);
connectionToCloseActual.close();
// Remove the timeout handler since we closed successfully
mainHandler.removeCallbacks(timeoutRunnable);
- WKLoggerUtils.getInstance().i(TAG , " Successfully closed connection: " + connId);
+ WKLoggerUtils.getInstance().i(TAG, " Successfully closed connection: " + connId);
} else {
- WKLoggerUtils.getInstance().i(TAG , " Connection was already closed or not open when async close executed: " + connectionToCloseActual.getId());
+ WKLoggerUtils.getInstance().i(TAG, " Connection was already closed or not open when async close executed: " + connectionToCloseActual.getId());
}
} catch (IOException e) {
WKLoggerUtils.getInstance().e(TAG, "IOException during async connection close for " + connectionToCloseActual.getId() + ": " + e.getMessage());
@@ -1008,4 +1073,14 @@ public class WKConnection {
closeThread.setDaemon(true);
closeThread.start();
}
+
+ private boolean tryLockWithTimeout() {
+ try {
+ return connectionLock.tryLock(LOCK_TIMEOUT, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ WKLoggerUtils.getInstance().e(TAG, "获取锁被中断: " + e.getMessage());
+ Thread.currentThread().interrupt();
+ return false;
+ }
+ }
}
\ No newline at end of file