Skip to content

Commit

Permalink
HMAC Push notification updates (#283)
Browse files Browse the repository at this point in the history
* generate new iOS proto code for pushes

* add new subscribe with metadata method to the push server

* create a type alias

* add the implementation side

* Update if/def to include typealias declarations

Also update connect-swift package version.

---------

Co-authored-by: Ethan Mateja <[email protected]>
  • Loading branch information
nplasterer and zombieobject authored Mar 14, 2024
1 parent 023d983 commit 89b62b4
Show file tree
Hide file tree
Showing 6 changed files with 717 additions and 435 deletions.
42 changes: 30 additions & 12 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/bufbuild/connect-swift",
"state" : {
"revision" : "6f5afc57f44a3ed15b9a01381ce73f84d15e43db",
"version" : "0.3.0"
"revision" : "1701d3d1b2c4c63fcccfd7094f86a88672fa5acb",
"version" : "0.12.0"
}
},
{
Expand All @@ -41,8 +41,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/xmtp/libxmtp-swift",
"state" : {
"revision" : "28ee27a4ded8b996a74850e366247e9fe51d782a",
"version" : "0.4.2-beta4"
"revision" : "f8c4be0d591671067c8e7772b7c402931f33ed54",
"version" : "0.4.3-beta1"
}
},
{
Expand All @@ -59,8 +59,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-atomics.git",
"state" : {
"revision" : "919eb1d83e02121cdb434c7bfc1f0c66ef17febe",
"version" : "1.0.2"
"revision" : "cd142fd2f64be2100422d658e7411e39489da985",
"version" : "1.2.0"
}
},
{
Expand Down Expand Up @@ -104,17 +104,26 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio.git",
"state" : {
"revision" : "edfceecba13d68c1c993382806e72f7e96feaa86",
"version" : "2.44.0"
"revision" : "fc63f0cf4e55a4597407a9fc95b16a2bc44b4982",
"version" : "2.64.0"
}
},
{
"identity" : "swift-nio-http2",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-http2.git",
"state" : {
"revision" : "0904bf0feb5122b7e5c3f15db7df0eabe623dd87",
"version" : "1.30.0"
}
},
{
"identity" : "swift-nio-ssl",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-ssl.git",
"state" : {
"revision" : "4fb7ead803e38949eb1d6fabb849206a72c580f3",
"version" : "2.23.0"
"revision" : "7c381eb6083542b124a6c18fae742f55001dc2b5",
"version" : "2.26.0"
}
},
{
Expand All @@ -131,8 +140,17 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "ab3a58b7209a17d781c0d1dbb3e1ff3da306bae8",
"version" : "1.20.3"
"revision" : "65e8f29b2d63c4e38e736b25c27b83e012159be8",
"version" : "1.25.2"
}
},
{
"identity" : "swift-system",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-system.git",
"state" : {
"revision" : "025bcb1165deab2e20d4eaba79967ce73013f496",
"version" : "1.2.1"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ let package = Package(
.package(url: "https://github.com/GigaBitcoin/secp256k1.swift.git", exact: "0.10.0"),
.package(url: "https://github.com/argentlabs/web3.swift", from: "1.1.0"),
.package(url: "https://github.com/1024jp/GzipSwift", from: "5.2.0"),
.package(url: "https://github.com/bufbuild/connect-swift", exact: "0.3.0"),
.package(url: "https://github.com/bufbuild/connect-swift", exact: "0.12.0"),
.package(url: "https://github.com/apple/swift-docc-plugin.git", from: "1.0.0"),
.package(url: "https://github.com/xmtp/libxmtp-swift", exact: "0.4.3-beta2"),
],
Expand Down
217 changes: 120 additions & 97 deletions Sources/XMTPiOS/Push/XMTPPush.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,134 +4,157 @@
//
// Created by Pat Nakajima on 1/20/23.
//
#if canImport(UIKit)
import Connect
import UIKit
import UserNotifications

enum XMTPPushError: Error {
case noPushServer
}
import Connect

public struct XMTPPush {
public static var shared = XMTPPush()
import UserNotifications

var installationID: String
var installationIDKey: String = "installationID"
public typealias NotificationSubscription = Notifications_V1_Subscription
public typealias NotificationSubscriptionHmacKey = Notifications_V1_Subscription.HmacKey

var pushServer: String = ""
enum XMTPPushError: Error {
case noPushServer
}

private init() {
if let id = UserDefaults.standard.string(forKey: installationIDKey) {
installationID = id
} else {
installationID = UUID().uuidString
UserDefaults.standard.set(installationID, forKey: installationIDKey)
}
}
#if canImport(UIKit)
import UIKit

public mutating func setPushServer(_ server: String) {
pushServer = server
}
public struct XMTPPush {
public static var shared = XMTPPush()

public func request() async throws -> Bool {
if pushServer == "" {
throw XMTPPushError.noPushServer
}
var installationID: String
var installationIDKey: String = "installationID"

if try await UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge]) {
// await UIApplication.shared.registerForRemoteNotifications()
var pushServer: String = ""

return true
}
private init() {
if let id = UserDefaults.standard.string(forKey: installationIDKey) {
installationID = id
} else {
installationID = UUID().uuidString
UserDefaults.standard.set(installationID, forKey: installationIDKey)
}
}

return false
public mutating func setPushServer(_ server: String) {
pushServer = server
}

public func request() async throws -> Bool {
if pushServer == "" {
throw XMTPPushError.noPushServer
}

public func register(token: String) async throws {
if pushServer == "" {
throw XMTPPushError.noPushServer
}
if try await UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge]) {
// await UIApplication.shared.registerForRemoteNotifications()

let request = Notifications_V1_RegisterInstallationRequest.with { request in
request.installationID = installationID
request.deliveryMechanism = Notifications_V1_DeliveryMechanism.with { delivery in
delivery.apnsDeviceToken = token
delivery.deliveryMechanismType = .apnsDeviceToken(token)
}
}
return true
}

_ = await client.registerInstallation(request: request)
return false
}

public func register(token: String) async throws {
if pushServer == "" {
throw XMTPPushError.noPushServer
}

public func subscribe(topics: [String]) async throws {
if pushServer == "" {
throw XMTPPushError.noPushServer
let request = Notifications_V1_RegisterInstallationRequest.with { request in
request.installationID = installationID
request.deliveryMechanism = Notifications_V1_DeliveryMechanism.with { delivery in
delivery.apnsDeviceToken = token
delivery.deliveryMechanismType = .apnsDeviceToken(token)
}
}

let request = Notifications_V1_SubscribeRequest.with { request in
request.installationID = installationID
request.topics = topics
}
_ = await client.registerInstallation(request: request)
}

_ = await client.subscribe(request: request)
public func subscribe(topics: [String]) async throws {
if pushServer == "" {
throw XMTPPushError.noPushServer
}

public func unsubscribe(topics: [String]) async throws {
if pushServer == "" {
throw XMTPPushError.noPushServer
}

let request = Notifications_V1_UnsubscribeRequest.with { request in
request.installationID = installationID
request.topics = topics
}

_ = await client.unsubscribe(request: request)
}

var client: Notifications_V1_NotificationsClient {
let protocolClient = ProtocolClient(
httpClient: URLSessionHTTPClient(),
config: ProtocolClientConfig(
host: pushServer,
networkProtocol: .connect,
codec: ProtoCodec()
)
)

return Notifications_V1_NotificationsClient(client: protocolClient)
let request = Notifications_V1_SubscribeRequest.with { request in
request.installationID = installationID
request.topics = topics
}

_ = await client.subscribe(request: request)
}
#else
public struct XMTPPush {
public static var shared = XMTPPush()
private init() {
fatalError("XMTPPush not available")

public func subscribeWithMetadata(subscriptions: [NotificationSubscription]) async throws {
if pushServer == "" {
throw XMTPPushError.noPushServer
}

public mutating func setPushServer(_: String) {
fatalError("XMTPPush not available")
let request = Notifications_V1_SubscribeWithMetadataRequest.with { request in
request.installationID = installationID
request.subscriptions = subscriptions
}

public func request() async throws -> Bool {
fatalError("XMTPPush not available")
_ = await client.subscribeWithMetadata(request: request)
}

public func unsubscribe(topics: [String]) async throws {
if pushServer == "" {
throw XMTPPushError.noPushServer
}

public func register(token _: String) async throws {
fatalError("XMTPPush not available")
let request = Notifications_V1_UnsubscribeRequest.with { request in
request.installationID = installationID
request.topics = topics
}

public func subscribe(topics _: [String]) async throws {
fatalError("XMTPPush not available")
}

public func unsubscribe(topics _: [String]) async throws {
fatalError("XMTPPush not available")
}
_ = await client.unsubscribe(request: request)
}

var client: Notifications_V1_NotificationsClient {
fatalError("XMTPPush not available")
}
var client: Notifications_V1_NotificationsClient {
let protocolClient = ProtocolClient(
httpClient: URLSessionHTTPClient(),
config: ProtocolClientConfig(
host: pushServer,
networkProtocol: .connect,
codec: ProtoCodec()
)
)

return Notifications_V1_NotificationsClient(client: protocolClient)
}
}
#else
public struct XMTPPush {
public static var shared = XMTPPush()
private init() {
fatalError("XMTPPush not available")
}

public mutating func setPushServer(_: String) {
fatalError("XMTPPush not available")
}

public func request() async throws -> Bool {
fatalError("XMTPPush not available")
}

public func register(token _: String) async throws {
fatalError("XMTPPush not available")
}

public func subscribe(topics _: [String]) async throws {
fatalError("XMTPPush not available")
}

public func subscribeWithMetadata(subscriptions _: [NotificationSubscription]) async throws {
fatalError("XMTPPush not available")
}

public func unsubscribe(topics _: [String]) async throws {
fatalError("XMTPPush not available")
}

var client: Notifications_V1_NotificationsClient {
fatalError("XMTPPush not available")
}
}
#endif
Loading

0 comments on commit 89b62b4

Please sign in to comment.