Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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