| @@ -0,0 +1,7 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <Workspace | |||
| version = "1.0"> | |||
| <FileRef | |||
| location = "self:"> | |||
| </FileRef> | |||
| </Workspace> | |||
| @@ -0,0 +1,14 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||
| <plist version="1.0"> | |||
| <dict> | |||
| <key>SchemeUserState</key> | |||
| <dict> | |||
| <key>Fueling.xcscheme_^#shared#^_</key> | |||
| <dict> | |||
| <key>orderHint</key> | |||
| <integer>0</integer> | |||
| </dict> | |||
| </dict> | |||
| </dict> | |||
| </plist> | |||
| @@ -0,0 +1,77 @@ | |||
| # ================================ | |||
| # Build image | |||
| # ================================ | |||
| FROM swift:5.8-jammy as build | |||
| # Install OS updates and, if needed, sqlite3 | |||
| RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ | |||
| && apt-get -q update \ | |||
| && apt-get -q dist-upgrade -y\ | |||
| && rm -rf /var/lib/apt/lists/* | |||
| # Set up a build area | |||
| WORKDIR /build | |||
| # First just resolve dependencies. | |||
| # This creates a cached layer that can be reused | |||
| # as long as your Package.swift/Package.resolved | |||
| # files do not change. | |||
| COPY ./Package.* ./ | |||
| RUN swift package resolve | |||
| # Copy entire repo into container | |||
| COPY . . | |||
| # Build everything, with optimizations | |||
| RUN swift build -c release --static-swift-stdlib | |||
| # Switch to the staging area | |||
| WORKDIR /staging | |||
| # Copy main executable to staging area | |||
| RUN cp "$(swift build --package-path /build -c release --show-bin-path)/App" ./ | |||
| # Copy resources bundled by SPM to staging area | |||
| RUN find -L "$(swift build --package-path /build -c release --show-bin-path)/" -regex '.*\.resources$' -exec cp -Ra {} ./ \; | |||
| # Copy any resources from the public directory and views directory if the directories exist | |||
| # Ensure that by default, neither the directory nor any of its contents are writable. | |||
| RUN [ -d /build/Public ] && { mv /build/Public ./Public && chmod -R a-w ./Public; } || true | |||
| RUN [ -d /build/Resources ] && { mv /build/Resources ./Resources && chmod -R a-w ./Resources; } || true | |||
| # ================================ | |||
| # Run image | |||
| # ================================ | |||
| FROM ubuntu:jammy | |||
| # Make sure all system packages are up to date, and install only essential packages. | |||
| RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ | |||
| && apt-get -q update \ | |||
| && apt-get -q dist-upgrade -y \ | |||
| && apt-get -q install -y \ | |||
| ca-certificates \ | |||
| tzdata \ | |||
| # If your app or its dependencies import FoundationNetworking, also install `libcurl4`. | |||
| # libcurl4 \ | |||
| # If your app or its dependencies import FoundationXML, also install `libxml2`. | |||
| # libxml2 \ | |||
| && rm -r /var/lib/apt/lists/* | |||
| # Create a vapor user and group with /app as its home directory | |||
| RUN useradd --user-group --create-home --system --skel /dev/null --home-dir /app vapor | |||
| # Switch to the new home directory | |||
| WORKDIR /app | |||
| # Copy built executable and any staged resources from builder | |||
| COPY --from=build --chown=vapor:vapor /staging /app | |||
| # Ensure all further commands run as the vapor user | |||
| USER vapor:vapor | |||
| # Let Docker bind to port 8080 | |||
| EXPOSE 8080 | |||
| # Start the Vapor service when the image is run, default to listening on 8080 in production environment | |||
| ENTRYPOINT ["./App"] | |||
| CMD ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"] | |||
| @@ -0,0 +1,239 @@ | |||
| { | |||
| "pins" : [ | |||
| { | |||
| "identity" : "async-http-client", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/swift-server/async-http-client.git", | |||
| "state" : { | |||
| "revision" : "333e60cc90f52973f7ee29cd8e3a7f6adfe79f4e", | |||
| "version" : "1.17.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "async-kit", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/vapor/async-kit.git", | |||
| "state" : { | |||
| "revision" : "a61da00d404ec91d12766f1b9aac7d90777b484d", | |||
| "version" : "1.17.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "console-kit", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/vapor/console-kit.git", | |||
| "state" : { | |||
| "revision" : "447f1046fb4e9df40973fe426ecb24a6f0e8d3b4", | |||
| "version" : "4.6.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "fluent", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/vapor/fluent.git", | |||
| "state" : { | |||
| "revision" : "4b4d8bf15a06fd60137e9c543e5503c4b842654e", | |||
| "version" : "4.8.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "fluent-kit", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/vapor/fluent-kit.git", | |||
| "state" : { | |||
| "revision" : "559dc9c730cde77cc9dac76fba73d6e0855f0220", | |||
| "version" : "1.42.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "fluent-postgres-driver", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/vapor/fluent-postgres-driver.git", | |||
| "state" : { | |||
| "revision" : "afc07463fc5589f5bf95f98ae2719d13ad9fbbcf", | |||
| "version" : "2.6.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "multipart-kit", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/vapor/multipart-kit.git", | |||
| "state" : { | |||
| "revision" : "1adfd69df2da08f7931d4281b257475e32c96734", | |||
| "version" : "4.5.4" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "postgres-kit", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/vapor/postgres-kit.git", | |||
| "state" : { | |||
| "revision" : "3ad08265aade48fff5f2ec772e96ecf51b7900a2", | |||
| "version" : "2.10.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "postgres-nio", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/vapor/postgres-nio.git", | |||
| "state" : { | |||
| "revision" : "98b8e1b1488c706f8bff9eb07560745630a64679", | |||
| "version" : "1.14.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "routing-kit", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/vapor/routing-kit.git", | |||
| "state" : { | |||
| "revision" : "611bc45c5dfb1f54b84d99b89d1f72191fb6b71b", | |||
| "version" : "4.7.2" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "sql-kit", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/vapor/sql-kit.git", | |||
| "state" : { | |||
| "revision" : "d547122756534d8224d4599739da0e82e4695623", | |||
| "version" : "3.25.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-algorithms", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/apple/swift-algorithms.git", | |||
| "state" : { | |||
| "revision" : "b14b7f4c528c942f121c8b860b9410b2bf57825e", | |||
| "version" : "1.0.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-atomics", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/apple/swift-atomics.git", | |||
| "state" : { | |||
| "revision" : "6c89474e62719ddcc1e9614989fff2f68208fe10", | |||
| "version" : "1.1.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-backtrace", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/swift-server/swift-backtrace.git", | |||
| "state" : { | |||
| "revision" : "f25620d5d05e2f1ba27154b40cafea2b67566956", | |||
| "version" : "1.3.3" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-collections", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/apple/swift-collections.git", | |||
| "state" : { | |||
| "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2", | |||
| "version" : "1.0.4" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-crypto", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/apple/swift-crypto.git", | |||
| "state" : { | |||
| "revision" : "33a20e650c33f6d72d822d558333f2085effa3dc", | |||
| "version" : "2.5.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-log", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/apple/swift-log.git", | |||
| "state" : { | |||
| "revision" : "32e8d724467f8fe623624570367e3d50c5638e46", | |||
| "version" : "1.5.2" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-metrics", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/apple/swift-metrics.git", | |||
| "state" : { | |||
| "revision" : "e8bced74bc6d747745935e469f45d03f048d6cbd", | |||
| "version" : "2.3.4" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-nio", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/apple/swift-nio.git", | |||
| "state" : { | |||
| "revision" : "f7c46552983b06b0958a1a4c8bc5199406ae4c8a", | |||
| "version" : "2.51.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-nio-extras", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/apple/swift-nio-extras.git", | |||
| "state" : { | |||
| "revision" : "0e0d0aab665ff1a0659ce75ac003081f2b1c8997", | |||
| "version" : "1.19.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-nio-http2", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/apple/swift-nio-http2.git", | |||
| "state" : { | |||
| "revision" : "6d021a48483dbb273a9be43f65234bdc9185b364", | |||
| "version" : "1.26.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-nio-ssl", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/apple/swift-nio-ssl.git", | |||
| "state" : { | |||
| "revision" : "9d0d5d8798a576fbf674a823734e65e15ca5f2ec", | |||
| "version" : "2.23.1" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-nio-transport-services", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/apple/swift-nio-transport-services.git", | |||
| "state" : { | |||
| "revision" : "59b966415dd336db6f388bbfe3fb43cfa549b981", | |||
| "version" : "1.16.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "swift-numerics", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/apple/swift-numerics", | |||
| "state" : { | |||
| "revision" : "0a5bc04095a675662cf24757cc0640aa2204253b", | |||
| "version" : "1.0.2" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "vapor", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/vapor/vapor.git", | |||
| "state" : { | |||
| "revision" : "f4b00a5350238fe896d865d96d64f12fcbbeda95", | |||
| "version" : "4.76.0" | |||
| } | |||
| }, | |||
| { | |||
| "identity" : "websocket-kit", | |||
| "kind" : "remoteSourceControl", | |||
| "location" : "https://github.com/vapor/websocket-kit.git", | |||
| "state" : { | |||
| "revision" : "2166cbe932b29b6419f9cd751e8b27c647e1238e", | |||
| "version" : "2.8.0" | |||
| } | |||
| } | |||
| ], | |||
| "version" : 2 | |||
| } | |||
| @@ -0,0 +1,35 @@ | |||
| // swift-tools-version:5.8 | |||
| import PackageDescription | |||
| let package = Package( | |||
| name: "Fueling", | |||
| platforms: [ | |||
| .macOS(.v12) | |||
| ], | |||
| dependencies: [ | |||
| // 💧 A server-side Swift web framework. | |||
| .package(url: "https://github.com/vapor/vapor.git", from: "4.76.0"), | |||
| .package(url: "https://github.com/vapor/fluent.git", from: "4.8.0"), | |||
| .package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.0.0"), | |||
| ], | |||
| targets: [ | |||
| .executableTarget( | |||
| name: "App", | |||
| dependencies: [ | |||
| .product(name: "Fluent", package: "fluent"), | |||
| .product(name: "FluentPostgresDriver", package: "fluent-postgres-driver"), | |||
| .product(name: "Vapor", package: "vapor") | |||
| ], | |||
| 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://www.swift.org/server/guides/building.html#building-for-production> for details. | |||
| .unsafeFlags(["-cross-module-optimization"], .when(configuration: .release)) | |||
| ] | |||
| ), | |||
| .testTarget(name: "AppTests", dependencies: [ | |||
| .target(name: "App"), | |||
| .product(name: "XCTVapor", package: "vapor"), | |||
| ]) | |||
| ] | |||
| ) | |||
| @@ -0,0 +1,41 @@ | |||
| // | |||
| // FuelEntryController.swift | |||
| // | |||
| // | |||
| // Created by Bill Ryckman on 4/24/23. | |||
| // | |||
| import Vapor | |||
| struct FuelEntryController: RouteCollection { | |||
| func boot(routes: RoutesBuilder) throws { | |||
| let fuelEntries = routes.grouped("fuel_entries") | |||
| fuelEntries.get(use: index) | |||
| fuelEntries.post(use: create) | |||
| fuelEntries.group(":fuelEntryID") { fuelEntry in | |||
| fuelEntry.delete(use: delete) | |||
| } | |||
| } | |||
| func index(req: Request) async throws -> [FuelEntry] { | |||
| try await FuelEntry.query(on: req.db).all() | |||
| } | |||
| func create(req: Request) async throws -> FuelEntry { | |||
| let fuelEntry = try req.content.decode(FuelEntry.self) | |||
| try await fuelEntry.save(on: req.db) | |||
| return fuelEntry | |||
| } | |||
| func delete(req: Request) async throws -> HTTPStatus { | |||
| guard let fuelEntry = try await FuelEntry.find(req.parameters.get("fuelEntryID"), on: req.db) else { | |||
| throw Abort(.notFound) | |||
| } | |||
| try await fuelEntry.delete(on: req.db) | |||
| return .noContent | |||
| } | |||
| } | |||
| @@ -0,0 +1,31 @@ | |||
| import Fluent | |||
| import Vapor | |||
| struct TodoController: RouteCollection { | |||
| func boot(routes: RoutesBuilder) throws { | |||
| let todos = routes.grouped("todos") | |||
| todos.get(use: index) | |||
| todos.post(use: create) | |||
| todos.group(":todoID") { todo in | |||
| todo.delete(use: delete) | |||
| } | |||
| } | |||
| func index(req: Request) async throws -> [Todo] { | |||
| try await Todo.query(on: req.db).all() | |||
| } | |||
| func create(req: Request) async throws -> Todo { | |||
| let todo = try req.content.decode(Todo.self) | |||
| try await todo.save(on: req.db) | |||
| return todo | |||
| } | |||
| func delete(req: Request) async throws -> HTTPStatus { | |||
| guard let todo = try await Todo.find(req.parameters.get("todoID"), on: req.db) else { | |||
| throw Abort(.notFound) | |||
| } | |||
| try await todo.delete(on: req.db) | |||
| return .noContent | |||
| } | |||
| } | |||
| @@ -0,0 +1,34 @@ | |||
| // | |||
| // File.swift | |||
| // | |||
| // | |||
| // Created by Bill Ryckman on 4/26/23. | |||
| // | |||
| import Vapor | |||
| import Fluent | |||
| struct CreateFuelEntry: AsyncMigration { | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .id() | |||
| .field("timestamp", .datetime) | |||
| .field("user_id", .string) | |||
| .field("gps_location", .string) | |||
| .field("image", .string) | |||
| .field("product", .string) | |||
| .field("make", .string) | |||
| .field("model", .string) | |||
| .field("serial_number", .string) | |||
| .field("tank_id", .string) | |||
| .field("fuel_amount", .double) | |||
| .field("fuel_type", .string) | |||
| .field("is_override", .bool) | |||
| .create() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema("fuel_entries").delete() | |||
| } | |||
| } | |||
| @@ -0,0 +1,14 @@ | |||
| import Fluent | |||
| struct CreateTodo: AsyncMigration { | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema("todos") | |||
| .id() | |||
| .field("title", .string, .required) | |||
| .create() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema("todos").delete() | |||
| } | |||
| } | |||
| @@ -0,0 +1,105 @@ | |||
| // | |||
| // FuelEntry.swift | |||
| // | |||
| // | |||
| // Created by Bill Ryckman on 4/24/23. | |||
| // | |||
| import Fluent | |||
| import Vapor | |||
| final class FuelEntry: Model, Content { | |||
| static let schema = "fuel_entries" | |||
| @ID(key: .id) | |||
| var id: UUID? | |||
| @Field(key: "timestamp") | |||
| var timestamp: Date | |||
| @Field(key: "user_id") | |||
| var userID: String | |||
| @Field(key: "gps_location") | |||
| var gpsLocation: String | |||
| @Field(key: "image") | |||
| var image: String | |||
| @Field(key: "product") | |||
| var product: String | |||
| @Field(key: "make") | |||
| var make: String | |||
| @Field(key: "model") | |||
| var model: String | |||
| @Field(key: "serial_number") | |||
| var serialNumber: String | |||
| @Field(key: "tank_id") | |||
| var tankID: String | |||
| @Field(key: "fuel_amount") | |||
| var fuelAmount: Double | |||
| @Field(key: "fuel_type") | |||
| var fuelType: String | |||
| @Field(key: "is_override") | |||
| var isOverride: Bool | |||
| init() {} | |||
| init(id: UUID? = nil, timestamp: Date, userID: String, gpsLocation: String, image: String, product: String, make: String, model: String, serialNumber: String, tankID: String, fuelAmount: Double, fuelType: String, isOverride: Bool) { | |||
| self.id = id | |||
| self.timestamp = timestamp | |||
| self.userID = userID | |||
| self.gpsLocation = gpsLocation | |||
| self.image = image | |||
| self.product = product | |||
| self.make = make | |||
| self.model = model | |||
| self.serialNumber = serialNumber | |||
| self.tankID = tankID | |||
| self.fuelAmount = fuelAmount | |||
| self.fuelType = fuelType | |||
| self.isOverride = isOverride | |||
| } | |||
| } | |||
| //extension FuelEntry: Content {} | |||
| //extension FuelEntry: Migration { | |||
| // func prepare(on database: FluentKit.Database) -> NIOCore.EventLoopFuture<Void> { | |||
| // <#code#> | |||
| // } | |||
| // | |||
| // func revert(on database: FluentKit.Database) -> NIOCore.EventLoopFuture<Void> { | |||
| // <#code#> | |||
| // } | |||
| // func prepare(on database: Database) -> EventLoopFuture<Void> { | |||
| // return database.schema("fuel_entries") | |||
| // .id() | |||
| // .field("timestamp", .datetime) | |||
| // .field("user_id", .string) | |||
| // .field("gps_location", .string) | |||
| // .field("image", .string) | |||
| // .field("product", .string) | |||
| // .field("make", .string) | |||
| // .field("model", .string) | |||
| // .field("serial_number", .string) | |||
| // .field("tank_id", .string) | |||
| // .field("fuel_amount", .double) | |||
| // .field("fuel_type", .string) | |||
| // .field("is_override", .bool) | |||
| // .create() | |||
| // } | |||
| // | |||
| // func revert(on database: Database) -> EventLoopFuture<Void> { | |||
| // return database.schema("fuel_entries").delete() | |||
| // } | |||
| //} | |||
| //extension FuelEntry: Parameter {} | |||
| @@ -0,0 +1,19 @@ | |||
| import Fluent | |||
| import Vapor | |||
| final class Todo: Model, Content { | |||
| static let schema = "todos" | |||
| @ID(key: .id) | |||
| var id: UUID? | |||
| @Field(key: "title") | |||
| var title: String | |||
| init() { } | |||
| init(id: UUID? = nil, title: String) { | |||
| self.id = id | |||
| self.title = title | |||
| } | |||
| } | |||
| @@ -0,0 +1,29 @@ | |||
| import Fluent | |||
| import FluentPostgresDriver | |||
| import Vapor | |||
| // configures your application | |||
| public func configure(_ app: Application) async throws { | |||
| // uncomment to serve files from /Public folder | |||
| // app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory)) | |||
| app.databases.use(.postgres(hostname: "localhost", username: "mcarman", password: "@ng31F@rm0823262", database: "fueling"), as: .psql) | |||
| // app.databases.use(.postgres( | |||
| // hostname: Environment.get("localhost") ?? "localhost", | |||
| // port: Environment.get("5432").flatMap(Int.init(_:)) ?? PostgresConfiguration.ianaPortNumber, | |||
| // username: Environment.get("mcarman") ?? "vapor_username", | |||
| // //username: Environment.get("bryckman") ?? "vapor_username", | |||
| // password: Environment.get("@ng31F@rm0823262" ?? "vapor_password"), | |||
| // //password: Environment.get("55H1ck0ry1669") ?? "vapor_password", | |||
| // database: Environment.get("fueling") ?? "vapor_database" | |||
| // ), as: .psql) | |||
| app.http.server.configuration.port = 3001 | |||
| // app.migrations.add(CreateTodo()) | |||
| app.migrations.add(CreateFuelEntry()) | |||
| try await app.autoMigrate().get() | |||
| // register routes | |||
| try routes(app) | |||
| } | |||
| @@ -0,0 +1,35 @@ | |||
| import Vapor | |||
| import Dispatch | |||
| import Logging | |||
| /// This extension is temporary and can be removed once Vapor gets this support. | |||
| private extension Vapor.Application { | |||
| static let baseExecutionQueue = DispatchQueue(label: "vapor.codes.entrypoint") | |||
| func runFromAsyncMainEntrypoint() async throws { | |||
| try await withCheckedThrowingContinuation { continuation in | |||
| Vapor.Application.baseExecutionQueue.async { [self] in | |||
| do { | |||
| try self.run() | |||
| continuation.resume() | |||
| } catch { | |||
| continuation.resume(throwing: error) | |||
| } | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @main | |||
| enum Entrypoint { | |||
| static func main() async throws { | |||
| var env = try Environment.detect() | |||
| try LoggingSystem.bootstrap(from: &env) | |||
| let app = Application(env) | |||
| defer { app.shutdown() } | |||
| try await configure(app) | |||
| try await app.runFromAsyncMainEntrypoint() | |||
| } | |||
| } | |||
| @@ -0,0 +1,34 @@ | |||
| //import Fluent | |||
| //import Vapor | |||
| // | |||
| //func routes(_ app: Application) throws { | |||
| // app.get { req async in | |||
| // "It works!" | |||
| // } | |||
| // | |||
| // app.get("hello") { req async -> String in | |||
| // "Hello, world!" | |||
| // } | |||
| // | |||
| // try app.register(collection: TodoController()) | |||
| //} | |||
| import Vapor | |||
| func routes(_ app: Application) throws { | |||
| let fuelEntryController = FuelEntryController() | |||
| app.get("fuel-entries") { req in | |||
| try await fuelEntryController.index(req: req) | |||
| } | |||
| app.post("fuel-entries") { req in | |||
| try await fuelEntryController.create(req: req) | |||
| } | |||
| app.delete("fuel-entries", ":fuelEntryID") { req in | |||
| try await fuelEntryController.delete(req: req) | |||
| } | |||
| } | |||
| @@ -0,0 +1,15 @@ | |||
| @testable import App | |||
| import XCTVapor | |||
| final class AppTests: XCTestCase { | |||
| func testHelloWorld() async throws { | |||
| let app = Application(.testing) | |||
| defer { app.shutdown() } | |||
| try await configure(app) | |||
| try app.test(.GET, "hello", afterResponse: { res in | |||
| XCTAssertEqual(res.status, .ok) | |||
| XCTAssertEqual(res.body.string, "Hello, world!") | |||
| }) | |||
| } | |||
| } | |||
| @@ -0,0 +1,74 @@ | |||
| # Docker Compose file for Vapor | |||
| # | |||
| # Install Docker on your system to run and test | |||
| # your Vapor app in a production-like environment. | |||
| # | |||
| # Note: This file is intended for testing and does not | |||
| # implement best practices for a production deployment. | |||
| # | |||
| # Learn more: https://docs.docker.com/compose/reference/ | |||
| # | |||
| # Build images: docker-compose build | |||
| # Start app: docker-compose up app | |||
| # Start database: docker-compose up db | |||
| # Run migrations: docker-compose run migrate | |||
| # Stop all: docker-compose down (add -v to wipe db) | |||
| # | |||
| version: '3.7' | |||
| volumes: | |||
| db_data: | |||
| x-shared_environment: &shared_environment | |||
| LOG_LEVEL: ${LOG_LEVEL:-debug} | |||
| DATABASE_HOST: db | |||
| DATABASE_NAME: vapor_database | |||
| DATABASE_USERNAME: vapor_username | |||
| DATABASE_PASSWORD: vapor_password | |||
| services: | |||
| app: | |||
| image: fueling:latest | |||
| build: | |||
| context: . | |||
| environment: | |||
| <<: *shared_environment | |||
| depends_on: | |||
| - db | |||
| ports: | |||
| - '8080:8080' | |||
| # user: '0' # uncomment to run as root for testing purposes even though Dockerfile defines 'vapor' user. | |||
| command: ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"] | |||
| migrate: | |||
| image: fueling:latest | |||
| build: | |||
| context: . | |||
| environment: | |||
| <<: *shared_environment | |||
| depends_on: | |||
| - db | |||
| command: ["migrate", "--yes"] | |||
| deploy: | |||
| replicas: 0 | |||
| revert: | |||
| image: fueling:latest | |||
| build: | |||
| context: . | |||
| environment: | |||
| <<: *shared_environment | |||
| depends_on: | |||
| - db | |||
| command: ["migrate", "--revert", "--yes"] | |||
| deploy: | |||
| replicas: 0 | |||
| db: | |||
| image: postgres:15-alpine | |||
| volumes: | |||
| - db_data:/var/lib/postgresql/data/pgdata | |||
| environment: | |||
| PGDATA: /var/lib/postgresql/data/pgdata | |||
| POSTGRES_USER: vapor_username | |||
| POSTGRES_PASSWORD: vapor_password | |||
| POSTGRES_DB: vapor_database | |||
| ports: | |||
| - '5432:5432' | |||