Sudden crashes, yay!
This commit is contained in:
parent
8a1b95c352
commit
e0ef7ba79a
17 changed files with 391 additions and 87 deletions
8
Makefile
8
Makefile
|
@ -16,12 +16,9 @@ clean:
|
||||||
find . -type f -name '*.dylib' -delete
|
find . -type f -name '*.dylib' -delete
|
||||||
find . -type f -name '*.dill' -delete
|
find . -type f -name '*.dill' -delete
|
||||||
|
|
||||||
%-run: % example/main.dart
|
%-run: % example/main.dill
|
||||||
dart example/main.dill
|
dart example/main.dill
|
||||||
|
|
||||||
example/main.dill: ./**/*.dart
|
|
||||||
dart --snapshot="$@" example/main.dart
|
|
||||||
|
|
||||||
mac: libangel_wings.dylib
|
mac: libangel_wings.dylib
|
||||||
|
|
||||||
linux: lib/src/libangel_wings.so
|
linux: lib/src/libangel_wings.so
|
||||||
|
@ -42,3 +39,6 @@ lib/src/libangel_wings.dylib: $(objects)
|
||||||
|
|
||||||
%.o: %.cc lib/src/angel_wings.h %.h
|
%.o: %.cc lib/src/angel_wings.h %.h
|
||||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
%.dill: %.dart
|
||||||
|
dart --snapshot="$@" $<
|
23
benchmark/empty.dart
Normal file
23
benchmark/empty.dart
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'util.dart';
|
||||||
|
|
||||||
|
const AngelBenchmark emptyBenchmark = _EmptyBenchmark();
|
||||||
|
|
||||||
|
main() => runBenchmarks([emptyBenchmark]);
|
||||||
|
|
||||||
|
class _EmptyBenchmark implements AngelBenchmark {
|
||||||
|
const _EmptyBenchmark();
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get name => 'empty';
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<void> rawHandler(HttpRequest req, HttpResponse res) {
|
||||||
|
return res.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setupAngel(Angel app) {}
|
||||||
|
}
|
110
benchmark/util.dart
Normal file
110
benchmark/util.dart
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:isolate';
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:angel_framework/http.dart';
|
||||||
|
import 'package:angel_wings/angel_wings.dart';
|
||||||
|
import 'package:io/ansi.dart';
|
||||||
|
import 'package:pedantic/pedantic.dart';
|
||||||
|
import 'package:tuple/tuple.dart';
|
||||||
|
|
||||||
|
Future<Process> _runWrk(
|
||||||
|
{ProcessStartMode mode = ProcessStartMode.inheritStdio}) async {
|
||||||
|
return await Process.start('wrk', ['http://localhost:$testPort'], mode: mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _warmUp() async {
|
||||||
|
var wrk = await _runWrk();
|
||||||
|
await wrk.exitCode;
|
||||||
|
// await wrk.stderr.drain();
|
||||||
|
// await wrk.stdout.drain();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _10s() => Future.delayed(Duration(seconds: 10));
|
||||||
|
|
||||||
|
const testPort = 8877;
|
||||||
|
|
||||||
|
Future<void> runBenchmarks(Iterable<AngelBenchmark> benchmarks,
|
||||||
|
{Iterable<String> factories = const [
|
||||||
|
// 'angel_http',
|
||||||
|
'angel_wings',
|
||||||
|
]}) async {
|
||||||
|
for (var benchmark in benchmarks) {
|
||||||
|
print(magenta.wrap('Entering benchmark: ${benchmark.name}'));
|
||||||
|
|
||||||
|
// // Run dart:io
|
||||||
|
// print(lightGray.wrap('Booting dart:io server (waiting 10s)...'));
|
||||||
|
// var isolates = <Isolate>[];
|
||||||
|
// for (int i = 0; i < Platform.numberOfProcessors; i++) {
|
||||||
|
// isolates.add(await Isolate.spawn(_httpIsolate, benchmark));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// await _10s();
|
||||||
|
// print(lightGray.wrap('Warming up dart:io server...'));
|
||||||
|
// await _warmUp();
|
||||||
|
|
||||||
|
// stdout
|
||||||
|
// ..write(lightGray.wrap('Now running `wrk` for '))
|
||||||
|
// ..write(cyan.wrap(benchmark.name))
|
||||||
|
// ..writeln(lightGray.wrap(' (waiting 10s)...'));
|
||||||
|
// var wrk = await _runWrk(mode: ProcessStartMode.inheritStdio);
|
||||||
|
// await wrk.exitCode;
|
||||||
|
// isolates.forEach((i) => i.kill(priority: Isolate.immediate));
|
||||||
|
|
||||||
|
// Run Angel HTTP, Wings
|
||||||
|
for (var fac in factories) {
|
||||||
|
print(lightGray.wrap('Booting $fac server...'));
|
||||||
|
|
||||||
|
var isolates = <Isolate>[];
|
||||||
|
for (int i = 0; i < Platform.numberOfProcessors; i++) {
|
||||||
|
isolates
|
||||||
|
.add(await Isolate.spawn(_angelIsolate, Tuple2(benchmark, fac)));
|
||||||
|
}
|
||||||
|
|
||||||
|
await _10s();
|
||||||
|
print(lightGray.wrap('Warming up $fac server...'));
|
||||||
|
await _warmUp();
|
||||||
|
stdout
|
||||||
|
..write(lightGray.wrap('Now running `wrk` for '))
|
||||||
|
..write(cyan.wrap(benchmark.name))
|
||||||
|
..writeln(lightGray.wrap('...'));
|
||||||
|
var wrk = await _runWrk(mode: ProcessStartMode.inheritStdio);
|
||||||
|
await wrk.exitCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _httpIsolate(AngelBenchmark benchmark) {
|
||||||
|
Future(() async {
|
||||||
|
var raw = await HttpServer.bind(InternetAddress.loopbackIPv4, testPort,
|
||||||
|
shared: true);
|
||||||
|
raw.listen((r) => benchmark.rawHandler(r, r.response));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _angelIsolate(Tuple2<AngelBenchmark, String> args) {
|
||||||
|
Future(() async {
|
||||||
|
var app = Angel();
|
||||||
|
Driver driver;
|
||||||
|
|
||||||
|
if (args.item2 == 'angel_http')
|
||||||
|
driver = AngelHttp.custom(app, startShared);
|
||||||
|
else if (args.item2 == 'angel_wings')
|
||||||
|
driver = AngelWings.custom(app, startSharedWings);
|
||||||
|
|
||||||
|
await app.configure(args.item1.setupAngel);
|
||||||
|
await driver.startServer(InternetAddress.loopbackIPv4, testPort);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class AngelBenchmark {
|
||||||
|
const AngelBenchmark();
|
||||||
|
|
||||||
|
String get name;
|
||||||
|
|
||||||
|
FutureOr<void> setupAngel(Angel app);
|
||||||
|
|
||||||
|
FutureOr<void> rawHandler(HttpRequest req, HttpResponse res);
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'dart:io';
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:angel_static/angel_static.dart';
|
import 'package:angel_static/angel_static.dart';
|
||||||
import 'package:angel_wings/angel_wings.dart';
|
import 'package:angel_wings/angel_wings.dart';
|
||||||
|
@ -16,9 +17,13 @@ main() async {
|
||||||
app.mimeTypeResolver.addExtension('yaml', 'text/x-yaml');
|
app.mimeTypeResolver.addExtension('yaml', 'text/x-yaml');
|
||||||
|
|
||||||
app.get('/', (req, res) => 'WINGS!!!');
|
app.get('/', (req, res) => 'WINGS!!!');
|
||||||
|
app.post('/', (req, res) async {
|
||||||
|
await req.parseBody();
|
||||||
|
return req.bodyAsMap;
|
||||||
|
});
|
||||||
app.fallback(vDir.handleRequest);
|
app.fallback(vDir.handleRequest);
|
||||||
app.fallback((req, res) => throw AngelHttpException.notFound());
|
app.fallback((req, res) => throw AngelHttpException.notFound());
|
||||||
|
|
||||||
await wings.startServer('127.0.0.1', 3000);
|
await wings.startServer(InternetAddress.loopbackIPv6, 3000);
|
||||||
print('Listening at ${wings.uri}');
|
print('Listening at ${wings.uri}');
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
22
example/shared.dart
Normal file
22
example/shared.dart
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:angel_wings/angel_wings.dart';
|
||||||
|
|
||||||
|
main() async {
|
||||||
|
var app = Angel();
|
||||||
|
var wings1 = AngelWings.custom(app, startSharedWings);
|
||||||
|
var wings2 = AngelWings.custom(app, startSharedWings);
|
||||||
|
var wings3 = AngelWings.custom(app, startSharedWings);
|
||||||
|
var wings4 = AngelWings.custom(app, startSharedWings);
|
||||||
|
await wings1.startServer('127.0.0.1', 3000);
|
||||||
|
await wings2.startServer('127.0.0.1', 3000);
|
||||||
|
await wings3.startServer('127.0.0.1', 3000);
|
||||||
|
await wings4.startServer('127.0.0.1', 3000);
|
||||||
|
print(wings1.uri);
|
||||||
|
print(wings2.uri);
|
||||||
|
print(wings3.uri);
|
||||||
|
print(wings4.uri);
|
||||||
|
await wings1.close();
|
||||||
|
await wings2.close();
|
||||||
|
await wings3.close();
|
||||||
|
await wings4.close();
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "angel_wings.h"
|
#include "angel_wings.h"
|
||||||
#include "wings_socket.h"
|
#include "wings_socket.h"
|
||||||
|
@ -32,7 +33,7 @@ void Dart_WingsSocket_bindIPv6(Dart_NativeArguments arguments)
|
||||||
void wingsReturnBound(Dart_NativeArguments arguments, WingsSocket *socket)
|
void wingsReturnBound(Dart_NativeArguments arguments, WingsSocket *socket)
|
||||||
{
|
{
|
||||||
Dart_Port sendPort;
|
Dart_Port sendPort;
|
||||||
HandleError(Dart_SendPortGetId(socket->getInfo().sendPortHandle, &sendPort));
|
HandleError(Dart_SendPortGetId(Dart_GetNativeArgument(arguments, 5), &sendPort));
|
||||||
socket->incrRef(sendPort);
|
socket->incrRef(sendPort);
|
||||||
auto ptr = (uint64_t)socket;
|
auto ptr = (uint64_t)socket;
|
||||||
Dart_Handle ptrHandle = Dart_NewIntegerFromUint64(ptr);
|
Dart_Handle ptrHandle = Dart_NewIntegerFromUint64(ptr);
|
||||||
|
@ -44,9 +45,11 @@ WingsSocket *wingsFindSocket(Dart_NativeArguments arguments, const WingsSocketIn
|
||||||
// Find an existing server, if any.
|
// Find an existing server, if any.
|
||||||
if (info.shared)
|
if (info.shared)
|
||||||
{
|
{
|
||||||
|
// std::cout << info.address << std::endl;
|
||||||
|
// std::cout << globalSocketList.size() << std::endl;
|
||||||
for (auto *socket : globalSocketList)
|
for (auto *socket : globalSocketList)
|
||||||
{
|
{
|
||||||
if (socket->getInfo() == info)
|
if (info.equals(socket->getInfo()))
|
||||||
{
|
{
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
|
102
lib/src/http.cc
102
lib/src/http.cc
|
@ -12,26 +12,45 @@ void Dart_WingsSocket_parseHttp(Dart_NativeArguments arguments)
|
||||||
Dart_SetReturnValue(arguments, send_port);
|
Dart_SetReturnValue(arguments, send_port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wingsHttp
|
||||||
|
{
|
||||||
|
Dart_Port port;
|
||||||
|
std::string lastHeader;
|
||||||
|
};
|
||||||
|
|
||||||
void wingsHttpCallback(Dart_Port dest_port_id, Dart_CObject *message)
|
void wingsHttpCallback(Dart_Port dest_port_id, Dart_CObject *message)
|
||||||
{
|
{
|
||||||
int64_t fd = -1;
|
int64_t fd = -1;
|
||||||
Dart_Port outPort = message->value.as_array.values[0]->value.as_send_port.id;
|
Dart_Port outPort = message->value.as_array.values[0]->value.as_send_port.id;
|
||||||
Dart_CObject *fdArg = message->value.as_array.values[1];
|
Dart_CObject *fdArg = message->value.as_array.values[1];
|
||||||
|
|
||||||
#define thePort (*((Dart_Port *)parser->data))
|
wingsHttp httpData = {outPort};
|
||||||
#define sendInt(n) \
|
|
||||||
Dart_CObject obj; \
|
#define theStruct (*((wingsHttp *)parser->data))
|
||||||
obj.type = Dart_CObject_kInt64; \
|
#define thePort theStruct.port
|
||||||
obj.value.as_int64 = (n); \
|
#define sendInt(n) \
|
||||||
Dart_PostCObject(thePort, &obj);
|
{ \
|
||||||
#define sendString() \
|
Dart_CObject obj; \
|
||||||
if (length > 0) \
|
obj.type = Dart_CObject_kInt64; \
|
||||||
{ \
|
obj.value.as_int64 = (n); \
|
||||||
std::string str(at, length); \
|
Dart_PostCObject(thePort, &obj); \
|
||||||
Dart_CObject obj; \
|
}
|
||||||
obj.type = Dart_CObject_kString; \
|
#define sendString(n) \
|
||||||
obj.value.as_string = (char *)str.c_str(); \
|
if (length > 0) \
|
||||||
Dart_PostCObject(thePort, &obj); \
|
{ \
|
||||||
|
Dart_CObject typeObj; \
|
||||||
|
typeObj.type = Dart_CObject_kInt32; \
|
||||||
|
typeObj.value.as_int32 = (n); \
|
||||||
|
std::string str(at, length); \
|
||||||
|
Dart_CObject strObj; \
|
||||||
|
strObj.type = Dart_CObject_kString; \
|
||||||
|
strObj.value.as_string = (char *)str.c_str(); \
|
||||||
|
Dart_CObject *values[2] = {&typeObj, &strObj}; \
|
||||||
|
Dart_CObject out; \
|
||||||
|
out.type = Dart_CObject_kArray; \
|
||||||
|
out.value.as_array.length = 2; \
|
||||||
|
out.value.as_array.values = values; \
|
||||||
|
Dart_PostCObject(thePort, &out); \
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fdArg->type == Dart_CObject_kInt32)
|
if (fdArg->type == Dart_CObject_kInt32)
|
||||||
|
@ -52,17 +71,24 @@ void wingsHttpCallback(Dart_Port dest_port_id, Dart_CObject *message)
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.on_headers_complete = [](http_parser *parser) {
|
settings.on_headers_complete = [](http_parser *parser) {
|
||||||
{
|
Dart_CObject type;
|
||||||
sendInt(0);
|
type.type = Dart_CObject_kInt32;
|
||||||
}
|
type.value.as_int32 = 2;
|
||||||
{
|
Dart_CObject value;
|
||||||
sendInt(parser->method);
|
value.type = Dart_CObject_kInt32;
|
||||||
}
|
value.value.as_int32 = parser->method;
|
||||||
|
Dart_CObject *values[2] = {&type, &value};
|
||||||
|
Dart_CObject out;
|
||||||
|
out.type = Dart_CObject_kArray;
|
||||||
|
out.value.as_array.length = 2;
|
||||||
|
out.value.as_array.values = values;
|
||||||
|
Dart_PostCObject(thePort, &out);
|
||||||
|
sendInt(100);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.on_message_complete = [](http_parser *parser) {
|
settings.on_message_complete = [](http_parser *parser) {
|
||||||
sendInt(1);
|
sendInt(200);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -75,22 +101,46 @@ void wingsHttpCallback(Dart_Port dest_port_id, Dart_CObject *message)
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.on_url = [](http_parser *parser, const char *at, size_t length) {
|
settings.on_url = [](http_parser *parser, const char *at, size_t length) {
|
||||||
sendString();
|
sendString(0);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.on_header_field = [](http_parser *parser, const char *at, size_t length) {
|
settings.on_header_field = [](http_parser *parser, const char *at, size_t length) {
|
||||||
sendString();
|
theStruct.lastHeader = std::string(at, length);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.on_header_value = [](http_parser *parser, const char *at, size_t length) {
|
settings.on_header_value = [](http_parser *parser, const char *at, size_t length) {
|
||||||
sendString();
|
if (!theStruct.lastHeader.empty())
|
||||||
|
{
|
||||||
|
std::string vStr(at, length);
|
||||||
|
Dart_CObject type;
|
||||||
|
type.type = Dart_CObject_kInt32;
|
||||||
|
type.value.as_int32 = 1;
|
||||||
|
Dart_CObject name;
|
||||||
|
name.type = Dart_CObject_kString;
|
||||||
|
name.value.as_string = (char *)theStruct.lastHeader.c_str();
|
||||||
|
Dart_CObject value;
|
||||||
|
value.type = Dart_CObject_kString;
|
||||||
|
value.value.as_string = (char *)vStr.c_str();
|
||||||
|
Dart_CObject *values[3] = {&type, &name, &value};
|
||||||
|
Dart_CObject out;
|
||||||
|
out.type = Dart_CObject_kArray;
|
||||||
|
out.value.as_array.length = 3;
|
||||||
|
out.value.as_array.values = values;
|
||||||
|
Dart_PostCObject(thePort, &out);
|
||||||
|
theStruct.lastHeader.clear();
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.on_body = [](http_parser *parser, const char *at, size_t length) {
|
settings.on_body = [](http_parser *parser, const char *at, size_t length) {
|
||||||
sendString();
|
Dart_CObject obj;
|
||||||
|
obj.type = Dart_CObject_kTypedData;
|
||||||
|
obj.value.as_typed_data.type = Dart_TypedData_kUint8;
|
||||||
|
obj.value.as_typed_data.length = length;
|
||||||
|
obj.value.as_typed_data.values = (uint8_t *)at;
|
||||||
|
Dart_PostCObject(thePort, &obj);
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,7 +151,7 @@ void wingsHttpCallback(Dart_Port dest_port_id, Dart_CObject *message)
|
||||||
// http_parser parser;
|
// http_parser parser;
|
||||||
auto *parser = (http_parser *)malloc(sizeof(http_parser));
|
auto *parser = (http_parser *)malloc(sizeof(http_parser));
|
||||||
http_parser_init(parser, HTTP_BOTH);
|
http_parser_init(parser, HTTP_BOTH);
|
||||||
parser->data = &outPort;
|
parser->data = &httpData;
|
||||||
|
|
||||||
while ((recved = recv(fd, buf, len, 0)) >= 0)
|
while ((recved = recv(fd, buf, len, 0)) >= 0)
|
||||||
{
|
{
|
||||||
|
|
Binary file not shown.
|
@ -159,5 +159,13 @@ void Dart_WingsSocket_closeDescriptor(Dart_NativeArguments arguments)
|
||||||
|
|
||||||
void Dart_WingsSocket_close(Dart_NativeArguments arguments)
|
void Dart_WingsSocket_close(Dart_NativeArguments arguments)
|
||||||
{
|
{
|
||||||
// TODO: Actually do something.
|
Dart_Port port;
|
||||||
|
uint64_t ptr;
|
||||||
|
Dart_Handle pointerHandle = Dart_GetNativeArgument(arguments, 0);
|
||||||
|
Dart_Handle sendPortHandle = Dart_GetNativeArgument(arguments, 1);
|
||||||
|
HandleError(Dart_IntegerToUint64(pointerHandle, &ptr));
|
||||||
|
HandleError(Dart_SendPortGetId(sendPortHandle, &port));
|
||||||
|
|
||||||
|
auto *socket = (WingsSocket *)ptr;
|
||||||
|
socket->decrRef(port);
|
||||||
}
|
}
|
|
@ -7,13 +7,17 @@ import 'wings_request.dart';
|
||||||
import 'wings_response.dart';
|
import 'wings_response.dart';
|
||||||
import 'wings_socket.dart';
|
import 'wings_socket.dart';
|
||||||
|
|
||||||
|
Future<WingsSocket> startSharedWings(dynamic addr, int port) {
|
||||||
|
return WingsSocket.bind(addr, port, shared: true);
|
||||||
|
}
|
||||||
|
|
||||||
class AngelWings extends Driver<WingsClientSocket, int, WingsSocket,
|
class AngelWings extends Driver<WingsClientSocket, int, WingsSocket,
|
||||||
WingsRequestContext, WingsResponseContext> {
|
WingsRequestContext, WingsResponseContext> {
|
||||||
factory AngelWings(Angel app) {
|
factory AngelWings(Angel app) {
|
||||||
return AngelWings._(app, WingsSocket.bind);
|
return AngelWings.custom(app, WingsSocket.bind);
|
||||||
}
|
}
|
||||||
|
|
||||||
AngelWings._(
|
AngelWings.custom(
|
||||||
Angel app, Future<WingsSocket> Function(dynamic, int) serverGenerator)
|
Angel app, Future<WingsSocket> Function(dynamic, int) serverGenerator)
|
||||||
: super(app, serverGenerator);
|
: super(app, serverGenerator);
|
||||||
|
|
||||||
|
@ -24,6 +28,12 @@ class AngelWings extends Driver<WingsClientSocket, int, WingsSocket,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<WingsSocket> close() async {
|
||||||
|
await server?.close();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future closeResponse(int response) {
|
Future closeResponse(int response) {
|
||||||
closeNativeSocketDescriptor(response);
|
closeNativeSocketDescriptor(response);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'dart:isolate';
|
import 'dart:isolate';
|
||||||
|
import 'dart:typed_data';
|
||||||
import 'package:angel_container/angel_container.dart';
|
import 'package:angel_container/angel_container.dart';
|
||||||
import 'package:angel_framework/angel_framework.dart';
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
import 'package:mock_request/mock_request.dart';
|
import 'package:mock_request/mock_request.dart';
|
||||||
|
@ -94,52 +95,86 @@ class WingsRequestContext extends RequestContext<WingsClientSocket> {
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<WingsRequestContext> from(Angel app, WingsClientSocket socket) {
|
static Future<WingsRequestContext> from(Angel app, WingsClientSocket socket) {
|
||||||
var state = _ParseState.url;
|
// var state = _ParseState.url;
|
||||||
var c = Completer<WingsRequestContext>();
|
var c = Completer<WingsRequestContext>();
|
||||||
var recv = RawReceivePort();
|
var recv = RawReceivePort();
|
||||||
var rq = WingsRequestContext._(app, socket, recv);
|
var rq = WingsRequestContext._(app, socket, recv);
|
||||||
rq._remoteAddress = socket.remoteAddress;
|
rq._remoteAddress = socket.remoteAddress;
|
||||||
String lastHeader;
|
var ct = StreamController();
|
||||||
recv.handler = (e) {
|
recv.handler = ct.add;
|
||||||
if (state == _ParseState.url) {
|
recv.handler = (ee) {
|
||||||
rq._uri = Uri.parse(e as String);
|
if (ee is Uint8List) {
|
||||||
var path = rq._uri.path.replaceAll(_straySlashes, '');
|
if (!rq._body.isClosed) rq._body.add(ee);
|
||||||
if (path.isEmpty) path = '/';
|
} else if (ee is List) {
|
||||||
rq._path = path;
|
var type = ee[0] as int;
|
||||||
state = _ParseState.headerField;
|
|
||||||
} else if (state == _ParseState.headerField) {
|
if (type == 2) {
|
||||||
if (e == 0) {
|
rq._method = methodToString(ee[1] as int);
|
||||||
state = _ParseState.method;
|
|
||||||
} else {
|
} else {
|
||||||
lastHeader = e as String; //Uri.decodeFull(e as String);
|
var value = ee[1] as String;
|
||||||
state = _ParseState.headerValue;
|
|
||||||
}
|
if (type == 0) {
|
||||||
} else if (state == _ParseState.headerValue) {
|
rq._uri = Uri.parse(value);
|
||||||
if (e == 0) {
|
var path = rq._uri.path.replaceAll(_straySlashes, '');
|
||||||
state = _ParseState.method;
|
if (path.isEmpty) path = '/';
|
||||||
} else {
|
rq._path = path;
|
||||||
var value = e as String; //Uri.decodeFull(e as String);
|
} else if (type == 1) {
|
||||||
if (lastHeader != null) {
|
var k = value, v = ee[2] as String;
|
||||||
if (lastHeader == 'cookie') {
|
if (k == 'cookie') {
|
||||||
rq.__cookies.add(Cookie.fromSetCookieValue(value));
|
rq.__cookies.add(Cookie.fromSetCookieValue(v));
|
||||||
} else {
|
} else {
|
||||||
rq._headers.add(lastHeader, value);
|
rq._headers.add(k, v);
|
||||||
}
|
}
|
||||||
lastHeader = null;
|
} else {
|
||||||
|
// print("h: $ee');");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state = _ParseState.headerField;
|
} else if (ee == 100) {
|
||||||
} else if (state == _ParseState.method) {
|
// Headers done, just listen for body.
|
||||||
rq._method = methodToString(e as int);
|
|
||||||
state = _ParseState.body;
|
|
||||||
c.complete(rq);
|
c.complete(rq);
|
||||||
} else if (state == _ParseState.body) {
|
} else if (ee == 200) {
|
||||||
if (e == 1) {
|
// Message complete.
|
||||||
rq._body.close();
|
rq._body.close();
|
||||||
} else {
|
|
||||||
rq._body.add(e as List<int>);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// if (state == _ParseState.url) {
|
||||||
|
// rq._uri = Uri.parse(e as String);
|
||||||
|
// var path = rq._uri.path.replaceAll(_straySlashes, '');
|
||||||
|
// if (path.isEmpty) path = '/';
|
||||||
|
// rq._path = path;
|
||||||
|
// state = _ParseState.headerField;
|
||||||
|
// } else if (state == _ParseState.headerField) {
|
||||||
|
// if (e == 0) {
|
||||||
|
// state = _ParseState.method;
|
||||||
|
// } else {
|
||||||
|
// lastHeader = e as String; //Uri.decodeFull(e as String);
|
||||||
|
// state = _ParseState.headerValue;
|
||||||
|
// }
|
||||||
|
// } else if (state == _ParseState.headerValue) {
|
||||||
|
// if (e == 0) {
|
||||||
|
// state = _ParseState.method;
|
||||||
|
// } else {
|
||||||
|
// var value = e as String; //Uri.decodeFull(e as String);
|
||||||
|
// if (lastHeader != null) {
|
||||||
|
// if (lastHeader == 'cookie') {
|
||||||
|
// rq.__cookies.add(Cookie.fromSetCookieValue(value));
|
||||||
|
// } else {
|
||||||
|
// rq._headers.add(lastHeader, value);
|
||||||
|
// }
|
||||||
|
// lastHeader = null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// state = _ParseState.headerField;
|
||||||
|
// } else if (state == _ParseState.method) {
|
||||||
|
// rq._method = methodToString(e as int);
|
||||||
|
// state = _ParseState.body;
|
||||||
|
// c.complete(rq);
|
||||||
|
// } else if (state == _ParseState.body) {
|
||||||
|
// if (e == 1) {
|
||||||
|
// rq._body.close();
|
||||||
|
// } else {
|
||||||
|
// rq._body.add(e as List<int>);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
};
|
};
|
||||||
wingsParseHttp().send([recv.sendPort, socket.fileDescriptor]);
|
wingsParseHttp().send([recv.sendPort, socket.fileDescriptor]);
|
||||||
return c.future;
|
return c.future;
|
||||||
|
|
|
@ -5,17 +5,22 @@ using namespace wings;
|
||||||
|
|
||||||
std::vector<WingsSocket *> wings::globalSocketList;
|
std::vector<WingsSocket *> wings::globalSocketList;
|
||||||
|
|
||||||
bool WingsSocketInfo::operator==(const WingsSocketInfo &other) const
|
bool WingsSocketInfo::equals(const WingsSocketInfo &right) const
|
||||||
{
|
{
|
||||||
return (strcmp(address, other.address) == 0) &&
|
// std::cout << address << " vs " << right.address << std::endl;
|
||||||
port == other.port;
|
// std::cout << port << " vs " << right.port << std::endl;
|
||||||
|
return (strcmp(address, right.address) == 0) &&
|
||||||
|
port == right.port;
|
||||||
}
|
}
|
||||||
|
|
||||||
WingsSocket::WingsSocket(sa_family_t family, int sockfd, const WingsSocketInfo &info)
|
WingsSocket::WingsSocket(sa_family_t family, int sockfd, const WingsSocketInfo &info)
|
||||||
: sockfd(sockfd), info(info), family(family)
|
: sockfd(sockfd), info(info), family(family)
|
||||||
{
|
{
|
||||||
|
index = 0;
|
||||||
|
open = true;
|
||||||
refCount = 0;
|
refCount = 0;
|
||||||
workerThread = nullptr;
|
workerThread = nullptr;
|
||||||
|
this->info.address = strdup(info.address);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WingsSocket::incrRef(Dart_Port port)
|
void WingsSocket::incrRef(Dart_Port port)
|
||||||
|
@ -24,6 +29,31 @@ void WingsSocket::incrRef(Dart_Port port)
|
||||||
sendPorts.push_back(port);
|
sendPorts.push_back(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WingsSocket::decrRef(Dart_Port port)
|
||||||
|
{
|
||||||
|
auto it = std::find(sendPorts.begin(), sendPorts.end(), port);
|
||||||
|
|
||||||
|
if (it != sendPorts.end())
|
||||||
|
{
|
||||||
|
sendPorts.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
refCount--;
|
||||||
|
|
||||||
|
if (refCount <= 0 && open)
|
||||||
|
{
|
||||||
|
close(sockfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dart_Port WingsSocket::nextPort()
|
||||||
|
{
|
||||||
|
if (index >= sendPorts.size())
|
||||||
|
index = 0;
|
||||||
|
Dart_Port port = sendPorts.at(index++);
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
|
||||||
const WingsSocketInfo &WingsSocket::getInfo() const
|
const WingsSocketInfo &WingsSocket::getInfo() const
|
||||||
{
|
{
|
||||||
return info;
|
return info;
|
||||||
|
@ -59,6 +89,7 @@ void WingsSocket::threadCallback(Dart_Port dest_port_id,
|
||||||
Dart_Port outPort = message->value.as_array.values[0]->value.as_send_port.id;
|
Dart_Port outPort = message->value.as_array.values[0]->value.as_send_port.id;
|
||||||
Dart_CObject *ptrArg = message->value.as_array.values[1];
|
Dart_CObject *ptrArg = message->value.as_array.values[1];
|
||||||
|
|
||||||
|
// If there are no listeners, quit.
|
||||||
if (ptrArg->type == Dart_CObject_kInt32)
|
if (ptrArg->type == Dart_CObject_kInt32)
|
||||||
{
|
{
|
||||||
auto as64 = (int64_t)ptrArg->value.as_int32;
|
auto as64 = (int64_t)ptrArg->value.as_int32;
|
||||||
|
@ -71,6 +102,11 @@ void WingsSocket::threadCallback(Dart_Port dest_port_id,
|
||||||
|
|
||||||
if (socket != nullptr)
|
if (socket != nullptr)
|
||||||
{
|
{
|
||||||
|
if (socket->sendPorts.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int sock;
|
int sock;
|
||||||
unsigned long index = 0;
|
unsigned long index = 0;
|
||||||
sockaddr addr;
|
sockaddr addr;
|
||||||
|
@ -106,14 +142,11 @@ void WingsSocket::threadCallback(Dart_Port dest_port_id,
|
||||||
obj.value.as_array.length = 2;
|
obj.value.as_array.length = 2;
|
||||||
obj.value.as_array.values = values;
|
obj.value.as_array.values = values;
|
||||||
|
|
||||||
Dart_PostCObject(outPort, &obj);
|
// Dart_PostCObject(outPort, &obj);
|
||||||
// Dispatch the fd to the next listener.
|
// Dispatch the fd to the next listener.
|
||||||
// auto &ports = socket->sendPorts;
|
auto port = socket->nextPort();
|
||||||
// Dart_Port port = ports.at(index++);
|
// Dart_PostCObject(port, &obj);
|
||||||
// if (index >= ports.size())
|
Dart_PostCObject(outPort, &obj);
|
||||||
// index = 0;
|
|
||||||
// Dart_Handle intHandle = Dart_NewInteger(sock);
|
|
||||||
// Dart_Post(port, intHandle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -18,7 +18,7 @@ int bindWingsIPv6ServerSocket(
|
||||||
bool shared,
|
bool shared,
|
||||||
int backlog,
|
int backlog,
|
||||||
bool v6Only,
|
bool v6Only,
|
||||||
SendPort sendPort) native 'Dart_WingsSocket_bindIPV6';
|
SendPort sendPort) native 'Dart_WingsSocket_bindIPv6';
|
||||||
|
|
||||||
String getWingsServerSocketAddress(int pointer)
|
String getWingsServerSocketAddress(int pointer)
|
||||||
native 'Dart_WingsSocket_getAddress';
|
native 'Dart_WingsSocket_getAddress';
|
||||||
|
@ -33,7 +33,8 @@ void closeNativeSocketDescriptor(int fd)
|
||||||
|
|
||||||
SendPort wingsSocketListen(int pointer) native 'Dart_WingsSocket_listen';
|
SendPort wingsSocketListen(int pointer) native 'Dart_WingsSocket_listen';
|
||||||
|
|
||||||
void closeWingsSocket(int pointer) native 'Dart_WingsSocket_close';
|
void closeWingsSocket(int pointer, SendPort sendPort)
|
||||||
|
native 'Dart_WingsSocket_close';
|
||||||
|
|
||||||
SendPort wingsParseHttp() native 'Dart_WingsSocket_parseHttp';
|
SendPort wingsParseHttp() native 'Dart_WingsSocket_parseHttp';
|
||||||
|
|
||||||
|
@ -120,7 +121,7 @@ class WingsSocket extends Stream<WingsClientSocket> {
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
if (_open) {
|
if (_open) {
|
||||||
_open = false;
|
_open = false;
|
||||||
closeWingsSocket(_pointer);
|
closeWingsSocket(_pointer, _recv.sendPort);
|
||||||
_recv.close();
|
_recv.close();
|
||||||
await _ctrl.close();
|
await _ctrl.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct WingsSocketInfo
|
||||||
uint64_t backlog;
|
uint64_t backlog;
|
||||||
bool v6Only;
|
bool v6Only;
|
||||||
Dart_Handle sendPortHandle;
|
Dart_Handle sendPortHandle;
|
||||||
bool operator==(const WingsSocketInfo &other) const;
|
bool equals(const WingsSocketInfo &right) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WingsSocket
|
class WingsSocket
|
||||||
|
@ -30,16 +30,20 @@ class WingsSocket
|
||||||
public:
|
public:
|
||||||
WingsSocket(sa_family_t family, int sockfd, const WingsSocketInfo &info);
|
WingsSocket(sa_family_t family, int sockfd, const WingsSocketInfo &info);
|
||||||
void incrRef(Dart_Port port);
|
void incrRef(Dart_Port port);
|
||||||
|
void decrRef(Dart_Port port);
|
||||||
const WingsSocketInfo &getInfo() const;
|
const WingsSocketInfo &getInfo() const;
|
||||||
void start(Dart_NativeArguments arguments);
|
void start(Dart_NativeArguments arguments);
|
||||||
int getFD() const;
|
int getFD() const;
|
||||||
sa_family_t getFamily() const;
|
sa_family_t getFamily() const;
|
||||||
|
Dart_Port nextPort();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void threadCallback(Dart_Port dest_port_id, Dart_CObject *message);
|
static void threadCallback(Dart_Port dest_port_id, Dart_CObject *message);
|
||||||
WingsSocketInfo info;
|
WingsSocketInfo info;
|
||||||
|
unsigned long index;
|
||||||
int sockfd;
|
int sockfd;
|
||||||
int refCount;
|
int refCount;
|
||||||
|
bool open;
|
||||||
sa_family_t family;
|
sa_family_t family;
|
||||||
std::unique_ptr<std::thread> workerThread;
|
std::unique_ptr<std::thread> workerThread;
|
||||||
std::vector<Dart_Port> sendPorts;
|
std::vector<Dart_Port> sendPorts;
|
||||||
|
|
Binary file not shown.
Loading…
Reference in a new issue