Skip to content

Commit 8c5cef4

Browse files
Added convenience send methods that automatically encode a topic
1 parent 4453277 commit 8c5cef4

File tree

2 files changed

+156
-12
lines changed

2 files changed

+156
-12
lines changed

Sources/WebPush/WebPushManager.swift

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ public actor WebPushManager: Sendable {
250250
/// - Parameters:
251251
/// - message: The message to send as raw data.
252252
/// - subscriber: The subscriber to send the push message to.
253-
/// - deduplicationTopic: The topic to use when deduplicating messages stored on a Push Service.
253+
/// - deduplicationTopic: The topic to use when deduplicating messages stored on a Push Service. When specifying a topic, prefer to use ``send(data:to:encodableDeduplicationTopic:expiration:urgency:logger:)`` instead.
254254
/// - expiration: The expiration of the push message, after wich delivery will no longer be attempted.
255255
/// - urgency: The urgency of the delivery of the push message.
256256
/// - logger: The logger to use for status updates. If not provided, the background activity logger will be used instead. When running in a server environment, your contextual logger should be used instead giving you full control of logging and metadata.
@@ -281,14 +281,47 @@ public actor WebPushManager: Sendable {
281281
}
282282
}
283283

284+
/// Send a push message as raw data.
285+
///
286+
/// The service worker you registered is expected to know how to decode the data you send.
287+
///
288+
/// - Parameters:
289+
/// - message: The message to send as raw data.
290+
/// - subscriber: The subscriber to send the push message to.
291+
/// - encodableDeduplicationTopic: The topic to use when deduplicating messages stored on a Push Service.
292+
/// - expiration: The expiration of the push message, after wich delivery will no longer be attempted.
293+
/// - urgency: The urgency of the delivery of the push message.
294+
/// - logger: The logger to use for status updates. If not provided, the background activity logger will be used instead. When running in a server environment, your contextual logger should be used instead giving you full control of logging and metadata.
295+
@inlinable
296+
public func send(
297+
data message: some DataProtocol,
298+
to subscriber: some SubscriberProtocol,
299+
encodableDeduplicationTopic: some Encodable,
300+
expiration: Expiration = .recommendedMaximum,
301+
urgency: Urgency = .high,
302+
logger: Logger? = nil
303+
) async throws {
304+
try await send(
305+
data: message,
306+
to: subscriber,
307+
deduplicationTopic: Topic(
308+
encodableTopic: encodableDeduplicationTopic,
309+
salt: subscriber.userAgentKeyMaterial.authenticationSecret
310+
),
311+
expiration: expiration,
312+
urgency: urgency,
313+
logger: logger
314+
)
315+
}
316+
284317
/// Send a push message as a string.
285318
///
286319
/// The service worker you registered is expected to know how to decode the string you send.
287320
///
288321
/// - Parameters:
289322
/// - message: The message to send as a string.
290323
/// - subscriber: The subscriber to send the push message to.
291-
/// - deduplicationTopic: The topic to use when deduplicating messages stored on a Push Service.
324+
/// - deduplicationTopic: The topic to use when deduplicating messages stored on a Push Service. When specifying a topic, prefer to use ``send(string:to:encodableDeduplicationTopic:expiration:urgency:logger:)`` instead.
292325
/// - expiration: The expiration of the push message, after wich delivery will no longer be attempted.
293326
/// - urgency: The urgency of the delivery of the push message.
294327
/// - logger: The logger to use for status updates. If not provided, the background activity logger will be used instead. When running in a server environment, your contextual logger should be used instead giving you full control of logging and metadata.
@@ -310,14 +343,47 @@ public actor WebPushManager: Sendable {
310343
)
311344
}
312345

346+
/// Send a push message as a string.
347+
///
348+
/// The service worker you registered is expected to know how to decode the string you send.
349+
///
350+
/// - Parameters:
351+
/// - message: The message to send as a string.
352+
/// - subscriber: The subscriber to send the push message to.
353+
/// - encodableDeduplicationTopic: The topic to use when deduplicating messages stored on a Push Service.
354+
/// - expiration: The expiration of the push message, after wich delivery will no longer be attempted.
355+
/// - urgency: The urgency of the delivery of the push message.
356+
/// - logger: The logger to use for status updates. If not provided, the background activity logger will be used instead. When running in a server environment, your contextual logger should be used instead giving you full control of logging and metadata.
357+
@inlinable
358+
public func send(
359+
string message: some StringProtocol,
360+
to subscriber: some SubscriberProtocol,
361+
encodableDeduplicationTopic: some Encodable,
362+
expiration: Expiration = .recommendedMaximum,
363+
urgency: Urgency = .high,
364+
logger: Logger? = nil
365+
) async throws {
366+
try await send(
367+
string: message,
368+
to: subscriber,
369+
deduplicationTopic: Topic(
370+
encodableTopic: encodableDeduplicationTopic,
371+
salt: subscriber.userAgentKeyMaterial.authenticationSecret
372+
),
373+
expiration: expiration,
374+
urgency: urgency,
375+
logger: logger
376+
)
377+
}
378+
313379
/// Send a push message as encoded JSON.
314380
///
315381
/// The service worker you registered is expected to know how to decode the JSON you send. Note that dates are encoded using ``/Foundation/JSONEncoder/DateEncodingStrategy/millisecondsSince1970``, and data is encoded using ``/Foundation/JSONEncoder/DataEncodingStrategy/base64``.
316382
///
317383
/// - Parameters:
318384
/// - message: The message to send as JSON.
319385
/// - subscriber: The subscriber to send the push message to.
320-
/// - deduplicationTopic: The topic to use when deduplicating messages stored on a Push Service.
386+
/// - deduplicationTopic: The topic to use when deduplicating messages stored on a Push Service. When specifying a topic, prefer to use ``send(json:to:encodableDeduplicationTopic:expiration:urgency:logger:)`` instead.
321387
/// - expiration: The expiration of the push message, after wich delivery will no longer be attempted.
322388
/// - urgency: The urgency of the delivery of the push message.
323389
/// - logger: The logger to use for status updates. If not provided, the background activity logger will be used instead. When running in a server environment, your contextual logger should be used instead giving you full control of logging and metadata.
@@ -339,6 +405,39 @@ public actor WebPushManager: Sendable {
339405
)
340406
}
341407

408+
/// Send a push message as encoded JSON.
409+
///
410+
/// The service worker you registered is expected to know how to decode the JSON you send. Note that dates are encoded using ``/Foundation/JSONEncoder/DateEncodingStrategy/millisecondsSince1970``, and data is encoded using ``/Foundation/JSONEncoder/DataEncodingStrategy/base64``.
411+
///
412+
/// - Parameters:
413+
/// - message: The message to send as JSON.
414+
/// - subscriber: The subscriber to send the push message to.
415+
/// - encodableDeduplicationTopic: The topic to use when deduplicating messages stored on a Push Service.
416+
/// - expiration: The expiration of the push message, after wich delivery will no longer be attempted.
417+
/// - urgency: The urgency of the delivery of the push message.
418+
/// - logger: The logger to use for status updates. If not provided, the background activity logger will be used instead. When running in a server environment, your contextual logger should be used instead giving you full control of logging and metadata.
419+
@inlinable
420+
public func send(
421+
json message: some Encodable&Sendable,
422+
to subscriber: some SubscriberProtocol,
423+
encodableDeduplicationTopic: some Encodable,
424+
expiration: Expiration = .recommendedMaximum,
425+
urgency: Urgency = .high,
426+
logger: Logger? = nil
427+
) async throws {
428+
try await send(
429+
json: message,
430+
to: subscriber,
431+
deduplicationTopic: Topic(
432+
encodableTopic: encodableDeduplicationTopic,
433+
salt: subscriber.userAgentKeyMaterial.authenticationSecret
434+
),
435+
expiration: expiration,
436+
urgency: urgency,
437+
logger: logger
438+
)
439+
}
440+
342441
/// Route a message to the current executor.
343442
/// - Parameters:
344443
/// - message: The message to send.

Tests/WebPushTests/WebPushManagerTests.swift

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ struct WebPushManagerTests {
385385
}
386386

387387
@Test func sendCustomTopic() async throws {
388-
try await confirmation { requestWasMade in
388+
try await confirmation(expectedCount: 6) { requestWasMade in
389389
let vapidConfiguration = VAPID.Configuration.makeTesting()
390390

391391
let subscriberPrivateKey = P256.KeyAgreement.PrivateKey(compactRepresentable: false)
@@ -423,23 +423,48 @@ struct WebPushManagerTests {
423423
userAgentKeyMaterial: subscriber.userAgentKeyMaterial
424424
)
425425

426-
#expect(String(decoding: message, as: UTF8.self) == "hello")
426+
#expect(String(decoding: message, as: UTF8.self) == "\"hello\"")
427427

428428
requestWasMade()
429429
return HTTPClientResponse(status: .created)
430430
}))
431431
)
432432

433433
try await manager.send(
434-
string: "hello",
434+
string: "\"hello\"",
435435
to: subscriber,
436436
deduplicationTopic: Topic(encodableTopic: "topic-id", salt: subscriber.userAgentKeyMaterial.authenticationSecret)
437437
)
438+
try await manager.send(
439+
string: "\"hello\"",
440+
to: subscriber,
441+
encodableDeduplicationTopic: "topic-id"
442+
)
443+
try await manager.send(
444+
data: "\"hello\"".utf8Bytes,
445+
to: subscriber,
446+
deduplicationTopic: Topic(encodableTopic: "topic-id", salt: subscriber.userAgentKeyMaterial.authenticationSecret)
447+
)
448+
try await manager.send(
449+
data: "\"hello\"".utf8Bytes,
450+
to: subscriber,
451+
encodableDeduplicationTopic: "topic-id"
452+
)
453+
try await manager.send(
454+
json: "hello",
455+
to: subscriber,
456+
deduplicationTopic: Topic(encodableTopic: "topic-id", salt: subscriber.userAgentKeyMaterial.authenticationSecret)
457+
)
458+
try await manager.send(
459+
json: "hello",
460+
to: subscriber,
461+
encodableDeduplicationTopic: "topic-id"
462+
)
438463
}
439464
}
440465

441466
@Test func sendCustomExpiration() async throws {
442-
try await confirmation { requestWasMade in
467+
try await confirmation(expectedCount: 3) { requestWasMade in
443468
let vapidConfiguration = VAPID.Configuration.makeTesting()
444469

445470
let subscriberPrivateKey = P256.KeyAgreement.PrivateKey(compactRepresentable: false)
@@ -477,23 +502,33 @@ struct WebPushManagerTests {
477502
userAgentKeyMaterial: subscriber.userAgentKeyMaterial
478503
)
479504

480-
#expect(String(decoding: message, as: UTF8.self) == "hello")
505+
#expect(String(decoding: message, as: UTF8.self) == "\"hello\"")
481506

482507
requestWasMade()
483508
return HTTPClientResponse(status: .created)
484509
}))
485510
)
486511

487512
try await manager.send(
488-
string: "hello",
513+
string: "\"hello\"",
514+
to: subscriber,
515+
expiration: .dropIfUndeliverable
516+
)
517+
try await manager.send(
518+
data: "\"hello\"".utf8Bytes,
519+
to: subscriber,
520+
expiration: .dropIfUndeliverable
521+
)
522+
try await manager.send(
523+
json: "hello",
489524
to: subscriber,
490525
expiration: .dropIfUndeliverable
491526
)
492527
}
493528
}
494529

495530
@Test func sendCustomUrgency() async throws {
496-
try await confirmation { requestWasMade in
531+
try await confirmation(expectedCount: 3) { requestWasMade in
497532
let vapidConfiguration = VAPID.Configuration.makeTesting()
498533

499534
let subscriberPrivateKey = P256.KeyAgreement.PrivateKey(compactRepresentable: false)
@@ -531,15 +566,25 @@ struct WebPushManagerTests {
531566
userAgentKeyMaterial: subscriber.userAgentKeyMaterial
532567
)
533568

534-
#expect(String(decoding: message, as: UTF8.self) == "hello")
569+
#expect(String(decoding: message, as: UTF8.self) == "\"hello\"")
535570

536571
requestWasMade()
537572
return HTTPClientResponse(status: .created)
538573
}))
539574
)
540575

541576
try await manager.send(
542-
string: "hello",
577+
string: "\"hello\"",
578+
to: subscriber,
579+
urgency: .low
580+
)
581+
try await manager.send(
582+
data: "\"hello\"".utf8Bytes,
583+
to: subscriber,
584+
urgency: .low
585+
)
586+
try await manager.send(
587+
json: "hello",
543588
to: subscriber,
544589
urgency: .low
545590
)

0 commit comments

Comments
 (0)