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:
Mattt 2025-03-31 05:30:45 -07:00 • committed by GitHub
commit d55140bc46
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 42 additions and 9 deletions

View file

@ -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

View file

@ -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 {

View file

@ -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 {

View file

@ -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

View file

@ -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(

View file

@ -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")