From c30288e3b9abfdb7ead77f5500bb0be5a521c89c Mon Sep 17 00:00:00 2001 From: Thong Dang Date: Wed, 1 Sep 2021 00:18:51 +0700 Subject: [PATCH] Publish isolate_http version 1.0.0 --- isolate_http/.gitignore | 75 ++++++++++++ isolate_http/.metadata | 10 ++ isolate_http/.vscode/launch.json | 19 +++ isolate_http/CHANGELOG.md | 3 + isolate_http/LICENSE | 21 ++++ isolate_http/README.md | 52 ++++++++ isolate_http/example/main.dart | 14 +++ isolate_http/lib/isolate_http.dart | 7 ++ isolate_http/lib/src/http_file.dart | 68 +++++++++++ isolate_http/lib/src/http_method.dart | 20 ++++ isolate_http/lib/src/isolate_http.dart | 90 ++++++++++++++ .../lib/src/isolate_http_request.dart | 82 +++++++++++++ .../lib/src/isolate_http_response.dart | 28 +++++ isolate_http/pubspec.lock | 113 ++++++++++++++++++ isolate_http/pubspec.yaml | 16 +++ 15 files changed, 618 insertions(+) create mode 100644 isolate_http/.gitignore create mode 100644 isolate_http/.metadata create mode 100644 isolate_http/.vscode/launch.json create mode 100644 isolate_http/CHANGELOG.md create mode 100644 isolate_http/LICENSE create mode 100644 isolate_http/README.md create mode 100644 isolate_http/example/main.dart create mode 100644 isolate_http/lib/isolate_http.dart create mode 100644 isolate_http/lib/src/http_file.dart create mode 100644 isolate_http/lib/src/http_method.dart create mode 100644 isolate_http/lib/src/isolate_http.dart create mode 100644 isolate_http/lib/src/isolate_http_request.dart create mode 100644 isolate_http/lib/src/isolate_http_response.dart create mode 100644 isolate_http/pubspec.lock create mode 100644 isolate_http/pubspec.yaml diff --git a/isolate_http/.gitignore b/isolate_http/.gitignore new file mode 100644 index 0000000..bb431f0 --- /dev/null +++ b/isolate_http/.gitignore @@ -0,0 +1,75 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.buildlog/ +.history +.svn/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.packages +.pub-cache/ +.pub/ +build/ + +# Android related +**/android/**/gradle-wrapper.jar +**/android/.gradle +**/android/captures/ +**/android/gradlew +**/android/gradlew.bat +**/android/local.properties +**/android/**/GeneratedPluginRegistrant.java + +# iOS/XCode related +**/ios/**/*.mode1v3 +**/ios/**/*.mode2v3 +**/ios/**/*.moved-aside +**/ios/**/*.pbxuser +**/ios/**/*.perspectivev3 +**/ios/**/*sync/ +**/ios/**/.sconsign.dblite +**/ios/**/.tags* +**/ios/**/.vagrant/ +**/ios/**/DerivedData/ +**/ios/**/Icon? +**/ios/**/Pods/ +**/ios/**/.symlinks/ +**/ios/**/profile +**/ios/**/xcuserdata +**/ios/.generated/ +**/ios/Flutter/App.framework +**/ios/Flutter/Flutter.framework +**/ios/Flutter/Flutter.podspec +**/ios/Flutter/Generated.xcconfig +**/ios/Flutter/app.flx +**/ios/Flutter/app.zip +**/ios/Flutter/flutter_assets/ +**/ios/Flutter/flutter_export_environment.sh +**/ios/ServiceDefinitions.json +**/ios/Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!**/ios/**/default.mode1v3 +!**/ios/**/default.mode2v3 +!**/ios/**/default.pbxuser +!**/ios/**/default.perspectivev3 +!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages diff --git a/isolate_http/.metadata b/isolate_http/.metadata new file mode 100644 index 0000000..21111a0 --- /dev/null +++ b/isolate_http/.metadata @@ -0,0 +1,10 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: fba99f6cf9a14512e461e3122c8ddfaa25394e89 + channel: stable + +project_type: package diff --git a/isolate_http/.vscode/launch.json b/isolate_http/.vscode/launch.json new file mode 100644 index 0000000..42a1d50 --- /dev/null +++ b/isolate_http/.vscode/launch.json @@ -0,0 +1,19 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "isolate_http", + "request": "launch", + "type": "dart" + }, + { + "name": "isolate_http (profile mode)", + "request": "launch", + "type": "dart", + "flutterMode": "profile" + } + ] +} \ No newline at end of file diff --git a/isolate_http/CHANGELOG.md b/isolate_http/CHANGELOG.md new file mode 100644 index 0000000..930daeb --- /dev/null +++ b/isolate_http/CHANGELOG.md @@ -0,0 +1,3 @@ +# [1.0.0] - 01/09/2021 + +* Initial package. diff --git a/isolate_http/LICENSE b/isolate_http/LICENSE new file mode 100644 index 0000000..7391ccc --- /dev/null +++ b/isolate_http/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Thong Dang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/isolate_http/README.md b/isolate_http/README.md new file mode 100644 index 0000000..cfd2218 --- /dev/null +++ b/isolate_http/README.md @@ -0,0 +1,52 @@ +# IsolateHttp + +[![Pub][pub_v_image_url]][pub_url] + +IsolateHttp provides a way to launch [http package][http_pub_url] with [IsolateFlutter][isolate_flutter_pub_url]. + +## Usage + +Performing a `GET` request: + +```dart +final _response = await IsolateHttp().get('https://example.com/product', + headers: {'Authorization': 'abc='}); +print(_response); +``` + +Performing a `POST` request: + +```dart +final _response = await IsolateHttp().post('https://example.com/product', + headers: {'Authorization': 'abc='}, + body: {'size': 'XL', 'price': 236}, + files: [ + HttpFile.fromPath('files', 'path/image_1.png') + ]); +print(_response); +``` + +Performing a `DELETE` request: + +```dart +final _response = await IsolateHttp().delete('https://example.com/product/1', + headers: {'Authorization': 'abc='}); +print(_response); +``` + +## Author + +IsolateHttp is developed by Thong Dang. You can contact me at thongdn.it@gmail.com + +If you like my project, you can support me [![Buy Me A Coffee][buy_me_a_coffee_image_url]][buy_me_a_coffee_url] or star (like) for it. + +Thank you! ❤️ + +[//]: # (reference links) + +[http_pub_url]: https://pub.dev/packages/http +[isolate_flutter_pub_url]: https://pub.dev/packages/isolate_flutter +[pub_url]: https://pub.dev/packages/isolate_http +[pub_v_image_url]: https://img.shields.io/pub/v/isolate_http.svg +[buy_me_a_coffee_image_url]: https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png +[buy_me_a_coffee_url]: https://www.buymeacoffee.com/thongdn.it diff --git a/isolate_http/example/main.dart b/isolate_http/example/main.dart new file mode 100644 index 0000000..2231129 --- /dev/null +++ b/isolate_http/example/main.dart @@ -0,0 +1,14 @@ +import 'package:isolate_http/isolate_http.dart'; + +void main(List args) async { + // https://developers.google.com/books + final _response = await IsolateHttp().get( + 'https://www.googleapis.com/auth/books/v1/volumes', + query: {'q': 'flutter'}); + if (_response.statusCode == 200) { + final _bodyJson = _response.bodyJson; + print(_bodyJson); + } else { + print('Request failed with status: ${_response.statusCode}.'); + } +} diff --git a/isolate_http/lib/isolate_http.dart b/isolate_http/lib/isolate_http.dart new file mode 100644 index 0000000..bd89f4d --- /dev/null +++ b/isolate_http/lib/isolate_http.dart @@ -0,0 +1,7 @@ +library isolate_http; + +export 'src/http_file.dart'; +export 'src/http_method.dart'; +export 'src/isolate_http.dart'; +export 'src/isolate_http_request.dart'; +export 'src/isolate_http_response.dart'; diff --git a/isolate_http/lib/src/http_file.dart b/isolate_http/lib/src/http_file.dart new file mode 100644 index 0000000..625e09b --- /dev/null +++ b/isolate_http/lib/src/http_file.dart @@ -0,0 +1,68 @@ +import 'package:http/http.dart'; +import 'package:http_parser/http_parser.dart'; + +/// A file to be uploaded as part of a [IsolateHttp]. +class HttpFile { + /// The name of the form field for the file. + final String field; + + /// Byte array of the file. + final List bytes; + + /// The path to a file on disk. + final String filePath; + + /// The encoding to use when translating [value] into bytes is taken from + /// [contentType] if it has a charset set. Otherwise, it defaults to UTF-8. + /// [contentType] currently defaults to `text/plain; charset=utf-8`, but in + /// the future may be inferred from [filename]. + final String value; + + /// The basename of the file. + final String filename; + + /// The content-type of the file. + final MediaType contentType; + + HttpFile._(this.field, + {this.bytes, this.filePath, this.value, this.filename, this.contentType}); + + /// Creates a new [HttpFile] from a byte array. + factory HttpFile.fromBytes(String field, List bytes, + {String filename, MediaType contentType}) { + return HttpFile._(field, + bytes: bytes, filename: filename, contentType: contentType); + } + + /// Creates a new [HttpFile] from a path to a file on disk. + factory HttpFile.fromPath(String field, String filePath, + {String filename, MediaType contentType}) { + return HttpFile._(field, + filePath: filePath, filename: filename, contentType: contentType); + } + + /// Creates a new [HttpFile] from a string. + factory HttpFile.fromString(String field, String value, + {String filename, MediaType contentType}) { + return HttpFile._(field, + value: value, filename: filename, contentType: contentType); + } + + /// Convert [HttpFile] to [MultipartFile]. + /// + /// A file to be uploaded as part of a [MultipartRequest]. + /// This doesn't need to correspond to a physical file. + Future toMultipartFile() async { + if (bytes != null) { + return MultipartFile.fromBytes(field, bytes, + filename: filename, contentType: contentType); + } else if (filePath != null) { + return MultipartFile.fromPath(field, filePath, + filename: filename, contentType: contentType); + } else if (value != null) { + return MultipartFile.fromString(field, value, + filename: filename, contentType: contentType); + } + return null; + } +} diff --git a/isolate_http/lib/src/http_method.dart b/isolate_http/lib/src/http_method.dart new file mode 100644 index 0000000..1f47f91 --- /dev/null +++ b/isolate_http/lib/src/http_method.dart @@ -0,0 +1,20 @@ +abstract class HttpMethod { + /// [get] is used to request data from a specified resource. + static const get = 'GET'; + + /// [post] is used to send data to a server to create/update a resource. + static const post = 'POST'; + + /// [head] is almost identical to GET, but without the response body. + static const head = 'HEAD'; + + /// [put] is used to send data to a server to create/update a resource. + /// + /// The difference between POST and PUT is that PUT requests are idempotent. + /// That is, calling the same PUT request multiple times will always produce the same result. + /// In contrast, calling a POST request repeatedly have side effects of creating the same resource multiple times. + static const put = 'PUT'; + + /// The [delete] method deletes the specified resource. + static const delete = 'DELETE'; +} diff --git a/isolate_http/lib/src/isolate_http.dart b/isolate_http/lib/src/isolate_http.dart new file mode 100644 index 0000000..bf8cd16 --- /dev/null +++ b/isolate_http/lib/src/isolate_http.dart @@ -0,0 +1,90 @@ +import 'package:http/http.dart'; + +import 'package:isolate_flutter/isolate_flutter.dart'; + +import 'package:isolate_http/src/http_file.dart'; +import 'package:isolate_http/src/http_method.dart'; +import 'package:isolate_http/src/isolate_http_request.dart'; +import 'package:isolate_http/src/isolate_http_response.dart'; + +/// Isolate Http +/// +/// [head], [get], [post], [put], [delete], [send] +class IsolateHttp { + const IsolateHttp(); + + /// Sends an HTTP HEAD request with the given headers to the given URL. + Future head(String url, + {Map query, Map headers}) async { + final _isolateHttpRequest = IsolateHttpRequest(url, + method: HttpMethod.head, query: query, headers: headers); + return send(_isolateHttpRequest); + } + + /// Sends an HTTP GET request with the given headers to the given URL. + Future get(String url, + {Map query, Map headers}) async { + final _isolateHttpRequest = IsolateHttpRequest(url, + method: HttpMethod.get, query: query, headers: headers); + return send(_isolateHttpRequest); + } + + /// Sends an HTTP POST request with the given headers and body to the given URL. + Future post(String url, + {Map query, + Map headers, + Map body, + List files}) async { + final _isolateHttpRequest = IsolateHttpRequest(url, + method: HttpMethod.post, + query: query, + headers: headers, + body: body, + files: files); + return send(_isolateHttpRequest); + } + + /// Sends an HTTP PUT request with the given headers and body to the given URL. + Future put(String url, + {Map query, + Map headers, + Map body, + List files}) async { + final _isolateHttpRequest = IsolateHttpRequest(url, + method: HttpMethod.put, + query: query, + headers: headers, + body: body, + files: files); + return send(_isolateHttpRequest); + } + + /// Sends an HTTP DELETE request with the given headers to the given URL. + Future delete(String url, + {Map query, + Map headers, + Map body}) async { + final _isolateHttpRequest = IsolateHttpRequest(url, + method: HttpMethod.delete, query: query, headers: headers, body: body); + return send(_isolateHttpRequest); + } + + /// Sends an [IsolateHttpRequest] and returns the [IsolateHttpResponse]. + Future send(IsolateHttpRequest request) async { + final _isolateHttpResponse = + await IsolateFlutter.createAndStart(_call, request); + return _isolateHttpResponse; + } +} + +Future _call(IsolateHttpRequest isolateHttpRequest) async { + final _request = await isolateHttpRequest.toRequest(); + if (_request != null) { + final streamedResponse = await _request.send(); + final httpResponse = await Response.fromStream(streamedResponse); + final _isolateHttpResponse = IsolateHttpResponse( + httpResponse.body, httpResponse.statusCode, httpResponse.headers); + return _isolateHttpResponse; + } + return null; +} diff --git a/isolate_http/lib/src/isolate_http_request.dart b/isolate_http/lib/src/isolate_http_request.dart new file mode 100644 index 0000000..cbc6a65 --- /dev/null +++ b/isolate_http/lib/src/isolate_http_request.dart @@ -0,0 +1,82 @@ +import 'dart:convert'; + +import 'package:http/http.dart'; + +import 'package:isolate_http/src/http_file.dart'; +import 'package:isolate_http/src/http_method.dart'; + +class IsolateHttpRequest { + /// The url to which the request will be sent. + final String url; + + /// The [HttpMethod] of the request. + /// + /// Most commonly "GET" or "POST", less commonly "HEAD", "PUT", or "DELETE". + /// Non-standard method names are also supported. + final String method; + + /// List [queryParameters] in [http] + final Map query; + + /// The headers of the request. + final Map headers; + + /// The body of the request. + final Map body; + + /// List of files to be uploaded of the request. + final List files; + + IsolateHttpRequest( + this.url, { + this.method = HttpMethod.get, + this.query, + this.headers, + this.body, + this.files, + }); + + Uri get uri { + String _requestUrl = url; + if (query?.isNotEmpty == true) { + final _queryString = Uri(queryParameters: query).query; + _requestUrl += '?$_queryString'; + } + return Uri.tryParse(_requestUrl); + } + + /// Convert [IsolateHttpRequest] to [BaseRequest] (The base class for HTTP requests). + Future toRequest() async { + final _uri = uri; + if (_uri != null) { + if (files?.isNotEmpty == true) { + MultipartRequest _request = MultipartRequest(method, _uri); + if (headers?.isNotEmpty == true) { + _request.headers.addAll(headers); + } + + body?.forEach((key, value) { + _request.fields[key] = jsonEncode(value); + }); + + for (var file in files) { + final _file = await file.toMultipartFile(); + if (_file != null) { + _request.files.add(_file); + } + } + return _request; + } else { + Request _request = Request(method, _uri); + if (headers?.isNotEmpty == true) { + _request.headers.addAll(headers); + } + if (body?.isNotEmpty == true) { + _request.body = jsonEncode(body); + } + return _request; + } + } + return null; + } +} diff --git a/isolate_http/lib/src/isolate_http_response.dart b/isolate_http/lib/src/isolate_http_response.dart new file mode 100644 index 0000000..7a82b50 --- /dev/null +++ b/isolate_http/lib/src/isolate_http_response.dart @@ -0,0 +1,28 @@ +import 'dart:convert'; + +/// The response using for Isolate Http. +class IsolateHttpResponse { + /// The body of the response as a String. + final String body; + + /// The headers of the response as a Map. + final Map headers; + + /// The status code of the response as int. + final int statusCode; + + IsolateHttpResponse(this.body, this.statusCode, this.headers); + + /// Return the body as as Json (dynamic). + dynamic get bodyJson => jsonDecode(body); + + /// Return the body as as Map. + Map get bodyAsMap => bodyJson is Map + ? bodyJson + : throw ArgumentError("body is not Map"); + + /// Return the body as as List. + List get bodyAsList => bodyJson is List + ? bodyJson + : throw ArgumentError("body is not List"); +} diff --git a/isolate_http/pubspec.lock b/isolate_http/pubspec.lock new file mode 100644 index 0000000..a0fc4b6 --- /dev/null +++ b/isolate_http/pubspec.lock @@ -0,0 +1,113 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + characters: + dependency: transitive + description: + name: characters + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + charcode: + dependency: transitive + description: + name: charcode + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.3" + collection: + dependency: transitive + description: + name: collection + url: "https://pub.dartlang.org" + source: hosted + version: "1.14.13" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + http: + dependency: "direct main" + description: + name: http + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.2" + http_parser: + dependency: "direct main" + description: + name: http_parser + url: "https://pub.dartlang.org" + source: hosted + version: "3.1.4" + isolate_flutter: + dependency: "direct main" + description: + name: isolate_flutter + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + meta: + dependency: transitive + description: + name: meta + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.8" + path: + dependency: transitive + description: + name: path + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + pedantic: + dependency: transitive + description: + name: pedantic + url: "https://pub.dartlang.org" + source: hosted + version: "1.9.0" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.99" + source_span: + dependency: transitive + description: + name: source_span + url: "https://pub.dartlang.org" + source: hosted + version: "1.7.0" + string_scanner: + dependency: transitive + description: + name: string_scanner + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.5" + term_glyph: + dependency: transitive + description: + name: term_glyph + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + typed_data: + dependency: transitive + description: + name: typed_data + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" + vector_math: + dependency: transitive + description: + name: vector_math + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.8" +sdks: + dart: ">=2.9.0-14.0.dev <3.0.0" diff --git a/isolate_http/pubspec.yaml b/isolate_http/pubspec.yaml new file mode 100644 index 0000000..be758ee --- /dev/null +++ b/isolate_http/pubspec.yaml @@ -0,0 +1,16 @@ +name: isolate_http +description: IsolateHttp provides a way to launch 'http' library in Isolate with IsolatesFlutter. +version: 1.0.0 +homepage: https://github.com/thongdn-it/isolate_flutter/tree/master/isolate_http +repository: https://github.com/thongdn-it/isolate_flutter/tree/master/isolate_http + +environment: + sdk: ">=2.7.0 <3.0.0" + +dependencies: + flutter: + sdk: flutter + + isolate_flutter: ^1.0.0 + http: ^0.12.0 + http_parser: ">=0.0.1 <4.0.0" \ No newline at end of file