Line data Source code
1 :
2 : import 'package:args/args.dart';
3 : import 'package:check/returned_data.dart';
4 : import 'package:http/http.dart';
5 :
6 : const String version = 'dev';
7 :
8 : enum Method { head, get, post, put, patch, delete }
9 :
10 1 : ArgParser buildParser() {
11 1 : return ArgParser()
12 1 : ..addFlag(
13 : 'help',
14 : abbr: 'h',
15 : negatable: false,
16 : help: 'Print this usage information.',
17 : )
18 1 : ..addOption(
19 : 'timeout',
20 : abbr: 't',
21 : help: 'Set the timeout for the request.',
22 : defaultsTo: '10',
23 : valueHelp: 'in seconds',
24 : )
25 1 : ..addOption(
26 : 'content-type',
27 : help: 'Set the content type for the request.',
28 : defaultsTo: 'application/json',
29 : valueHelp: 'type',
30 : )
31 1 : ..addOption(
32 : 'user-agent',
33 : help: 'Set the user agent for the request.',
34 : defaultsTo: 'check/$version',
35 : valueHelp: 'agent',
36 : )
37 1 : ..addFlag('fail', help: 'Fail on non-200 status code.', defaultsTo: true)
38 1 : ..addFlag(
39 : 'verbose',
40 : abbr: 'v',
41 : negatable: false,
42 : help: 'Show additional command output.',
43 : )
44 1 : ..addFlag('version', negatable: false, help: 'Print the tool version.');
45 : }
46 :
47 0 : void printUsage(ArgParser argParser) {
48 0 : print('Usage: check <flags> [METHOD] URL');
49 0 : print(argParser.usage);
50 : }
51 :
52 1 : Future<ReturnedData> check(List<String> arguments) async {
53 1 : final ArgParser argParser = buildParser();
54 : try {
55 1 : final ArgResults results = argParser.parse(arguments);
56 1 : final verbose = results.wasParsed('verbose');
57 : Method method = Method.get;
58 : int urlPos = 0;
59 : Duration timeout = const Duration(seconds: 10);
60 :
61 1 : if (results.wasParsed('help')) {
62 0 : printUsage(argParser);
63 0 : return ReturnedData.empty();
64 : }
65 :
66 1 : if (results.wasParsed('version')) {
67 0 : print('check version: $version');
68 0 : return ReturnedData.empty();
69 : }
70 :
71 1 : if (results.wasParsed('timeout')) {
72 : try {
73 0 : final int value = int.parse(results['timeout']);
74 0 : if (value < 1) {
75 0 : throw FormatException('Invalid timeout value: ${results['timeout']}');
76 : }
77 0 : timeout = Duration(seconds: value);
78 0 : } on Exception {
79 0 : throw FormatException('Invalid timeout value: ${results['timeout']}');
80 : }
81 : }
82 :
83 : if (verbose) {
84 0 : print('[VERBOSE] Positional arguments: ${results.rest}');
85 0 : print('[VERBOSE] All arguments: ${results.arguments}');
86 : }
87 :
88 2 : if (results.rest.isEmpty) {
89 : throw const FormatException('No URL provided.');
90 : }
91 :
92 : try {
93 4 : method = Method.values.byName(results.rest.first.toLowerCase());
94 : urlPos = 1;
95 1 : } on Error {
96 0 : if (verbose) print('[VERBOSE] Using default method: GET');
97 : }
98 :
99 0 : if (verbose) print('[VERBOSE] Method: $method');
100 :
101 3 : if (results.rest.length <= urlPos) {
102 : throw const FormatException('No URL provided.');
103 : }
104 :
105 2 : String url = results.rest[urlPos];
106 :
107 2 : if (url.startsWith(RegExp(r':\d+'))) {
108 1 : url = 'http://localhost$url';
109 : }
110 :
111 0 : if (verbose) print('[VERBOSE] URL: $url');
112 :
113 1 : Uri uri = Uri.parse(url);
114 :
115 2 : if (uri.scheme.isEmpty) {
116 0 : uri = Uri.parse('http://$uri');
117 : }
118 :
119 0 : if (verbose) print('[VERBOSE] URI: $uri');
120 :
121 1 : final Map<String, String> headers = <String, String>{
122 1 : 'User-Agent': results['user-agent'],
123 1 : 'Content-Type': results['content-type'],
124 : };
125 :
126 : Response response;
127 :
128 : switch (method) {
129 1 : case Method.head:
130 0 : if (verbose) print('[VERBOSE] HEAD: $uri');
131 2 : response = await head(uri, headers: headers).timeout(timeout);
132 1 : case Method.get:
133 0 : if (verbose) print('[VERBOSE] GET: $uri');
134 2 : response = await get(uri, headers: headers).timeout(timeout);
135 1 : case Method.post:
136 0 : if (verbose) print('[VERBOSE] POST: $uri');
137 2 : response = await post(uri, headers: headers).timeout(timeout);
138 1 : case Method.put:
139 0 : if (verbose) print('[VERBOSE] PUT: $uri');
140 2 : response = await put(uri, headers: headers).timeout(timeout);
141 1 : case Method.patch:
142 0 : if (verbose) print('[VERBOSE] PATCH: $uri');
143 2 : response = await patch(uri, headers: headers).timeout(timeout);
144 1 : case Method.delete:
145 0 : if (verbose) print('[VERBOSE] DELETE: $uri');
146 2 : response = await delete(uri, headers: headers).timeout(timeout);
147 : }
148 :
149 1 : final int code = response.statusCode;
150 :
151 0 : if (verbose) print('[VERBOSE] Status code: $code');
152 :
153 : int exitCode;
154 :
155 1 : if (code < 199) {
156 : exitCode = 9;
157 2 : } else if (code >= 200 && code < 300) {
158 : exitCode = 0;
159 1 : } else if (code >= 545) {
160 : exitCode = 255;
161 : } else {
162 1 : exitCode = code - 290;
163 : }
164 :
165 1 : return ReturnedData(
166 : exitCode: exitCode,
167 : statusCode: code,
168 1 : canFail: results['fail'],
169 : );
170 0 : } on FormatException catch (e) {
171 0 : print('');
172 0 : print(e.message);
173 0 : print('');
174 0 : printUsage(argParser);
175 0 : return ReturnedData(exitCode: 1, statusCode: 0, canFail: true);
176 0 : } on Exception catch (e) {
177 0 : print('');
178 0 : print(e);
179 0 : print('');
180 0 : return ReturnedData(exitCode: 7, statusCode: 0, canFail: true);
181 0 : } on Error catch (e) {
182 0 : print('');
183 0 : print(e);
184 0 : print('');
185 0 : return ReturnedData(exitCode: 8, statusCode: 0, canFail: true);
186 : }
187 : }
|