Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 23 additions & 14 deletions servers/swift-nio/ExampleServer/Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 19 additions & 15 deletions servers/swift-nio/ExampleServer/Package.swift
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
// swift-tools-version: 5.7
// swift-tools-version: 5.8
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "ExampleServer",
platforms: [
.macOS(.v10_15),
.macOS(.v10_15)
],
dependencies: [
.package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0"),
.package(url: "https://github.com/apple/swift-nio-transport-services.git", from: "1.13.0"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.32.0"),
.package(url: "https://github.com/apple/swift-nio-extras.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-http-types.git", from: "1.0.0"),
.package(path: "../NIOResumableUpload"),
.package(path: "../NIOResumableUpload/Dependencies/NIOHTTPTypes"),
],

targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.executableTarget(
name: "ExampleServer",
dependencies: [
.product(name: "NIO", package: "swift-nio"),
.product(name: "NIOExtras", package: "swift-nio-extras"),
.product(name: "NIOHTTP1", package: "swift-nio"),
.product(name: "NIOCore", package: "swift-nio"),
.product(name: "NIOHTTP1", package: "swift-nio"),
.product(name: "NIOTransportServices", package: "swift-nio-transport-services"),
.product(name: "NIOPosix", package: "swift-nio"),
.product(name: "HTTPTypes", package: "swift-http-types"),
.product(name: "NIOHTTPTypesHTTP1", package: "swift-nio-extras"),
.product(name: "NIOHTTPTypes", package: "swift-nio-extras"),
.product(name: "NIOResumableUpload", package: "NIOResumableUpload"),
.product(name: "NIOHTTPTypesHTTP1", package: "NIOHTTPTypes"),
.product(name: "NIOHTTPTypes", package: "NIOHTTPTypes"),
],
path: "Sources"),
]
),
.testTarget(
name: "ExampleServerTests",
dependencies: ["ExampleServer"],
path: "Tests/ExampleServerTests"
)
]
)
113 changes: 113 additions & 0 deletions servers/swift-nio/ExampleServer/Sources/ExampleServer/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import Foundation
import HTTPTypes
import NIOCore
import NIOHTTP1
import NIOHTTPTypes
import NIOHTTPTypesHTTP1
import NIOPosix
import NIOResumableUpload

let HOST = "127.0.0.1"
let PORT = 8080

@available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *)
final class UploadServerHandler: ChannelDuplexHandler {
typealias InboundIn = HTTPRequestPart
typealias OutboundIn = Never
typealias OutboundOut = HTTPResponsePart

let uploadDirectory: URL
var fileHandle: FileHandle? = nil

init() {
self.uploadDirectory = URL(fileURLWithPath: "uploads", isDirectory: true).standardized
try? FileManager.default.createDirectory(at: self.uploadDirectory, withIntermediateDirectories: true)
print("Upload directory created at \(self.uploadDirectory.path)")
}

func channelRead(context: ChannelHandlerContext, data: NIOAny) {
switch self.unwrapInboundIn(data) {
case .head(let request):
print("Received request head: \(request)")
switch request.method {
case .post, .put:
let fileName = UUID().uuidString
let url = self.uploadDirectory.appendingPathComponent(fileName, isDirectory: false).standardized
print("Generated file path: \(url.path)")
if url.path.hasPrefix(self.uploadDirectory.path) {
_ = FileManager.default.createFile(atPath: url.path, contents: nil)
self.fileHandle = try? FileHandle(forWritingTo: url)
print("Creating file at \(url.path)")
}
if self.fileHandle == nil {
print("Failed to create file handle")
let response = HTTPResponse(status: .badRequest)
self.write(context: context, data: self.wrapOutboundOut(.head(response)), promise: nil)
self.write(context: context, data: self.wrapOutboundOut(.end(nil)), promise: nil)
self.flush(context: context)
}
default:
print("Request method not implemented: \(request.method)")
let response = HTTPResponse(status: .notImplemented)
self.write(context: context, data: self.wrapOutboundOut(.head(response)), promise: nil)
self.write(context: context, data: self.wrapOutboundOut(.end(nil)), promise: nil)
self.flush(context: context)
}
case .body(let body):
do {
print("Received body data: \(body)")
try body.withUnsafeReadableBytes { buffer in
try fileHandle?.write(contentsOf: buffer)
}
} catch {
print("Failed to write data to file: \(error)")
exit(1)
}
case .end:
if let fileHandle = self.fileHandle {
do {
try fileHandle.close()
print("File closed successfully")
let response = HTTPResponse(status: .created)
self.write(context: context, data: self.wrapOutboundOut(.head(response)), promise: nil)
self.write(context: context, data: self.wrapOutboundOut(.end(nil)), promise: nil)
self.flush(context: context)
} catch {
print("Failed to close file handle: \(error)")
let response = HTTPResponse(status: .internalServerError)
self.write(context: context, data: self.wrapOutboundOut(.head(response)), promise: nil)
self.write(context: context, data: self.wrapOutboundOut(.end(nil)), promise: nil)
self.flush(context: context)
}
}
}
}
}

if #available(macOS 10.15.4, iOS 13.4, watchOS 6.2, tvOS 13.4, *) {
let uploadContext = HTTPResumableUploadContext(origin: "http://\(HOST):\(PORT)")
print("Upload context created with origin http://\(HOST):\(PORT)")

let group = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
let server = try ServerBootstrap(group: group).childChannelInitializer { channel in
channel.pipeline.configureHTTPServerPipeline().flatMap {
channel.pipeline.addHandlers([
HTTP1ToHTTPServerCodec(secure: false),
HTTPResumableUploadHandler(
context: uploadContext,
handlers: [
UploadServerHandler()
]
),
])
}
}
.bind(host: HOST, port: PORT)
.wait()

print("Server listening on \(HOST):\(PORT)")
try server.closeFuture.wait()
} else {
print("Unsupported OS")
exit(1)
}
80 changes: 0 additions & 80 deletions servers/swift-nio/ExampleServer/Sources/main.swift

This file was deleted.

Loading