Skip to content

Move ParseHTTPClient to Dio #459

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Oct 8, 2020
Merged
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
7 changes: 5 additions & 2 deletions packages/dart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -782,7 +782,7 @@ These classes are used by default to represent files, but you can also build you

Have a look at the example application for a small (non web) example.


When uploading or downloading a file, you can use the `progressCallback`-parameter to track the progress of the http request.
```dart
//A short example for showing an image from a ParseFileBase
Widget buildImage(ParseFileBase image){
Expand Down Expand Up @@ -820,7 +820,10 @@ someParseObject.set("image", parseFile);
//This saves the ParseObject as well as all of its children, and the ParseFileBase is such a child.
await someParseObject.save();
```

```dart
//progressCallback example
file.upload(progressCallback: (int count, int total) => print("$count of $total"));
```
## Other Features of this library
Main:
* Installation (View the example application)
Expand Down
11 changes: 7 additions & 4 deletions packages/dart/lib/parse_server_sdk.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import 'dart:io';
import 'dart:math';
import 'dart:typed_data';

import 'package:http/http.dart';
import 'package:http/io_client.dart';
import 'package:dio/dio.dart' hide Options;
import 'package:dio/dio.dart' as dio show Options;
import 'package:meta/meta.dart';
import 'package:mime_type/mime_type.dart';
import 'package:parse_server_sdk/src/network/http_client_adapter.dart';
import 'package:parse_server_sdk/src/network/parse_websocket.dart'
as parse_web_socket;
import 'package:path/path.dart' as path;
Expand All @@ -23,6 +25,7 @@ part 'src/base/parse_constants.dart';
part 'src/data/parse_core_data.dart';
part 'src/data/parse_subclass_handler.dart';
part 'src/enums/parse_enum_api_rq.dart';
part 'src/network/dio-options.dart';
part 'src/network/parse_connectivity.dart';
part 'src/network/parse_http_client.dart';
part 'src/network/parse_live_query.dart';
Expand Down Expand Up @@ -150,8 +153,8 @@ class Parse {
const ParseApiRQ type = ParseApiRQ.healthCheck;

try {
final Response response =
await _client.get('${ParseCoreData().serverUrl}$keyEndPointHealth');
final Response<String> response = await _client
.get<String>('${ParseCoreData().serverUrl}$keyEndPointHealth');
parseResponse =
handleResponse<Parse>(null, response, type, _debug, className);
} on Exception catch (e) {
Expand Down
2 changes: 1 addition & 1 deletion packages/dart/lib/src/base/parse_constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const String keyHeaderSessionToken = 'X-Parse-Session-Token';
const String keyHeaderRevocableSession = 'X-Parse-Revocable-Session';
const String keyHeaderUserAgent = 'user-agent';
const String keyHeaderApplicationId = 'X-Parse-Application-Id';
const String keyHeaderContentType = 'Content-Type';
const String keyHeaderContentType = Headers.contentTypeHeader;
const String keyHeaderContentTypeJson = 'application/json';
const String keyHeaderMasterKey = 'X-Parse-Master-Key';
const String keyHeaderClientKey = 'X-Parse-Client-Key';
Expand Down
34 changes: 34 additions & 0 deletions packages/dart/lib/src/network/dio-options.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
part of flutter_parse_sdk;

class Options extends dio.Options {
Options({
String method,
int sendTimeout,
int receiveTimeout,
Map<String, dynamic> extra,
Map<String, dynamic> headers,
ResponseType responseType,
String contentType,
ValidateStatus validateStatus,
bool receiveDataWhenStatusError,
bool followRedirects,
int maxRedirects,
RequestEncoder requestEncoder,
ResponseDecoder responseDecoder,
}) : super(
method: method,
sendTimeout: sendTimeout,
receiveTimeout: receiveTimeout,
extra: extra,
headers: headers,
responseType: responseType,
contentType: contentType ??
(headers ?? <String, dynamic>{})[Headers.contentTypeHeader],
validateStatus: validateStatus,
receiveDataWhenStatusError: receiveDataWhenStatusError,
followRedirects: followRedirects,
maxRedirects: maxRedirects,
requestEncoder: requestEncoder,
responseDecoder: responseDecoder,
);
}
2 changes: 2 additions & 0 deletions packages/dart/lib/src/network/http_client_adapter.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export 'http_client_adapter_native.dart'
if (dart.library.js) 'http_client_adapter_web.dart';
14 changes: 14 additions & 0 deletions packages/dart/lib/src/network/http_client_adapter_native.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import 'dart:io';

import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';

HttpClientAdapter createHttpClientAdapter(SecurityContext securityContext) {
final DefaultHttpClientAdapter defaultHttpClientAdapter =
DefaultHttpClientAdapter();

if (securityContext != null)
defaultHttpClientAdapter.onHttpClientCreate =
(HttpClient client) => HttpClient(context: securityContext);
return defaultHttpClientAdapter;
}
10 changes: 10 additions & 0 deletions packages/dart/lib/src/network/http_client_adapter_web.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'dart:io';

import 'package:dio/adapter_browser.dart';
import 'package:dio/dio.dart';

HttpClientAdapter createHttpClientAdapter(SecurityContext securityContext) {
final BrowserHttpClientAdapter browserHttpClientAdapter =
BrowserHttpClientAdapter();
return browserHttpClientAdapter;
}
56 changes: 36 additions & 20 deletions packages/dart/lib/src/network/parse_http_client.dart
Original file line number Diff line number Diff line change
@@ -1,46 +1,62 @@
part of flutter_parse_sdk;

/// Creates a custom version of HTTP Client that has Parse Data Preset
class ParseHTTPClient extends BaseClient {
class ParseHTTPClient with DioMixin implements Dio {
ParseHTTPClient({bool sendSessionId = false, SecurityContext securityContext})
: _sendSessionId = sendSessionId,
_client = securityContext != null
? IOClient(HttpClient(context: securityContext))
: Client();
: _sendSessionId = sendSessionId {
options = BaseOptions();
httpClientAdapter = createHttpClientAdapter(securityContext);
}

final Client _client;
final bool _sendSessionId;
final String _userAgent = '$keyLibraryName $keySdkVersion';
ParseCoreData data = ParseCoreData();
Map<String, String> additionalHeaders;

/// Overrides the call method for HTTP Client and adds custom headers
@override
Future<StreamedResponse> send(BaseRequest request) {
Future<Response<T>> request<T>(
String path, {
dynamic data,
Map<String, dynamic> queryParameters,
CancelToken cancelToken,
dio.Options options,
ProgressCallback onSendProgress,
ProgressCallback onReceiveProgress,
}) {
options ??= Options();
if (!identical(0, 0.0)) {
request.headers[keyHeaderUserAgent] = _userAgent;
options.headers[keyHeaderUserAgent] = _userAgent;
}
request.headers[keyHeaderApplicationId] = data.applicationId;
options.headers[keyHeaderApplicationId] = this.data.applicationId;
if ((_sendSessionId == true) &&
(data.sessionId != null) &&
(request.headers[keyHeaderSessionToken] == null))
request.headers[keyHeaderSessionToken] = data.sessionId;
(this.data.sessionId != null) &&
(options.headers[keyHeaderSessionToken] == null))
options.headers[keyHeaderSessionToken] = this.data.sessionId;

if (data.clientKey != null)
request.headers[keyHeaderClientKey] = data.clientKey;
if (data.masterKey != null)
request.headers[keyHeaderMasterKey] = data.masterKey;
if (this.data.clientKey != null)
options.headers[keyHeaderClientKey] = this.data.clientKey;
if (this.data.masterKey != null)
options.headers[keyHeaderMasterKey] = this.data.masterKey;

/// If developer wants to add custom headers, extend this class and add headers needed.
if (additionalHeaders != null && additionalHeaders.isNotEmpty) {
additionalHeaders
.forEach((String key, String value) => request.headers[key] = value);
.forEach((String key, String value) => options.headers[key] = value);
}

if (data.debug) {
logCUrl(request);
if (this.data.debug) {
logCUrl(options, data, path);
}

return _client.send(request);
return super.request(
path,
data: data,
queryParameters: queryParameters,
cancelToken: cancelToken,
options: options,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
);
}
}
8 changes: 6 additions & 2 deletions packages/dart/lib/src/network/parse_query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,12 @@ class QueryBuilder<T extends ParseObject> {
/// Finishes the query and calls the server
///
/// Make sure to call this after defining your queries
Future<ParseResponse> query<T extends ParseObject>() async {
return object.query<T>(buildQuery());
Future<ParseResponse> query<T extends ParseObject>(
{ProgressCallback progressCallback}) async {
return object.query<T>(
buildQuery(),
progressCallback: progressCallback,
);
}

Future<ParseResponse> distinct<T extends ParseObject>(
Expand Down
4 changes: 2 additions & 2 deletions packages/dart/lib/src/objects/parse_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class ParseConfig extends ParseObject {
Future<ParseResponse> getConfigs() async {
try {
final String uri = '${ParseCoreData().serverUrl}/config';
final Response result = await _client.get(uri);
final Response<String> result = await _client.get<String>(uri);
return handleResponse<ParseConfig>(
this, result, ParseApiRQ.getConfigs, _debug, parseClassName);
} on Exception catch (e) {
Expand All @@ -29,7 +29,7 @@ class ParseConfig extends ParseObject {
try {
final String uri = '${ParseCoreData().serverUrl}/config';
final String body = '{\"params\":{\"$key\": \"${parseEncode(value)}\"}}';
final Response result = await _client.put(uri, body: body);
final Response<String> result = await _client.put<String>(uri, data: body);
return handleResponse<ParseConfig>(
this, result, ParseApiRQ.addConfig, _debug, parseClassName);
} on Exception catch (e) {
Expand Down
28 changes: 17 additions & 11 deletions packages/dart/lib/src/objects/parse_file.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,26 @@ class ParseFile extends ParseFileBase {
}

@override
Future<ParseFile> download() async {
Future<ParseFile> download({ProgressCallback progressCallback}) async {
if (url == null) {
return this;
}

file = File('${ParseCoreData().fileDirectory}/$name');
await file.create();
final Response response = await _client.get(url);
await file.writeAsBytes(response.bodyBytes);
final Response<List<int>> response = await _client.get<List<int>>(
url,
options: Options(responseType: ResponseType.bytes),
onReceiveProgress: progressCallback,
);
await file.writeAsBytes(response.data);

return this;
}

/// Uploads a file to Parse Server
@override
Future<ParseResponse> upload() async {
Future<ParseResponse> upload({ProgressCallback progressCallback}) async {
if (saved) {
//Creates a Fake Response to return the correct result
final Map<String, String> response = <String, String>{
Expand All @@ -64,23 +68,25 @@ class ParseFile extends ParseFileBase {
};
return handleResponse<ParseFile>(
this,
Response(json.encode(response), 201),
Response<String>(data: json.encode(response), statusCode: 201),
ParseApiRQ.upload,
_debug,
parseClassName);
}

final String ext = path.extension(file.path).replaceAll('.', '');
final Map<String, String> headers = <String, String>{
HttpHeaders.contentTypeHeader: getContentType(ext)
HttpHeaders.contentTypeHeader: mime(file.path) ?? 'application/octet-stream',
};
try {
final String uri = _client.data.serverUrl + '$_path';
final List<int> body = await file.readAsBytes();
final Response response =
await _client.post(uri, headers: headers, body: body);
final Response<String> response = await _client.post<String>(
uri,
options: Options(headers: headers),
data: file.openRead(),
onSendProgress: progressCallback,
);
if (response.statusCode == 201) {
final Map<String, dynamic> map = json.decode(response.body);
final Map<String, dynamic> map = json.decode(response.data);
url = map['url'].toString();
name = map['name'].toString();
}
Expand Down
4 changes: 2 additions & 2 deletions packages/dart/lib/src/objects/parse_file_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ abstract class ParseFileBase extends ParseObject {
}

/// Uploads a file to Parse Server
Future<ParseResponse> upload();
Future<ParseResponse> upload({ProgressCallback progressCallback});

Future<ParseFileBase> download();
Future<ParseFileBase> download({ProgressCallback progressCallback});
}
29 changes: 18 additions & 11 deletions packages/dart/lib/src/objects/parse_file_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,23 @@ class ParseWebFile extends ParseFileBase {
Uint8List file;

@override
Future<ParseWebFile> download() async {
Future<ParseWebFile> download({ProgressCallback progressCallback}) async {
if (url == null) {
return this;
}

final Response response = await _client.get(url);
file = response.bodyBytes;
final Response<List<int>> response = await _client.get<List<int>>(
url,
options: Options(responseType: ResponseType.bytes),
onReceiveProgress: progressCallback,
);
file = response.data;

return this;
}

@override
Future<ParseResponse> upload() async {
Future<ParseResponse> upload({ProgressCallback progressCallback}) async {
if (saved) {
//Creates a Fake Response to return the correct result
final Map<String, String> response = <String, String>{
Expand All @@ -39,23 +43,26 @@ class ParseWebFile extends ParseFileBase {
};
return handleResponse<ParseWebFile>(
this,
Response(json.encode(response), 201),
Response<String>(data: json.encode(response), statusCode: 201),
ParseApiRQ.upload,
_debug,
parseClassName);
}

final Map<String, String> headers = <String, String>{
HttpHeaders.contentTypeHeader: url ?? name != null
? getContentType(path.extension(url ?? name))
: 'text/plain'
HttpHeaders.contentTypeHeader:
mime(url ?? name) ?? 'application/octet-stream',
};
try {
final String uri = _client.data.serverUrl + '$_path';
final Response response =
await _client.post(uri, headers: headers, body: file);
final Response<String> response = await _client.post<String>(
uri,
options: Options(headers: headers),
data: Stream<List<int>>.fromIterable(<List<int>>[file]),
onSendProgress: progressCallback,
);
if (response.statusCode == 201) {
final Map<String, dynamic> map = json.decode(response.body);
final Map<String, dynamic> map = json.decode(response.data);
url = map['url'].toString();
name = map['name'].toString();
}
Expand Down
Loading