cyberhybridhub/server/lib/handlers/trading_dev_handler.dart

65 lines
2.0 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:shelf/shelf.dart';
import 'package:shelf_router/shelf_router.dart';
import '../cors_headers.dart';
import '../firebase_auth.dart';
import '../trading/trading_dev_actions.dart';
const String tradingDevBasePath = '/v1/me/trading/dev';
/// Dev-only HTTP endpoints to exercise the trading flow without waiting for
/// real market conditions. Mounted only when `TRADING_DEV_ENDPOINTS_ENABLED=true`.
///
/// Endpoints:
/// * `POST /v1/me/trading/dev/force-fire` — seeds dipped snapshots for the
/// caller and runs one [TradingPipeline.evaluate] cycle. The next worker
/// tick (or an immediate SignalR push from `createAndDeliverQuestion`)
/// surfaces the question in the Flutter UI.
Handler tradingDevHandler({
required FirebaseAuthVerifier auth,
required TradingDevActions devActions,
}) {
final Router router = Router();
router.post('$tradingDevBasePath/force-fire', (Request request) async {
final String? firebaseUid = await _verify(auth, request);
if (firebaseUid == null) {
return _jsonResponse(401, <String, dynamic>{'error': 'Unauthorized'});
}
try {
final ForceFireResult result = await devActions.forceFireDip(firebaseUid);
return _jsonResponse(200, result.toJson());
} catch (e, st) {
stderr.writeln('trading dev force-fire failed for $firebaseUid: $e\n$st');
return _jsonResponse(500, <String, dynamic>{'error': 'Internal error'});
}
});
return (Request request) async {
if (request.method == 'OPTIONS') {
return Response.ok('', headers: apiCorsHeaders());
}
return router.call(request);
};
}
Future<String?> _verify(FirebaseAuthVerifier auth, Request request) {
return auth.verifyBearerToken(
request.headers['Authorization'] ?? request.headers['authorization'],
);
}
Response _jsonResponse(int status, Map<String, dynamic> body) {
return Response(
status,
body: jsonEncode(body),
headers: <String, String>{
...apiCorsHeaders(),
'Content-Type': 'application/json',
},
);
}