From 3fcd6e8d854e936410501a40d4e1892c85008b25 Mon Sep 17 00:00:00 2001 From: Tanner Date: Mon, 9 Dec 2019 17:26:15 -0500 Subject: [PATCH] beta.2 (#5) * beta.2 * updates * remove extra spaces --- .github/FUNDING.yml | 2 + .github/workflows/test.yml | 18 +++ Package.swift | 17 +-- Sources/APNS/APNS.swift | 149 +++++++++++++++++++++++ Sources/APNS/Exported.swift | 1 + Sources/APNSKit/Exported.swift | 9 -- Sources/APNSKit/apns_kit.swift | 18 --- Tests/APNSKitTests/XCTestManifests.swift | 7 -- Tests/APNSTests/APNSTests.swift | 28 +++++ Tests/LinuxMain.swift | 6 - circle.yml | 24 ---- 11 files changed, 208 insertions(+), 71 deletions(-) create mode 100644 .github/FUNDING.yml create mode 100644 .github/workflows/test.yml create mode 100644 Sources/APNS/APNS.swift create mode 100644 Sources/APNS/Exported.swift delete mode 100644 Sources/APNSKit/Exported.swift delete mode 100644 Sources/APNSKit/apns_kit.swift delete mode 100644 Tests/APNSKitTests/XCTestManifests.swift create mode 100644 Tests/APNSTests/APNSTests.swift delete mode 100644 Tests/LinuxMain.swift delete mode 100644 circle.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..0a22eec --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +github: [tanner0101] # loganwright, joscdk +open_collective: vapor diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..4207acc --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,18 @@ +name: test +on: +- pull_request +jobs: + xenial: + container: + image: vapor/swift:5.1-xenial + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: swift test --enable-test-discovery --sanitize=thread + bionic: + container: + image: vapor/swift:5.1-bionic + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - run: swift test --enable-test-discovery --sanitize=thread diff --git a/Package.swift b/Package.swift index 4146e05..7b46be5 100644 --- a/Package.swift +++ b/Package.swift @@ -1,17 +1,20 @@ -// swift-tools-version:5.0 +// swift-tools-version:5.1 import PackageDescription let package = Package( - name: "apns-kit", + name: "apns", + platforms: [ + .macOS(.v10_14) + ], products: [ - .library(name: "APNSKit", targets: ["APNSKit"]), + .library(name: "APNS", targets: ["APNS"]), ], dependencies: [ - .package(url: "https://github.com/kylebrowning/APNSwift.git", from: "1.3.0"), - .package(url: "https://github.com/vapor/async-kit.git", from: "1.0.0-alpha.1"), + .package(url: "https://github.com/kylebrowning/APNSwift.git", .branch("master")), + .package(url: "https://github.com/vapor/vapor.git", .branch("master")), ], targets: [ - .target(name: "APNSKit", dependencies: ["AsyncKit", "APNSwift"]), - .testTarget(name: "APNSKitTests", dependencies: ["APNSKit"]), + .target(name: "APNS", dependencies: ["APNSwift", "Vapor"]), + .testTarget(name: "APNSTests", dependencies: ["APNS", "XCTVapor"]), ] ) diff --git a/Sources/APNS/APNS.swift b/Sources/APNS/APNS.swift new file mode 100644 index 0000000..4cf0dd3 --- /dev/null +++ b/Sources/APNS/APNS.swift @@ -0,0 +1,149 @@ +import Vapor + +extension Application { + public var apns: APNS { + .init(application: self) + } + + public struct APNS { + final class Storage { + var pool: EventLoopGroupConnectionPool? + init() { } + } + + struct Key: StorageKey { + typealias Value = Storage + } + + struct Lifecycle: LifecycleHandler { + func shutdown(_ application: Application) { + if let pool = application.apns.storage.pool { + pool.shutdown() + } + } + } + + var storage: Storage { + if self.application.storage[Key.self] == nil { + self.initialize() + } + return self.application.storage[Key.self]! + } + + let application: Application + + public func configure(_ configuration: APNSwiftConfiguration) { + assert(self.storage.pool == nil, "APNS can only be configured once") + self.storage.pool = .init( + source: .init(configuration: configuration), + maxConnectionsPerEventLoop: 1, + logger: self.application.logger, + on: self.application.eventLoopGroup + ) + } + + func initialize() { + self.application.storage[Key.self] = .init() + self.application.lifecycle.use(Lifecycle()) + } + } +} + +private struct BasicNotification: APNSwiftNotification { + let aps: APNSwiftPayload + init(aps: APNSwiftPayload) { + self.aps = aps + } +} + +extension Request { + public var apns: APNS { + .init(request: self) + } + + public struct APNS { + let request: Request + + public func send( + _ alert: APNSwiftPayload.APNSwiftAlert, + pushType: APNSwiftConnection.PushType = .alert, + to deviceToken: String, + with encoder: JSONEncoder = JSONEncoder(), + expiration: Date? = nil, + priority: Int? = nil, + collapseIdentifier: String? = nil, + topic: String? = nil + ) -> EventLoopFuture { + self.send(APNSwiftPayload(alert: alert), pushType: pushType, to: deviceToken, with: encoder, expiration: expiration, priority: priority, collapseIdentifier: collapseIdentifier, topic: topic) + } + + public func send( + _ payload: APNSwiftPayload, + pushType: APNSwiftConnection.PushType = .alert, + to deviceToken: String, + with encoder: JSONEncoder = JSONEncoder(), + expiration: Date? = nil, + priority: Int? = nil, + collapseIdentifier: String? = nil, + topic: String? = nil + ) -> EventLoopFuture { + self.send(BasicNotification(aps: payload), pushType: pushType, to: deviceToken, with: encoder, expiration: expiration, priority: priority, collapseIdentifier: collapseIdentifier, topic: topic) + } + + public func send( + _ notification: Notification, + pushType: APNSwiftConnection.PushType = .alert, + to deviceToken: String, + with encoder: JSONEncoder = JSONEncoder(), + expiration: Date? = nil, + priority: Int? = nil, + collapseIdentifier: String? = nil, + topic: String? = nil + ) -> EventLoopFuture + where Notification: APNSwiftNotification + { + guard let pool = self.request.application.apns.storage.pool else { + fatalError("APNS not configured. Configure with app.apns.configure(...)") + } + return pool.withConnection( + logger: self.request.logger, + on: self.request.eventLoop + ) { + $0.send( + notification, + pushType: pushType, + to: deviceToken, + with: encoder, + expiration: expiration, + priority: priority, + collapseIdentifier: collapseIdentifier, + topic: topic + ) + } + } + } +} + +public final class APNSConnectionSource: ConnectionPoolSource { + private let configuration: APNSwiftConfiguration + + public init(configuration: APNSwiftConfiguration) { + self.configuration = configuration + } + public func makeConnection( + logger: Logger, + on eventLoop: EventLoop + ) -> EventLoopFuture { + APNSwiftConnection.connect(configuration: self.configuration, on: eventLoop) + } +} + +extension APNSwiftConnection: ConnectionPoolItem { + public var eventLoop: EventLoop { + self.channel.eventLoop + } + + public var isClosed: Bool { + self.channel.isActive + } +} diff --git a/Sources/APNS/Exported.swift b/Sources/APNS/Exported.swift new file mode 100644 index 0000000..6c9a12d --- /dev/null +++ b/Sources/APNS/Exported.swift @@ -0,0 +1 @@ +@_exported import APNSwift diff --git a/Sources/APNSKit/Exported.swift b/Sources/APNSKit/Exported.swift deleted file mode 100644 index 0d96eb3..0000000 --- a/Sources/APNSKit/Exported.swift +++ /dev/null @@ -1,9 +0,0 @@ -// -// Exported.swift -// APNSKit -// -// Created by Kyle Browning on 3/23/19. -// - -@_exported import AsyncKit -@_exported import APNSwift diff --git a/Sources/APNSKit/apns_kit.swift b/Sources/APNSKit/apns_kit.swift deleted file mode 100644 index 6e3ca07..0000000 --- a/Sources/APNSKit/apns_kit.swift +++ /dev/null @@ -1,18 +0,0 @@ -public final class APNSConnectionSource: ConnectionPoolSource { - public let eventLoop: EventLoop - private let configuration: APNSwiftConfiguration - - public init(configuration: APNSwiftConfiguration, on eventLoop: EventLoop) { - self.eventLoop = eventLoop - self.configuration = configuration - } - public func makeConnection() -> EventLoopFuture { - return APNSwiftConnection.connect(configuration: self.configuration, on: self.eventLoop) - } -} -extension APNSwiftConnection: ConnectionPoolItem { - public var isClosed: Bool { - // TODO: implement this. - return false - } -} diff --git a/Tests/APNSKitTests/XCTestManifests.swift b/Tests/APNSKitTests/XCTestManifests.swift deleted file mode 100644 index 8dbb720..0000000 --- a/Tests/APNSKitTests/XCTestManifests.swift +++ /dev/null @@ -1,7 +0,0 @@ -import XCTest - -#if !canImport(ObjectiveC) -public func allTests() -> [XCTestCaseEntry] { - return [] -} -#endif diff --git a/Tests/APNSTests/APNSTests.swift b/Tests/APNSTests/APNSTests.swift new file mode 100644 index 0000000..31796ac --- /dev/null +++ b/Tests/APNSTests/APNSTests.swift @@ -0,0 +1,28 @@ +import APNS +import XCTVapor + +class APNSTests: XCTestCase { + func testApplication() throws { + let app = Application(.testing) + defer { app.shutdown() } + + try app.apns.configure(.init( + keyIdentifier: "9UC9ZLQ8YW", + teamIdentifier: "ABBM6U9RM5", + signer: .init(buffer: ByteBufferAllocator().buffer(capacity: 1024)), + topic: "com.grasscove.Fern", + environment: .sandbox + )) + + app.get("test-push") { req -> EventLoopFuture in + req.apns.send( + .init(title: "Hello", subtitle: "This is a test from vapor/apns"), + to: "98AAD4A2398DDC58595F02FA307DF9A15C18B6111D1B806949549085A8E6A55D" + ).map { .ok } + } + + try app.test(.GET, "test-push") { res in + XCTAssertEqual(res.status, .internalServerError) + } + } +} diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift deleted file mode 100644 index 3c6f89c..0000000 --- a/Tests/LinuxMain.swift +++ /dev/null @@ -1,6 +0,0 @@ -import XCTest - - -var tests = [XCTestCaseEntry]() - -XCTMain(tests) diff --git a/circle.yml b/circle.yml deleted file mode 100644 index c91cf11..0000000 --- a/circle.yml +++ /dev/null @@ -1,24 +0,0 @@ -version: 2 - -jobs: - linux: - docker: - - image: swift:5.0 - steps: - - run: apt-get update; apt-get -y install libnghttp2-dev openssl libssl-dev - - checkout - - run: swift build - - run: swift test - linux-release: - docker: - - image: swift:5.0 - steps: - - run: apt-get update; apt-get -y install libnghttp2-dev openssl libssl-dev - - checkout - - run: swift build -c release -workflows: - version: 2 - tests: - jobs: - - linux - - linux-release