Implementation
String serverFile(
ServerServer server,
String Function(Spec) formatter, {
required Options options,
}) {
final imports = [
if (options.ignoreLints case final lints when lints.isNotEmpty)
"// ignore_for_file: ${options.ignoreLints.join(', ')}\n",
"import 'dart:io';",
"import 'dart:async';",
'',
"import 'package:path/path.dart' as p;",
for (final imprt in {
if (server.context.mode.isDebug)
'package:revali_construct/revali_construct.dart',
'package:revali_router/revali_router.dart',
...server.packageImports(),
})
"import '$imprt';",
'',
for (final imprt in {...server.pathImports()}) "import '../../$imprt';",
];
final app = server.app;
if (app == null) {
throw Exception('No app found');
}
final main = Method(
(b) => b
..name = 'main'
..returns = refer('void')
..requiredParameters.add(
Parameter(
(b) => b
..name = 'args'
..type = refer('List<String>'),
),
)
..body = Block.of([
if (server.context.mode.isDebug)
refer('hotReload').call([
Method(
(b) => b
..lambda = true
..body = refer(
'createServer',
).call([literalNull, refer('args')]).code,
).closure,
]).statement
else
refer('createServer').call([literalNull, refer('args')]).statement,
]),
);
final createServer = Method(
(b) => b
..name = 'createServer'
..returns = TypeReference(
(p) => p
..symbol = (Future).name
..types.add(refer((HttpServer).name)),
)
..modifier = MethodModifier.async
..optionalParameters.addAll([
Parameter(
(e) => e
..name = 'providedServer'
..named = false
..type = refer('${(HttpServer).name}?'),
),
Parameter(
(e) => e
..name = 'rawArgs'
..named = false
..defaultTo = const Code('const []')
..type = refer('List<String>'),
),
])
..body = Block.of([
declareFinal('args')
.assign(
refer((Args).name).newInstanceNamed('parse', [refer('rawArgs')]),
)
.statement,
declareFinal(
'app',
type: refer((AppConfig).name),
).assign(createApp(app)).statement,
declareFinal('server', late: true, type: refer('HttpServer')).statement,
tryCatch(
refer('server')
.assign(
refer('providedServer').ifNullThen(
refer((HttpServer).name)
.property(app.isSecure ? 'bindSecure' : 'bind')
.call(
[
refer('app').property('host'),
refer('app').property('port'),
if (app.isSecure)
refer(
'app',
).property('securityContext').nullChecked,
],
{
if (app.isSecure)
'requestClientCertificate': refer(
'app',
).property('requestClientCertificate'),
if (server.context.mode.isDebug)
'shared': literalTrue,
},
)
.awaited,
),
)
.statement,
Block.of([
refer(
'print',
).call([literalString(r'Failed to bind server:\n$e')]).statement,
refer('exit').call([literalNum(1)]).statement,
]),
),
const Code('\n'),
...createDependencyInjection(server),
const Code('\n'),
...createRoutesVariable(server),
const Code('\n'),
Block.of([
const Code('if ('),
refer('app').property('prefix').code,
const Code(' case'),
declareFinal('prefix?').code,
const Code(' when '),
refer('prefix').property('isNotEmpty').code,
const Code(') {'),
refer('_routes')
.assign(
literalList([
refer((Route).name).newInstance(
[refer('prefix')],
{'routes': refer('_routes')},
),
]),
)
.statement,
const Code('}'),
]),
const Code('\n'),
declareFinal('router')
.assign(
refer((Router).name).newInstance([], {
if (server.context.mode.isNotRelease) 'debug': literalTrue,
'routes': literalList([
refer('_routes').spread,
refer('public').spread,
]),
if (app.observers.hasObservers)
'observers': literalList([
if (app.observers.types.expand((e) => e.types)
case final observers when observers.isNotEmpty)
for (final observer in observers) createClass(observer),
if (app.observers.mimics case final mimics
when mimics.isNotEmpty)
for (final type in mimics) createMimic(type),
]),
'reflects': refer('reflects'),
'defaultResponses': refer('app').property('defaultResponses'),
if (server.app case final app?
when app.globalRouteAnnotations.hasAnnotations)
'globalComponents': refer((LifecycleComponentsImpl).name)
.newInstance([], {
...createModifierArgs(
annotations: app.globalRouteAnnotations,
),
}),
}),
)
.statement,
const Code('\n'),
refer('handleRequests')
.call([
refer('server'),
refer('router').property('handle'),
refer('router').property('responseHandler'),
refer('router').property('close'),
])
.property('ignore')
.call([])
.statement,
const Code('\n'),
refer(
'app',
).property('onServerStarted').call([refer('server')]).statement,
const Code('\n'),
refer('server').returned.statement,
]),
);
final parts = <Spec>[main, createServer];
final content = parts.map(formatter).join('\n');
return '''
${imports.join('\n')}
$content''';
}