aboutsummaryrefslogtreecommitdiff
path: root/Sources/swiftGopherClient
diff options
context:
space:
mode:
Diffstat (limited to 'Sources/swiftGopherClient')
-rw-r--r--Sources/swiftGopherClient/gopherClient.swift50
-rw-r--r--Sources/swiftGopherClient/gopherRequestResponseHandler.swift37
-rw-r--r--Sources/swiftGopherClient/gopherTypes.swift122
3 files changed, 46 insertions, 163 deletions
diff --git a/Sources/swiftGopherClient/gopherClient.swift b/Sources/swiftGopherClient/gopherClient.swift
index e508285..eabbbc4 100644
--- a/Sources/swiftGopherClient/gopherClient.swift
+++ b/Sources/swiftGopherClient/gopherClient.swift
@@ -7,12 +7,18 @@
import Foundation
import NIO
+import NIOTransportServices
+import GopherHelpers
public class GopherClient {
private let group: EventLoopGroup
public init() {
- self.group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
+ if #available(macOS 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *) {
+ self.group = NIOTSEventLoopGroup()
+ } else {
+ self.group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
+ }
}
deinit {
@@ -20,22 +26,40 @@ public class GopherClient {
}
public func sendRequest(to host: String, port: Int = 70, message: String, completion: @escaping (Result<[gopherItem], Error>) -> Void) {
- let bootstrap = ClientBootstrap(group: group)
- .channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
- .channelInitializer { channel in
- channel.pipeline.addHandler(GopherRequestResponseHandler(message: message, completion: completion))
+ if #available(macOS 10.14, iOS 12.0, tvOS 12.0, watchOS 6.0, *) {
+ let bootstrap = NIOTSConnectionBootstrap(group: group)
+ .channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
+ .channelInitializer { channel in
+ channel.pipeline.addHandler(GopherRequestResponseHandler(message: message, completion: completion))
+ }
+ bootstrap.connect(host: host, port: port).whenComplete { result in
+ switch result {
+ case .success(let channel):
+ channel.closeFuture.whenComplete { _ in
+ print("Connection closed")
+ }
+ case .failure(let error):
+ completion(.failure(error))
+ }
}
-
- bootstrap.connect(host: host, port: port).whenComplete { result in
- switch result {
- case .success(let channel):
- channel.closeFuture.whenComplete { _ in
- print("Connection closed")
+ } else {
+ let bootstrap = ClientBootstrap(group: group)
+ .channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
+ .channelInitializer { channel in
+ channel.pipeline.addHandler(GopherRequestResponseHandler(message: message, completion: completion))
+ }
+ bootstrap.connect(host: host, port: port).whenComplete { result in
+ switch result {
+ case .success(let channel):
+ channel.closeFuture.whenComplete { _ in
+ print("Connection closed")
+ }
+ case .failure(let error):
+ completion(.failure(error))
}
- case .failure(let error):
- completion(.failure(error))
}
}
+
}
private func shutdownEventLoopGroup() {
diff --git a/Sources/swiftGopherClient/gopherRequestResponseHandler.swift b/Sources/swiftGopherClient/gopherRequestResponseHandler.swift
index 3d15d66..d69c8c8 100644
--- a/Sources/swiftGopherClient/gopherRequestResponseHandler.swift
+++ b/Sources/swiftGopherClient/gopherRequestResponseHandler.swift
@@ -7,6 +7,7 @@
import Foundation
import NIO
+import GopherHelpers
final class GopherRequestResponseHandler: ChannelInboundHandler {
typealias InboundIn = ByteBuffer
@@ -31,17 +32,12 @@ final class GopherRequestResponseHandler: ChannelInboundHandler {
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
var buffer = unwrapInboundIn(data)
accumulatedData.writeBuffer(&buffer)
- if let receivedString = buffer.getString(at: 0, length: buffer.readableBytes) {
- print("Received from server: \(receivedString)")
- }
- //completion(.success(receivedString))
- //context.close(promise: nil)
}
func channelInactive(context: ChannelHandlerContext) {
- // Parse GopherServerResponse
- parseGopherServerResponse(response: accumulatedData.readString(length: accumulatedData.readableBytes) ?? "")
- //completion(.success(accumulatedData.readString(length: accumulatedData.readableBytes) ?? ""))
+ if let dataCopy = accumulatedData.getSlice(at: 0, length: accumulatedData.readableBytes) {
+ parseGopherServerResponse(response: accumulatedData.readString(length: accumulatedData.readableBytes) ?? "", originalBytes: dataCopy)
+ }
}
func errorCaught(context: ChannelHandlerContext, error: Error) {
@@ -49,9 +45,10 @@ final class GopherRequestResponseHandler: ChannelInboundHandler {
context.close(promise: nil)
}
- func createGopherItem(rawLine: String, itemType: gopherItemType = .info) -> gopherItem {
+ func createGopherItem(rawLine: String, itemType: gopherItemType = .info, rawData: ByteBuffer) -> gopherItem {
var item = gopherItem(rawLine: rawLine)
item.parsedItemType = itemType
+ item.rawData = rawData
if rawLine.isEmpty {
item.valid = false
@@ -77,7 +74,7 @@ final class GopherRequestResponseHandler: ChannelInboundHandler {
return item
}
- func parseGopherServerResponse(response: String) {
+ func parseGopherServerResponse(response: String, originalBytes: ByteBuffer) {
var gopherServerResponse: [gopherItem] = []
print("parsing")
@@ -87,8 +84,7 @@ final class GopherRequestResponseHandler: ChannelInboundHandler {
for line in response.split(separator: "\r\n") {
let lineItemType = getGopherFileType(item: "\(line.first ?? " ")")
- let item = createGopherItem(rawLine: String(line), itemType: lineItemType)
- print(item.message)
+ let item = createGopherItem(rawLine: String(line), itemType: lineItemType, rawData: originalBytes)
gopherServerResponse.append(item)
}
@@ -96,23 +92,8 @@ final class GopherRequestResponseHandler: ChannelInboundHandler {
print("done parsing")
completion(.success(gopherServerResponse))
-
- //completion(.success(response))
}
}
-public struct gopherItem {
-
- public var rawLine: String
- public var message: String = ""
- public var parsedItemType: gopherItemType = .info
- public var host: String = "error.host"
- public var port: Int = 1
- public var selector: String = ""
- public var valid: Bool = true
-
- public init(rawLine: String) {
- self.rawLine = rawLine
- }
-}
+
diff --git a/Sources/swiftGopherClient/gopherTypes.swift b/Sources/swiftGopherClient/gopherTypes.swift
deleted file mode 100644
index efec92e..0000000
--- a/Sources/swiftGopherClient/gopherTypes.swift
+++ /dev/null
@@ -1,122 +0,0 @@
-//
-// gopherTypes.swift
-//
-//
-// Created by Navan Chauhan on 12/12/23.
-//
-
-import Foundation
-
-/*
-
- From Wikipedia
-
- Canonical types
- 0 Text file
- 1 Gopher submenu
- 2 CCSO Nameserver
- 3 Error code returned by a Gopher server to indicate failure
- 4 BinHex-encoded file (primarily for Macintosh computers)
- 5 DOS file
- 6 uuencoded file
- 7 Gopher full-text search
- 8 Telnet
- 9 Binary file
- + Mirror or alternate server (for load balancing or in case of primary server downtime)
- g GIF file
- I Image file
- T Telnet 3270
- gopher+ types
- : Bitmap image
- ; Movie file
- < Sound file
- Non-canonical types
- d Doc. Seen used alongside PDF's and .DOC's
- h HTML file
- i Informational message, widely used.[25]
- p image file "(especially the png format)"
- r document rtf file "rich text Format")
- s Sound file (especially the WAV format)
- P document pdf file "Portable Document Format")
- X document xml file "eXtensive Markup Language" )
- */
-
-public enum gopherItemType {
- case text
- case directory
- case nameserver
- case error
- case binhex
- case bindos
- case uuencoded
- case search
- case telnet
- case binary
- case mirror
- case gif
- case image
- case tn3270Session
- case bitmap
- case movie
- case sound
- case doc
- case html
- case info
-}
-
-func getGopherFileType(item: String) -> gopherItemType {
- switch item {
- case "0":
- return .text
- case "1":
- return .directory
- case "2":
- return .nameserver
- case "3":
- return .error
- case "4":
- return .binhex
- case "5":
- return .bindos
- case "6":
- return .uuencoded
- case "7":
- return .search
- case "8":
- return .telnet
- case "9":
- return .binary
- case "+":
- return .mirror
- case "g":
- return .gif
- case "I":
- return .image
- case "T":
- return .tn3270Session
- case ":":
- return .bitmap
- case ";":
- return .movie
- case "<":
- return .sound
- case "d":
- return .doc
- case "h":
- return .html
- case "i":
- return .info
- case "p":
- return .image
- case "r":
- return .doc
- case "s":
- return .doc
- case "P":
- return .doc
- case "X":
- return .doc
- default:
- return .info
- }
-}