|
|
|
@ -25,6 +25,7 @@ class CustomSseClientTransport( |
|
|
|
private val urlString: String?, |
|
|
|
private val reconnectionTime: Duration? = null, |
|
|
|
private val requestBuilder: HttpRequestBuilder.() -> Unit = {}, |
|
|
|
private val onConnectionLost: (() -> Unit)? = null |
|
|
|
) : AbstractTransport() { |
|
|
|
private val TAG = "CustomSseClientTransport" |
|
|
|
|
|
|
|
@ -35,8 +36,10 @@ class CustomSseClientTransport( |
|
|
|
private val initialized = AtomicBoolean(false) |
|
|
|
private var session: ClientSSESession by Delegates.notNull() |
|
|
|
private val endpoint = CompletableDeferred<String>() |
|
|
|
private val isConnected = AtomicBoolean(false) |
|
|
|
|
|
|
|
private var job: Job? = null |
|
|
|
private var connectionMonitorJob: Job? = null |
|
|
|
|
|
|
|
// 创建JSON解析器 |
|
|
|
private val json = Json { |
|
|
|
@ -95,74 +98,118 @@ class CustomSseClientTransport( |
|
|
|
*/ |
|
|
|
private suspend fun collectEvents() { |
|
|
|
job = scope.launch(CoroutineName("CustomSseMcpClientTransport.collect#${hashCode()}")) { |
|
|
|
session.incoming.collect { event -> |
|
|
|
when (event.event) { |
|
|
|
"error" -> { |
|
|
|
val e = IllegalStateException("SSE error: ${event.data}") |
|
|
|
Log.e(TAG, "SSE错误: ${event.data}") |
|
|
|
_onError(e) |
|
|
|
throw e |
|
|
|
} |
|
|
|
try { |
|
|
|
session.incoming.collect { event -> |
|
|
|
when (event.event) { |
|
|
|
"error" -> { |
|
|
|
Log.e(TAG, "SSE错误: ${event.data}") |
|
|
|
isConnected.set(false) |
|
|
|
val exception = Exception("SSE Error: ${event.data}") |
|
|
|
_onError(exception) |
|
|
|
onConnectionLost?.invoke() |
|
|
|
throw exception |
|
|
|
} |
|
|
|
|
|
|
|
"open" -> { |
|
|
|
// SSE连接已打开 |
|
|
|
} |
|
|
|
"ping" -> { |
|
|
|
// 心跳 |
|
|
|
} |
|
|
|
"endpoint" -> { |
|
|
|
try { |
|
|
|
val eventData = event.data ?: "" |
|
|
|
"open" -> { |
|
|
|
// SSE连接已打开 |
|
|
|
Log.d(TAG, "SSE连接已打开") |
|
|
|
isConnected.set(true) |
|
|
|
} |
|
|
|
"ping" -> { |
|
|
|
// 心跳 |
|
|
|
} |
|
|
|
"endpoint" -> { |
|
|
|
try { |
|
|
|
val eventData = event.data ?: "" |
|
|
|
|
|
|
|
// 构建完整的端点URL |
|
|
|
val fullEndpoint = if (eventData.contains(hostPart)) { |
|
|
|
eventData |
|
|
|
} else if (eventData.startsWith("/")) { |
|
|
|
"$hostPart$eventData" |
|
|
|
} else { |
|
|
|
eventData |
|
|
|
} |
|
|
|
|
|
|
|
// 添加查询参数 |
|
|
|
val endpointWithParams = if (queryParams.isNotEmpty()) { |
|
|
|
if (fullEndpoint.contains("?")) { |
|
|
|
val queryString = queryParams.entries.joinToString("&") { "${it.key}=${it.value}" } |
|
|
|
"$fullEndpoint&$queryString" |
|
|
|
// 构建完整的端点URL |
|
|
|
val fullEndpoint = if (eventData.contains(hostPart)) { |
|
|
|
eventData |
|
|
|
} else if (eventData.startsWith("/")) { |
|
|
|
"$hostPart$eventData" |
|
|
|
} else { |
|
|
|
val queryString = queryParams.entries.joinToString("&") { "${it.key}=${it.value}" } |
|
|
|
"$fullEndpoint?$queryString" |
|
|
|
eventData |
|
|
|
} |
|
|
|
} else { |
|
|
|
fullEndpoint |
|
|
|
|
|
|
|
// 添加查询参数 |
|
|
|
val endpointWithParams = if (queryParams.isNotEmpty()) { |
|
|
|
if (fullEndpoint.contains("?")) { |
|
|
|
val queryString = queryParams.entries.joinToString("&") { "${it.key}=${it.value}" } |
|
|
|
"$fullEndpoint&$queryString" |
|
|
|
} else { |
|
|
|
val queryString = queryParams.entries.joinToString("&") { "${it.key}=${it.value}" } |
|
|
|
"$fullEndpoint?$queryString" |
|
|
|
} |
|
|
|
} else { |
|
|
|
fullEndpoint |
|
|
|
} |
|
|
|
|
|
|
|
endpoint.complete(endpointWithParams) |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "处理endpoint事件失败: ${e.message}", e) |
|
|
|
_onError(e) |
|
|
|
close() |
|
|
|
error(e) |
|
|
|
} |
|
|
|
|
|
|
|
endpoint.complete(endpointWithParams) |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "处理endpoint事件失败: ${e.message}", e) |
|
|
|
_onError(e) |
|
|
|
close() |
|
|
|
error(e) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
else -> { |
|
|
|
try { |
|
|
|
val data = event.data |
|
|
|
if (data != null) { |
|
|
|
try { |
|
|
|
val message = json.decodeFromString<JSONRPCMessage>(data) |
|
|
|
_onMessage(message) |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "解析JSON-RPC消息失败: ${e.message}", e) |
|
|
|
_onError(e) |
|
|
|
else -> { |
|
|
|
try { |
|
|
|
val data = event.data |
|
|
|
if (data != null) { |
|
|
|
try { |
|
|
|
val message = json.decodeFromString<JSONRPCMessage>(data) |
|
|
|
_onMessage(message) |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "解析JSON-RPC消息失败: ${e.message}", e) |
|
|
|
_onError(e) |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "处理事件失败: ${e.message}", e) |
|
|
|
_onError(e) |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "处理事件失败: ${e.message}", e) |
|
|
|
_onError(e) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (e: CancellationException) { |
|
|
|
Log.d(TAG, "SSE事件收集被取消") |
|
|
|
throw e |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "SSE连接异常断开: ${e.message}", e) |
|
|
|
isConnected.set(false) |
|
|
|
_onError(e) |
|
|
|
onConnectionLost?.invoke() |
|
|
|
throw e |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 启动连接监控 |
|
|
|
startConnectionMonitor() |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 启动连接监控,定期检查连接状态 |
|
|
|
*/ |
|
|
|
private fun startConnectionMonitor() { |
|
|
|
connectionMonitorJob = scope.launch { |
|
|
|
while (isActive && isConnected.get()) { |
|
|
|
try { |
|
|
|
delay(10000) // 每10秒检查一次 |
|
|
|
|
|
|
|
// 检查session是否仍然活跃 |
|
|
|
if (session.coroutineContext[Job]?.isCancelled == true) { |
|
|
|
Log.w(TAG, "检测到SSE会话已取消") |
|
|
|
isConnected.set(false) |
|
|
|
onConnectionLost?.invoke() |
|
|
|
break |
|
|
|
} |
|
|
|
} catch (e: Exception) { |
|
|
|
Log.e(TAG, "连接监控异常: ${e.message}", e) |
|
|
|
isConnected.set(false) |
|
|
|
onConnectionLost?.invoke() |
|
|
|
break |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -212,6 +259,8 @@ class CustomSseClientTransport( |
|
|
|
|
|
|
|
// 等待endpoint就绪 |
|
|
|
endpoint.await() |
|
|
|
|
|
|
|
Log.d(TAG, "CustomSseClientTransport启动完成") |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
@ -245,6 +294,13 @@ class CustomSseClientTransport( |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 检查连接状态 |
|
|
|
*/ |
|
|
|
fun isConnectionActive(): Boolean { |
|
|
|
return isConnected.get() && session.coroutineContext[Job]?.isActive == true |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* 关闭传输层 |
|
|
|
*/ |
|
|
|
@ -253,8 +309,14 @@ class CustomSseClientTransport( |
|
|
|
Log.e(TAG, "关闭失败: 传输层未初始化") |
|
|
|
error("CustomSseClientTransport is not initialized!") |
|
|
|
} |
|
|
|
|
|
|
|
isConnected.set(false) |
|
|
|
connectionMonitorJob?.cancel() |
|
|
|
session.cancel() |
|
|
|
_onClose() |
|
|
|
job?.cancelAndJoin() |
|
|
|
connectionMonitorJob?.cancelAndJoin() |
|
|
|
|
|
|
|
Log.d(TAG, "CustomSseClientTransport已关闭") |
|
|
|
} |
|
|
|
} |
|
|
|
} |