feat: implement web service

Signed-off-by: The one with the braid <info@braid.business>
This commit is contained in:
The one with the braid 2023-11-26 19:42:29 +01:00
parent 44494eaa90
commit 6e7f19a764
26 changed files with 331 additions and 512 deletions

View file

@ -0,0 +1,69 @@
import 'dart:typed_data';
import 'package:http/http.dart';
import 'package:pkpass/pkpass.dart';
import 'package:pkpass/pkpass_web_wervice/utils/http_date.dart';
import 'web_service_error.dart';
/// PassKit WebService implementation
///
/// A Representational State Transfer (REST)style web service protocol is used
/// to communicate with your server about changes to passes, and to fetch the
/// latest version of a pass when it has changed.
///
/// https://developer.apple.com/library/archive/documentation/PassKit/Reference/PassKit_WebService/WebService.html#//apple_ref/doc/uid/TP40011988
class PkPassWebService {
static const _apiVersion = 'v1';
static Client? _client;
/// The [PassMetadata] to check for updates.
final PassMetadata metadata;
/// An optional [Client] used for any http requests
final Client? client;
const PkPassWebService(this.metadata, {this.client});
PassWebService get webService {
final service = metadata.webService;
if (service == null) noWebServiceProvided();
return service;
}
Client get httpClient {
final client = this.client;
if (client != null) return client;
return _client ??= Client();
}
/// Getting the Latest Version of a Pass
///
/// Requests the latest version of the current PkPass file
///
/// [modifiedSince] should be provided in order to support "304 Not Modified"
Future<Uint8List?> getLatestVersion([DateTime? modifiedSince]) async {
final identifier = metadata.passTypeIdentifier;
final serial = metadata.serialNumber;
final endpoint = '/$_apiVersion/passes/$identifier/$serial';
final response = await httpClient.get(
Uri.parse(webService.webServiceURL.toString() + endpoint),
headers: {
if (modifiedSince != null)
'If-Modified-Since': HttpDate.format(modifiedSince),
'Authorization': 'ApplePass ${webService.authenticationToken}',
},
);
switch (response.statusCode) {
case 200:
return response.bodyBytes;
case 304:
return null;
default:
throw WebServiceResponseError(response);
}
}
Never noWebServiceProvided() => throw WebServiceUnavailable();
}