Add 'packages/wings/' from commit '361e7e5f4a3ec6463f0348bdc8eb0a3b7549340a'
git-subtree-dir: packages/wings git-subtree-mainline:61c716502b
git-subtree-split:361e7e5f4a
This commit is contained in:
commit
13e863f295
36 changed files with 2619 additions and 0 deletions
121
packages/wings/.clang-format
Normal file
121
packages/wings/.clang-format
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
# BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -2
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlines: Right
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: MultiLine
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: true
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
SplitEmptyNamespace: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeInheritanceComma: false
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
ColumnLimit: 80
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
FixNamespaceComments: true
|
||||||
|
ForEachMacros:
|
||||||
|
- foreach
|
||||||
|
- Q_FOREACH
|
||||||
|
- BOOST_FOREACH
|
||||||
|
IncludeBlocks: Preserve
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||||
|
Priority: 2
|
||||||
|
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||||
|
Priority: 3
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 2
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
ObjCBinPackProtocolList: Auto
|
||||||
|
ObjCBlockIndentWidth: 2
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PenaltyBreakAssignment: 2
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 1000000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: true
|
||||||
|
SortIncludes: true
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: true
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
StatementMacros:
|
||||||
|
- Q_UNUSED
|
||||||
|
- QT_REQUIRE_VERSION
|
||||||
|
TabWidth: 8
|
||||||
|
UseTab: Never
|
||||||
|
...
|
||||||
|
|
67
packages/wings/.gitignore
vendored
Normal file
67
packages/wings/.gitignore
vendored
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# See https://www.dartlang.org/guides/libraries/private-files
|
||||||
|
|
||||||
|
# Files and directories created by pub
|
||||||
|
.dart_tool/
|
||||||
|
.packages
|
||||||
|
build/
|
||||||
|
# If you're building an application, you may want to check-in your pubspec.lock
|
||||||
|
pubspec.lock
|
||||||
|
|
||||||
|
# Directory created by dartdoc
|
||||||
|
# If you don't generate documentation locally you can remove this line.
|
||||||
|
doc/api/
|
||||||
|
|
||||||
|
# Avoid committing generated Javascript files:
|
||||||
|
*.dart.js
|
||||||
|
*.info.json # Produced by the --dump-info flag.
|
||||||
|
*.js # When generated by dart2js. Don't specify *.js if your
|
||||||
|
# project includes source files written in JavaScript.
|
||||||
|
*.js_
|
||||||
|
*.js.deps
|
||||||
|
*.js.map
|
||||||
|
|
||||||
|
*.o
|
||||||
|
# *.dylib
|
||||||
|
*.a
|
||||||
|
# *.so
|
||||||
|
*.lib
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
# Created by https://www.gitignore.io/api/cmake
|
||||||
|
# Edit at https://www.gitignore.io/?templates=cmake
|
||||||
|
|
||||||
|
### CMake ###
|
||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
Testing
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps
|
||||||
|
|
||||||
|
### CMake Patch ###
|
||||||
|
# External projects
|
||||||
|
*-prefix/
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/cmake
|
||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/vagrant
|
||||||
|
# Edit at https://www.gitignore.io/?templates=vagrant
|
||||||
|
|
||||||
|
### Vagrant ###
|
||||||
|
# General
|
||||||
|
.vagrant/
|
||||||
|
|
||||||
|
# Log files (if you are creating logs in debug mode, uncomment this)
|
||||||
|
# *.log
|
||||||
|
|
||||||
|
### Vagrant Patch ###
|
||||||
|
*.box
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/vagrant
|
6
packages/wings/.gitmodules
vendored
Normal file
6
packages/wings/.gitmodules
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
[submodule "cmake_dart_utils"]
|
||||||
|
path = cmake_dart_utils
|
||||||
|
url = https://github.com/thosakwe/cmake_dart_utils.git
|
||||||
|
[submodule "lib/src/http-parser"]
|
||||||
|
path = lib/src/http-parser
|
||||||
|
url = https://github.com/nodejs/http-parser.git
|
6
packages/wings/CMakeLists.txt
Normal file
6
packages/wings/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
project(angel_wings)
|
||||||
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake_dart_utils/cmake")
|
||||||
|
find_package(Dart REQUIRED)
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
add_subdirectory(lib/src)
|
51
packages/wings/README.md
Normal file
51
packages/wings/README.md
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
# wings
|
||||||
|
Native HTTP driver for Angel, for a nice speed boost.
|
||||||
|
|
||||||
|
Not ready for production.
|
||||||
|
|
||||||
|
## How does it work?
|
||||||
|
Typically, Angel uses the `AngelHttp` driver, which is wrapper over the `HttpServer` functionality in
|
||||||
|
`dart:io`, which in turns uses the `ServerSocket` and `Socket` functionality. This is great - Dart's standard
|
||||||
|
library comes with an HTTP server, which saves a lot of difficult in implementation.
|
||||||
|
|
||||||
|
However, abstraction tends to come with a cost. Wings seeks to minimize abstraction entirely. Rather than
|
||||||
|
using the built-in Dart network stack, Wings' HTTP server is implemented in C++ as a Dart native extension,
|
||||||
|
and the `AngelWings` driver listens to events from the extension and converts them directly into
|
||||||
|
`RequestContext` objects, without any additional abstraction within. This reduces the amount of computation
|
||||||
|
performed on each request, and helps to minimize response latency. Sending data from the response buffer in plain
|
||||||
|
Dart surprisingly is the most expensive operation, as is revealed by the Observatory.
|
||||||
|
|
||||||
|
By combining Dart's powerful VM with a native code server based on
|
||||||
|
[the same one used in Node.js](https://github.com/nodejs/http-parser),
|
||||||
|
`AngelWings` trims several milliseconds off every request, both saving resources and reducing
|
||||||
|
load times for high-traffic applications.
|
||||||
|
|
||||||
|
## How can I use it?
|
||||||
|
The intended way to use `AngelWings` is via
|
||||||
|
[`package:build_native`](https://github.com/thosakwe/build_native);
|
||||||
|
however, the situation surrounding distributing native extensions is yet far from ideal,
|
||||||
|
so this package includes pre-built binaries out-of-the-box.
|
||||||
|
|
||||||
|
Thanks to this, you can use it like any other Dart package, by installing it via Pub.
|
||||||
|
|
||||||
|
## Brief example
|
||||||
|
Using `AngelWings` is almost identical to using `AngelHttp`; however, it does
|
||||||
|
not support SSL, and therefore should be placed behind a reverse proxy like `nginx` in production.
|
||||||
|
|
||||||
|
```dart
|
||||||
|
main() async {
|
||||||
|
var app = new Angel();
|
||||||
|
var wings = new AngelWings(app, shared: true, useZone: false);
|
||||||
|
|
||||||
|
app.injectEncoders({'gzip': gzip.encoder, 'deflate': zlib.encoder});
|
||||||
|
|
||||||
|
app.get('/hello', 'Hello, native world! This is Angel WINGS.');
|
||||||
|
|
||||||
|
var fs = const LocalFileSystem();
|
||||||
|
var vDir = new VirtualDirectory(app, fs, source: fs.directory('web'));
|
||||||
|
app.use(vDir.handleRequest);
|
||||||
|
|
||||||
|
await wings.startServer('127.0.0.1', 3000);
|
||||||
|
print('Listening at http://${wings.address.address}:${wings.port}');
|
||||||
|
}
|
||||||
|
```
|
6
packages/wings/Vagrantfile
vendored
Normal file
6
packages/wings/Vagrantfile
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# -*- mode: ruby -*-
|
||||||
|
# vi: set ft=ruby :
|
||||||
|
Vagrant.configure("2") do |config|
|
||||||
|
config.vm.box = "ubuntu/bionic64"
|
||||||
|
config.vm.provision "shell", path: "provision.sh"
|
||||||
|
end
|
6
packages/wings/analysis_options.yaml
Normal file
6
packages/wings/analysis_options.yaml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
include: package:pedantic/analysis_options.yaml
|
||||||
|
analyzer:
|
||||||
|
exclude:
|
||||||
|
- cmake_dart_utils/example/*
|
||||||
|
strong-mode:
|
||||||
|
implicit-casts: false
|
23
packages/wings/benchmark/empty.dart
Normal file
23
packages/wings/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
packages/wings/benchmark/util.dart
Normal file
110
packages/wings/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: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
packages/wings/cmake_dart_utils
Submodule
1
packages/wings/cmake_dart_utils
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 315b1741fc59cd18faba32b604edf4eed0bd6e4b
|
34
packages/wings/example/main.dart
Normal file
34
packages/wings/example/main.dart
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
import 'dart:io';
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:angel_static/angel_static.dart';
|
||||||
|
import 'package:angel_wings/angel_wings.dart';
|
||||||
|
import 'package:file/local.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'package:pretty_logging/pretty_logging.dart';
|
||||||
|
|
||||||
|
main() async {
|
||||||
|
hierarchicalLoggingEnabled = true;
|
||||||
|
|
||||||
|
var logger = Logger.detached('wings')
|
||||||
|
..level = Level.ALL
|
||||||
|
..onRecord.listen(prettyLog);
|
||||||
|
var app = Angel(logger: logger);
|
||||||
|
var wings = AngelWings(app);
|
||||||
|
var fs = LocalFileSystem();
|
||||||
|
var vDir = CachingVirtualDirectory(app, fs,
|
||||||
|
source: fs.currentDirectory, allowDirectoryListing: true);
|
||||||
|
|
||||||
|
app.mimeTypeResolver.addExtension('yaml', 'text/x-yaml');
|
||||||
|
|
||||||
|
app.get('/', (req, res) => 'WINGS!!!');
|
||||||
|
app.post('/', (req, res) async {
|
||||||
|
await req.parseBody();
|
||||||
|
return req.bodyAsMap;
|
||||||
|
});
|
||||||
|
|
||||||
|
app.fallback(vDir.handleRequest);
|
||||||
|
app.fallback((req, res) => throw AngelHttpException.notFound());
|
||||||
|
|
||||||
|
await wings.startServer(InternetAddress.loopbackIPv4, 3000);
|
||||||
|
print('Listening at ${wings.uri}');
|
||||||
|
}
|
22
packages/wings/example/shared.dart
Normal file
22
packages/wings/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();
|
||||||
|
}
|
27
packages/wings/example/socket.dart
Normal file
27
packages/wings/example/socket.dart
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:angel_wings/angel_wings.dart';
|
||||||
|
|
||||||
|
main() async {
|
||||||
|
var app = Angel();
|
||||||
|
var socket = await WingsSocket.bind('127.0.0.1', 3000);
|
||||||
|
print('Listening at http://localhost:3000');
|
||||||
|
|
||||||
|
await for (var fd in socket) {
|
||||||
|
var response = '''
|
||||||
|
HTTP/1.1 200 Not Found\r
|
||||||
|
Date: Fri, 31 Dec 1999 23:59:59 GMT\r
|
||||||
|
server: wings-test\r\n\r
|
||||||
|
Nope, nothing's here!
|
||||||
|
\r\n\r
|
||||||
|
''';
|
||||||
|
var bytes = utf8.encode(response);
|
||||||
|
var data = Uint8List.fromList(bytes);
|
||||||
|
var rq = await WingsRequestContext.from(app, fd);
|
||||||
|
print('Yay: $rq');
|
||||||
|
print(rq.headers);
|
||||||
|
writeToNativeSocket(fd.fileDescriptor, data);
|
||||||
|
closeNativeSocketDescriptor(fd.fileDescriptor);
|
||||||
|
}
|
||||||
|
}
|
4
packages/wings/lib/angel_wings.dart
Normal file
4
packages/wings/lib/angel_wings.dart
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export 'src/wings_driver.dart';
|
||||||
|
export 'src/wings_request.dart';
|
||||||
|
export 'src/wings_response.dart';
|
||||||
|
export 'src/wings_socket.dart';
|
8
packages/wings/lib/src/CMakeLists.txt
Normal file
8
packages/wings/lib/src/CMakeLists.txt
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
include_directories("${CMAKE_CURRENT_LIST_DIR}")
|
||||||
|
add_dart_native_extension(angel_wings
|
||||||
|
http-parser/http_parser.c
|
||||||
|
angel_wings.h angel_wings.cc
|
||||||
|
bind.cc http.cc wings_socket.cc
|
||||||
|
util.cc)
|
||||||
|
install(TARGETS angel_wings LIBRARY DESTINATION "${CMAKE_CURRENT_LIST_DIR}")
|
||||||
|
install(TARGETS angel_wings LIBRARY DESTINATION "${CMAKE_CURRENT_LIST_DIR}/../..")
|
55
packages/wings/lib/src/angel_wings.cc
Normal file
55
packages/wings/lib/src/angel_wings.cc
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
#include "angel_wings.h"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <dart_api.h>
|
||||||
|
#include <iostream>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// The name of the initialization function is the extension name followed
|
||||||
|
// by _Init.
|
||||||
|
DART_EXPORT Dart_Handle angel_wings_Init(Dart_Handle parent_library) {
|
||||||
|
if (Dart_IsError(parent_library))
|
||||||
|
return parent_library;
|
||||||
|
|
||||||
|
Dart_Handle result_code =
|
||||||
|
Dart_SetNativeResolver(parent_library, ResolveName, NULL);
|
||||||
|
if (Dart_IsError(result_code))
|
||||||
|
return result_code;
|
||||||
|
|
||||||
|
return Dart_Null();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dart_Handle HandleError(Dart_Handle handle) {
|
||||||
|
if (Dart_IsError(handle))
|
||||||
|
Dart_PropagateError(handle);
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dart_NativeFunction ResolveName(Dart_Handle name, int argc,
|
||||||
|
bool *auto_setup_scope) {
|
||||||
|
// If we fail, we return NULL, and Dart throws an exception.
|
||||||
|
if (!Dart_IsString(name))
|
||||||
|
return NULL;
|
||||||
|
Dart_NativeFunction result = NULL;
|
||||||
|
const char *cname;
|
||||||
|
HandleError(Dart_StringToCString(name, &cname));
|
||||||
|
|
||||||
|
if (strcmp("Dart_WingsSocket_bindIPv4", cname) == 0)
|
||||||
|
result = Dart_WingsSocket_bindIPv4;
|
||||||
|
if (strcmp("Dart_WingsSocket_bindIPv6", cname) == 0)
|
||||||
|
result = Dart_WingsSocket_bindIPv6;
|
||||||
|
if (strcmp("Dart_WingsSocket_getAddress", cname) == 0)
|
||||||
|
result = Dart_WingsSocket_getAddress;
|
||||||
|
if (strcmp("Dart_WingsSocket_getPort", cname) == 0)
|
||||||
|
result = Dart_WingsSocket_getPort;
|
||||||
|
if (strcmp("Dart_WingsSocket_write", cname) == 0)
|
||||||
|
result = Dart_WingsSocket_write;
|
||||||
|
if (strcmp("Dart_WingsSocket_closeDescriptor", cname) == 0)
|
||||||
|
result = Dart_WingsSocket_closeDescriptor;
|
||||||
|
if (strcmp("Dart_WingsSocket_close", cname) == 0)
|
||||||
|
result = Dart_WingsSocket_close;
|
||||||
|
if (strcmp("Dart_WingsSocket_listen", cname) == 0)
|
||||||
|
result = Dart_WingsSocket_listen;
|
||||||
|
if (strcmp("Dart_WingsSocket_parseHttp", cname) == 0)
|
||||||
|
result = Dart_WingsSocket_parseHttp;
|
||||||
|
return result;
|
||||||
|
}
|
25
packages/wings/lib/src/angel_wings.h
Normal file
25
packages/wings/lib/src/angel_wings.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef ANGEL_WINGS_WINGS_H
|
||||||
|
#define ANGEL_WINGS_WINGS_H
|
||||||
|
|
||||||
|
#include "angel_wings.h"
|
||||||
|
#include <dart_api.h>
|
||||||
|
#include <dart_native_api.h>
|
||||||
|
|
||||||
|
Dart_NativeFunction ResolveName(Dart_Handle name, int argc,
|
||||||
|
bool *auto_setup_scope);
|
||||||
|
Dart_Handle HandleError(Dart_Handle handle);
|
||||||
|
|
||||||
|
void wingsThrowError(const char *msg, const char *lib = "dart:core",
|
||||||
|
const char *name = "StateError", int n = -1);
|
||||||
|
void Dart_WingsSocket_bindIPv4(Dart_NativeArguments arguments);
|
||||||
|
void Dart_WingsSocket_bindIPv6(Dart_NativeArguments arguments);
|
||||||
|
void Dart_WingsSocket_getAddress(Dart_NativeArguments arguments);
|
||||||
|
void Dart_WingsSocket_getPort(Dart_NativeArguments arguments);
|
||||||
|
void Dart_WingsSocket_write(Dart_NativeArguments arguments);
|
||||||
|
void Dart_WingsSocket_closeDescriptor(Dart_NativeArguments arguments);
|
||||||
|
void Dart_WingsSocket_close(Dart_NativeArguments arguments);
|
||||||
|
void Dart_WingsSocket_listen(Dart_NativeArguments arguments);
|
||||||
|
void Dart_WingsSocket_parseHttp(Dart_NativeArguments arguments);
|
||||||
|
void wingsHttpCallback(Dart_Port dest_port_id, Dart_CObject *message);
|
||||||
|
|
||||||
|
#endif
|
161
packages/wings/lib/src/bind.cc
Normal file
161
packages/wings/lib/src/bind.cc
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
#include "angel_wings.h"
|
||||||
|
#include "wings_socket.h"
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <vector>
|
||||||
|
using namespace wings;
|
||||||
|
|
||||||
|
void getWingsSocketInfo(Dart_NativeArguments arguments, WingsSocketInfo *info);
|
||||||
|
|
||||||
|
WingsSocket *wingsFindSocket(Dart_NativeArguments arguments,
|
||||||
|
const WingsSocketInfo &info, int af);
|
||||||
|
|
||||||
|
WingsSocket *wingsBindNewSocket(Dart_NativeArguments arguments,
|
||||||
|
const WingsSocketInfo &info, int af);
|
||||||
|
|
||||||
|
void wingsReturnBound(Dart_NativeArguments arguments, WingsSocket *socket);
|
||||||
|
|
||||||
|
void Dart_WingsSocket_bind(sa_family_t af, Dart_NativeArguments arguments) {
|
||||||
|
WingsSocketInfo info;
|
||||||
|
getWingsSocketInfo(arguments, &info);
|
||||||
|
WingsSocket *socket = wingsFindSocket(arguments, info, af);
|
||||||
|
wingsReturnBound(arguments, socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dart_WingsSocket_bindIPv4(Dart_NativeArguments arguments) {
|
||||||
|
Dart_WingsSocket_bind(AF_INET, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dart_WingsSocket_bindIPv6(Dart_NativeArguments arguments) {
|
||||||
|
Dart_WingsSocket_bind(AF_INET6, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wingsReturnBound(Dart_NativeArguments arguments, WingsSocket *socket) {
|
||||||
|
Dart_Port sendPort;
|
||||||
|
HandleError(
|
||||||
|
Dart_SendPortGetId(Dart_GetNativeArgument(arguments, 5), &sendPort));
|
||||||
|
socket->incrRef(sendPort);
|
||||||
|
auto ptr = (uint64_t)socket;
|
||||||
|
Dart_Handle ptrHandle = Dart_NewIntegerFromUint64(ptr);
|
||||||
|
Dart_SetReturnValue(arguments, ptrHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
WingsSocket *wingsFindSocket(Dart_NativeArguments arguments,
|
||||||
|
const WingsSocketInfo &info, int af) {
|
||||||
|
// Find an existing server, if any.
|
||||||
|
if (info.shared) {
|
||||||
|
// std::cout << info.address << std::endl;
|
||||||
|
// std::cout << globalSocketList.size() << std::endl;
|
||||||
|
for (auto *socket : globalSocketList) {
|
||||||
|
if (info.equals(socket->getInfo())) {
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wingsBindNewSocket(arguments, info, af);
|
||||||
|
}
|
||||||
|
|
||||||
|
WingsSocket *wingsBindNewSocket(Dart_NativeArguments arguments,
|
||||||
|
const WingsSocketInfo &info, int af) {
|
||||||
|
sockaddr *addr;
|
||||||
|
sockaddr_in v4;
|
||||||
|
sockaddr_in6 v6;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
int sock = socket(af, SOCK_STREAM, IPPROTO_TCP);
|
||||||
|
|
||||||
|
if (sock < 0) {
|
||||||
|
wingsThrowError("Failed to create socket.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = 1;
|
||||||
|
ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
wingsThrowError("Cannot reuse address for socket.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Only on Mac???
|
||||||
|
// ret = setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &i, sizeof(i));
|
||||||
|
|
||||||
|
// if (ret < 0)
|
||||||
|
// {
|
||||||
|
// wingsThrowStateError("Cannot reuse port for socket.");
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (af == AF_INET6) {
|
||||||
|
v6.sin6_family = AF_INET6;
|
||||||
|
v6.sin6_port = htons((uint16_t)info.port);
|
||||||
|
ret = inet_pton(AF_INET6, info.address, &v6.sin6_addr.s6_addr);
|
||||||
|
if (ret >= 0)
|
||||||
|
ret = bind(sock, (const sockaddr *)&v6, sizeof(v6));
|
||||||
|
} else {
|
||||||
|
v4.sin_family = AF_INET;
|
||||||
|
v4.sin_port = htons((uint16_t)info.port);
|
||||||
|
v4.sin_addr.s_addr = inet_addr(info.address);
|
||||||
|
bind(sock, (const sockaddr *)&v4, sizeof(v4));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
wingsThrowError("Failed to bind socket.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(sock, SOMAXCONN) < 0) {
|
||||||
|
wingsThrowError("Failed to set SOMAXCONN on bound socket.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(sock, (int)info.backlog) < 0) {
|
||||||
|
wingsThrowError("Failed to set backlog on bound socket.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
|
||||||
|
wingsThrowError("Failed to make socket non-blocking.");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *out = new WingsSocket(af, sock, info);
|
||||||
|
globalSocketList.push_back(out);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void getWingsSocketInfo(Dart_NativeArguments arguments, WingsSocketInfo *info) {
|
||||||
|
Dart_Handle addressHandle = Dart_GetNativeArgument(arguments, 0);
|
||||||
|
Dart_Handle portHandle = Dart_GetNativeArgument(arguments, 1);
|
||||||
|
Dart_Handle sharedHandle = Dart_GetNativeArgument(arguments, 2);
|
||||||
|
Dart_Handle backlogHandle = Dart_GetNativeArgument(arguments, 3);
|
||||||
|
Dart_Handle v6OnlyHandle = Dart_GetNativeArgument(arguments, 4);
|
||||||
|
info->sendPortHandle = Dart_GetNativeArgument(arguments, 5);
|
||||||
|
|
||||||
|
HandleError(Dart_StringToCString(addressHandle, &info->address));
|
||||||
|
HandleError(Dart_IntegerToUint64(portHandle, &info->port));
|
||||||
|
HandleError(Dart_BooleanValue(sharedHandle, &info->shared));
|
||||||
|
HandleError(Dart_IntegerToUint64(backlogHandle, &info->backlog));
|
||||||
|
HandleError(Dart_BooleanValue(v6OnlyHandle, &info->v6Only));
|
||||||
|
}
|
||||||
|
|
||||||
|
void wingsThrowError(const char *msg, const char *lib, const char *name,
|
||||||
|
int n) {
|
||||||
|
Dart_Handle msgHandle = Dart_NewStringFromCString(msg);
|
||||||
|
Dart_Handle emptyHandle = Dart_NewStringFromCString("");
|
||||||
|
Dart_Handle stateErrorHandle = Dart_NewStringFromCString(name);
|
||||||
|
Dart_Handle dartCoreHandle = Dart_NewStringFromCString(lib);
|
||||||
|
Dart_Handle dartCore = Dart_LookupLibrary(dartCoreHandle);
|
||||||
|
Dart_Handle stateError = Dart_GetType(dartCore, stateErrorHandle, 0, nullptr);
|
||||||
|
|
||||||
|
std::vector<Dart_Handle> args;
|
||||||
|
args.push_back(msgHandle);
|
||||||
|
|
||||||
|
if (n > -1) {
|
||||||
|
args.push_back(Dart_NewInteger(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
Dart_Handle errHandle =
|
||||||
|
Dart_New(stateError, emptyHandle, args.size(), args.data());
|
||||||
|
Dart_ThrowException(errHandle);
|
||||||
|
}
|
1
packages/wings/lib/src/http-parser
Submodule
1
packages/wings/lib/src/http-parser
Submodule
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 28f3c35c215ffbe0241685901338fad484660454
|
175
packages/wings/lib/src/http.cc
Normal file
175
packages/wings/lib/src/http.cc
Normal file
|
@ -0,0 +1,175 @@
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "angel_wings.h"
|
||||||
|
#include "wings_socket.h"
|
||||||
|
#include <http-parser/http_parser.h>
|
||||||
|
#include <iostream>
|
||||||
|
using namespace wings;
|
||||||
|
|
||||||
|
void Dart_WingsSocket_parseHttp(Dart_NativeArguments arguments) {
|
||||||
|
Dart_Port service_port =
|
||||||
|
Dart_NewNativePort("WingsHttpCallback", &wingsHttpCallback, true);
|
||||||
|
Dart_Handle send_port = Dart_NewSendPort(service_port);
|
||||||
|
Dart_SetReturnValue(arguments, send_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wingsHttp {
|
||||||
|
Dart_Port port;
|
||||||
|
std::string lastHeader;
|
||||||
|
};
|
||||||
|
|
||||||
|
void wingsHttpCallback(Dart_Port dest_port_id, Dart_CObject *message) {
|
||||||
|
int64_t fd = -1;
|
||||||
|
Dart_Port outPort = message->value.as_array.values[0]->value.as_send_port.id;
|
||||||
|
Dart_CObject *fdArg = message->value.as_array.values[1];
|
||||||
|
|
||||||
|
wingsHttp httpData = {outPort};
|
||||||
|
|
||||||
|
#define theStruct (*((wingsHttp *)parser->data))
|
||||||
|
#define thePort theStruct.port
|
||||||
|
#define sendInt(n) \
|
||||||
|
{ \
|
||||||
|
Dart_CObject obj; \
|
||||||
|
obj.type = Dart_CObject_kInt64; \
|
||||||
|
obj.value.as_int64 = (n); \
|
||||||
|
Dart_PostCObject(thePort, &obj); \
|
||||||
|
}
|
||||||
|
#define sendString(n) \
|
||||||
|
if (length > 0) { \
|
||||||
|
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) {
|
||||||
|
fd = (int64_t)fdArg->value.as_int32;
|
||||||
|
} else {
|
||||||
|
fd = fdArg->value.as_int64;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd != -1) {
|
||||||
|
http_parser_settings settings;
|
||||||
|
|
||||||
|
settings.on_message_begin = [](http_parser *parser) { return 0; };
|
||||||
|
|
||||||
|
settings.on_headers_complete = [](http_parser *parser) {
|
||||||
|
Dart_CObject type;
|
||||||
|
type.type = Dart_CObject_kInt32;
|
||||||
|
type.value.as_int32 = 2;
|
||||||
|
Dart_CObject value;
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
settings.on_message_complete = [](http_parser *parser) {
|
||||||
|
sendInt(200);
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
settings.on_chunk_complete = [](http_parser *parser) { return 0; };
|
||||||
|
|
||||||
|
settings.on_chunk_header = [](http_parser *parser) { return 0; };
|
||||||
|
|
||||||
|
settings.on_url = [](http_parser *parser, const char *at, size_t length) {
|
||||||
|
sendString(0);
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
settings.on_header_field = [](http_parser *parser, const char *at,
|
||||||
|
size_t length) {
|
||||||
|
theStruct.lastHeader = std::string(at, length);
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
settings.on_header_value = [](http_parser *parser, const char *at,
|
||||||
|
size_t length) {
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
settings.on_body = [](http_parser *parser, const char *at, size_t length) {
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t len = 80 * 1024, nparsed = 0;
|
||||||
|
char buf[len];
|
||||||
|
ssize_t recved = 0;
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
// http_parser parser;
|
||||||
|
auto *parser = (http_parser *)malloc(sizeof(http_parser));
|
||||||
|
http_parser_init(parser, HTTP_BOTH);
|
||||||
|
parser->data = &httpData;
|
||||||
|
|
||||||
|
while ((recved = recv(fd, buf, len, 0)) >= 0) {
|
||||||
|
if (false) // (isUpgrade)
|
||||||
|
{
|
||||||
|
// send_string(&parser, buf, (size_t)recved, 7, true);
|
||||||
|
} else {
|
||||||
|
/* Start up / continue the parser.
|
||||||
|
* Note we pass recved==0 to signal that EOF has been received.
|
||||||
|
*/
|
||||||
|
nparsed = http_parser_execute(parser, &settings, buf, recved);
|
||||||
|
|
||||||
|
if (nparsed != recved) {
|
||||||
|
// TODO: End it...!
|
||||||
|
} else if (recved == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if ((isUpgrade = parser.upgrade) == 1)
|
||||||
|
// {
|
||||||
|
// send_notification(&parser, 6);
|
||||||
|
// }
|
||||||
|
// else if (nparsed != recved)
|
||||||
|
// {
|
||||||
|
// close(rq->sock);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// memset(buf, 0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
packages/wings/lib/src/libangel_wings.dylib
Executable file
BIN
packages/wings/lib/src/libangel_wings.dylib
Executable file
Binary file not shown.
BIN
packages/wings/lib/src/libangel_wings.so
Normal file
BIN
packages/wings/lib/src/libangel_wings.so
Normal file
Binary file not shown.
146
packages/wings/lib/src/util.cc
Normal file
146
packages/wings/lib/src/util.cc
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "angel_wings.h"
|
||||||
|
#include "wings_socket.h"
|
||||||
|
#include <dart_native_api.h>
|
||||||
|
#include <iostream>
|
||||||
|
using namespace wings;
|
||||||
|
|
||||||
|
void Dart_WingsSocket_listen(Dart_NativeArguments arguments) {
|
||||||
|
uint64_t ptr;
|
||||||
|
Dart_Handle pointerHandle = Dart_GetNativeArgument(arguments, 0);
|
||||||
|
HandleError(Dart_IntegerToUint64(pointerHandle, &ptr));
|
||||||
|
|
||||||
|
auto *socket = (WingsSocket *)ptr;
|
||||||
|
socket->start(arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wingsSockName {
|
||||||
|
sa_family_t family;
|
||||||
|
sockaddr_in v4;
|
||||||
|
sockaddr_in6 v6;
|
||||||
|
|
||||||
|
struct sockaddr *ptr() const {
|
||||||
|
if (family == AF_INET6) {
|
||||||
|
return (sockaddr *)&v6;
|
||||||
|
} else {
|
||||||
|
return (sockaddr *)&v4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *addrPtr() const {
|
||||||
|
if (family == AF_INET6) {
|
||||||
|
return (void *)&v6.sin6_addr;
|
||||||
|
} else {
|
||||||
|
return (void *)&v4.sin_addr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
socklen_t length() const {
|
||||||
|
if (family == AF_INET6) {
|
||||||
|
return sizeof(v6);
|
||||||
|
} else {
|
||||||
|
return sizeof(v4);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void wingsThrowOSError() {
|
||||||
|
wingsThrowError(strerror(errno), "dart:io", "OSError", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wingsReadSocket(Dart_NativeArguments arguments, wingsSockName *out) {
|
||||||
|
uint64_t ptr;
|
||||||
|
Dart_Handle pointerHandle = Dart_GetNativeArgument(arguments, 0);
|
||||||
|
HandleError(Dart_IntegerToUint64(pointerHandle, &ptr));
|
||||||
|
|
||||||
|
auto *socket = (WingsSocket *)ptr;
|
||||||
|
int fd = socket->getFD();
|
||||||
|
|
||||||
|
socklen_t len;
|
||||||
|
out->family = socket->getFamily();
|
||||||
|
len = out->length();
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
// result = connect(fd, out->ptr(), len);
|
||||||
|
|
||||||
|
// if (result < 0)
|
||||||
|
// {
|
||||||
|
// wingsThrowOSError();
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
|
||||||
|
result = getsockname(fd, out->ptr(), &len);
|
||||||
|
|
||||||
|
if (result == -1) {
|
||||||
|
wingsThrowOSError();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dart_WingsSocket_getAddress(Dart_NativeArguments arguments) {
|
||||||
|
wingsSockName sock;
|
||||||
|
if (wingsReadSocket(arguments, &sock)) {
|
||||||
|
char addrBuf[INET6_ADDRSTRLEN + 1] = {0};
|
||||||
|
|
||||||
|
auto *result =
|
||||||
|
inet_ntop(sock.family, sock.addrPtr(), addrBuf, sock.length());
|
||||||
|
|
||||||
|
if (result == NULL) {
|
||||||
|
wingsThrowOSError();
|
||||||
|
}
|
||||||
|
|
||||||
|
Dart_Handle outHandle = Dart_NewStringFromCString(addrBuf);
|
||||||
|
Dart_SetReturnValue(arguments, outHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dart_WingsSocket_getPort(Dart_NativeArguments arguments) {
|
||||||
|
wingsSockName sock;
|
||||||
|
if (wingsReadSocket(arguments, &sock)) {
|
||||||
|
Dart_Handle outHandle;
|
||||||
|
|
||||||
|
if (sock.family == AF_INET6) {
|
||||||
|
outHandle = Dart_NewIntegerFromUint64(ntohs(sock.v6.sin6_port));
|
||||||
|
} else {
|
||||||
|
outHandle = Dart_NewIntegerFromUint64(ntohs(sock.v4.sin_port));
|
||||||
|
}
|
||||||
|
|
||||||
|
Dart_SetReturnValue(arguments, outHandle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dart_WingsSocket_write(Dart_NativeArguments arguments) {
|
||||||
|
int64_t fd;
|
||||||
|
void *data;
|
||||||
|
Dart_TypedData_Type type;
|
||||||
|
intptr_t len;
|
||||||
|
Dart_Handle fdHandle = Dart_GetNativeArgument(arguments, 0);
|
||||||
|
Dart_Handle dataHandle = Dart_GetNativeArgument(arguments, 1);
|
||||||
|
HandleError(Dart_IntegerToInt64(fdHandle, &fd));
|
||||||
|
HandleError(Dart_TypedDataAcquireData(dataHandle, &type, &data, &len));
|
||||||
|
write(fd, data, len);
|
||||||
|
HandleError(Dart_TypedDataReleaseData(dataHandle));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dart_WingsSocket_closeDescriptor(Dart_NativeArguments arguments) {
|
||||||
|
int64_t fd;
|
||||||
|
Dart_Handle fdHandle = Dart_GetNativeArgument(arguments, 0);
|
||||||
|
HandleError(Dart_IntegerToInt64(fdHandle, &fd));
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Dart_WingsSocket_close(Dart_NativeArguments arguments) {
|
||||||
|
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);
|
||||||
|
}
|
98
packages/wings/lib/src/wings_driver.dart
Normal file
98
packages/wings/lib/src/wings_driver.dart
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io' show Cookie;
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'wings_request.dart';
|
||||||
|
import 'wings_response.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,
|
||||||
|
WingsRequestContext, WingsResponseContext> {
|
||||||
|
factory AngelWings(Angel app) {
|
||||||
|
return AngelWings.custom(app, WingsSocket.bind);
|
||||||
|
}
|
||||||
|
|
||||||
|
AngelWings.custom(
|
||||||
|
Angel app, Future<WingsSocket> Function(dynamic, int) serverGenerator)
|
||||||
|
: super(app, serverGenerator);
|
||||||
|
|
||||||
|
@override
|
||||||
|
void addCookies(int response, Iterable<Cookie> cookies) {
|
||||||
|
for (var cookie in cookies) {
|
||||||
|
setHeader(response, 'set-cookie', cookie.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<WingsSocket> close() async {
|
||||||
|
await server?.close();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future closeResponse(int response) {
|
||||||
|
closeNativeSocketDescriptor(response);
|
||||||
|
return Future.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<WingsRequestContext> createRequestContext(
|
||||||
|
WingsClientSocket request, int response) {
|
||||||
|
return WingsRequestContext.from(app, request);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<WingsResponseContext> createResponseContext(
|
||||||
|
WingsClientSocket request, int response,
|
||||||
|
[WingsRequestContext correspondingRequest]) {
|
||||||
|
return Future.value(WingsResponseContext(
|
||||||
|
app, request.fileDescriptor, correspondingRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<int> createResponseStreamFromRawRequest(WingsClientSocket request) {
|
||||||
|
return Stream.fromIterable([request.fileDescriptor]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setChunkedEncoding(int response, bool value) {
|
||||||
|
// TODO: implement setChunkedEncoding
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setContentLength(int response, int length) {
|
||||||
|
writeStringToResponse(response, 'content-length: $length\r\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setHeader(int response, String key, String value) {
|
||||||
|
writeStringToResponse(response, '$key: $value\r\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void setStatusCode(int response, int value) {
|
||||||
|
// HTTP-Version SP Status-Code SP Reason-Phrase CRLF
|
||||||
|
writeStringToResponse(response, 'HTTP/1.1 $value\r\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Uri get uri {
|
||||||
|
return Uri(scheme: 'http', host: server.address.address, port: server.port);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void writeStringToResponse(int response, String value) {
|
||||||
|
writeToResponse(response, utf8.encode(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void writeToResponse(int response, List<int> data) {
|
||||||
|
var buf = data is Uint8List ? data : Uint8List.fromList(data);
|
||||||
|
writeToNativeSocket(response, buf);
|
||||||
|
}
|
||||||
|
}
|
215
packages/wings/lib/src/wings_request.dart
Normal file
215
packages/wings/lib/src/wings_request.dart
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:isolate';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:angel_container/angel_container.dart';
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:mock_request/mock_request.dart';
|
||||||
|
import 'wings_socket.dart';
|
||||||
|
|
||||||
|
enum _ParseState { method, url, headerField, headerValue, body }
|
||||||
|
|
||||||
|
final RegExp _straySlashes = RegExp(r'(^/+)|(/+$)');
|
||||||
|
|
||||||
|
class WingsRequestContext extends RequestContext<WingsClientSocket> {
|
||||||
|
final WingsClientSocket rawRequest;
|
||||||
|
final Container container;
|
||||||
|
|
||||||
|
final StreamController<List<int>> _body = StreamController();
|
||||||
|
List<Cookie> _cookies, __cookies;
|
||||||
|
final LockableMockHttpHeaders _headers = LockableMockHttpHeaders();
|
||||||
|
final RawReceivePort _recv;
|
||||||
|
InternetAddress _remoteAddress;
|
||||||
|
String _method, _override, _path;
|
||||||
|
Uri _uri;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Angel app;
|
||||||
|
|
||||||
|
WingsRequestContext._(this.app, this.rawRequest, this._recv)
|
||||||
|
: container = app.container.createChild();
|
||||||
|
|
||||||
|
Future<void> close() async {
|
||||||
|
await _body.close();
|
||||||
|
_recv.close();
|
||||||
|
await super.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int DELETE = 0,
|
||||||
|
GET = 1,
|
||||||
|
HEAD = 2,
|
||||||
|
POST = 3,
|
||||||
|
PUT = 4,
|
||||||
|
CONNECT = 5,
|
||||||
|
OPTIONS = 6,
|
||||||
|
TRACE = 7,
|
||||||
|
COPY = 8,
|
||||||
|
LOCK = 9,
|
||||||
|
MKCOL = 10,
|
||||||
|
MOVE = 11,
|
||||||
|
PROPFIND = 12,
|
||||||
|
PROPPATCH = 13,
|
||||||
|
SEARCH = 14,
|
||||||
|
UNLOCK = 15,
|
||||||
|
BIND = 16,
|
||||||
|
REBIND = 17,
|
||||||
|
UNBIND = 18,
|
||||||
|
ACL = 19,
|
||||||
|
REPORT = 20,
|
||||||
|
MKACTIVITY = 21,
|
||||||
|
CHECKOUT = 22,
|
||||||
|
MERGE = 23,
|
||||||
|
MSEARCH = 24,
|
||||||
|
NOTIFY = 25,
|
||||||
|
SUBSCRIBE = 26,
|
||||||
|
UNSUBSCRIBE = 27,
|
||||||
|
PATCH = 28,
|
||||||
|
PURGE = 29,
|
||||||
|
MKCALENDAR = 30,
|
||||||
|
LINK = 31,
|
||||||
|
UNLINK = 32,
|
||||||
|
SOURCE = 33;
|
||||||
|
|
||||||
|
static String methodToString(int method) {
|
||||||
|
switch (method) {
|
||||||
|
case DELETE:
|
||||||
|
return 'DELETE';
|
||||||
|
case GET:
|
||||||
|
return 'GET';
|
||||||
|
case HEAD:
|
||||||
|
return 'HEAD';
|
||||||
|
case POST:
|
||||||
|
return 'POST';
|
||||||
|
case PUT:
|
||||||
|
return 'PUT';
|
||||||
|
case CONNECT:
|
||||||
|
return 'CONNECT';
|
||||||
|
case OPTIONS:
|
||||||
|
return 'OPTIONS';
|
||||||
|
case PATCH:
|
||||||
|
return 'PATCH';
|
||||||
|
case PURGE:
|
||||||
|
return 'PURGE';
|
||||||
|
default:
|
||||||
|
throw ArgumentError('Unknown method $method.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<WingsRequestContext> from(Angel app, WingsClientSocket socket) {
|
||||||
|
// var state = _ParseState.url;
|
||||||
|
var c = Completer<WingsRequestContext>();
|
||||||
|
var recv = RawReceivePort();
|
||||||
|
var rq = WingsRequestContext._(app, socket, recv);
|
||||||
|
rq._remoteAddress = socket.remoteAddress;
|
||||||
|
var ct = StreamController();
|
||||||
|
recv.handler = ct.add;
|
||||||
|
recv.handler = (ee) {
|
||||||
|
if (ee is Uint8List) {
|
||||||
|
if (!rq._body.isClosed) rq._body.add(ee);
|
||||||
|
} else if (ee is List) {
|
||||||
|
var type = ee[0] as int;
|
||||||
|
|
||||||
|
if (type == 2) {
|
||||||
|
rq._method = methodToString(ee[1] as int);
|
||||||
|
} else {
|
||||||
|
var value = ee[1] as String;
|
||||||
|
|
||||||
|
if (type == 0) {
|
||||||
|
rq._uri = Uri.parse(value);
|
||||||
|
var path = rq._uri.path.replaceAll(_straySlashes, '');
|
||||||
|
if (path.isEmpty) path = '/';
|
||||||
|
rq._path = path;
|
||||||
|
} else if (type == 1) {
|
||||||
|
var k = value, v = ee[2] as String;
|
||||||
|
if (k == 'cookie') {
|
||||||
|
rq.__cookies.add(Cookie.fromSetCookieValue(v));
|
||||||
|
} else {
|
||||||
|
rq._headers.add(k, v);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// print("h: $ee');");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ee == 100) {
|
||||||
|
// Headers done, just listen for body.
|
||||||
|
c.complete(rq);
|
||||||
|
} else if (ee == 200) {
|
||||||
|
// Message complete.
|
||||||
|
rq._body.close();
|
||||||
|
}
|
||||||
|
// 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]);
|
||||||
|
return c.future;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Stream<List<int>> get body => _body.stream;
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<Cookie> get cookies => _cookies ??= List.unmodifiable(__cookies);
|
||||||
|
|
||||||
|
@override
|
||||||
|
HttpHeaders get headers => _headers;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get hostname => headers.value('host');
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get method => _override ??=
|
||||||
|
(headers.value('x-http-method-override')?.toUpperCase() ?? _method);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get originalMethod => _method;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get path => _path;
|
||||||
|
|
||||||
|
@override
|
||||||
|
InternetAddress get remoteAddress => _remoteAddress;
|
||||||
|
|
||||||
|
@override
|
||||||
|
// TODO: implement session
|
||||||
|
HttpSession get session => null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Uri get uri => _uri;
|
||||||
|
}
|
215
packages/wings/lib/src/wings_response.dart
Normal file
215
packages/wings/lib/src/wings_response.dart
Normal file
|
@ -0,0 +1,215 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'package:angel_framework/angel_framework.dart';
|
||||||
|
import 'package:charcode/ascii.dart';
|
||||||
|
import 'wings_request.dart';
|
||||||
|
import 'wings_socket.dart';
|
||||||
|
|
||||||
|
class WingsResponseContext extends ResponseContext<int> {
|
||||||
|
@override
|
||||||
|
final Angel app;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final WingsRequestContext correspondingRequest;
|
||||||
|
|
||||||
|
LockableBytesBuilder _buffer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
final int rawResponse;
|
||||||
|
|
||||||
|
bool _isDetached = false, _isClosed = false, _streamInitialized = false;
|
||||||
|
|
||||||
|
WingsResponseContext(this.app, this.rawResponse, [this.correspondingRequest]);
|
||||||
|
|
||||||
|
Iterable<String> __allowedEncodings;
|
||||||
|
|
||||||
|
Iterable<String> get _allowedEncodings {
|
||||||
|
return __allowedEncodings ??= correspondingRequest.headers
|
||||||
|
.value('accept-encoding')
|
||||||
|
?.split(',')
|
||||||
|
?.map((s) => s.trim())
|
||||||
|
?.where((s) => s.isNotEmpty)
|
||||||
|
?.map((str) {
|
||||||
|
// Ignore quality specifications in accept-encoding
|
||||||
|
// ex. gzip;q=0.8
|
||||||
|
if (!str.contains(';')) return str;
|
||||||
|
return str.split(';')[0];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _openStream() {
|
||||||
|
if (!_streamInitialized) {
|
||||||
|
// If this is the first stream added to this response,
|
||||||
|
// then add headers, status code, etc.
|
||||||
|
var outHeaders = <String, String>{};
|
||||||
|
var statusLine =
|
||||||
|
utf8.encode('HTTP/1.1 $statusCode').followedBy([$cr, $lf]);
|
||||||
|
writeToNativeSocket(rawResponse, Uint8List.fromList(statusLine.toList()));
|
||||||
|
|
||||||
|
headers.forEach((k, v) => outHeaders[k] = v);
|
||||||
|
|
||||||
|
if (headers.containsKey('content-length')) {
|
||||||
|
var l = int.tryParse(headers['content-length']);
|
||||||
|
if (l != null) {
|
||||||
|
outHeaders['content-length'] = l.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentType != null) {
|
||||||
|
outHeaders['content-type'] = contentType.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoders.isNotEmpty && correspondingRequest != null) {
|
||||||
|
if (_allowedEncodings != null) {
|
||||||
|
for (var encodingName in _allowedEncodings) {
|
||||||
|
Converter<List<int>, List<int>> encoder;
|
||||||
|
String key = encodingName;
|
||||||
|
|
||||||
|
if (encoders.containsKey(encodingName)) {
|
||||||
|
encoder = encoders[encodingName];
|
||||||
|
} else if (encodingName == '*') {
|
||||||
|
encoder = encoders[key = encoders.keys.first];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoder != null) {
|
||||||
|
outHeaders['content-encoding'] = key;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _wh(String k, String v) {
|
||||||
|
// var vv =Uri.encodeComponent(v);
|
||||||
|
var vv = v;
|
||||||
|
var headerLine = utf8.encode('$k: $vv').followedBy([$cr, $lf]);
|
||||||
|
writeToNativeSocket(
|
||||||
|
rawResponse, Uint8List.fromList(headerLine.toList()));
|
||||||
|
}
|
||||||
|
|
||||||
|
outHeaders.forEach(_wh);
|
||||||
|
|
||||||
|
for (var c in cookies) {
|
||||||
|
_wh('set-cookie', c.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
writeToNativeSocket(rawResponse, Uint8List.fromList([$cr, $lf]));
|
||||||
|
|
||||||
|
//_isClosed = true;
|
||||||
|
return _streamInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future addStream(Stream<List<int>> stream) {
|
||||||
|
if (_isClosed && isBuffered) throw ResponseContext.closed();
|
||||||
|
_openStream();
|
||||||
|
|
||||||
|
Stream<List<int>> output = stream;
|
||||||
|
|
||||||
|
if (encoders.isNotEmpty && correspondingRequest != null) {
|
||||||
|
if (_allowedEncodings != null) {
|
||||||
|
for (var encodingName in _allowedEncodings) {
|
||||||
|
Converter<List<int>, List<int>> encoder;
|
||||||
|
String key = encodingName;
|
||||||
|
|
||||||
|
if (encoders.containsKey(encodingName)) {
|
||||||
|
encoder = encoders[encodingName];
|
||||||
|
} else if (encodingName == '*') {
|
||||||
|
encoder = encoders[key = encoders.keys.first];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoder != null) {
|
||||||
|
output = encoders[key].bind(output);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output.forEach((buf) {
|
||||||
|
if (!_isClosed) {
|
||||||
|
writeToNativeSocket(
|
||||||
|
rawResponse, buf is Uint8List ? buf : Uint8List.fromList(buf));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void add(List<int> data) {
|
||||||
|
if (_isClosed && isBuffered) {
|
||||||
|
throw ResponseContext.closed();
|
||||||
|
} else if (!isBuffered) {
|
||||||
|
if (!_isClosed) {
|
||||||
|
_openStream();
|
||||||
|
|
||||||
|
if (encoders.isNotEmpty && correspondingRequest != null) {
|
||||||
|
if (_allowedEncodings != null) {
|
||||||
|
for (var encodingName in _allowedEncodings) {
|
||||||
|
Converter<List<int>, List<int>> encoder;
|
||||||
|
String key = encodingName;
|
||||||
|
|
||||||
|
if (encoders.containsKey(encodingName)) {
|
||||||
|
encoder = encoders[encodingName];
|
||||||
|
} else if (encodingName == '*') {
|
||||||
|
encoder = encoders[key = encoders.keys.first];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encoder != null) {
|
||||||
|
data = encoders[key].convert(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeToNativeSocket(
|
||||||
|
rawResponse, data is Uint8List ? data : Uint8List.fromList(data));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buffer.add(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future close() async {
|
||||||
|
if (!_isDetached) {
|
||||||
|
if (!_isClosed) {
|
||||||
|
_isClosed = true;
|
||||||
|
if (!isBuffered) {
|
||||||
|
_openStream();
|
||||||
|
closeNativeSocketDescriptor(rawResponse);
|
||||||
|
} else {
|
||||||
|
_buffer.lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await correspondingRequest?.close();
|
||||||
|
await super.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
BytesBuilder get buffer => _buffer;
|
||||||
|
|
||||||
|
@override
|
||||||
|
int detach() {
|
||||||
|
_isDetached = true;
|
||||||
|
return rawResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isBuffered => _buffer != null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool get isOpen => !_isClosed && !_isDetached;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void useBuffer() {
|
||||||
|
_buffer = LockableBytesBuilder();
|
||||||
|
}
|
||||||
|
}
|
129
packages/wings/lib/src/wings_socket.cc
Normal file
129
packages/wings/lib/src/wings_socket.cc
Normal file
|
@ -0,0 +1,129 @@
|
||||||
|
#include "wings_socket.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <vector>
|
||||||
|
using namespace wings;
|
||||||
|
|
||||||
|
std::vector<WingsSocket *> wings::globalSocketList;
|
||||||
|
|
||||||
|
bool WingsSocketInfo::equals(const WingsSocketInfo &right) const {
|
||||||
|
// std::cout << address << " vs " << right.address << std::endl;
|
||||||
|
// 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)
|
||||||
|
: sockfd(sockfd), info(info), family(family) {
|
||||||
|
portIterator = sendPorts.begin();
|
||||||
|
open = true;
|
||||||
|
refCount = 0;
|
||||||
|
workerThread = nullptr;
|
||||||
|
this->info.address = strdup(info.address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WingsSocket::incrRef(Dart_Port port) {
|
||||||
|
refCount++;
|
||||||
|
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);
|
||||||
|
open = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dart_Port WingsSocket::nextPort() {
|
||||||
|
portIterator++;
|
||||||
|
if (portIterator == sendPorts.end())
|
||||||
|
portIterator = sendPorts.begin();
|
||||||
|
return *portIterator;
|
||||||
|
}
|
||||||
|
|
||||||
|
const WingsSocketInfo &WingsSocket::getInfo() const { return info; }
|
||||||
|
|
||||||
|
int WingsSocket::getFD() const { return sockfd; }
|
||||||
|
|
||||||
|
sa_family_t WingsSocket::getFamily() const { return family; }
|
||||||
|
|
||||||
|
bool WingsSocket::isClosed() const { return !open; }
|
||||||
|
|
||||||
|
void WingsSocket::start(Dart_NativeArguments arguments) {
|
||||||
|
// if (workerThread == nullptr)
|
||||||
|
// {
|
||||||
|
// workerThread = std::make_unique<std::thread>(threadCallback, this);
|
||||||
|
// }
|
||||||
|
Dart_Port service_port =
|
||||||
|
Dart_NewNativePort("WingsThreadCallback", &threadCallback, true);
|
||||||
|
Dart_Handle send_port = Dart_NewSendPort(service_port);
|
||||||
|
Dart_SetReturnValue(arguments, send_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WingsSocket::threadCallback(Dart_Port dest_port_id,
|
||||||
|
Dart_CObject *message) {
|
||||||
|
|
||||||
|
WingsSocket *socket = nullptr;
|
||||||
|
Dart_Port outPort = message->value.as_array.values[0]->value.as_send_port.id;
|
||||||
|
Dart_CObject *ptrArg = message->value.as_array.values[1];
|
||||||
|
|
||||||
|
// If there are no listeners, quit.
|
||||||
|
if (ptrArg->type == Dart_CObject_kInt32) {
|
||||||
|
auto as64 = (int64_t)ptrArg->value.as_int32;
|
||||||
|
socket = (WingsSocket *)as64;
|
||||||
|
} else {
|
||||||
|
socket = (WingsSocket *)ptrArg->value.as_int64;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket != nullptr) {
|
||||||
|
if (socket->sendPorts.empty() || socket->isClosed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int sock;
|
||||||
|
unsigned long index = 0;
|
||||||
|
sockaddr addr;
|
||||||
|
socklen_t len;
|
||||||
|
|
||||||
|
if ((sock = accept(socket->sockfd, &addr, &len)) != -1) {
|
||||||
|
char addrBuf[INET6_ADDRSTRLEN] = {0};
|
||||||
|
|
||||||
|
if (addr.sa_family == AF_INET6) {
|
||||||
|
auto as6 = (sockaddr_in6 *)&addr;
|
||||||
|
inet_ntop(addr.sa_family, &(as6->sin6_addr), addrBuf, len);
|
||||||
|
} else {
|
||||||
|
auto as4 = (sockaddr_in *)&addr;
|
||||||
|
inet_ntop(AF_INET, &(as4->sin_addr), addrBuf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
Dart_CObject fdObj;
|
||||||
|
fdObj.type = Dart_CObject_kInt64;
|
||||||
|
fdObj.value.as_int64 = sock;
|
||||||
|
|
||||||
|
Dart_CObject addrObj;
|
||||||
|
addrObj.type = Dart_CObject_kString;
|
||||||
|
addrObj.value.as_string = addrBuf;
|
||||||
|
|
||||||
|
Dart_CObject *values[2] = {&fdObj, &addrObj};
|
||||||
|
|
||||||
|
Dart_CObject obj;
|
||||||
|
obj.type = Dart_CObject_kArray;
|
||||||
|
obj.value.as_array.length = 2;
|
||||||
|
obj.value.as_array.values = values;
|
||||||
|
|
||||||
|
// Dart_PostCObject(outPort, &obj);
|
||||||
|
// Dispatch the fd to the next listener.
|
||||||
|
auto port = socket->nextPort();
|
||||||
|
Dart_PostCObject(port, &obj);
|
||||||
|
// Dart_PostCObject(outPort, &obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
130
packages/wings/lib/src/wings_socket.dart
Normal file
130
packages/wings/lib/src/wings_socket.dart
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:io';
|
||||||
|
import 'dart:isolate';
|
||||||
|
import 'dart:typed_data';
|
||||||
|
import 'dart-ext:angel_wings';
|
||||||
|
|
||||||
|
int bindWingsIPv4ServerSocket(
|
||||||
|
String address,
|
||||||
|
int port,
|
||||||
|
bool shared,
|
||||||
|
int backlog,
|
||||||
|
bool v6Only,
|
||||||
|
SendPort sendPort) native 'Dart_WingsSocket_bindIPv4';
|
||||||
|
|
||||||
|
int bindWingsIPv6ServerSocket(
|
||||||
|
String address,
|
||||||
|
int port,
|
||||||
|
bool shared,
|
||||||
|
int backlog,
|
||||||
|
bool v6Only,
|
||||||
|
SendPort sendPort) native 'Dart_WingsSocket_bindIPv6';
|
||||||
|
|
||||||
|
String getWingsServerSocketAddress(int pointer)
|
||||||
|
native 'Dart_WingsSocket_getAddress';
|
||||||
|
|
||||||
|
int getWingsServerSocketPort(int pointer) native 'Dart_WingsSocket_getPort';
|
||||||
|
|
||||||
|
void writeToNativeSocket(int fd, Uint8List data)
|
||||||
|
native 'Dart_WingsSocket_write';
|
||||||
|
|
||||||
|
void closeNativeSocketDescriptor(int fd)
|
||||||
|
native 'Dart_WingsSocket_closeDescriptor';
|
||||||
|
|
||||||
|
SendPort wingsSocketListen(int pointer) native 'Dart_WingsSocket_listen';
|
||||||
|
|
||||||
|
void closeWingsSocket(int pointer, SendPort sendPort)
|
||||||
|
native 'Dart_WingsSocket_close';
|
||||||
|
|
||||||
|
SendPort wingsParseHttp() native 'Dart_WingsSocket_parseHttp';
|
||||||
|
|
||||||
|
class WingsClientSocket {
|
||||||
|
final int fileDescriptor;
|
||||||
|
final InternetAddress remoteAddress;
|
||||||
|
|
||||||
|
WingsClientSocket(this.fileDescriptor, this.remoteAddress);
|
||||||
|
}
|
||||||
|
|
||||||
|
class WingsSocket extends Stream<WingsClientSocket> {
|
||||||
|
final StreamController<WingsClientSocket> _ctrl = StreamController();
|
||||||
|
SendPort _acceptor;
|
||||||
|
InternetAddress _address;
|
||||||
|
final int _pointer;
|
||||||
|
final RawReceivePort _recv;
|
||||||
|
bool _open = true;
|
||||||
|
int _port;
|
||||||
|
|
||||||
|
WingsSocket._(this._pointer, this._recv) {
|
||||||
|
_acceptor = wingsSocketListen(_pointer);
|
||||||
|
_recv.handler = (h) {
|
||||||
|
if (!_ctrl.isClosed) {
|
||||||
|
_ctrl.add(
|
||||||
|
WingsClientSocket(h[0] as int, InternetAddress(h[1] as String)));
|
||||||
|
_acceptor.send([_recv.sendPort, _pointer]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_acceptor.send([_recv.sendPort, _pointer]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future<WingsSocket> bind(address, int port,
|
||||||
|
{bool shared = false, int backlog = 0, bool v6Only = false}) async {
|
||||||
|
var recv = RawReceivePort();
|
||||||
|
int ptr;
|
||||||
|
InternetAddress addr;
|
||||||
|
|
||||||
|
if (address is InternetAddress) {
|
||||||
|
addr = address;
|
||||||
|
} else if (address is String) {
|
||||||
|
var addrs = await InternetAddress.lookup(address);
|
||||||
|
if (addrs.isNotEmpty) {
|
||||||
|
addr = addrs[0];
|
||||||
|
} else {
|
||||||
|
throw StateError('Internet address lookup failed: $address');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw ArgumentError.value(
|
||||||
|
address, 'address', 'must be an InternetAddress or String');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (addr.type == InternetAddressType.IPv6) {
|
||||||
|
ptr = bindWingsIPv6ServerSocket(
|
||||||
|
addr.address, port, shared, backlog, v6Only, recv.sendPort);
|
||||||
|
} else {
|
||||||
|
ptr = bindWingsIPv4ServerSocket(
|
||||||
|
addr.address, port, shared, backlog, v6Only, recv.sendPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WingsSocket._(ptr, recv); //.._address = addr;
|
||||||
|
} catch (e) {
|
||||||
|
recv.close();
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InternetAddress get address =>
|
||||||
|
_address ??= InternetAddress(getWingsServerSocketAddress(_pointer));
|
||||||
|
|
||||||
|
int get port => _port ??= getWingsServerSocketPort(_pointer);
|
||||||
|
|
||||||
|
@override
|
||||||
|
StreamSubscription<WingsClientSocket> listen(
|
||||||
|
void Function(WingsClientSocket event) onData,
|
||||||
|
{Function onError,
|
||||||
|
void Function() onDone,
|
||||||
|
bool cancelOnError}) {
|
||||||
|
return _ctrl.stream
|
||||||
|
.listen(onData, onError: onError, cancelOnError: cancelOnError);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> close(){
|
||||||
|
if (_open) {
|
||||||
|
_open = false;
|
||||||
|
closeWingsSocket(_pointer, _recv.sendPort);
|
||||||
|
_recv.close();
|
||||||
|
_ctrl.close();
|
||||||
|
}
|
||||||
|
return Future.value();
|
||||||
|
}
|
||||||
|
}
|
54
packages/wings/lib/src/wings_socket.h
Normal file
54
packages/wings/lib/src/wings_socket.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef WINGS_SOCKET_H
|
||||||
|
#define WINGS_SOCKET_H
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <dart_api.h>
|
||||||
|
#include <dart_native_api.h>
|
||||||
|
#include <list>
|
||||||
|
#include <memory>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace wings {
|
||||||
|
struct WingsSocketInfo {
|
||||||
|
const char *address;
|
||||||
|
uint64_t port;
|
||||||
|
bool shared;
|
||||||
|
uint64_t backlog;
|
||||||
|
bool v6Only;
|
||||||
|
Dart_Handle sendPortHandle;
|
||||||
|
bool equals(const WingsSocketInfo &right) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
class WingsSocket {
|
||||||
|
public:
|
||||||
|
WingsSocket(sa_family_t family, int sockfd, const WingsSocketInfo &info);
|
||||||
|
void incrRef(Dart_Port port);
|
||||||
|
void decrRef(Dart_Port port);
|
||||||
|
const WingsSocketInfo &getInfo() const;
|
||||||
|
void start(Dart_NativeArguments arguments);
|
||||||
|
int getFD() const;
|
||||||
|
bool isClosed() const;
|
||||||
|
sa_family_t getFamily() const;
|
||||||
|
Dart_Port nextPort();
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void threadCallback(Dart_Port dest_port_id, Dart_CObject *message);
|
||||||
|
WingsSocketInfo info;
|
||||||
|
std::list<Dart_Port>::iterator portIterator;
|
||||||
|
int sockfd;
|
||||||
|
int refCount;
|
||||||
|
bool open;
|
||||||
|
sa_family_t family;
|
||||||
|
std::unique_ptr<std::thread> workerThread;
|
||||||
|
std::list<Dart_Port> sendPorts;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern std::vector<WingsSocket *> globalSocketList;
|
||||||
|
} // namespace wings
|
||||||
|
|
||||||
|
#endif
|
BIN
packages/wings/libangel_wings.dylib
Executable file
BIN
packages/wings/libangel_wings.dylib
Executable file
Binary file not shown.
BIN
packages/wings/libangel_wings.so
Normal file
BIN
packages/wings/libangel_wings.so
Normal file
Binary file not shown.
24
packages/wings/provision.sh
Executable file
24
packages/wings/provision.sh
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Install Dart, globally.
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install apt-transport-https
|
||||||
|
sudo sh -c 'curl https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -'
|
||||||
|
sudo sh -c 'curl https://storage.googleapis.com/download.dartlang.org/linux/debian/dart_stable.list > /etc/apt/sources.list.d/dart_stable.list'
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y dart
|
||||||
|
export PATH="$PATH:/usr/lib/dart/bin"
|
||||||
|
echo 'export PATH="$PATH:/usr/lib/dart/bin"' >> ~vagrant/.profile
|
||||||
|
|
||||||
|
# Install build tooling, CMake, etc.
|
||||||
|
sudo apt-get install -y build-essential
|
||||||
|
sudo apt-get install -y cmake
|
||||||
|
|
||||||
|
# Build the library.
|
||||||
|
pushd /vagrant
|
||||||
|
mkdir -p cmake-build-vagrant
|
||||||
|
pushd cmake-build-vagrant
|
||||||
|
cmake ..
|
||||||
|
cmake --build . --target install
|
||||||
|
popd
|
||||||
|
popd
|
11
packages/wings/pubspec.yaml
Normal file
11
packages/wings/pubspec.yaml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
name: angel_wings
|
||||||
|
environment:
|
||||||
|
sdk: ">=2.0.0-dev <3.0.0"
|
||||||
|
dependencies:
|
||||||
|
angel_framework: ^2.0.0-alpha
|
||||||
|
mock_request: ^1.0.0
|
||||||
|
dev_dependencies:
|
||||||
|
angel_static: ^2.0.0
|
||||||
|
io: ^0.3.2
|
||||||
|
pedantic: ^1.0.0
|
||||||
|
pretty_logging: ^1.0.0
|
672
packages/wings/ubuntu-bionic-18.04-cloudimg-console.log
Normal file
672
packages/wings/ubuntu-bionic-18.04-cloudimg-console.log
Normal file
|
@ -0,0 +1,672 @@
|
||||||
|
[ 0.000000] Linux version 4.15.0-60-generic (buildd@lgw01-amd64-030) (gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04.1)) #67-Ubuntu SMP Thu Aug 22 16:55:30 UTC 2019 (Ubuntu 4.15.0-60.67-generic 4.15.18)
|
||||||
|
[ 0.000000] Command line: BOOT_IMAGE=/boot/vmlinuz-4.15.0-60-generic root=LABEL=cloudimg-rootfs ro console=tty1 console=ttyS0
|
||||||
|
[ 0.000000] KERNEL supported cpus:
|
||||||
|
[ 0.000000] Intel GenuineIntel
|
||||||
|
[ 0.000000] AMD AuthenticAMD
|
||||||
|
[ 0.000000] Centaur CentaurHauls
|
||||||
|
[ 0.000000] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
|
||||||
|
[ 0.000000] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
|
||||||
|
[ 0.000000] x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
|
||||||
|
[ 0.000000] x86/fpu: xstate_offset[2]: 576, xstate_sizes[2]: 256
|
||||||
|
[ 0.000000] x86/fpu: Enabled xstate features 0x7, context size is 832 bytes, using 'standard' format.
|
||||||
|
[ 0.000000] e820: BIOS-provided physical RAM map:
|
||||||
|
[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
|
||||||
|
[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
|
||||||
|
[ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
|
||||||
|
[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000003ffeffff] usable
|
||||||
|
[ 0.000000] BIOS-e820: [mem 0x000000003fff0000-0x000000003fffffff] ACPI data
|
||||||
|
[ 0.000000] BIOS-e820: [mem 0x00000000fec00000-0x00000000fec00fff] reserved
|
||||||
|
[ 0.000000] BIOS-e820: [mem 0x00000000fee00000-0x00000000fee00fff] reserved
|
||||||
|
[ 0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
|
||||||
|
[ 0.000000] NX (Execute Disable) protection: active
|
||||||
|
[ 0.000000] SMBIOS 2.5 present.
|
||||||
|
[ 0.000000] DMI: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006
|
||||||
|
[ 0.000000] Hypervisor detected: KVM
|
||||||
|
[ 0.000000] e820: last_pfn = 0x3fff0 max_arch_pfn = 0x400000000
|
||||||
|
[ 0.000000] MTRR: Disabled
|
||||||
|
[ 0.000000] x86/PAT: MTRRs disabled, skipping PAT initialization too.
|
||||||
|
[ 0.000000] CPU MTRRs all blank - virtualized system.
|
||||||
|
[ 0.000000] x86/PAT: Configuration [0-7]: WB WT UC- UC WB WT UC- UC
|
||||||
|
[ 0.000000] found SMP MP-table at [mem 0x0009fff0-0x0009ffff]
|
||||||
|
[ 0.000000] Scanning 1 areas for low memory corruption
|
||||||
|
[ 0.000000] RAMDISK: [mem 0x35a8b000-0x36d3cfff]
|
||||||
|
[ 0.000000] ACPI: Early table checksum verification disabled
|
||||||
|
[ 0.000000] ACPI: RSDP 0x00000000000E0000 000024 (v02 VBOX )
|
||||||
|
[ 0.000000] ACPI: XSDT 0x000000003FFF0030 00003C (v01 VBOX VBOXXSDT 00000001 ASL 00000061)
|
||||||
|
[ 0.000000] ACPI: FACP 0x000000003FFF00F0 0000F4 (v04 VBOX VBOXFACP 00000001 ASL 00000061)
|
||||||
|
[ 0.000000] ACPI: DSDT 0x000000003FFF0470 0022EA (v02 VBOX VBOXBIOS 00000002 INTL 20100528)
|
||||||
|
[ 0.000000] ACPI: FACS 0x000000003FFF0200 000040
|
||||||
|
[ 0.000000] ACPI: FACS 0x000000003FFF0200 000040
|
||||||
|
[ 0.000000] ACPI: APIC 0x000000003FFF0240 00005C (v02 VBOX VBOXAPIC 00000001 ASL 00000061)
|
||||||
|
[ 0.000000] ACPI: SSDT 0x000000003FFF02A0 0001CC (v01 VBOX VBOXCPUT 00000002 INTL 20100528)
|
||||||
|
[ 0.000000] No NUMA configuration found
|
||||||
|
[ 0.000000] Faking a node at [mem 0x0000000000000000-0x000000003ffeffff]
|
||||||
|
[ 0.000000] NODE_DATA(0) allocated [mem 0x3ffc5000-0x3ffeffff]
|
||||||
|
[ 0.000000] kvm-clock: cpu 0, msr 0:3ff44001, primary cpu clock
|
||||||
|
[ 0.000000] kvm-clock: Using msrs 4b564d01 and 4b564d00
|
||||||
|
[ 0.000000] kvm-clock: using sched offset of 6313796290 cycles
|
||||||
|
[ 0.000000] clocksource: kvm-clock: mask: 0xffffffffffffffff max_cycles: 0x1cd42e4dffb, max_idle_ns: 881590591483 ns
|
||||||
|
[ 0.000000] Zone ranges:
|
||||||
|
[ 0.000000] DMA [mem 0x0000000000001000-0x0000000000ffffff]
|
||||||
|
[ 0.000000] DMA32 [mem 0x0000000001000000-0x000000003ffeffff]
|
||||||
|
[ 0.000000] Normal empty
|
||||||
|
[ 0.000000] Device empty
|
||||||
|
[ 0.000000] Movable zone start for each node
|
||||||
|
[ 0.000000] Early memory node ranges
|
||||||
|
[ 0.000000] node 0: [mem 0x0000000000001000-0x000000000009efff]
|
||||||
|
[ 0.000000] node 0: [mem 0x0000000000100000-0x000000003ffeffff]
|
||||||
|
[ 0.000000] Reserved but unavailable: 98 pages
|
||||||
|
[ 0.000000] Initmem setup node 0 [mem 0x0000000000001000-0x000000003ffeffff]
|
||||||
|
[ 0.000000] ACPI: PM-Timer IO Port: 0x4008
|
||||||
|
[ 0.000000] IOAPIC[0]: apic_id 2, version 32, address 0xfec00000, GSI 0-23
|
||||||
|
[ 0.000000] ACPI: INT_SRC_OVR (bus 0 bus_irq 0 global_irq 2 dfl dfl)
|
||||||
|
[ 0.000000] ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 low level)
|
||||||
|
[ 0.000000] Using ACPI (MADT) for SMP configuration information
|
||||||
|
[ 0.000000] smpboot: Allowing 2 CPUs, 0 hotplug CPUs
|
||||||
|
[ 0.000000] PM: Registered nosave memory: [mem 0x00000000-0x00000fff]
|
||||||
|
[ 0.000000] PM: Registered nosave memory: [mem 0x0009f000-0x0009ffff]
|
||||||
|
[ 0.000000] PM: Registered nosave memory: [mem 0x000a0000-0x000effff]
|
||||||
|
[ 0.000000] PM: Registered nosave memory: [mem 0x000f0000-0x000fffff]
|
||||||
|
[ 0.000000] e820: [mem 0x40000000-0xfebfffff] available for PCI devices
|
||||||
|
[ 0.000000] Booting paravirtualized kernel on KVM
|
||||||
|
[ 0.000000] clocksource: refined-jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645519600211568 ns
|
||||||
|
[ 0.000000] random: get_random_bytes called from start_kernel+0x99/0x4fd with crng_init=0
|
||||||
|
[ 0.000000] setup_percpu: NR_CPUS:8192 nr_cpumask_bits:2 nr_cpu_ids:2 nr_node_ids:1
|
||||||
|
[ 0.000000] percpu: Embedded 46 pages/cpu s151552 r8192 d28672 u1048576
|
||||||
|
[ 0.000000] PV qspinlock hash table entries: 256 (order: 0, 4096 bytes)
|
||||||
|
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 257913
|
||||||
|
[ 0.000000] Policy zone: DMA32
|
||||||
|
[ 0.000000] Kernel command line: BOOT_IMAGE=/boot/vmlinuz-4.15.0-60-generic root=LABEL=cloudimg-rootfs ro console=tty1 console=ttyS0
|
||||||
|
[ 0.000000] Memory: 983440K/1048120K available (12300K kernel code, 2481K rwdata, 4172K rodata, 2436K init, 2384K bss, 64680K reserved, 0K cma-reserved)
|
||||||
|
[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=2, Nodes=1
|
||||||
|
[ 0.000000] Kernel/User page tables isolation: enabled
|
||||||
|
[ 0.000000] ftrace: allocating 39306 entries in 154 pages
|
||||||
|
[ 0.004000] Hierarchical RCU implementation.
|
||||||
|
[ 0.004000] RCU restricting CPUs from NR_CPUS=8192 to nr_cpu_ids=2.
|
||||||
|
[ 0.004000] Tasks RCU enabled.
|
||||||
|
[ 0.004000] RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=2
|
||||||
|
[ 0.004000] NR_IRQS: 524544, nr_irqs: 440, preallocated irqs: 16
|
||||||
|
[ 0.004000] Console: colour VGA+ 80x25
|
||||||
|
[ 0.004000] console [tty1] enabled
|
||||||
|
[ 0.004000] console [ttyS0] enabled
|
||||||
|
[ 0.004000] ACPI: Core revision 20170831
|
||||||
|
[ 0.004000] ACPI: 2 ACPI AML tables successfully acquired and loaded
|
||||||
|
[ 0.004000] APIC: Switch to symmetric I/O mode setup
|
||||||
|
[ 0.004000] x2apic enabled
|
||||||
|
[ 0.004000] Switched APIC routing to physical x2apic.
|
||||||
|
[ 0.005261] ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1
|
||||||
|
[ 0.008004] tsc: Detected 1799.999 MHz processor
|
||||||
|
[ 0.012012] Calibrating delay loop (skipped) preset value.. 3599.99 BogoMIPS (lpj=7199996)
|
||||||
|
[ 0.014430] pid_max: default: 32768 minimum: 301
|
||||||
|
[ 0.016036] Security Framework initialized
|
||||||
|
[ 0.017257] Yama: becoming mindful.
|
||||||
|
[ 0.018593] AppArmor: AppArmor initialized
|
||||||
|
[ 0.021844] Dentry cache hash table entries: 131072 (order: 8, 1048576 bytes)
|
||||||
|
[ 0.024088] Inode-cache hash table entries: 65536 (order: 7, 524288 bytes)
|
||||||
|
[ 0.028022] Mount-cache hash table entries: 2048 (order: 2, 16384 bytes)
|
||||||
|
[ 0.030085] Mountpoint-cache hash table entries: 2048 (order: 2, 16384 bytes)
|
||||||
|
[ 0.032346] Last level iTLB entries: 4KB 64, 2MB 8, 4MB 8
|
||||||
|
[ 0.036002] Last level dTLB entries: 4KB 64, 2MB 0, 4MB 0, 1GB 4
|
||||||
|
[ 0.038331] Spectre V1 : Mitigation: usercopy/swapgs barriers and __user pointer sanitization
|
||||||
|
[ 0.040053] Spectre V2 : Mitigation: Full generic retpoline
|
||||||
|
[ 0.044003] Spectre V2 : Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch
|
||||||
|
[ 0.047370] Speculative Store Bypass: Vulnerable
|
||||||
|
[ 0.048050] MDS: Vulnerable: Clear CPU buffers attempted, no microcode
|
||||||
|
[ 0.050738] Freeing SMP alternatives memory: 36K
|
||||||
|
[ 0.060000] smpboot: CPU0: Intel(R) Core(TM) i5-5350U CPU @ 1.80GHz (family: 0x6, model: 0x3d, stepping: 0x4)
|
||||||
|
[ 0.060095] Performance Events: unsupported p6 CPU model 61 no PMU driver, software events only.
|
||||||
|
[ 0.063096] Hierarchical SRCU implementation.
|
||||||
|
[ 0.064650] NMI watchdog: Perf event create on CPU 0 failed with -2
|
||||||
|
[ 0.066472] NMI watchdog: Perf NMI watchdog permanently disabled
|
||||||
|
[ 0.068053] smp: Bringing up secondary CPUs ...
|
||||||
|
[ 0.069490] x86: Booting SMP configuration:
|
||||||
|
[ 0.070770] .... node #0, CPUs: #1
|
||||||
|
[ 0.004000] kvm-clock: cpu 1, msr 0:3ff44041, secondary cpu clock
|
||||||
|
[ 0.078095] smp: Brought up 1 node, 2 CPUs
|
||||||
|
[ 0.078095] smpboot: Max logical packages: 1
|
||||||
|
[ 0.080007] smpboot: Total of 2 processors activated (7199.99 BogoMIPS)
|
||||||
|
[ 0.085029] devtmpfs: initialized
|
||||||
|
[ 0.085718] x86/mm: Memory block size: 128MB
|
||||||
|
[ 0.088152] evm: security.selinux
|
||||||
|
[ 0.089578] evm: security.SMACK64
|
||||||
|
[ 0.090723] evm: security.SMACK64EXEC
|
||||||
|
[ 0.092005] evm: security.SMACK64TRANSMUTE
|
||||||
|
[ 0.093324] evm: security.SMACK64MMAP
|
||||||
|
[ 0.094789] evm: security.apparmor
|
||||||
|
[ 0.096003] evm: security.ima
|
||||||
|
[ 0.097270] evm: security.capability
|
||||||
|
[ 0.100127] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 7645041785100000 ns
|
||||||
|
[ 0.104010] futex hash table entries: 512 (order: 3, 32768 bytes)
|
||||||
|
[ 0.108000] pinctrl core: initialized pinctrl subsystem
|
||||||
|
[ 0.108153] RTC time: 4:37:25, date: 09/29/19
|
||||||
|
[ 0.112223] NET: Registered protocol family 16
|
||||||
|
[ 0.114097] audit: initializing netlink subsys (disabled)
|
||||||
|
[ 0.116040] audit: type=2000 audit(1569731852.938:1): state=initialized audit_enabled=0 res=1
|
||||||
|
[ 0.120020] cpuidle: using governor ladder
|
||||||
|
[ 0.121972] cpuidle: using governor menu
|
||||||
|
[ 0.124054] ACPI: bus type PCI registered
|
||||||
|
[ 0.125660] acpiphp: ACPI Hot Plug PCI Controller Driver version: 0.5
|
||||||
|
[ 0.128144] PCI: Using configuration type 1 for base access
|
||||||
|
[ 0.132420] HugeTLB registered 2.00 MiB page size, pre-allocated 0 pages
|
||||||
|
[ 0.136070] ACPI: Added _OSI(Module Device)
|
||||||
|
[ 0.137755] ACPI: Added _OSI(Processor Device)
|
||||||
|
[ 0.139558] ACPI: Added _OSI(3.0 _SCP Extensions)
|
||||||
|
[ 0.140012] ACPI: Added _OSI(Processor Aggregator Device)
|
||||||
|
[ 0.142205] ACPI: Added _OSI(Linux-Dell-Video)
|
||||||
|
[ 0.144009] ACPI: Added _OSI(Linux-Lenovo-NV-HDMI-Audio)
|
||||||
|
[ 0.146265] ACPI: Added _OSI(Linux-HPI-Hybrid-Graphics)
|
||||||
|
[ 0.148559] ACPI: Executed 1 blocks of module-level executable AML code
|
||||||
|
[ 0.157460] ACPI: Interpreter enabled
|
||||||
|
[ 0.159031] ACPI: (supports S0 S5)
|
||||||
|
[ 0.160004] ACPI: Using IOAPIC for interrupt routing
|
||||||
|
[ 0.162232] PCI: Using host bridge windows from ACPI; if necessary, use "pci=nocrs" and report a bug
|
||||||
|
[ 0.164282] ACPI: Enabled 2 GPEs in block 00 to 07
|
||||||
|
[ 0.177420] ACPI: PCI Root Bridge [PCI0] (domain 0000 [bus 00-ff])
|
||||||
|
[ 0.179619] acpi PNP0A03:00: _OSC: OS supports [ASPM ClockPM Segments MSI]
|
||||||
|
[ 0.180559] acpi PNP0A03:00: _OSC: not requesting OS control; OS requires [ExtendedConfig ASPM ClockPM MSI]
|
||||||
|
[ 0.184016] acpi PNP0A03:00: fail to add MMCONFIG information, can't access extended PCI configuration space under this bridge.
|
||||||
|
[ 0.188599] PCI host bridge to bus 0000:00
|
||||||
|
[ 0.190032] pci_bus 0000:00: root bus resource [io 0x0000-0x0cf7 window]
|
||||||
|
[ 0.192012] pci_bus 0000:00: root bus resource [io 0x0d00-0xffff window]
|
||||||
|
[ 0.196010] pci_bus 0000:00: root bus resource [mem 0x000a0000-0x000bffff window]
|
||||||
|
[ 0.198997] pci_bus 0000:00: root bus resource [mem 0x40000000-0xfdffffff window]
|
||||||
|
[ 0.200005] pci_bus 0000:00: root bus resource [bus 00-ff]
|
||||||
|
[ 0.209096] pci 0000:00:01.1: legacy IDE quirk: reg 0x10: [io 0x01f0-0x01f7]
|
||||||
|
[ 0.212011] pci 0000:00:01.1: legacy IDE quirk: reg 0x14: [io 0x03f6]
|
||||||
|
[ 0.214198] pci 0000:00:01.1: legacy IDE quirk: reg 0x18: [io 0x0170-0x0177]
|
||||||
|
[ 0.216011] pci 0000:00:01.1: legacy IDE quirk: reg 0x1c: [io 0x0376]
|
||||||
|
[ 0.250063] pci 0000:00:07.0: quirk: [io 0x4000-0x403f] claimed by PIIX4 ACPI
|
||||||
|
[ 0.252032] pci 0000:00:07.0: quirk: [io 0x4100-0x410f] claimed by PIIX4 SMB
|
||||||
|
[ 0.268428] ACPI: PCI Interrupt Link [LNKA] (IRQs 5 9 10 *11)
|
||||||
|
[ 0.271342] ACPI: PCI Interrupt Link [LNKB] (IRQs 5 9 *10 11)
|
||||||
|
[ 0.272177] ACPI: PCI Interrupt Link [LNKC] (IRQs 5 *9 10 11)
|
||||||
|
[ 0.274371] ACPI: PCI Interrupt Link [LNKD] (IRQs 5 9 10 *11)
|
||||||
|
[ 0.276529] SCSI subsystem initialized
|
||||||
|
[ 0.280075] pci 0000:00:02.0: vgaarb: setting as boot VGA device
|
||||||
|
[ 0.282678] pci 0000:00:02.0: vgaarb: VGA device added: decodes=io+mem,owns=io+mem,locks=none
|
||||||
|
[ 0.284008] pci 0000:00:02.0: vgaarb: bridge control possible
|
||||||
|
[ 0.288007] vgaarb: loaded
|
||||||
|
[ 0.289501] ACPI: bus type USB registered
|
||||||
|
[ 0.292045] usbcore: registered new interface driver usbfs
|
||||||
|
[ 0.294316] usbcore: registered new interface driver hub
|
||||||
|
[ 0.296044] usbcore: registered new device driver usb
|
||||||
|
[ 0.300127] EDAC MC: Ver: 3.0.0
|
||||||
|
[ 0.302311] PCI: Using ACPI for IRQ routing
|
||||||
|
[ 0.304830] NetLabel: Initializing
|
||||||
|
[ 0.308006] NetLabel: domain hash size = 128
|
||||||
|
[ 0.310637] NetLabel: protocols = UNLABELED CIPSOv4 CALIPSO
|
||||||
|
[ 0.312043] NetLabel: unlabeled traffic allowed by default
|
||||||
|
[ 0.316129] clocksource: Switched to clocksource kvm-clock
|
||||||
|
[ 0.338523] VFS: Disk quotas dquot_6.6.0
|
||||||
|
[ 0.340526] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
|
||||||
|
[ 0.344063] AppArmor: AppArmor Filesystem Enabled
|
||||||
|
[ 0.347415] pnp: PnP ACPI init
|
||||||
|
[ 0.354536] pnp: PnP ACPI: found 3 devices
|
||||||
|
[ 0.377986] clocksource: acpi_pm: mask: 0xffffff max_cycles: 0xffffff, max_idle_ns: 2085701024 ns
|
||||||
|
[ 0.384610] NET: Registered protocol family 2
|
||||||
|
[ 0.391662] TCP established hash table entries: 8192 (order: 4, 65536 bytes)
|
||||||
|
[ 0.396743] TCP bind hash table entries: 8192 (order: 5, 131072 bytes)
|
||||||
|
[ 0.401916] TCP: Hash tables configured (established 8192 bind 8192)
|
||||||
|
[ 0.406238] UDP hash table entries: 512 (order: 2, 16384 bytes)
|
||||||
|
[ 0.409854] UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
|
||||||
|
[ 0.414792] NET: Registered protocol family 1
|
||||||
|
[ 0.418002] pci 0000:00:00.0: Limiting direct PCI/PCI transfers
|
||||||
|
[ 0.423100] pci 0000:00:01.0: Activating ISA DMA hang workarounds
|
||||||
|
[ 0.427601] pci 0000:00:02.0: Video device with shadowed ROM at [mem 0x000c0000-0x000dffff]
|
||||||
|
[ 0.434649] Unpacking initramfs...
|
||||||
|
[ 0.787407] Freeing initrd memory: 19144K
|
||||||
|
[ 0.789209] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x19f228ab7a2, max_idle_ns: 440795289252 ns
|
||||||
|
[ 0.793332] platform rtc_cmos: registered platform RTC device (no PNP device found)
|
||||||
|
[ 0.796800] Scanning for low memory corruption every 60 seconds
|
||||||
|
[ 0.799238] Initialise system trusted keyrings
|
||||||
|
[ 0.801081] Key type blacklist registered
|
||||||
|
[ 0.802821] workingset: timestamp_bits=36 max_order=18 bucket_order=0
|
||||||
|
[ 0.805819] zbud: loaded
|
||||||
|
[ 0.807186] squashfs: version 4.0 (2009/01/31) Phillip Lougher
|
||||||
|
[ 0.810037] fuse init (API version 7.26)
|
||||||
|
[ 0.815469] Key type asymmetric registered
|
||||||
|
[ 0.816858] Asymmetric key parser 'x509' registered
|
||||||
|
[ 0.818479] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 246)
|
||||||
|
[ 0.821254] io scheduler noop registered
|
||||||
|
[ 0.822470] io scheduler deadline registered
|
||||||
|
[ 0.823827] io scheduler cfq registered (default)
|
||||||
|
[ 0.826132] ACPI: AC Adapter [AC] (on-line)
|
||||||
|
[ 0.827462] input: Power Button as /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
|
||||||
|
[ 0.830032] ACPI: Power Button [PWRF]
|
||||||
|
[ 0.831785] input: Sleep Button as /devices/LNXSYSTM:00/LNXSLPBN:00/input/input1
|
||||||
|
[ 0.834809] ACPI: Sleep Button [SLPF]
|
||||||
|
[ 0.838210] ACPI: Battery Slot [BAT0] (battery present)
|
||||||
|
[ 0.840233] Serial: 8250/16550 driver, 32 ports, IRQ sharing enabled
|
||||||
|
|