1- import 'dart:io' ;
1+ import 'dart:io' ;
22
33import 'package:dart_frog/dart_frog.dart' ;
44import 'package:ht_api/src/config/environment_config.dart' ;
5+ import 'package:ht_data_postgres/ht_data_postgres.dart' ;
6+ import 'package:ht_data_repository/ht_data_repository.dart' ;
7+ import 'package:ht_shared/ht_shared.dart' ;
58import 'package:logging/logging.dart' ;
69import 'package:postgres/postgres.dart' ;
10+ import 'package:uuid/uuid.dart' ;
711
812/// Global logger instance.
9- final _log = Logger ('ht_api' );
13+ final _log = Logger ('ht_api' );
1014
1115/// Global PostgreSQL connection instance.
12- late final Connection _connection;
16+ late final Connection _connection;
17+
18+ /// Creates a data repository for a given type [T] .
19+ ///
20+ /// This helper function centralizes the creation of repositories,
21+ /// ensuring they all use the same database connection and logger.
22+ HtDataRepository <T > _createRepository <T >({
23+ required String tableName,
24+ required FromJson <T > fromJson,
25+ required ToJson <T > toJson,
26+ }) {
27+ return HtDataRepository <T >(
28+ dataClient: HtDataPostgresClient <T >(
29+ connection: _connection,
30+ tableName: tableName,
31+ fromJson: fromJson,
32+ toJson: toJson,
33+ log: _log,
34+ ),
35+ );
36+ }
1337
1438/// The main entry point for the server.
1539///
@@ -31,21 +55,111 @@ Future<HttpServer> run(Handler handler, InternetAddress ip, int port) async {
3155
3256 // 2. Establish Database Connection
3357 _log.info ('Connecting to PostgreSQL database...' );
58+ final dbUri = Uri .parse (EnvironmentConfig .databaseUrl);
59+ String ? username;
60+ String ? password;
61+ if (dbUri.userInfo.isNotEmpty) {
62+ final parts = dbUri.userInfo.split (':' );
63+ username = Uri .decodeComponent (parts.first);
64+ if (parts.length > 1 ) {
65+ password = Uri .decodeComponent (parts.last);
66+ }
67+ }
68+
3469 _connection = await Connection .open (
35- Endpoint .uri (Uri .parse (EnvironmentConfig .databaseUrl)),
36- settings: const ConnectionSettings (sslMode: SslMode .prefer),
70+ Endpoint (
71+ host: dbUri.host,
72+ port: dbUri.port,
73+ database: dbUri.path.substring (1 ), // Remove leading '/'
74+ username: username,
75+ password: password,
76+ ),
77+ // Using `require` is a more secure default. For local development against
78+ // a non-SSL database, this may need to be changed to `SslMode.disable`.
79+ settings: const ConnectionSettings (sslMode: SslMode .require),
3780 );
3881 _log.info ('PostgreSQL database connection established.' );
3982
40- // 3. Start the server and set up shutdown logic
41- return serve (
42- handler,
83+ // 3. Initialize Repositories
84+ final headlineRepository = _createRepository <Headline >(
85+ tableName: 'headlines' ,
86+ fromJson: Headline .fromJson,
87+ toJson: (h) => h.toJson (),
88+ );
89+ final categoryRepository = _createRepository <Category >(
90+ tableName: 'categories' ,
91+ fromJson: Category .fromJson,
92+ toJson: (c) => c.toJson (),
93+ );
94+ final sourceRepository = _createRepository <Source >(
95+ tableName: 'sources' ,
96+ fromJson: Source .fromJson,
97+ toJson: (s) => s.toJson (),
98+ );
99+ final countryRepository = _createRepository <Country >(
100+ tableName: 'countries' ,
101+ fromJson: Country .fromJson,
102+ toJson: (c) => c.toJson (),
103+ );
104+ final userRepository = _createRepository <User >(
105+ tableName: 'users' ,
106+ fromJson: User .fromJson,
107+ toJson: (u) => u.toJson (),
108+ );
109+ final userAppSettingsRepository = _createRepository <UserAppSettings >(
110+ tableName: 'user_app_settings' ,
111+ fromJson: UserAppSettings .fromJson,
112+ toJson: (s) => s.toJson (),
113+ );
114+ final userContentPreferencesRepository =
115+ _createRepository <UserContentPreferences >(
116+ tableName: 'user_content_preferences' ,
117+ fromJson: UserContentPreferences .fromJson,
118+ toJson: (p) => p.toJson (),
119+ );
120+ final appConfigRepository = _createRepository <AppConfig >(
121+ tableName: 'app_config' ,
122+ fromJson: AppConfig .fromJson,
123+ toJson: (c) => c.toJson (),
124+ );
125+
126+ // 4. Create the main handler with all dependencies provided
127+ final finalHandler = handler
128+ .use (provider <Uuid >((_) => const Uuid ()))
129+ .use (provider <HtDataRepository <Headline >>((_) => headlineRepository))
130+ .use (provider <HtDataRepository <Category >>((_) => categoryRepository))
131+ .use (provider <HtDataRepository <Source >>((_) => sourceRepository))
132+ .use (provider <HtDataRepository <Country >>((_) => countryRepository))
133+ .use (provider <HtDataRepository <User >>((_) => userRepository))
134+ .use (
135+ provider <HtDataRepository <UserAppSettings >>(
136+ (_) => userAppSettingsRepository,
137+ ),
138+ )
139+ .use (
140+ provider <HtDataRepository <UserContentPreferences >>(
141+ (_) => userContentPreferencesRepository,
142+ ),
143+ )
144+ .use (provider <HtDataRepository <AppConfig >>((_) => appConfigRepository));
145+
146+ // 5. Start the server
147+ final server = await serve (
148+ finalHandler,
43149 ip,
44150 port,
45- onShutdown: () async {
46- _log.info ('Server shutting down. Closing database connection...' );
47- await _connection.close ();
48- _log.info ('Database connection closed.' );
49- },
50151 );
51- }
152+ _log.info ('Server listening on port ${server .port }' );
153+
154+ // 6. Handle graceful shutdown
155+ ProcessSignal .sigint.watch ().listen ((_) async {
156+ _log.info ('Received SIGINT. Shutting down...' );
157+ await _connection.close ();
158+ _log.info ('Database connection closed.' );
159+ await server.close (force: true );
160+ _log.info ('Server shut down.' );
161+ exit (0 );
162+ });
163+
164+ return server;
165+ }
0 commit comments