1
- import 'dart:io' ;
1
+ import 'dart:io' ;
2
2
3
3
import 'package:dart_frog/dart_frog.dart' ;
4
4
import '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' ;
5
8
import 'package:logging/logging.dart' ;
6
9
import 'package:postgres/postgres.dart' ;
10
+ import 'package:uuid/uuid.dart' ;
7
11
8
12
/// Global logger instance.
9
- final _log = Logger ('ht_api' );
13
+ final _log = Logger ('ht_api' );
10
14
11
15
/// 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
+ }
13
37
14
38
/// The main entry point for the server.
15
39
///
@@ -31,21 +55,111 @@ Future<HttpServer> run(Handler handler, InternetAddress ip, int port) async {
31
55
32
56
// 2. Establish Database Connection
33
57
_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
+
34
69
_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),
37
80
);
38
81
_log.info ('PostgreSQL database connection established.' );
39
82
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,
43
149
ip,
44
150
port,
45
- onShutdown: () async {
46
- _log.info ('Server shutting down. Closing database connection...' );
47
- await _connection.close ();
48
- _log.info ('Database connection closed.' );
49
- },
50
151
);
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