OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, the Dartino project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 import 'dart:dartino'; | |
6 import 'dart:typed_data'; | |
7 | |
8 import 'package:file/file.dart'; | |
9 import 'package:http/http.dart'; | |
10 import 'package:socket/socket.dart'; | |
11 | |
12 abstract class _Connection { | |
13 final String host; | |
14 final int port; | |
15 final bool open; | |
16 void close(); | |
17 Socket accept(); | |
18 } | |
19 | |
20 class _ConnectionImpl implements _Connection { | |
21 final String host; | |
22 ServerSocket _socket; | |
23 get port => _socket.port; | |
24 _ConnectionImpl(this.host, port) { | |
25 _socket = new ServerSocket(host, port); | |
26 } | |
27 bool get open => _socket != null; | |
28 void close() { | |
29 if (!open) return; | |
30 _socket.close(); | |
31 _socket = null; | |
32 } | |
33 Socket accept() => _socket.accept(); | |
34 } | |
35 | |
36 class _ConnectionInvertedImpl implements _Connection { | |
37 final String host = '127.0.0.1'; | |
38 final int port; | |
39 bool open = true; | |
40 _ConnectionInvertedImpl(this.port) { | |
41 // Signal availability to the "client". | |
42 accept().close(); | |
43 } | |
44 void close() { | |
45 open = false; | |
46 } | |
47 Socket accept() { | |
48 return new Socket.connect(host, port); | |
49 } | |
50 } | |
51 | |
52 abstract class DataStorage { | |
53 ByteBuffer readResponseFile(String resource); | |
54 | |
55 String encode(String resource) { | |
56 List<String> parts = resource.split('/'); | |
57 parts.add(Uri.encodeComponent(parts.removeLast())); | |
58 return parts.join('/'); | |
59 } | |
60 } | |
61 | |
62 class FileDataStorage extends DataStorage { | |
63 String _dataDir = 'samples/github/lib/src/github_mock_data'; | |
64 | |
65 ByteBuffer readResponseFile(String resource) { | |
66 String path = '$_dataDir/${encode(resource)}.data'; | |
67 if (File.existsAsFile(path)) { | |
68 File file = new File.open(path); | |
69 return file.read(file.length); | |
70 } | |
71 return null; | |
72 } | |
73 } | |
74 | |
75 class GithubMock { | |
76 final int delay; | |
77 bool verbose = false; | |
78 DataStorage dataStorage = new FileDataStorage(); | |
79 _Connection _connection; | |
80 static const String _requestSuffix = ' HTTP/1.1'; | |
81 | |
82 String get host => _connection.host; | |
83 int get port => _connection.port; | |
84 | |
85 GithubMock([host = '127.0.0.1', int port = 0, int this.delay = 0]) { | |
86 _connection = new _ConnectionImpl(host, port); | |
87 } | |
88 | |
89 GithubMock.invertedForTesting(int port, [int this.delay = 0]) { | |
90 _connection = new _ConnectionInvertedImpl(port); | |
91 } | |
92 | |
93 void close() { | |
94 _connection.close(); | |
95 } | |
96 | |
97 void spawn() { | |
98 Fiber.fork(run); | |
99 } | |
100 | |
101 void run() { | |
102 if (verbose) print('Running server on $host:$port'); | |
103 while (_connection.open) { | |
104 try { | |
105 _accept(_connection.accept()); | |
106 } on SocketException catch (_) { | |
107 // outstanding accept throws when the server closes. | |
108 } | |
109 } | |
110 if (verbose) print('Terminated server'); | |
111 } | |
112 | |
113 void _accept(Socket socket) { | |
114 if (delay > 0) sleep(delay); | |
115 var data = new Uint8List.view(socket.readNext()); | |
116 var request = new String.fromCharCodes(data); | |
117 | |
118 // TODO(zerny): Use String.indexOf for start/end once implemented. | |
119 int start = -1; | |
120 for (int i = 0; i < request.length; ++i) { | |
121 if (request[i] == '/') { | |
122 start = i + 1; | |
123 break; | |
124 } | |
125 } | |
126 if (start < 0) { | |
127 print('GithubMock: Ill-formed request.'); | |
128 socket.close(); | |
129 return; | |
130 } | |
131 | |
132 int end = -1; | |
133 for (int i = start; i < request.length; ++i) { | |
134 if (_requestSuffix == request.substring(i, i + _requestSuffix.length)) { | |
135 end = i; | |
136 break; | |
137 } | |
138 } | |
139 if (end < 0) { | |
140 print('GithubMock: Ill-formed request.'); | |
141 socket.close(); | |
142 return; | |
143 } | |
144 | |
145 String resource = request.substring(start, end); | |
146 int code = 200; | |
147 var response = dataStorage.readResponseFile(resource); | |
148 | |
149 if (response == null) { | |
150 code = 404; | |
151 response = dataStorage.readResponseFile('404'); | |
152 } | |
153 | |
154 if (verbose) { | |
155 print('Response $code on request for $resource'); | |
156 } | |
157 | |
158 socket.write(response); | |
159 socket.close(); | |
160 } | |
161 } | |
OLD | NEW |