Skip to content
Merged
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
2 changes: 1 addition & 1 deletion frameworks/Swift/hummingbird-core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Hummingbird Core is the HTTP server for the Hummingbird framework.

## Important Libraries
This version of Hummingbird requires
* [Swift 5.7](https://swift.org)
* [Swift 5.10](https://swift.org)
* [SwiftNIO 2.x](https://github.com/apple/swift-nio/)

## Test URLs
Expand Down
4 changes: 2 additions & 2 deletions frameworks/Swift/hummingbird-core/hummingbird-core.dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ================================
# Build image
# ================================
FROM swift:5.10 as build
FROM swift:6.1 AS build
WORKDIR /build

# Copy entire repo into container
Expand All @@ -15,7 +15,7 @@ RUN swift build \
# ================================
# Run image
# ================================
FROM swift:5.10-slim
FROM swift:6.1-slim
WORKDIR /run

# Copy build artifacts
Expand Down
2 changes: 1 addition & 1 deletion frameworks/Swift/hummingbird/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Hummingbird is a lightweight, flexible HTTP server framework written in Swift.

## Important Libraries
This version of Hummingbird requires
* [Swift 5.7](https://swift.org)
* [Swift 5.10](https://swift.org)
* [SwiftNIO 2.x](https://github.com/apple/swift-nio/)
In these tests for database access it uses
* [PostgresKit 2.0](https://github.com/vapor/postgres-kit/)
Expand Down
4 changes: 2 additions & 2 deletions frameworks/Swift/hummingbird/hummingbird-postgres.dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ================================
# Build image
# ================================
FROM swift:5.10 as build
FROM swift:6.1 AS build
WORKDIR /build

# Copy entire repo into container
Expand All @@ -15,7 +15,7 @@ RUN swift build \
# ================================
# Run image
# ================================
FROM swift:5.10-slim
FROM swift:6.1-slim
WORKDIR /run

# Copy build artifacts
Expand Down
4 changes: 2 additions & 2 deletions frameworks/Swift/hummingbird/hummingbird.dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ================================
# Build image
# ================================
FROM swift:5.10 as build
FROM swift:6.1 AS build
WORKDIR /build

# Copy entire repo into container
Expand All @@ -15,7 +15,7 @@ RUN swift build \
# ================================
# Run image
# ================================
FROM swift:5.10-slim
FROM swift:6.1-slim
WORKDIR /run

# Copy build artifacts
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ================================
# Build image
# ================================
FROM swift:5.10 as build
FROM swift:6.1 AS build
WORKDIR /build

# Copy entire repo into container
Expand All @@ -15,7 +15,7 @@ RUN swift build \
# ================================
# Run image
# ================================
FROM swift:5.10-slim
FROM swift:6.1-slim
WORKDIR /run

# Copy build artifacts
Expand Down
4 changes: 2 additions & 2 deletions frameworks/Swift/hummingbird2/hummingbird2.dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# ================================
# Build image
# ================================
FROM swift:5.10 as build
FROM swift:6.1 AS build
WORKDIR /build

# Copy entire repo into container
Expand All @@ -15,7 +15,7 @@ RUN swift build \
# ================================
# Run image
# ================================
FROM swift:5.10-slim
FROM swift:6.1-slim
WORKDIR /run

# Copy build artifacts
Expand Down
14 changes: 6 additions & 8 deletions frameworks/Swift/hummingbird2/src-postgres/Package.swift
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
// swift-tools-version:5.10
// swift-tools-version:6.1
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "server",
platforms: [.macOS(.v14)],
products: [
.executable(name: "server", targets: ["server"])
],
dependencies: [
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.0.0-beta.4"),
.package(url: "https://github.com/hummingbird-project/swift-mustache.git", from: "2.0.0-beta"),
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.0.0"),
.package(url: "https://github.com/hummingbird-project/swift-mustache.git", from: "2.0.0"),
.package(url: "https://github.com/vapor/postgres-nio.git", from: "1.21.0"),
],
targets: [
.executableTarget(name: "server",
.executableTarget(
name: "server",
dependencies: [
.product(name: "Hummingbird", package: "hummingbird"),
.product(name: "Mustache", package: "swift-mustache"),
Expand All @@ -27,6 +25,6 @@ let package = Package(
// builds. See <https://github.com/swift-server/guides#building-for-production> for details.
.unsafeFlags(["-cross-module-optimization"], .when(configuration: .release))
]
),
)
]
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import PostgresNIO
struct HTML: ResponseGenerator, Sendable {
let html: String
public func response(from request: Request, context: some RequestContext) -> Response {
let buffer = context.allocator.buffer(string: html)
return Response(status: .ok, headers: [.contentType: "text/html; charset=utf-8"], body: .init(byteBuffer: buffer))
return Response(
status: .ok, headers: [.contentType: "text/html; charset=utf-8"],
body: .init(byteBuffer: .init(string: html)))
}
}

Expand All @@ -17,9 +18,10 @@ final class FortunesController: Sendable {

init(postgresClient: PostgresClient) {
self.postgresClient = postgresClient
self.template = try! MustacheTemplate(string: """
<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>{{#.}}<tr><td>{{id}}</td><td>{{message}}</td></tr>{{/.}}</table></body></html>
""")
self.template = try! MustacheTemplate(
string: """
<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table><tr><th>id</th><th>message</th></tr>{{#.}}<tr><td>{{id}}</td><td>{{message}}</td></tr>{{/.}}</table></body></html>
""")
}

var routes: RouteCollection<Context> {
Expand All @@ -28,11 +30,11 @@ final class FortunesController: Sendable {
}

/// In this test, the framework's ORM is used to fetch all rows from a database
/// table containing an unknown number of Unix fortune cookie messages (the
/// table has 12 rows, but the code cannot have foreknowledge of the table's
/// size). An additional fortune cookie message is inserted into the list at
/// runtime and then the list is sorted by the message text. Finally, the list
/// is delivered to the client using a server-side HTML template. The message
/// table containing an unknown number of Unix fortune cookie messages (the
/// table has 12 rows, but the code cannot have foreknowledge of the table's
/// size). An additional fortune cookie message is inserted into the list at
/// runtime and then the list is sorted by the message text. Finally, the list
/// is delivered to the client using a server-side HTML template. The message
/// text must be considered untrusted and properly escaped and the UTF-8 fortune messages must be rendered properly.
@Sendable func fortunes(request: Request, context: Context) async throws -> HTML {
let rows = try await self.postgresClient.execute(SelectFortuneStatement())
Expand All @@ -43,14 +45,14 @@ final class FortunesController: Sendable {

fortunes.append(.init(id: 0, message: "Additional fortune added at request time."))
let sortedFortunes = fortunes.sorted { $0.message < $1.message }
return HTML(html: self.template.render(sortedFortunes) )
return HTML(html: self.template.render(sortedFortunes))

}

struct SelectFortuneStatement: PostgresPreparedStatement {
typealias Row = (Int32, String)

static var sql = "SELECT id, message FROM Fortune"
static let sql = "SELECT id, message FROM Fortune"

func makeBindings() throws -> PostgresNIO.PostgresBindings {
return .init()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,20 @@ struct WorldController {
.get("updates", use: updates)
}

/// In this test, each request is processed by fetching a single row from a
/// In this test, each request is processed by fetching a single row from a
/// simple database table. That row is then serialized as a JSON response.
@Sendable func single(request: Request, context: Context) async throws -> World {
let id = Int32.random(in: 1...10_000)
let rows = try await self.postgresClient.execute(SelectWorldStatement(id: id))
guard let row = try await rows.first(where: {_ in true }) else {
guard let row = try await rows.first(where: { _ in true }) else {
throw HTTPError(.notFound)
}
return World(id: row.0, randomNumber: row.1)
}

/// In this test, each request is processed by fetching multiple rows from a
/// simple database table and serializing these rows as a JSON response. The
/// test is run multiple times: testing 1, 5, 10, 15, and 20 queries per request.
/// In this test, each request is processed by fetching multiple rows from a
/// simple database table and serializing these rows as a JSON response. The
/// test is run multiple times: testing 1, 5, 10, 15, and 20 queries per request.
/// All tests are run at 512 concurrency.
@Sendable func multiple(request: Request, context: Context) async throws -> [World] {
let queries = (request.uri.queryParameters.get("queries", as: Int.self) ?? 1).bound(1, 500)
Expand All @@ -34,23 +34,24 @@ struct WorldController {
result.reserveCapacity(queries)
for _ in 0..<queries {
let id = Int32.random(in: 1...10_000)
let rows = try await conn.execute(SelectWorldStatement(id: id), logger: context.logger)
guard let row = try await rows.first(where: {_ in true }) else {
let rows = try await conn.execute(
SelectWorldStatement(id: id), logger: context.logger)
guard let row = try await rows.first(where: { _ in true }) else {
throw HTTPError(.notFound)
}
result.append( World(id: row.0, randomNumber: row.1))
result.append(World(id: row.0, randomNumber: row.1))
}
return result
}
}

/// This test exercises database writes. Each request is processed by fetching
/// multiple rows from a simple database table, converting the rows to in-memory
/// objects, modifying one attribute of each object in memory, updating each
/// associated row in the database individually, and then serializing the list
/// of objects as a JSON response. The test is run multiple times: testing 1, 5,
/// 10, 15, and 20 updates per request. Note that the number of statements per
/// request is twice the number of updates since each update is paired with one
/// This test exercises database writes. Each request is processed by fetching
/// multiple rows from a simple database table, converting the rows to in-memory
/// objects, modifying one attribute of each object in memory, updating each
/// associated row in the database individually, and then serializing the list
/// of objects as a JSON response. The test is run multiple times: testing 1, 5,
/// 10, 15, and 20 updates per request. Note that the number of statements per
/// request is twice the number of updates since each update is paired with one
/// query to fetch the object. All tests are run at 512 concurrency.
@Sendable func updates(request: Request, context: Context) async throws -> [World] {
let queries = (request.uri.queryParameters.get("queries", as: Int.self) ?? 1).bound(1, 500)
Expand All @@ -59,12 +60,15 @@ struct WorldController {
result.reserveCapacity(queries)
for _ in 0..<queries {
let id = Int32.random(in: 1...10_000)
let rows = try await conn.execute(SelectWorldStatement(id: id), logger: context.logger)
guard let row = try await rows.first(where: {_ in true }) else {
let rows = try await conn.execute(
SelectWorldStatement(id: id), logger: context.logger)
guard let row = try await rows.first(where: { _ in true }) else {
throw HTTPError(.notFound)
}
let randomNumber = Int32.random(in: 1...10_000)
_ = try await conn.execute(UpdateWorldStatement(id: id, randomNumber: randomNumber), logger: context.logger)
_ = try await conn.execute(
UpdateWorldStatement(id: id, randomNumber: randomNumber), logger: context.logger
)
result.append(World(id: row.0, randomNumber: randomNumber))
}
return result
Expand All @@ -76,7 +80,7 @@ struct WorldController {

let id: Int32

static var sql = "SELECT id, randomnumber FROM World WHERE id = $1"
static let sql = "SELECT id, randomnumber FROM World WHERE id = $1"

func makeBindings() throws -> PostgresNIO.PostgresBindings {
var bindings = PostgresNIO.PostgresBindings(capacity: 1)
Expand All @@ -93,7 +97,7 @@ struct WorldController {
let id: Int32
let randomNumber: Int32

static var sql = "UPDATE World SET randomnumber = $2 WHERE id = $1"
static let sql = "UPDATE World SET randomnumber = $2 WHERE id = $1"

func makeBindings() throws -> PostgresNIO.PostgresBindings {
var bindings = PostgresNIO.PostgresBindings(capacity: 2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,10 @@ extension Int {
}

struct TechFrameworkRequestContext: RequestContext {
static let jsonEncoder = JSONEncoder()
static let jsonDecoder = JSONDecoder()

var coreContext: Hummingbird.CoreRequestContextStorage

// Use a global JSON Encoder
var responseEncoder: JSONEncoder { Self.jsonEncoder }
// Use a global JSON Decoder
var requestDecoder: JSONDecoder { Self.jsonDecoder }
var coreContext: CoreRequestContextStorage

init(source: ApplicationRequestContextSource) {
self.init(channel: source.channel, logger: source.logger)
}

init(channel: any Channel, logger: Logger) {
self.coreContext = CoreRequestContextStorage(
source: ApplicationRequestContextSource(channel: channel, logger: logger)
)
self.coreContext = CoreRequestContextStorage(source: source)
}
}

Expand All @@ -40,15 +26,15 @@ func runApp() async throws {
let serverPort = env.get("SERVER_PORT", as: Int.self) ?? 8080

var postgresConfiguration = PostgresClient.Configuration(
host: "tfb-database",
username: "benchmarkdbuser",
password: "benchmarkdbpass",
database: "hello_world",
host: "tfb-database",
username: "benchmarkdbuser",
password: "benchmarkdbpass",
database: "hello_world",
tls: .disable
)
postgresConfiguration.options.maximumConnections = 100
let postgresClient = PostgresClient(
configuration: postgresConfiguration,
configuration: postgresConfiguration,
eventLoopGroup: MultiThreadedEventLoopGroup.singleton
)
let router = Router(context: TechFrameworkRequestContext.self)
Expand Down
14 changes: 6 additions & 8 deletions frameworks/Swift/hummingbird2/src/Package.swift
Original file line number Diff line number Diff line change
@@ -1,28 +1,26 @@
// swift-tools-version:5.10
// swift-tools-version:6.1
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "server",
platforms: [.macOS(.v14)],
products: [
.executable(name: "server", targets: ["server"])
],
dependencies: [
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.0.0-beta"),
.package(url: "https://github.com/hummingbird-project/hummingbird.git", from: "2.0.0")
],
targets: [
.target(name: "server",
.executableTarget(
name: "server",
dependencies: [
.product(name: "Hummingbird", package: "hummingbird"),
.product(name: "Hummingbird", package: "hummingbird")
],
swiftSettings: [
// Enable better optimizations when building in Release configuration. Despite the use of
// the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release
// builds. See <https://github.com/swift-server/guides#building-for-production> for details.
.unsafeFlags(["-cross-module-optimization"], .when(configuration: .release))
]
),
)
]
)
Loading
Loading