Import System package when available (#34)
* Import System package when available * Add isResourceTemporarilyUnavailable helper method to reduce number of imports of System / SystemPackage
This commit is contained in:
parent
97b756c0f4
commit
d55140bc46
6 changed files with 42 additions and 9 deletions
|
|
@ -1,5 +1,11 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
#if canImport(System)
|
||||||
|
import System
|
||||||
|
#else
|
||||||
|
@preconcurrency import SystemPackage
|
||||||
|
#endif
|
||||||
|
|
||||||
/// A model context protocol error.
|
/// A model context protocol error.
|
||||||
public enum Error: Sendable {
|
public enum Error: Sendable {
|
||||||
// Standard JSON-RPC 2.0 errors (-32700 to -32603)
|
// Standard JSON-RPC 2.0 errors (-32700 to -32603)
|
||||||
|
|
@ -29,6 +35,20 @@ public enum Error: Sendable {
|
||||||
case .transportError: return -32001
|
case .transportError: return -32001
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if an error represents a "resource temporarily unavailable" condition
|
||||||
|
public static func isResourceTemporarilyUnavailable(_ error: Swift.Error) -> Bool {
|
||||||
|
#if canImport(System)
|
||||||
|
if let errno = error as? System.Errno, errno == .resourceTemporarilyUnavailable {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if let errno = error as? SystemPackage.Errno, errno == .resourceTemporarilyUnavailable {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: LocalizedError
|
// MARK: LocalizedError
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
import Darwin
|
import Darwin
|
||||||
import Logging
|
import Logging
|
||||||
import SystemPackage
|
|
||||||
|
|
||||||
import struct Foundation.Data
|
import struct Foundation.Data
|
||||||
|
|
||||||
|
#if canImport(System)
|
||||||
|
import System
|
||||||
|
#else
|
||||||
|
@preconcurrency import SystemPackage
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Protocol defining the transport layer for MCP communication
|
/// Protocol defining the transport layer for MCP communication
|
||||||
public protocol Transport: Actor {
|
public protocol Transport: Actor {
|
||||||
var logger: Logger { get }
|
var logger: Logger { get }
|
||||||
|
|
@ -107,7 +112,7 @@ public actor StdioTransport: Transport {
|
||||||
messageContinuation.yield(message)
|
messageContinuation.yield(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch let error as Errno where error == .resourceTemporarilyUnavailable {
|
} catch let error where Error.isResourceTemporarilyUnavailable(error) {
|
||||||
try? await Task.sleep(nanoseconds: 10_000_000) // 10ms backoff
|
try? await Task.sleep(nanoseconds: 10_000_000) // 10ms backoff
|
||||||
continue
|
continue
|
||||||
} catch {
|
} catch {
|
||||||
|
|
@ -147,7 +152,7 @@ public actor StdioTransport: Transport {
|
||||||
if written > 0 {
|
if written > 0 {
|
||||||
remaining = remaining.dropFirst(written)
|
remaining = remaining.dropFirst(written)
|
||||||
}
|
}
|
||||||
} catch let error as Errno where error == .resourceTemporarilyUnavailable {
|
} catch let error where Error.isResourceTemporarilyUnavailable(error) {
|
||||||
try await Task.sleep(nanoseconds: 10_000_000) // 10ms backoff
|
try await Task.sleep(nanoseconds: 10_000_000) // 10ms backoff
|
||||||
continue
|
continue
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import Logging
|
import Logging
|
||||||
import SystemPackage
|
|
||||||
|
|
||||||
import struct Foundation.Data
|
import struct Foundation.Data
|
||||||
import struct Foundation.Date
|
import struct Foundation.Date
|
||||||
|
|
@ -180,7 +179,7 @@ public actor Client {
|
||||||
"Unexpected message received by client", metadata: metadata)
|
"Unexpected message received by client", metadata: metadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch let error as Errno where error == .resourceTemporarilyUnavailable {
|
} catch let error where Error.isResourceTemporarilyUnavailable(error) {
|
||||||
try? await Task.sleep(nanoseconds: 10_000_000) // 10ms
|
try? await Task.sleep(nanoseconds: 10_000_000) // 10ms
|
||||||
continue
|
continue
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import Logging
|
import Logging
|
||||||
import SystemPackage
|
|
||||||
|
|
||||||
import struct Foundation.Data
|
import struct Foundation.Data
|
||||||
import struct Foundation.Date
|
import struct Foundation.Date
|
||||||
|
|
@ -202,7 +201,7 @@ public actor Server {
|
||||||
}
|
}
|
||||||
throw Error.parseError("Invalid message format")
|
throw Error.parseError("Invalid message format")
|
||||||
}
|
}
|
||||||
} catch let error as Errno where error == .resourceTemporarilyUnavailable {
|
} catch let error where Error.isResourceTemporarilyUnavailable(error) {
|
||||||
// Resource temporarily unavailable, retry after a short delay
|
// Resource temporarily unavailable, retry after a short delay
|
||||||
try? await Task.sleep(nanoseconds: 10_000_000) // 10ms
|
try? await Task.sleep(nanoseconds: 10_000_000) // 10ms
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,15 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Logging
|
import Logging
|
||||||
import SystemPackage
|
|
||||||
import Testing
|
import Testing
|
||||||
|
|
||||||
@testable import MCP
|
@testable import MCP
|
||||||
|
|
||||||
|
#if canImport(System)
|
||||||
|
import System
|
||||||
|
#else
|
||||||
|
@preconcurrency import SystemPackage
|
||||||
|
#endif
|
||||||
|
|
||||||
@Suite("Roundtrip Tests")
|
@Suite("Roundtrip Tests")
|
||||||
struct RoundtripTests {
|
struct RoundtripTests {
|
||||||
@Test(
|
@Test(
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,14 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SystemPackage
|
|
||||||
import Testing
|
import Testing
|
||||||
|
|
||||||
@testable import MCP
|
@testable import MCP
|
||||||
|
|
||||||
|
#if canImport(System)
|
||||||
|
import System
|
||||||
|
#else
|
||||||
|
@preconcurrency import SystemPackage
|
||||||
|
#endif
|
||||||
|
|
||||||
@Suite("Stdio Transport Tests")
|
@Suite("Stdio Transport Tests")
|
||||||
struct StdioTransportTests {
|
struct StdioTransportTests {
|
||||||
@Test("Connection")
|
@Test("Connection")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue