Skip to content

Commit

Permalink
Better content
Browse files Browse the repository at this point in the history
  • Loading branch information
rk0cc committed Jan 10, 2024
1 parent ce81fd6 commit 8a31aa9
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 156 deletions.
4 changes: 4 additions & 0 deletions model/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 3.3.2

* More readability for client source codes.

## 3.3.1

* Remove `testing` library annotations.
Expand Down
73 changes: 73 additions & 0 deletions model/lib/src/client/client.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import 'dart:math' show Random;

import 'package:http/http.dart'
hide delete, get, head, patch, post, put, read, readBytes, runWithClient;
import 'package:http/testing.dart';
import 'package:meta/meta.dart';

import '../disguise_ua/disguise_ua.dart';
import '../exception/content_type_mismatched.dart';
import '../fetch/fetch.dart' show MetaFetch;

part 'mock_client.dart';

/// [Client] implementation for OgHref packages.
@internal
final class OgHrefClient extends BaseClient {
/// Default request user agent value.
static const String DEFAULT_USER_AGENT_STRING = "oghref/2";

/// Default timeout duration in seconds.
static const int DEFAULT_TIMEOUT = 10;

/// Allow redirection if necessary.
final bool redirect;

final Client _c = Client();

/// Current user agent preference of following requests.
static String _userAgent = DEFAULT_USER_AGENT_STRING;

/// Specify new value of user agent if offered.
static set userAgent(String value) {
_userAgent = value;
}

/// Return current user agent string.
///
/// If [disguise] enabled, it returns [disguisedUserAgent] instead of
/// user defined.
static String get userAgent {
if (disguise) {
try {
return disguisedUserAgent;
} on UnsupportedError {
// Mostly triggered if running in VM.
}
}

return _userAgent;
}

/// Specify timeout of response after specific seconds.
static int timeoutAt = DEFAULT_TIMEOUT;

/// If implemented under HTML, [userAgent] will be replaced by browser
/// provided one when making request.
static bool disguise = true;

OgHrefClient(this.redirect);

@override
Future<StreamedResponse> send(BaseRequest request) {
request
..headers["user-agent"] = userAgent
..followRedirects = redirect;
return _c.send(request).timeout(Duration(seconds: timeoutAt));
}

@override
void close() {
_c.close();
}
}
237 changes: 85 additions & 152 deletions model/lib/src/client.dart → model/lib/src/client/mock_client.dart
Original file line number Diff line number Diff line change
@@ -1,150 +1,7 @@
import 'dart:math' show Random;
part of 'client.dart';

import 'package:http/http.dart'
hide delete, get, head, patch, post, put, read, readBytes, runWithClient;
import 'package:http/testing.dart';
import 'package:meta/meta.dart';

import 'disguise_ua/disguise_ua.dart';
import 'exception/content_type_mismatched.dart';
import 'fetch/fetch.dart' show MetaFetch;

/// [Client] implementation for OgHref packages.
@internal
final class OgHrefClient extends BaseClient {
/// Default request user agent value.
static const String DEFAULT_USER_AGENT_STRING = "oghref/2";

/// Default timeout duration in seconds.
static const int DEFAULT_TIMEOUT = 10;

/// Allow redirection if necessary.
final bool redirect;

final Client _c = Client();

/// Current user agent preference of following requests.
static String _userAgent = DEFAULT_USER_AGENT_STRING;

/// Specify new value of user agent if offered.
static set userAgent(String value) {
_userAgent = value;
}

/// Return current user agent string.
///
/// If [disguise] enabled, it returns [disguisedUserAgent] instead of
/// user defined.
static String get userAgent {
if (disguise) {
try {
return disguisedUserAgent;
} on UnsupportedError {
// Mostly triggered if running in VM.
}
}

return _userAgent;
}

/// Specify timeout of response after specific seconds.
static int timeoutAt = DEFAULT_TIMEOUT;

/// If implemented under HTML, [userAgent] will be replaced by browser
/// provided one when making request.
static bool disguise = true;

OgHrefClient(this.redirect);

@override
Future<StreamedResponse> send(BaseRequest request) {
request
..headers["user-agent"] = userAgent
..followRedirects = redirect;
return _c.send(request).timeout(Duration(seconds: timeoutAt));
}

@override
void close() {
_c.close();
}
}

/// Simulated environment based on [MockClient] that
/// all generated content are specified by
/// tester already.
final class MockOgHrefClient extends BaseClient
implements MockClient, OgHrefClient {
@override
late final Client _c;

/// Redirect features is always disabled for [MockOgHrefClient].
@override
bool get redirect => false;

/// Define new replicated [Client] for executing under
/// test environment.
///
/// All expected content in specific links should be stored
/// into [contentLinker] which is a [Map] with [Uri] key and
/// [String] value to denotes expected content in [contentType]
/// when "surfing" URL. If the incoming [Request.url]
/// can be found in [contentLinker], the returned [Response]
/// will provided content of the [Uri] in status code `200`.
/// Otherwise, it returns empty [String] with status code
/// `404`.
///
/// Default [contentType] uses `text/plain` as returned value
/// when making [Response]. However, there are only three
/// eligable values can be used without throwing [ContentTypeMismatchedException]
/// in [MetaFetch.fetchFromHttp] or [MetaFetch.fetchAllFromHttp] that
/// they are the most suitable type for using in webpage:
///
/// * `text/plain`
/// * `text/html`
/// * `application/xhtml+xml`
///
/// Moreover, every [Uri] mapped in [contentLinker] **MUST BE** used
/// `HTTP(S)` protocol. If at least one [Uri.scheme] return other than
/// `HTTP(S)`, it throws [ArgumentError].
MockOgHrefClient(Map<Uri, String> contentLinker,
{String contentType = "text/plain"}) {
if (contentLinker.keys.any((element) => !_isHttpScheme(element))) {
throw ArgumentError(
"Content linker's URL must be assigned with HTTP(S) scheme.");
}

_c = MockClient((request) {
final Map<Uri, String> ctxLinker = Map.unmodifiable(contentLinker);

Uri incomingUrl = request.url;

if (!_isHttpScheme(incomingUrl)) {
throw ClientException(
"The request should be HTTP(S), eventhough is mock client.");
}

return Future.delayed(Duration(milliseconds: Random().nextInt(750) + 250),
() {
String? bodyCtx = ctxLinker[incomingUrl];

if (bodyCtx == null) {
return Response("", 404,
headers: {"content-type": contentType}, request: request);
}

return Response(bodyCtx, 200,
headers: {"content-type": contentType}, request: request);
});
});
}

/// Uses [sample files](https://github.com/rk0cc/oghref/tree/main/model/sample) to defined
/// content of the simulated HTML files with hosted IP address as `127.0.0.2` with `HTTPS`
/// protocol.
factory MockOgHrefClient.usesSample() => MockOgHrefClient({
Uri.parse("https://127.0.0.2/1.html"): r"""
<!DOCTYPE html>
const List<String> _sampleContents = [
r"""<!DOCTYPE html>
<html>
<head>
<title>Sample 1</title>
Expand All @@ -162,8 +19,7 @@ final class MockOgHrefClient extends BaseClient
</body>
</html>
""",
Uri.parse("https://127.0.0.2/2.html"): r"""
<!DOCTYPE html>
r"""<!DOCTYPE html>
<html>
<head>
<title>Sample 2</title>
Expand All @@ -183,8 +39,7 @@ final class MockOgHrefClient extends BaseClient
</body>
</html>
""",
Uri.parse("https://127.0.0.2/3.html"): r"""
<!DOCTYPE html>
r"""<!DOCTYPE html>
<!-- This file suppose read absolutely noting -->
<html>
<head>
Expand Down Expand Up @@ -224,8 +79,7 @@ final class MockOgHrefClient extends BaseClient
</body>
</html>
""",
Uri.parse("https://127.0.0.2/4.html"): r"""
<!DOCTYPE html>
r"""<!DOCTYPE html>
<html>
<head>
<title>Sample 1</title>
Expand All @@ -243,6 +97,85 @@ final class MockOgHrefClient extends BaseClient
</body>
</html>
"""
];

final Uri _sampleMockHost = Uri.https("127.0.0.2");

/// Simulated environment based on [MockClient] that
/// all generated content are specified by
/// tester already.
final class MockOgHrefClient extends BaseClient
implements MockClient, OgHrefClient {
@override
late final Client _c;

/// Redirect features is always disabled for [MockOgHrefClient].
@override
bool get redirect => false;

/// Define new replicated [Client] for executing under
/// test environment.
///
/// All expected content in specific links should be stored
/// into [contentLinker] which is a [Map] with [Uri] key and
/// [String] value to denotes expected content in [contentType]
/// when "surfing" URL. If the incoming [Request.url]
/// can be found in [contentLinker], the returned [Response]
/// will provided content of the [Uri] in status code `200`.
/// Otherwise, it returns empty [String] with status code
/// `404`.
///
/// Default [contentType] uses `text/plain` as returned value
/// when making [Response]. However, there are only three
/// eligable values can be used without throwing [ContentTypeMismatchedException]
/// in [MetaFetch.fetchFromHttp] or [MetaFetch.fetchAllFromHttp] that
/// they are the most suitable type for using in webpage:
///
/// * `text/plain`
/// * `text/html`
/// * `application/xhtml+xml`
///
/// Moreover, every [Uri] mapped in [contentLinker] **MUST BE** used
/// `HTTP(S)` protocol. If at least one [Uri.scheme] return other than
/// `HTTP(S)`, it throws [ArgumentError].
MockOgHrefClient(Map<Uri, String> contentLinker,
{String contentType = "text/plain"}) {
if (contentLinker.keys.any((element) => !_isHttpScheme(element))) {
throw ArgumentError(
"Content linker's URL must be assigned with HTTP(S) scheme.");
}

_c = MockClient((request) {
final Map<Uri, String> ctxLinker = Map.unmodifiable(contentLinker);

Uri incomingUrl = request.url;

if (!_isHttpScheme(incomingUrl)) {
throw ClientException(
"The request should be HTTP(S), eventhough is mock client.");
}

return Future.delayed(Duration(milliseconds: Random().nextInt(750) + 250),
() {
String? bodyCtx = ctxLinker[incomingUrl];

if (bodyCtx == null) {
return Response("", 404,
headers: {"content-type": contentType}, request: request);
}

return Response(bodyCtx, 200,
headers: {"content-type": contentType}, request: request);
});
});
}

/// Uses [sample files](https://github.com/rk0cc/oghref/tree/main/model/sample) to defined
/// content of the simulated HTML files with hosted IP address as `127.0.0.2` with `HTTPS`
/// protocol.
factory MockOgHrefClient.usesSample() => MockOgHrefClient(<Uri, String>{
for (int idx = 0; idx < _sampleContents.length; idx++)
_sampleMockHost.resolve("${idx + 1}.html"): _sampleContents[idx]
});

static bool _isHttpScheme(Uri url) {
Expand Down
2 changes: 1 addition & 1 deletion model/lib/src/content_type_verifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:meta/meta.dart';
import 'package:mime_dart/mime_dart.dart';
import 'package:path/path.dart' as p;

import 'client.dart';
import 'client/client.dart';
import 'model/url.dart';

/// Determine the content type category from MIME.
Expand Down
2 changes: 1 addition & 1 deletion model/lib/src/fetch/fetch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import '../exception/content_type_mismatched.dart';
import '../exception/non_http_url.dart';
import '../model/metainfo.dart';
import '../parser/property_parser.dart';
import '../client.dart';
import '../client/client.dart';
import '../content_type_verifier.dart';

part 'producer.dart';
Expand Down
2 changes: 1 addition & 1 deletion model/lib/testing.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
library testing;

export 'src/fetch/fetch.dart' show MetaFetchTester, MockOgHrefClientConstructor;
export 'src/client.dart' show MockOgHrefClient;
export 'src/client/client.dart' show MockOgHrefClient;
2 changes: 1 addition & 1 deletion model/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: oghref_model
description: Object standarized definition with parser interface for constructing rich information of given URL among various metadata protocols.
version: 3.3.1
version: 3.3.2
repository: https://github.com/rk0cc/oghref/tree/main/model
issue_tracker: https://github.com/rk0cc/oghref/issues
funding:
Expand Down

0 comments on commit 8a31aa9

Please sign in to comment.