diff --git a/Dockerfile.dev b/Dockerfile.dev index 7962e9c..856b0c5 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -4,15 +4,14 @@ ARG SWIFT_MODE="debug" # ================================ # Build image # ================================ -FROM swift:6.0-noble AS build +FROM swift:6.0.3-noble AS build ARG SWIFT_MODE # Install OS updates RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ && apt-get -q update \ - && apt-get -q dist-upgrade -y \ - && apt-get install -y libjemalloc-dev + && apt-get -q dist-upgrade -y # Set up a build area WORKDIR /build @@ -34,8 +33,7 @@ RUN --mount=type=cache,target=/build/.build swift build \ -c ${SWIFT_MODE} \ --product App \ --static-swift-stdlib \ - -Xswiftc -g \ - -Xlinker -ljemalloc + -Xswiftc -g # Switch to the staging area WORKDIR /staging diff --git a/Sources/ApiController/ApiController.swift b/Sources/ApiController/ApiController.swift index 86bd201..b0abe48 100644 --- a/Sources/ApiController/ApiController.swift +++ b/Sources/ApiController/ApiController.swift @@ -4,58 +4,58 @@ import Logging import PsychrometricClient import Routes -public extension DependencyValues { - var apiController: ApiController { - get { self[ApiController.self] } - set { self[ApiController.self] = newValue } - } -} - -@DependencyClient -public struct ApiController: Sendable { - public var json: @Sendable (SiteRoute.Api, Logger) async throws -> (any Encodable)? -} - -extension ApiController: TestDependencyKey { - public static let testValue: ApiController = Self() -} - -extension ApiController: DependencyKey { - public static var liveValue: ApiController { - @Dependency(\.psychrometricClient) var psychrometricClient - - return .init(json: { route, logger in - logger.debug("API Route: \(route)") - - switch route { - case let .calculateAtticVentilation(request): - logger.debug("Calculating attic ventilation: \(request)") - return try await request.respond(logger: logger) - - case let .calculateCapacitor(request): - logger.debug("Calculating capacitor: \(request)") - return try await request.respond(logger: logger) - - case let .calculateDehumidifierSize(request): - logger.debug("Calculating dehumidifier size: \(request)") - return try await request.respond(logger) - - case let .calculateFilterPressureDrop(request): - logger.debug("Calculating filter pressure drop: \(request)") - return try await request.respond(logger: logger) - - case let .calculateHVACSystemPerformance(request): - logger.debug("Calculating hvac system performance: \(request)") - return try await request.respond(logger: logger) - - case let .calculateMoldRisk(request): - logger.debug("Calculating mold risk: \(request)") - return try await psychrometricClient.respond(request, logger) - - case let .calculateRoomPressure(request): - logger.debug("Calculating room pressure: \(request)") - return try await request.respond(logger: logger) - } - }) - } -} +// public extension DependencyValues { +// var apiController: ApiController { +// get { self[ApiController.self] } +// set { self[ApiController.self] = newValue } +// } +// } +// +// @DependencyClient +// public struct ApiController: Sendable { +// public var json: @Sendable (SiteRoute.Api, Logger) async throws -> (any Encodable)? +// } +// +// extension ApiController: TestDependencyKey { +// public static let testValue: ApiController = Self() +// } +// +// extension ApiController: DependencyKey { +// public static var liveValue: ApiController { +// @Dependency(\.psychrometricClient) var psychrometricClient +// +// return .init(json: { route, logger in +// logger.debug("API Route: \(route)") +// +// switch route { +// case let .calculateAtticVentilation(request): +// logger.debug("Calculating attic ventilation: \(request)") +// return try await request.respond(logger: logger) +// +// case let .calculateCapacitor(request): +// logger.debug("Calculating capacitor: \(request)") +// return try await request.respond(logger: logger) +// +// case let .calculateDehumidifierSize(request): +// logger.debug("Calculating dehumidifier size: \(request)") +// return try await request.respond(logger) +// +// case let .calculateFilterPressureDrop(request): +// logger.debug("Calculating filter pressure drop: \(request)") +// return try await request.respond(logger: logger) +// +// case let .calculateHVACSystemPerformance(request): +// logger.debug("Calculating hvac system performance: \(request)") +// return try await request.respond(logger: logger) +// +// case let .calculateMoldRisk(request): +// logger.debug("Calculating mold risk: \(request)") +// return try await psychrometricClient.respond(request, logger) +// +// case let .calculateRoomPressure(request): +// logger.debug("Calculating room pressure: \(request)") +// return try await request.respond(logger: logger) +// } +// }) +// } +// } diff --git a/Sources/ApiController/Extensions/HeatingBalancePoint.swift b/Sources/ApiController/Extensions/HeatingBalancePoint.swift index c7f1118..10cd201 100644 --- a/Sources/ApiController/Extensions/HeatingBalancePoint.swift +++ b/Sources/ApiController/Extensions/HeatingBalancePoint.swift @@ -108,6 +108,7 @@ private extension HeatingBalancePoint.Request.Thermal { switch buildingHeatLoss { case let .known(btu: btu): return btu case let .estimated(squareFeet: squareFeet): + // TODO: Should this be 65 - designTemperature return squareFeet * climateZone!.averageHeatLossPerSquareFoot * (70 - designTemperature) } } diff --git a/Sources/App/Extensions/ApiController+respond.swift b/Sources/App/Extensions/ApiController+respond.swift index 0784ede..ccd1931 100644 --- a/Sources/App/Extensions/ApiController+respond.swift +++ b/Sources/App/Extensions/ApiController+respond.swift @@ -1,35 +1,35 @@ -import ApiController -import Routes -import Vapor - -extension ApiController { - - func respond(_ route: SiteRoute.Api, request: Vapor.Request) async throws -> any AsyncResponseEncodable { - guard let encodable = try await json(route, request.logger) else { - return HTTPStatus.ok - } - return AnyJSONResponse(value: encodable) - } -} - -struct AnyJSONResponse: AsyncResponseEncodable { - public var headers: HTTPHeaders = ["Content-Type": "application/json"] - let value: any Encodable - - init(additionalHeaders: HTTPHeaders = [:], value: any Encodable) { - if additionalHeaders.contains(name: .contentType) { - self.headers = additionalHeaders - } else { - headers.add(contentsOf: additionalHeaders) - } - self.value = value - } - - func encodeResponse(for request: Request) async throws -> Response { - try Response( - status: .ok, - headers: headers, - body: .init(data: JSONEncoder().encode(value)) - ) - } -} +// import ApiController +// import Routes +// import Vapor +// +// extension ApiController { +// +// func respond(_ route: SiteRoute.Api, request: Vapor.Request) async throws -> any AsyncResponseEncodable { +// guard let encodable = try await json(route, request.logger) else { +// return HTTPStatus.ok +// } +// return AnyJSONResponse(value: encodable) +// } +// } +// +// struct AnyJSONResponse: AsyncResponseEncodable { +// public var headers: HTTPHeaders = ["Content-Type": "application/json"] +// let value: any Encodable +// +// init(additionalHeaders: HTTPHeaders = [:], value: any Encodable) { +// if additionalHeaders.contains(name: .contentType) { +// self.headers = additionalHeaders +// } else { +// headers.add(contentsOf: additionalHeaders) +// } +// self.value = value +// } +// +// func encodeResponse(for request: Request) async throws -> Response { +// try Response( +// status: .ok, +// headers: headers, +// body: .init(data: JSONEncoder().encode(value)) +// ) +// } +// } diff --git a/Sources/App/Middleware/DependenciesMiddleware.swift b/Sources/App/Middleware/DependenciesMiddleware.swift index 1996fb9..b33c4ab 100644 --- a/Sources/App/Middleware/DependenciesMiddleware.swift +++ b/Sources/App/Middleware/DependenciesMiddleware.swift @@ -1,4 +1,4 @@ -import ApiController +// import ApiController import Dependencies import PsychrometricClientLive import Vapor @@ -9,19 +9,19 @@ import ViewController struct DependenciesMiddleware: AsyncMiddleware { private let values: DependencyValues.Continuation - private let apiController: ApiController + // private let apiController: ApiController private let psychrometricClient: PsychrometricClient // private let database: DatabaseClient private let viewController: ViewController init( // database: DatabaseClient, - apiController: ApiController = .liveValue, + // apiController: ApiController = .liveValue, psychrometricClient: PsychrometricClient = .liveValue, viewController: ViewController = .liveValue ) { self.values = withEscapedDependencies { $0 } - self.apiController = apiController + // self.apiController = apiController // self.database = database self.psychrometricClient = psychrometricClient self.viewController = viewController @@ -30,7 +30,7 @@ struct DependenciesMiddleware: AsyncMiddleware { func respond(to request: Request, chainingTo next: any AsyncResponder) async throws -> Response { try await values.yield { try await withDependencies { - $0.apiController = apiController + // $0.apiController = apiController // $0.database = database // $0.dateFormatter = .liveValue $0.psychrometricClient = psychrometricClient diff --git a/Sources/App/configure.swift b/Sources/App/configure.swift index 7cc3a4c..2107342 100644 --- a/Sources/App/configure.swift +++ b/Sources/App/configure.swift @@ -55,12 +55,12 @@ private func siteHandler( request: Request, route: SiteRoute ) async throws -> any AsyncResponseEncodable { - @Dependency(\.apiController) var apiController + // @Dependency(\.apiController) var apiController @Dependency(\.viewController) var viewController switch route { - case let .api(route): - return try await apiController.respond(route, request: request) + // case let .api(route): + // return try await apiController.respond(route, request: request) case .health: return HTTPStatus.ok case let .view(route): diff --git a/Sources/Routes/HTMXExtensions.swift b/Sources/Routes/HTMXExtensions.swift index 9f5fc33..7c465a5 100644 --- a/Sources/Routes/HTMXExtensions.swift +++ b/Sources/Routes/HTMXExtensions.swift @@ -22,8 +22,8 @@ public extension HTMLAttribute.hx { put(SiteRoute.View.router.path(for: route)) } - @Sendable - static func delete(route: SiteRoute.Api) -> HTMLAttribute { - delete(SiteRoute.Api.router.path(for: route)) - } + // @Sendable + // static func delete(route: SiteRoute.Api) -> HTMLAttribute { + // delete(SiteRoute.Api.router.path(for: route)) + // } } diff --git a/Sources/Routes/SiteRoutes.swift b/Sources/Routes/SiteRoutes.swift index c3d75f7..21f3031 100644 --- a/Sources/Routes/SiteRoutes.swift +++ b/Sources/Routes/SiteRoutes.swift @@ -7,14 +7,14 @@ import PsychrometricClient // swiftlint:disable type_body_length public enum SiteRoute: Equatable, Sendable { - case api(Api) + // case api(Api) case health case view(View) public static let router = OneOf { - Route(.case(Self.api)) { - Api.router - } + // Route(.case(Self.api)) { + // Api.router + // } Route(.case(Self.health)) { Path { "health" } Method.get @@ -25,74 +25,74 @@ public enum SiteRoute: Equatable, Sendable { } } -public extension SiteRoute { - - enum Api: Equatable, Sendable { - - case calculateAtticVentilation(AtticVentilation.Request) - case calculateCapacitor(Capacitor.Request) - case calculateDehumidifierSize(DehumidifierSize.Request) - case calculateFilterPressureDrop(FilterPressureDrop.Request) - case calculateHVACSystemPerformance(HVACSystemPerformance.Request) - case calculateMoldRisk(MoldRisk.Request) - case calculateRoomPressure(RoomPressure.Request) - - static let rootPath = Path { "api"; "v1" } - - public static let router = OneOf { - Route(.case(Self.calculateAtticVentilation)) { - Path { "api"; "v1"; "calculateAtticPressure" } - Method.post - Body(.json(AtticVentilation.Request.self)) - } - Route(.case(Self.calculateCapacitor)) { - Path { "api"; "v1"; "calculateRoomPressure" } - Method.post - OneOf { - Body(.json(Capacitor.Request.SizeRequest.self)) - .map(.case(Capacitor.Request.size)) - Body(.json(Capacitor.Request.TestRequest.self)) - .map(.case(Capacitor.Request.test)) - } - } - Route(.case(Self.calculateDehumidifierSize)) { - Path { "api"; "v1"; "calculateDehumidifierSize" } - Method.post - Body(.json(DehumidifierSize.Request.self)) - } - Route(.case(Self.calculateFilterPressureDrop)) { - Path { "api"; "v1"; "calculateFilterPressureDrop" } - Method.post - OneOf { - Body(.json(FilterPressureDrop.Request.Basic.self)) - .map(.case(FilterPressureDrop.Request.basic)) - Body(.json(FilterPressureDrop.Request.FanLaw.self)) - .map(.case(FilterPressureDrop.Request.fanLaw)) - } - } - Route(.case(Self.calculateHVACSystemPerformance)) { - Path { "api"; "v1"; "calculateHVACSystemPerformance" } - Method.post - Body(.json(HVACSystemPerformance.Request.self)) - } - Route(.case(Self.calculateMoldRisk)) { - Path { "api"; "v1"; "calculateMoldRisk" } - Method.post - Body(.json(MoldRisk.Request.self)) - } - Route(.case(Self.calculateRoomPressure)) { - Path { "api"; "v1"; "calculateRoomPressure" } - Method.post - OneOf { - Body(.json(RoomPressure.Request.KnownAirflow.self)) - .map(.case(RoomPressure.Request.knownAirflow)) - Body(.json(RoomPressure.Request.MeasuredPressure.self)) - .map(.case(RoomPressure.Request.measuredPressure)) - } - } - } - } -} +// public extension SiteRoute { +// +// enum Api: Equatable, Sendable { +// +// case calculateAtticVentilation(AtticVentilation.Request) +// case calculateCapacitor(Capacitor.Request) +// case calculateDehumidifierSize(DehumidifierSize.Request) +// case calculateFilterPressureDrop(FilterPressureDrop.Request) +// case calculateHVACSystemPerformance(HVACSystemPerformance.Request) +// case calculateMoldRisk(MoldRisk.Request) +// case calculateRoomPressure(RoomPressure.Request) +// +// static let rootPath = Path { "api"; "v1" } +// +// public static let router = OneOf { +// Route(.case(Self.calculateAtticVentilation)) { +// Path { "api"; "v1"; "calculateAtticPressure" } +// Method.post +// Body(.json(AtticVentilation.Request.self)) +// } +// Route(.case(Self.calculateCapacitor)) { +// Path { "api"; "v1"; "calculateRoomPressure" } +// Method.post +// OneOf { +// Body(.json(Capacitor.Request.SizeRequest.self)) +// .map(.case(Capacitor.Request.size)) +// Body(.json(Capacitor.Request.TestRequest.self)) +// .map(.case(Capacitor.Request.test)) +// } +// } +// Route(.case(Self.calculateDehumidifierSize)) { +// Path { "api"; "v1"; "calculateDehumidifierSize" } +// Method.post +// Body(.json(DehumidifierSize.Request.self)) +// } +// Route(.case(Self.calculateFilterPressureDrop)) { +// Path { "api"; "v1"; "calculateFilterPressureDrop" } +// Method.post +// OneOf { +// Body(.json(FilterPressureDrop.Request.Basic.self)) +// .map(.case(FilterPressureDrop.Request.basic)) +// Body(.json(FilterPressureDrop.Request.FanLaw.self)) +// .map(.case(FilterPressureDrop.Request.fanLaw)) +// } +// } +// Route(.case(Self.calculateHVACSystemPerformance)) { +// Path { "api"; "v1"; "calculateHVACSystemPerformance" } +// Method.post +// Body(.json(HVACSystemPerformance.Request.self)) +// } +// Route(.case(Self.calculateMoldRisk)) { +// Path { "api"; "v1"; "calculateMoldRisk" } +// Method.post +// Body(.json(MoldRisk.Request.self)) +// } +// Route(.case(Self.calculateRoomPressure)) { +// Path { "api"; "v1"; "calculateRoomPressure" } +// Method.post +// OneOf { +// Body(.json(RoomPressure.Request.KnownAirflow.self)) +// .map(.case(RoomPressure.Request.knownAirflow)) +// Body(.json(RoomPressure.Request.MeasuredPressure.self)) +// .map(.case(RoomPressure.Request.measuredPressure)) +// } +// } +// } +// } +// } public extension SiteRoute { enum View: Equatable, Sendable {