diff --git a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata index 706eede..919434a 100644 --- a/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +++ b/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:"> diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..245876b --- /dev/null +++ b/Package.resolved @@ -0,0 +1,43 @@ +{ + "object": { + "pins": [ + { + "package": "Socket", + "repositoryURL": "https://github.com/OperatorFoundation/BlueSocket", + "state": { + "branch": null, + "revision": "90212ea8b66787c2d51d03527a04748ba6ee7679", + "version": "1.1.0" + } + }, + { + "package": "Chord", + "repositoryURL": "https://github.com/OperatorFoundation/Chord", + "state": { + "branch": null, + "revision": "3d0189b4f6e71441d82c577c0f583fceace47684", + "version": "0.0.5" + } + }, + { + "package": "Datable", + "repositoryURL": "https://github.com/OperatorFoundation/Datable", + "state": { + "branch": null, + "revision": "1c23f2b72d0d0cf4386fad05f8a5db4b91e8d304", + "version": "3.0.2" + } + }, + { + "package": "SwiftQueue", + "repositoryURL": "https://github.com/OperatorFoundation/SwiftQueue", + "state": { + "branch": null, + "revision": "0e5979acbb104516a427bb2bb09debc50ca100b4", + "version": "0.0.3" + } + } + ] + }, + "version": 1 +} diff --git a/Package.swift b/Package.swift index 93590ed..513059f 100644 --- a/Package.swift +++ b/Package.swift @@ -17,6 +17,7 @@ let package = Package( // .package(url: /* package url */, from: "1.0.0"), .package(url: "https://github.com/OperatorFoundation/Chord", from: "0.0.5"), .package(url: "https://github.com/OperatorFoundation/Datable", from: "3.0.2"), + .package(name: "Socket", url: "https://github.com/OperatorFoundation/BlueSocket", from: "1.1.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. @@ -24,9 +25,15 @@ let package = Package( .target( name: "Transmission", dependencies: ["Chord"]), + .target( + name: "TransmissionLinux", + dependencies: ["Chord", "Socket"]), .testTarget( name: "TransmissionTests", dependencies: ["Transmission", "Datable"]), + .testTarget( + name: "TransmissionLinuxTests", + dependencies: ["TransmissionLinux", "Datable"]), ], swiftLanguageVersions: [.v5] ) diff --git a/Sources/TransmissionLinux/Connection.swift b/Sources/TransmissionLinux/Connection.swift new file mode 100644 index 0000000..576a27f --- /dev/null +++ b/Sources/TransmissionLinux/Connection.swift @@ -0,0 +1,69 @@ +import Foundation +import Socket +import Datable +import Chord + +public class Connection +{ + var connectLock = DispatchGroup() + var readLock = DispatchGroup() + var writeLock = DispatchGroup() + + let socket: Socket + + public init?(host: String, port: Int) + { + guard let socket = try? Socket.create() else {return nil} + self.socket = socket + + do + { + try self.socket.connect(to: host, port: Int32(port)) + } + catch + { + return nil + } + } + + public init(socket: Socket) + { + self.socket = socket + } + + public func read(size: Int) -> Data? + { + var data = Data() + + do + { + let _ = try self.socket.read(into: &data) + } + catch + { + return nil + } + + return data + } + + public func write(string: String) -> Bool + { + let data = string.data + return write(data: data) + } + + public func write(data: Data) -> Bool + { + do + { + try self.socket.write(from: data) + } + catch + { + return false + } + + return true + } +} diff --git a/Sources/TransmissionLinux/Listener.swift b/Sources/TransmissionLinux/Listener.swift new file mode 100644 index 0000000..d8fbeff --- /dev/null +++ b/Sources/TransmissionLinux/Listener.swift @@ -0,0 +1,36 @@ +// +// Listener.swift +// +// +// Created by Dr. Brandon Wiley on 8/31/20. +// + +import Foundation +import Socket +import Chord + +public class Listener +{ + var socket: Socket + + public init?(port: Int) + { + guard let socket = try? Socket.create() else {return nil} + self.socket = socket + + do + { + try socket.listen(on: port) + } + catch + { + return nil + } + } + + public func accept() -> Connection? + { + guard let newConnection = try? self.socket.acceptClientConnection(invokeDelegate: false) else {return nil} + return Connection(socket: newConnection) + } +} diff --git a/Tests/TransmissionLinuxTests/TransmissionLinuxTests.swift b/Tests/TransmissionLinuxTests/TransmissionLinuxTests.swift new file mode 100644 index 0000000..dd6ec78 --- /dev/null +++ b/Tests/TransmissionLinuxTests/TransmissionLinuxTests.swift @@ -0,0 +1,47 @@ +import XCTest +import Foundation +@testable import TransmissionLinux + +final class TransmissionTests: XCTestCase +{ + public func testConnection() + { + let lock = DispatchGroup() + let queue = DispatchQueue(label: "testing") + + lock.enter() + + queue.async + { + self.runServer(lock) + } + + lock.wait() + + runClient() + } + + func runServer(_ lock: DispatchGroup) + { + guard let listener = Listener(port: 1234) else {return} + lock.leave() + + guard let connection = listener.accept() else {return} + let _ = connection.read(size: 4) + let _ = connection.write(string: "back") + } + + func runClient() + { + let connection = Connection(host: "127.0.0.1", port: 1234) + XCTAssertNotNil(connection) + + let writeResult = connection!.write(string: "test") + XCTAssertTrue(writeResult) + + let result = connection!.read(size: 4) + XCTAssertNotNil(result) + + XCTAssertEqual(result!, "back") + } +}