Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.12.13
- Upgrade packages
- Correct deprecated methods

## 0.12.11

- Switch from `http_client` package to `http` package
Expand Down
16 changes: 7 additions & 9 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
analyzer:
strong-mode: true
# exclude:
# - path/to/excluded/files/**

# Lint rules and documentation, see http://dart-lang.github.io/linter/lints
linter:
rules:
- cancel_subscriptions
- hash_and_equals
- iterable_contains_unrelated_type
- list_remove_unrelated_type
- test_types_in_equals
- unrelated_type_equality_checks
- valid_regexps
cancel_subscriptions: true
hash_and_equals: true
iterable_contains_unrelated_type: true
list_remove_unrelated_type: true
test_types_in_equals: true
unrelated_type_equality_checks: true
valid_regexps: true
10 changes: 5 additions & 5 deletions example/dospace_example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ main() async {
}
}
dospace.Bucket bucket = spaces.bucket(bucketName);
String etag = await bucket.uploadFile(
String? etag = await bucket.uploadFile(
'README.md', 'README.md', 'text/plain', dospace.Permissions.public);
print('upload: $etag');

Expand All @@ -34,15 +34,15 @@ main() async {

// Basic pre-signed upload
{
String preSignUrl = bucket.preSignUpload('README.md');
String preSignUrl = bucket.preSignUpload('README.md')!;
print('upload url: ${preSignUrl}');
var httpClient = new http.Client();
var httpRequest = new http.Request('PUT', Uri.parse(preSignUrl));
http.StreamedResponse httpResponse = await httpClient.send(httpRequest);
String body = await utf8.decodeStream(httpResponse.stream);
print('${httpResponse.statusCode} ${httpResponse.reasonPhrase}');
print(body);
await httpClient.close();
httpClient.close();
}

// Pre-signed upload with specific payload
Expand All @@ -51,15 +51,15 @@ main() async {
int contentLength = await input.length();
Digest contentSha256 = await sha256.bind(input.openRead()).first;
String preSignUrl = bucket.preSignUpload('README.md',
contentLength: contentLength, contentSha256: contentSha256);
contentLength: contentLength, contentSha256: contentSha256)!;
print('strict upload url: ${preSignUrl}');
var httpClient = new http.Client();
var httpRequest = new http.Request('PUT', Uri.parse(preSignUrl));
http.StreamedResponse httpResponse = await httpClient.send(httpRequest);
String body = await utf8.decodeStream(httpResponse.stream);
print('${httpResponse.statusCode} ${httpResponse.reasonPhrase}');
print(body);
await httpClient.close();
httpClient.close();
}

print('done');
Expand Down
68 changes: 44 additions & 24 deletions lib/src/dospace_bucket.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ enum Permissions {

class Bucket extends Client {
Bucket(
{@required String region,
@required String accessKey,
@required String secretKey,
String endpointUrl,
http.Client httpClient})
{required String? region,
required String? accessKey,
required String? secretKey,
String? endpointUrl,
http.Client? httpClient})
: super(
region: region,
accessKey: accessKey,
Expand All @@ -39,12 +39,32 @@ class Bucket extends Client {
}
}

/// Delete an object
/// https://developers.digitalocean.com/documentation/spaces/#delete-object
Future<bool> deleteFile(String path) async {
String uriStr = endpointUrl + '/' + path;
http.Request request = new http.Request('DELETE', Uri.parse(uriStr));
request.headers['Content-Type'] = "application/json";
signRequest(request);

http.StreamedResponse response = await httpClient.send(request);
String body = await utf8.decodeStream(response.stream);

// "204 No Content" means the object was deleted (success)
if (response.statusCode != 204) {
throw new ClientException(
response.statusCode, response.reasonPhrase, response.headers, body);
}

return Future<bool>.value(true);
}

/// List the Bucket's Contents.
/// https://developers.digitalocean.com/documentation/spaces/#list-bucket-contents
Stream<BucketContent> listContents(
{String delimiter, String prefix, int maxKeys}) async* {
bool isTruncated;
String marker;
{String? delimiter, String? prefix, int? maxKeys}) async* {
late bool isTruncated;
String? marker;
do {
Uri uri = Uri.parse(endpointUrl + '/');
Map<String, dynamic> params = new Map<String, dynamic>();
Expand All @@ -70,10 +90,10 @@ class Bucket extends Client {
ele.text.toLowerCase() != "false" && ele.text != "0";
break;
case "Contents":
String key;
DateTime lastModifiedUtc;
String eTag;
int size;
String? key;
DateTime? lastModifiedUtc;
String? eTag;
int? size;
for (xml.XmlNode node in ele.children) {
if (node is xml.XmlElement) {
xml.XmlElement ele = node;
Expand Down Expand Up @@ -108,10 +128,10 @@ class Bucket extends Client {
}

/// Uploads file. Returns Etag.
Future<String> uploadFile(
Future<String?> uploadFile(
String key, dynamic file, String contentType, Permissions permissions,
{Map<String, String> meta}) async {
int contentLength = await file.length();
{Map<String, String>? meta}) async {
int? contentLength = await file.length();
Digest contentSha256 = await sha256.bind(file.openRead()).first;
String uriStr = endpointUrl + '/' + key;
http.StreamedRequest request =
Expand All @@ -136,14 +156,14 @@ class Bucket extends Client {
throw new ClientException(
response.statusCode, response.reasonPhrase, response.headers, body);
}
String etag = response.headers['etag'];
String? etag = response.headers['etag'];
return etag;
}

/// Uploads data from memory. Returns Etag.
Future<String> uploadData(
Future<String?> uploadData(
String key, Uint8List data, String contentType, Permissions permissions,
{Map<String, String> meta, Digest contentSha256}) async {
{Map<String, String>? meta, Digest? contentSha256}) async {
int contentLength = await data.length;
Digest contentSha256_ =
contentSha256 != null ? contentSha256 : await sha256.convert(data);
Expand All @@ -168,17 +188,17 @@ class Bucket extends Client {
throw new ClientException(
response.statusCode, response.reasonPhrase, response.headers, body);
}
String etag = response.headers['etag'];
String? etag = response.headers['etag'];
return etag;
}

String preSignUpload(String key,
{int contentLength,
String contentType,
Digest contentSha256,
String? preSignUpload(String key,
{int? contentLength,
String? contentType,
Digest? contentSha256,
Permissions permissions = Permissions.private,
int expires = 900,
Map<String, String> meta}) {
Map<String, String>? meta}) {
String uriStr = endpointUrl + '/' + key;
Uri uriBase = Uri.parse(uriStr);
Map<String, String> queryParameters = new Map<String, String>();
Expand Down
36 changes: 18 additions & 18 deletions lib/src/dospace_client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:xml/xml.dart' as xml;

class ClientException implements Exception {
final int statusCode;
final String reasonPhrase;
final String? reasonPhrase;
final Map<String, String> responseHeaders;
final String responseBody;
const ClientException(this.statusCode, this.reasonPhrase,
Expand All @@ -18,22 +18,22 @@ class ClientException implements Exception {
}

class Client {
final String region;
final String accessKey;
final String secretKey;
final String? region;
final String? accessKey;
final String? secretKey;
final String service;
final String endpointUrl;

@protected
final http.Client httpClient;

Client(
{@required this.region,
@required this.accessKey,
@required this.secretKey,
@required this.service,
String endpointUrl,
http.Client httpClient})
{required this.region,
required this.accessKey,
required this.secretKey,
required this.service,
String? endpointUrl,
http.Client? httpClient})
: this.endpointUrl =
endpointUrl ?? "https://${region}.digitaloceanspaces.com",
this.httpClient = httpClient ?? new http.Client() {
Expand All @@ -43,7 +43,7 @@ class Client {
}

Future<void> close() async {
await httpClient.close();
httpClient.close();
}

@protected
Expand All @@ -56,7 +56,7 @@ class Client {
throw new ClientException(
response.statusCode, response.reasonPhrase, response.headers, body);
}
xml.XmlDocument doc = xml.parse(body);
xml.XmlDocument doc = xml.XmlDocument.parse(body);
return doc;
}

Expand All @@ -75,8 +75,8 @@ class Client {
}

@protected
String signRequest(http.BaseRequest request,
{Digest contentSha256, bool preSignedUrl = false, int expires = 86400}) {
String? signRequest(http.BaseRequest request,
{Digest? contentSha256, bool preSignedUrl = false, int expires = 86400}) {
// Build canonical request
String httpMethod = request.method;
String canonicalURI = request.url.path;
Expand Down Expand Up @@ -104,7 +104,7 @@ class Client {
'${accessKey}/${dateYYYYMMDD}/${region}/${service}/aws4_request';

// Build canonical headers string
Map<String, String> headers = new Map<String, String>();
Map<String, String?> headers = new Map<String, String?>();
if (!preSignedUrl) {
request.headers['x-amz-date'] = dateIso8601; // Set date in header
if (contentSha256 != null) {
Expand All @@ -117,7 +117,7 @@ class Client {
headers['host'] = host; // Host is a builtin header
List<String> headerNames = headers.keys.toList()..sort();
String canonicalHeaders =
headerNames.map((s) => '${s}:${_trimAll(headers[s])}' + '\n').join();
headerNames.map((s) => '${s}:${_trimAll(headers[s]!)}' + '\n').join();

String signedHeaders = headerNames.join(';');

Expand All @@ -137,7 +137,7 @@ class Client {
}
List<String> queryKeys = queryParameters.keys.toList()..sort();
String canonicalQueryString = queryKeys
.map((s) => '${_uriEncode(s)}=${_uriEncode(queryParameters[s])}')
.map((s) => '${_uriEncode(s)}=${_uriEncode(queryParameters[s]!)}')
.join('&');

if (preSignedUrl) {
Expand All @@ -160,7 +160,7 @@ class Client {
Digest dateKey = new Hmac(sha256, utf8.encode("AWS4${secretKey}"))
.convert(utf8.encode(dateYYYYMMDD));
Digest dateRegionKey =
new Hmac(sha256, dateKey.bytes).convert(utf8.encode(region));
new Hmac(sha256, dateKey.bytes).convert(utf8.encode(region!));
Digest dateRegionServiceKey =
new Hmac(sha256, dateRegionKey.bytes).convert(utf8.encode(service));
Digest signingKey = new Hmac(sha256, dateRegionServiceKey.bytes)
Expand Down
16 changes: 8 additions & 8 deletions lib/src/dospace_results.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,21 @@ import 'package:meta/meta.dart';

class BucketContent {
/// The object's key.
final String key;
final String? key;

/// The date and time that the object was last modified in the format: %Y-%m-%dT%H:%M:%S.%3NZ (e.g. 2017-06-23T18:37:48.157Z)
final DateTime lastModifiedUtc;
final DateTime? lastModifiedUtc;

/// The entity tag containing an MD5 hash of the object.
final String eTag;
final String? eTag;

/// The size of the object in bytes.
final int size;
final int? size;

BucketContent({
@required this.key,
@required this.lastModifiedUtc,
@required this.eTag,
@required this.size,
required this.key,
required this.lastModifiedUtc,
required this.eTag,
required this.size,
});
}
16 changes: 8 additions & 8 deletions lib/src/dospace_spaces.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import 'dospace_bucket.dart';

class Spaces extends Client {
Spaces(
{@required String region,
@required String accessKey,
@required String secretKey,
String endpointUrl,
http.Client httpClient})
{required String? region,
required String? accessKey,
required String? secretKey,
String? endpointUrl,
http.Client? httpClient})
: super(
region: region,
accessKey: accessKey,
Expand All @@ -23,7 +23,7 @@ class Spaces extends Client {
// ...
}

Bucket bucket(String bucket) {
Bucket bucket(String? bucket) {
if (endpointUrl == "https://${region}.digitaloceanspaces.com") {
return new Bucket(
region: region,
Expand All @@ -39,7 +39,7 @@ class Spaces extends Client {

Future<List<String>> listAllBuckets() async {
xml.XmlDocument doc = await getUri(Uri.parse(endpointUrl + '/'));
List<String> res = new List<String>();
List<String> res = new List<String>.empty(growable: true);
for (xml.XmlElement root in doc.findElements('ListAllMyBucketsResult')) {
for (xml.XmlElement buckets in root.findElements('Buckets')) {
for (xml.XmlElement bucket in buckets.findElements('Bucket')) {
Expand All @@ -52,7 +52,7 @@ class Spaces extends Client {
return res;
}

String preSignListAllBuckets() {
String? preSignListAllBuckets() {
http.Request request =
new http.Request('GET', Uri.parse(endpointUrl + '/'));
return signRequest(request, preSignedUrl: true);
Expand Down
Loading